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)
945 /* depending on type */
951 /* PENDING: for re-target */
954 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
956 else if (offset == 0)
958 tsprintf (s, "%s", aop->aopu.aop_immd);
962 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
964 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
968 value *val = aop->aopu.aop_lit;
969 /* if it is a float then it gets tricky */
970 /* otherwise it is fairly simple */
971 if (!IS_FLOAT (val->type))
973 unsigned long v = (unsigned long) floatFromVal (val);
979 else if (offset == 0)
985 wassertl(0, "Encountered an invalid offset while fetching a literal");
989 tsprintf (buffer, "!immedword", v);
991 tsprintf (buffer, "!constword", v);
993 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
999 convertFloat (&f, floatFromVal (val));
1001 tsprintf (buffer, "!immedword", f.w[offset / 2]);
1003 tsprintf (buffer, "!constword", f.w[offset / 2]);
1004 rs = Safe_calloc (1, strlen (buffer) + 1);
1005 return strcpy (rs, buffer);
1014 aopGetWord (asmop * aop, int offset)
1016 return aopGetLitWordLong (aop, offset, TRUE);
1020 isPtr (const char *s)
1022 if (!strcmp (s, "hl"))
1024 if (!strcmp (s, "ix"))
1026 if (!strcmp (s, "iy"))
1032 adjustPair (const char *pair, int *pold, int new)
1038 emit2 ("inc %s", pair);
1043 emit2 ("dec %s", pair);
1051 spillPair (PAIR_HL);
1052 spillPair (PAIR_IY);
1056 requiresHL (asmop * aop)
1072 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1074 const char *l, *base;
1075 const char *pair = _pairs[pairId].name;
1076 l = aopGetLitWordLong (left, offset, FALSE);
1077 base = aopGetLitWordLong (left, 0, FALSE);
1078 wassert (l && pair && base);
1082 if (pairId == PAIR_HL || pairId == PAIR_IY)
1084 if (_G.pairs[pairId].last_type == left->type)
1086 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1088 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1090 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1093 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1100 _G.pairs[pairId].last_type = left->type;
1101 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1102 _G.pairs[pairId].offset = offset;
1104 /* Both a lit on the right and a true symbol on the left */
1105 emit2 ("ld %s,!hashedstr", pair, l);
1109 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1111 /* if this is remateriazable */
1112 if (isLitWord (aop)) {
1113 fetchLitPair (pairId, aop, offset);
1116 /* we need to get it byte by byte */
1117 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1118 aopGet (aop, offset, FALSE);
1119 switch (aop->size - offset) {
1121 emit2 ("ld l,!*hl");
1122 emit2 ("ld h,!immedbyte", 0);
1125 // PENDING: Requires that you are only fetching two bytes.
1128 emit2 ("ld h,!*hl");
1132 wassertl (0, "Attempted to fetch too much data into HL");
1136 else if (IS_Z80 && aop->type == AOP_IY) {
1137 /* Instead of fetching relative to IY, just grab directly
1138 from the address IY refers to */
1139 char *l = aopGetLitWordLong (aop, offset, FALSE);
1141 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1143 if (aop->size < 2) {
1144 emit2("ld %s,!zero", _pairs[pairId].h);
1148 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1149 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1151 /* PENDING: check? */
1152 if (pairId == PAIR_HL)
1153 spillPair (PAIR_HL);
1158 fetchPair (PAIR_ID pairId, asmop * aop)
1160 fetchPairLong (pairId, aop, 0);
1164 fetchHL (asmop * aop)
1166 fetchPair (PAIR_HL, aop);
1170 setupPairFromSP (PAIR_ID id, int offset)
1172 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1174 if (offset < INT8MIN || offset > INT8MAX)
1176 emit2 ("ld hl,!immedword", offset);
1177 emit2 ("add hl,sp");
1181 emit2 ("!ldahlsp", offset);
1186 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1191 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1192 fetchLitPair (pairId, aop, 0);
1196 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1198 fetchLitPair (pairId, aop, offset);
1199 _G.pairs[pairId].offset = offset;
1203 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1204 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1207 int offset = aop->aopu.aop_stk + _G.stack.offset;
1209 if (_G.pairs[pairId].last_type == aop->type &&
1210 _G.pairs[pairId].offset == offset)
1216 /* PENDING: Do this better. */
1217 sprintf (buffer, "%d", offset + _G.stack.pushed);
1218 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1219 emit2 ("add %s,sp", _pairs[pairId].name);
1220 _G.pairs[pairId].last_type = aop->type;
1221 _G.pairs[pairId].offset = offset;
1228 /* Doesnt include _G.stack.pushed */
1229 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1230 if (aop->aopu.aop_stk > 0)
1232 abso += _G.stack.param_offset;
1234 assert (pairId == PAIR_HL);
1235 /* In some cases we can still inc or dec hl */
1236 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1238 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1242 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1244 _G.pairs[pairId].offset = abso;
1249 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1255 _G.pairs[pairId].last_type = aop->type;
1261 emit2 ("!tlabeldef", key);
1265 /*-----------------------------------------------------------------*/
1266 /* aopGet - for fetching value of the aop */
1267 /*-----------------------------------------------------------------*/
1269 aopGet (asmop * aop, int offset, bool bit16)
1273 /* offset is greater than size then zero */
1274 /* PENDING: this seems a bit screwed in some pointer cases. */
1275 if (offset > (aop->size - 1) &&
1276 aop->type != AOP_LIT)
1278 tsprintf (s, "!zero");
1279 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1282 /* depending on type */
1286 /* PENDING: re-target */
1288 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1293 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1296 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1299 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1302 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1305 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1309 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1312 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1316 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1319 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1322 return aop->aopu.aop_reg[offset]->name;
1326 setupPair (PAIR_HL, aop, offset);
1327 tsprintf (s, "!*hl");
1329 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1333 setupPair (PAIR_IY, aop, offset);
1334 tsprintf (s, "!*iyx", offset);
1336 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1340 setupPair (PAIR_IY, aop, offset);
1341 tsprintf (s, "!*iyx", offset, offset);
1343 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1348 setupPair (PAIR_HL, aop, offset);
1349 tsprintf (s, "!*hl");
1353 if (aop->aopu.aop_stk >= 0)
1354 offset += _G.stack.param_offset;
1355 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1358 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1361 wassertl (0, "Tried to fetch from a bit variable");
1370 tsprintf(s, "!zero");
1371 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1375 wassert (offset < 2);
1376 return aop->aopu.aop_str[offset];
1379 return aopLiteral (aop->aopu.aop_lit, offset);
1383 unsigned long v = aop->aopu.aop_simplelit;
1386 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1388 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1392 return aop->aopu.aop_str[offset];
1395 setupPair (aop->aopu.aop_pairId, aop, offset);
1396 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1398 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1403 wassertl (0, "aopget got unsupported aop->type");
1408 isRegString (const char *s)
1410 if (!strcmp (s, "b") ||
1422 isConstant (const char *s)
1424 /* This is a bit of a hack... */
1425 return (*s == '#' || *s == '$');
1429 canAssignToPtr (const char *s)
1431 if (isRegString (s))
1438 /*-----------------------------------------------------------------*/
1439 /* aopPut - puts a string for a aop */
1440 /*-----------------------------------------------------------------*/
1442 aopPut (asmop * aop, const char *s, int offset)
1446 if (aop->size && offset > (aop->size - 1))
1448 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1449 "aopPut got offset > aop->size");
1454 tsprintf(buffer2, s);
1457 /* will assign value to value */
1458 /* depending on where it is ofcourse */
1464 if (strcmp (s, "a"))
1465 emit2 ("ld a,%s", s);
1466 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1471 if (strcmp (s, "a"))
1472 emit2 ("ld a,%s", s);
1473 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1477 if (!strcmp (s, "!*hl"))
1478 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1481 aop->aopu.aop_reg[offset]->name, s);
1486 if (!canAssignToPtr (s))
1488 emit2 ("ld a,%s", s);
1489 setupPair (PAIR_IY, aop, offset);
1490 emit2 ("ld !*iyx,a", offset);
1494 setupPair (PAIR_IY, aop, offset);
1495 emit2 ("ld !*iyx,%s", offset, s);
1501 /* PENDING: for re-target */
1502 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1504 emit2 ("ld a,!*hl");
1507 setupPair (PAIR_HL, aop, offset);
1509 emit2 ("ld !*hl,%s", s);
1514 if (!canAssignToPtr (s))
1516 emit2 ("ld a,%s", s);
1517 setupPair (PAIR_IY, aop, offset);
1518 emit2 ("ld !*iyx,a", offset);
1522 setupPair (PAIR_IY, aop, offset);
1523 emit2 ("ld !*iyx,%s", offset, s);
1530 /* PENDING: re-target */
1531 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1533 emit2 ("ld a,!*hl");
1536 setupPair (PAIR_HL, aop, offset);
1537 if (!canAssignToPtr (s))
1539 emit2 ("ld a,%s", s);
1540 emit2 ("ld !*hl,a");
1543 emit2 ("ld !*hl,%s", s);
1547 if (aop->aopu.aop_stk >= 0)
1548 offset += _G.stack.param_offset;
1549 if (!canAssignToPtr (s))
1551 emit2 ("ld a,%s", s);
1552 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1555 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1560 /* if bit variable */
1561 if (!aop->aopu.aop_dir)
1568 /* In bit space but not in C - cant happen */
1569 wassertl (0, "Tried to write into a bit variable");
1575 if (strcmp (aop->aopu.aop_str[offset], s))
1577 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1583 if (!offset && (strcmp (s, "acc") == 0))
1587 wassertl (0, "Tried to access past the end of A");
1591 if (strcmp (aop->aopu.aop_str[offset], s))
1592 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1597 wassert (offset < 2);
1598 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1602 setupPair (aop->aopu.aop_pairId, aop, offset);
1603 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1607 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1608 "aopPut got unsupported aop->type");
1613 #define AOP(op) op->aop
1614 #define AOP_TYPE(op) AOP(op)->type
1615 #define AOP_SIZE(op) AOP(op)->size
1616 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1619 commitPair (asmop * aop, PAIR_ID id)
1621 /* PENDING: Verify this. */
1622 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1626 aopPut (aop, "a", 0);
1627 aopPut (aop, "d", 1);
1632 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1634 char *l = aopGetLitWordLong (aop, 0, FALSE);
1637 emit2 ("ld (%s),%s", l, _pairs[id].name);
1641 aopPut (aop, _pairs[id].l, 0);
1642 aopPut (aop, _pairs[id].h, 1);
1647 /*-----------------------------------------------------------------*/
1648 /* getDataSize - get the operand data size */
1649 /*-----------------------------------------------------------------*/
1651 getDataSize (operand * op)
1654 size = AOP_SIZE (op);
1658 wassertl (0, "Somehow got a three byte data pointer");
1663 /*-----------------------------------------------------------------*/
1664 /* movLeft2Result - move byte from left to result */
1665 /*-----------------------------------------------------------------*/
1667 movLeft2Result (operand * left, int offl,
1668 operand * result, int offr, int sign)
1672 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1674 l = aopGet (AOP (left), offl, FALSE);
1678 aopPut (AOP (result), l, offr);
1682 if (getDataSize (left) == offl + 1)
1684 emit2 ("ld a,%s", l);
1685 aopPut (AOP (result), "a", offr);
1692 movLeft2ResultLong (operand * left, int offl,
1693 operand * result, int offr, int sign,
1698 movLeft2Result (left, offl, result, offr, sign);
1702 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1703 wassertl (size == 2, "Only implemented for two bytes or one");
1705 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1707 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1708 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1713 movLeft2Result (left, offl, result, offr, sign);
1714 movLeft2Result (left, offl+1, result, offr+1, sign);
1719 /** Put Acc into a register set
1722 outAcc (operand * result)
1725 size = getDataSize (result);
1728 aopPut (AOP (result), "a", 0);
1731 /* unsigned or positive */
1734 aopPut (AOP (result), "!zero", offset++);
1739 /** Take the value in carry and put it into a register
1742 outBitCLong (operand * result, bool swap_sense)
1744 /* if the result is bit */
1745 if (AOP_TYPE (result) == AOP_CRY)
1747 wassertl (0, "Tried to write carry to a bit");
1751 emit2 ("ld a,!zero");
1754 emit2 ("xor a,!immedbyte", 1);
1760 outBitC (operand * result)
1762 outBitCLong (result, FALSE);
1765 /*-----------------------------------------------------------------*/
1766 /* toBoolean - emit code for orl a,operator(sizeop) */
1767 /*-----------------------------------------------------------------*/
1769 _toBoolean (operand * oper)
1771 int size = AOP_SIZE (oper);
1775 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1778 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1782 if (AOP (oper)->type != AOP_ACC)
1785 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1790 /*-----------------------------------------------------------------*/
1791 /* genNot - generate code for ! operation */
1792 /*-----------------------------------------------------------------*/
1796 sym_link *optype = operandType (IC_LEFT (ic));
1798 /* assign asmOps to operand & result */
1799 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1800 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1802 /* if in bit space then a special case */
1803 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1805 wassertl (0, "Tried to negate a bit");
1808 /* if type float then do float */
1809 if (IS_FLOAT (optype))
1811 wassertl (0, "Tried to negate a float");
1814 _toBoolean (IC_LEFT (ic));
1819 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1820 emit2 ("sub a,!one");
1821 outBitC (IC_RESULT (ic));
1823 /* release the aops */
1824 freeAsmop (IC_LEFT (ic), NULL, ic);
1825 freeAsmop (IC_RESULT (ic), NULL, ic);
1828 /*-----------------------------------------------------------------*/
1829 /* genCpl - generate code for complement */
1830 /*-----------------------------------------------------------------*/
1838 /* assign asmOps to operand & result */
1839 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1840 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1842 /* if both are in bit space then
1844 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1845 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1847 wassertl (0, "Left and the result are in bit space");
1850 size = AOP_SIZE (IC_RESULT (ic));
1853 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1856 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1859 /* release the aops */
1860 freeAsmop (IC_LEFT (ic), NULL, ic);
1861 freeAsmop (IC_RESULT (ic), NULL, ic);
1865 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1872 store de into result
1877 store de into result
1879 const char *first = isAdd ? "add" : "sub";
1880 const char *later = isAdd ? "adc" : "sbc";
1882 wassertl (IS_GB, "Code is only relevent to the gbz80");
1883 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1885 fetchPair (PAIR_DE, left);
1888 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1891 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1894 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
1895 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
1897 fetchPairLong (PAIR_DE, left, MSB24);
1898 aopGet (right, MSB24, FALSE);
1902 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
1905 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
1907 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
1908 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
1912 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
1914 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
1917 /*-----------------------------------------------------------------*/
1918 /* genUminus - unary minus code generation */
1919 /*-----------------------------------------------------------------*/
1921 genUminus (iCode * ic)
1924 sym_link *optype, *rtype;
1927 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1928 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1930 /* if both in bit space then special
1932 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1933 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1935 wassertl (0, "Left and right are in bit space");
1939 optype = operandType (IC_LEFT (ic));
1940 rtype = operandType (IC_RESULT (ic));
1942 /* if float then do float stuff */
1943 if (IS_FLOAT (optype))
1945 wassertl (0, "Tried to do a unary minus on a float");
1949 /* otherwise subtract from zero */
1950 size = AOP_SIZE (IC_LEFT (ic));
1952 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1954 /* Create a new asmop with value zero */
1955 asmop *azero = newAsmop (AOP_SIMPLELIT);
1956 azero->aopu.aop_simplelit = 0;
1958 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1966 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1967 emit2 ("ld a,!zero");
1968 emit2 ("sbc a,%s", l);
1969 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1972 /* if any remaining bytes in the result */
1973 /* we just need to propagate the sign */
1974 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1979 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1983 /* release the aops */
1984 freeAsmop (IC_LEFT (ic), NULL, ic);
1985 freeAsmop (IC_RESULT (ic), NULL, ic);
1988 /*-----------------------------------------------------------------*/
1989 /* assignResultValue - */
1990 /*-----------------------------------------------------------------*/
1992 assignResultValue (operand * oper)
1994 int size = AOP_SIZE (oper);
1997 wassertl (size <= 4, "Got a result that is bigger than four bytes");
1998 topInA = requiresHL (AOP (oper));
2000 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2002 /* We do it the hard way here. */
2004 aopPut (AOP (oper), _fReturn[0], 0);
2005 aopPut (AOP (oper), _fReturn[1], 1);
2007 aopPut (AOP (oper), _fReturn[0], 2);
2008 aopPut (AOP (oper), _fReturn[1], 3);
2014 aopPut (AOP (oper), _fReturn[size], size);
2019 /** Simple restore that doesn't take into account what is used in the
2023 _restoreRegsAfterCall(void)
2025 if (_G.stack.pushedDE)
2028 _G.stack.pushedDE = FALSE;
2030 if (_G.stack.pushedBC)
2033 _G.stack.pushedBC = FALSE;
2035 _G.saves.saved = FALSE;
2039 _saveRegsForCall(iCode *ic, int sendSetSize)
2042 o Stack parameters are pushed before this function enters
2043 o DE and BC may be used in this function.
2044 o HL and DE may be used to return the result.
2045 o HL and DE may be used to send variables.
2046 o DE and BC may be used to store the result value.
2047 o HL may be used in computing the sent value of DE
2048 o The iPushes for other parameters occur before any addSets
2050 Logic: (to be run inside the first iPush or if none, before sending)
2051 o Compute if DE and/or BC are in use over the call
2052 o Compute if DE is used in the send set
2053 o Compute if DE and/or BC are used to hold the result value
2054 o If (DE is used, or in the send set) and is not used in the result, push.
2055 o If BC is used and is not in the result, push
2057 o If DE is used in the send set, fetch
2058 o If HL is used in the send set, fetch
2062 if (_G.saves.saved == FALSE) {
2063 bool deInUse, bcInUse;
2065 bool bcInRet = FALSE, deInRet = FALSE;
2068 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2070 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2071 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2073 deSending = (sendSetSize > 1);
2075 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2077 if (bcInUse && bcInRet == FALSE) {
2079 _G.stack.pushedBC = TRUE;
2081 if (deInUse && deInRet == FALSE) {
2083 _G.stack.pushedDE = TRUE;
2086 _G.saves.saved = TRUE;
2089 /* Already saved. */
2093 /*-----------------------------------------------------------------*/
2094 /* genIpush - genrate code for pushing this gets a little complex */
2095 /*-----------------------------------------------------------------*/
2097 genIpush (iCode * ic)
2099 int size, offset = 0;
2102 /* if this is not a parm push : ie. it is spill push
2103 and spill push is always done on the local stack */
2106 wassertl(0, "Encountered an unsupported spill push.");
2110 if (_G.saves.saved == FALSE) {
2111 /* Caller saves, and this is the first iPush. */
2112 /* Scan ahead until we find the function that we are pushing parameters to.
2113 Count the number of addSets on the way to figure out what registers
2114 are used in the send set.
2117 iCode *walk = ic->next;
2120 if (walk->op == SEND) {
2123 else if (walk->op == CALL || walk->op == PCALL) {
2132 _saveRegsForCall(walk, nAddSets);
2135 /* Already saved by another iPush. */
2138 /* then do the push */
2139 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2141 size = AOP_SIZE (IC_LEFT (ic));
2143 if (isPair (AOP (IC_LEFT (ic))))
2145 _G.stack.pushed += 2;
2146 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2152 fetchHL (AOP (IC_LEFT (ic)));
2154 spillPair (PAIR_HL);
2155 _G.stack.pushed += 2;
2160 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2162 spillPair (PAIR_HL);
2163 _G.stack.pushed += 2;
2164 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2166 spillPair (PAIR_HL);
2167 _G.stack.pushed += 2;
2173 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2175 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2177 emit2 ("ld a,(%s)", l);
2181 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2182 emit2 ("ld a,%s", l);
2190 freeAsmop (IC_LEFT (ic), NULL, ic);
2193 /*-----------------------------------------------------------------*/
2194 /* genIpop - recover the registers: can happen only for spilling */
2195 /*-----------------------------------------------------------------*/
2197 genIpop (iCode * ic)
2202 /* if the temp was not pushed then */
2203 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2206 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2207 size = AOP_SIZE (IC_LEFT (ic));
2208 offset = (size - 1);
2209 if (isPair (AOP (IC_LEFT (ic))))
2211 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2219 spillPair (PAIR_HL);
2220 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2224 freeAsmop (IC_LEFT (ic), NULL, ic);
2227 /* This is quite unfortunate */
2229 setArea (int inHome)
2232 static int lastArea = 0;
2234 if (_G.in_home != inHome) {
2236 const char *sz = port->mem.code_name;
2237 port->mem.code_name = "HOME";
2238 emit2("!area", CODE_NAME);
2239 port->mem.code_name = sz;
2242 emit2("!area", CODE_NAME); */
2243 _G.in_home = inHome;
2254 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2258 symbol *sym = OP_SYMBOL (op);
2260 if (sym->isspilt || sym->nRegs == 0)
2263 aopOp (op, ic, FALSE, FALSE);
2266 if (aop->type == AOP_REG)
2269 for (i = 0; i < aop->size; i++)
2271 if (pairId == PAIR_DE)
2273 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2274 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2276 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2279 else if (pairId == PAIR_BC)
2281 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2282 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2284 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2294 freeAsmop (IC_LEFT (ic), NULL, ic);
2298 /** Emit the code for a call statement
2301 emitCall (iCode * ic, bool ispcall)
2303 sym_link *dtype = operandType (IC_LEFT (ic));
2305 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2307 /* if caller saves & we have not saved then */
2313 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2315 /* if send set is not empty then assign */
2320 int nSend = elementsInSet(_G.sendSet);
2321 bool swapped = FALSE;
2323 int _z80_sendOrder[] = {
2328 /* Check if the parameters are swapped. If so route through hl instead. */
2329 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2331 sic = setFirstItem(_G.sendSet);
2332 sic = setNextItem(_G.sendSet);
2334 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2335 /* The second send value is loaded from one the one that holds the first
2336 send, i.e. it is overwritten. */
2337 /* Cache the first in HL, and load the second from HL instead. */
2338 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2339 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2345 for (sic = setFirstItem (_G.sendSet); sic;
2346 sic = setNextItem (_G.sendSet))
2349 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2351 size = AOP_SIZE (IC_LEFT (sic));
2352 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2353 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2355 // PENDING: Mild hack
2356 if (swapped == TRUE && send == 1) {
2358 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2361 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2363 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2366 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2370 freeAsmop (IC_LEFT (sic), NULL, sic);
2377 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2379 werror (W_INDIR_BANKED);
2381 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2383 if (isLitWord (AOP (IC_LEFT (ic))))
2385 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2389 symbol *rlbl = newiTempLabel (NULL);
2390 spillPair (PAIR_HL);
2391 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2393 _G.stack.pushed += 2;
2395 fetchHL (AOP (IC_LEFT (ic)));
2397 emit2 ("!tlabeldef", (rlbl->key + 100));
2398 _G.stack.pushed -= 2;
2400 freeAsmop (IC_LEFT (ic), NULL, ic);
2404 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2405 OP_SYMBOL (IC_LEFT (ic))->rname :
2406 OP_SYMBOL (IC_LEFT (ic))->name;
2407 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2409 emit2 ("call banked_call");
2410 emit2 ("!dws", name);
2411 emit2 ("!dw !bankimmeds", name);
2416 emit2 ("call %s", name);
2421 /* Mark the regsiters as restored. */
2422 _G.saves.saved = FALSE;
2424 /* if we need assign a result value */
2425 if ((IS_ITEMP (IC_RESULT (ic)) &&
2426 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2427 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2428 IS_TRUE_SYMOP (IC_RESULT (ic)))
2431 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2433 assignResultValue (IC_RESULT (ic));
2435 freeAsmop (IC_RESULT (ic), NULL, ic);
2438 /* adjust the stack for parameters if required */
2441 int i = ic->parmBytes;
2443 _G.stack.pushed -= i;
2446 emit2 ("!ldaspsp", i);
2453 emit2 ("ld hl,#%d", i);
2454 emit2 ("add hl,sp");
2472 if (_G.stack.pushedDE)
2474 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2475 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2477 if (dInUse && eInUse)
2493 wassertl (0, "Neither D or E were in use but it was pushed.");
2495 _G.stack.pushedDE = FALSE;
2498 if (_G.stack.pushedBC)
2500 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2501 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2503 // If both B and C are used in the return value, then we won't get
2505 if (bInUse && cInUse)
2521 wassertl (0, "Neither B or C were in use but it was pushed.");
2523 _G.stack.pushedBC = FALSE;
2527 /*-----------------------------------------------------------------*/
2528 /* genCall - generates a call statement */
2529 /*-----------------------------------------------------------------*/
2531 genCall (iCode * ic)
2533 emitCall (ic, FALSE);
2536 /*-----------------------------------------------------------------*/
2537 /* genPcall - generates a call by pointer statement */
2538 /*-----------------------------------------------------------------*/
2540 genPcall (iCode * ic)
2542 emitCall (ic, TRUE);
2545 /*-----------------------------------------------------------------*/
2546 /* resultRemat - result is rematerializable */
2547 /*-----------------------------------------------------------------*/
2549 resultRemat (iCode * ic)
2551 if (SKIP_IC (ic) || ic->op == IFX)
2554 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2556 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2557 if (sym->remat && !POINTER_SET (ic))
2564 extern set *publics;
2566 /*-----------------------------------------------------------------*/
2567 /* genFunction - generated code for function entry */
2568 /*-----------------------------------------------------------------*/
2570 genFunction (iCode * ic)
2572 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2576 bool bcInUse = FALSE;
2577 bool deInUse = FALSE;
2580 setArea (IFFUNC_NONBANKED (sym->type));
2582 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2585 _G.receiveOffset = 0;
2587 /* Record the last function name for debugging. */
2588 _G.lastFunctionName = sym->rname;
2590 /* Create the function header */
2591 emit2 ("!functionheader", sym->name);
2592 /* PENDING: portability. */
2593 emit2 ("__%s_start:", sym->rname);
2594 emit2 ("!functionlabeldef", sym->rname);
2596 if (options.profile)
2598 emit2 ("!profileenter");
2601 ftype = operandType (IC_LEFT (ic));
2603 /* if critical function then turn interrupts off */
2604 if (IFFUNC_ISCRITICAL (ftype))
2607 /* if this is an interrupt service routine then save all potentially used registers. */
2608 if (IFFUNC_ISISR (sym->type))
2613 /* PENDING: callee-save etc */
2615 _G.stack.param_offset = 0;
2618 /* Detect which registers are used. */
2622 for (i = 0; i < sym->regsUsed->size; i++)
2624 if (bitVectBitValue (sym->regsUsed, i))
2638 /* Other systems use DE as a temporary. */
2649 _G.stack.param_offset += 2;
2652 _G.stack.pushedBC = bcInUse;
2657 _G.stack.param_offset += 2;
2660 _G.stack.pushedDE = deInUse;
2663 /* adjust the stack for the function */
2664 _G.stack.last = sym->stack;
2666 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2667 emit2 ("!enterxl", sym->stack);
2668 else if (sym->stack)
2669 emit2 ("!enterx", sym->stack);
2672 _G.stack.offset = sym->stack;
2675 /*-----------------------------------------------------------------*/
2676 /* genEndFunction - generates epilogue for functions */
2677 /*-----------------------------------------------------------------*/
2679 genEndFunction (iCode * ic)
2681 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2683 if (IFFUNC_ISISR (sym->type))
2685 wassertl (0, "Tried to close an interrupt support function");
2689 if (IFFUNC_ISCRITICAL (sym->type))
2692 /* PENDING: calleeSave */
2694 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2696 emit2 ("!leavexl", _G.stack.offset);
2698 else if (_G.stack.offset)
2700 emit2 ("!leavex", _G.stack.offset);
2708 if (_G.stack.pushedDE)
2711 _G.stack.pushedDE = FALSE;
2714 if (_G.stack.pushedDE)
2717 _G.stack.pushedDE = FALSE;
2721 if (options.profile)
2723 emit2 ("!profileexit");
2727 /* Both baned and non-banked just ret */
2730 /* PENDING: portability. */
2731 emit2 ("__%s_end:", sym->rname);
2733 _G.flushStatics = 1;
2734 _G.stack.pushed = 0;
2735 _G.stack.offset = 0;
2738 /*-----------------------------------------------------------------*/
2739 /* genRet - generate code for return statement */
2740 /*-----------------------------------------------------------------*/
2745 /* Errk. This is a hack until I can figure out how
2746 to cause dehl to spill on a call */
2747 int size, offset = 0;
2749 /* if we have no return value then
2750 just generate the "ret" */
2754 /* we have something to return then
2755 move the return value into place */
2756 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2757 size = AOP_SIZE (IC_LEFT (ic));
2759 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2763 emit2 ("ld de,%s", l);
2767 emit2 ("ld hl,%s", l);
2772 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2774 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2775 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2781 l = aopGet (AOP (IC_LEFT (ic)), offset,
2783 if (strcmp (_fReturn[offset], l))
2784 emit2 ("ld %s,%s", _fReturn[offset++], l);
2788 freeAsmop (IC_LEFT (ic), NULL, ic);
2791 /* generate a jump to the return label
2792 if the next is not the return statement */
2793 if (!(ic->next && ic->next->op == LABEL &&
2794 IC_LABEL (ic->next) == returnLabel))
2796 emit2 ("jp !tlabel", returnLabel->key + 100);
2799 /*-----------------------------------------------------------------*/
2800 /* genLabel - generates a label */
2801 /*-----------------------------------------------------------------*/
2803 genLabel (iCode * ic)
2805 /* special case never generate */
2806 if (IC_LABEL (ic) == entryLabel)
2809 emitLabel (IC_LABEL (ic)->key + 100);
2812 /*-----------------------------------------------------------------*/
2813 /* genGoto - generates a ljmp */
2814 /*-----------------------------------------------------------------*/
2816 genGoto (iCode * ic)
2818 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2821 /*-----------------------------------------------------------------*/
2822 /* genPlusIncr :- does addition with increment if possible */
2823 /*-----------------------------------------------------------------*/
2825 genPlusIncr (iCode * ic)
2827 unsigned int icount;
2828 unsigned int size = getDataSize (IC_RESULT (ic));
2829 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2831 /* will try to generate an increment */
2832 /* if the right side is not a literal
2834 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2837 emitDebug ("; genPlusIncr");
2839 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2841 /* If result is a pair */
2842 if (resultId != PAIR_INVALID)
2844 if (isLitWord (AOP (IC_LEFT (ic))))
2846 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2849 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2851 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2852 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2858 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2862 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
2866 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2871 /* if the literal value of the right hand side
2872 is greater than 4 then it is not worth it */
2876 /* if increment 16 bits in register */
2877 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2883 symbol *tlbl = NULL;
2884 tlbl = newiTempLabel (NULL);
2887 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2890 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2893 emitLabel (tlbl->key + 100);
2897 /* if the sizes are greater than 1 then we cannot */
2898 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2899 AOP_SIZE (IC_LEFT (ic)) > 1)
2902 /* If the result is in a register then we can load then increment.
2904 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
2906 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
2909 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
2914 /* we can if the aops of the left & result match or
2915 if they are in registers and the registers are the
2917 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2921 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2929 /*-----------------------------------------------------------------*/
2930 /* outBitAcc - output a bit in acc */
2931 /*-----------------------------------------------------------------*/
2933 outBitAcc (operand * result)
2935 symbol *tlbl = newiTempLabel (NULL);
2936 /* if the result is a bit */
2937 if (AOP_TYPE (result) == AOP_CRY)
2939 wassertl (0, "Tried to write A into a bit");
2943 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2944 emit2 ("ld a,!one");
2945 emitLabel (tlbl->key + 100);
2951 couldDestroyCarry (asmop *aop)
2955 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
2964 shiftIntoPair (int idx, asmop *aop)
2966 PAIR_ID id = PAIR_INVALID;
2968 wassertl (IS_Z80, "Only implemented for the Z80");
2969 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
2981 wassertl (0, "Internal error - hit default case");
2984 emitDebug ("; Shift into pair idx %u", idx);
2988 setupPair (PAIR_HL, aop, 0);
2992 setupPair (PAIR_IY, aop, 0);
2994 emit2 ("pop %s", _pairs[id].name);
2997 aop->type = AOP_PAIRPTR;
2998 aop->aopu.aop_pairId = id;
2999 _G.pairs[id].offset = 0;
3000 _G.pairs[id].last_type = aop->type;
3004 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3006 wassert (left && right);
3010 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3012 shiftIntoPair (0, right);
3013 shiftIntoPair (1, result);
3015 else if (couldDestroyCarry (right))
3017 shiftIntoPair (0, right);
3019 else if (couldDestroyCarry (result))
3021 shiftIntoPair (0, result);
3030 /*-----------------------------------------------------------------*/
3031 /* genPlus - generates code for addition */
3032 /*-----------------------------------------------------------------*/
3034 genPlus (iCode * ic)
3036 int size, offset = 0;
3038 /* special cases :- */
3040 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3041 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3042 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3044 /* Swap the left and right operands if:
3046 if literal, literal on the right or
3047 if left requires ACC or right is already
3050 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3051 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3052 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3054 operand *t = IC_RIGHT (ic);
3055 IC_RIGHT (ic) = IC_LEFT (ic);
3059 /* if both left & right are in bit
3061 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3062 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3065 wassertl (0, "Tried to add two bits");
3068 /* if left in bit space & right literal */
3069 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3070 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3072 /* Can happen I guess */
3073 wassertl (0, "Tried to add a bit to a literal");
3076 /* if I can do an increment instead
3077 of add then GOOD for ME */
3078 if (genPlusIncr (ic) == TRUE)
3081 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3083 size = getDataSize (IC_RESULT (ic));
3085 /* Special case when left and right are constant */
3086 if (isPair (AOP (IC_RESULT (ic))))
3089 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3090 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3092 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3098 sprintf (buffer, "#(%s + %s)", left, right);
3099 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3104 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3106 /* Fetch into HL then do the add */
3107 spillPair (PAIR_HL);
3108 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3109 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3113 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD)
3115 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3116 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3118 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3123 ld hl,sp+n trashes C so we cant afford to do it during an
3124 add with stack based varibles. Worst case is:
3137 So you cant afford to load up hl if either left, right, or result
3138 is on the stack (*sigh*) The alt is:
3146 Combinations in here are:
3147 * If left or right are in bc then the loss is small - trap later
3148 * If the result is in bc then the loss is also small
3152 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3153 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3154 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3156 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3157 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3158 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3159 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3161 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3163 /* Swap left and right */
3164 operand *t = IC_RIGHT (ic);
3165 IC_RIGHT (ic) = IC_LEFT (ic);
3168 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3170 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3171 emit2 ("add hl,bc");
3175 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3176 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3177 emit2 ("add hl,de");
3179 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3185 /* Be paranoid on the GB with 4 byte variables due to how C
3186 can be trashed by lda hl,n(sp).
3188 _gbz80_emitAddSubLong (ic, TRUE);
3193 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3197 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3199 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3202 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3205 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3209 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3212 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3215 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3217 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3221 freeAsmop (IC_LEFT (ic), NULL, ic);
3222 freeAsmop (IC_RIGHT (ic), NULL, ic);
3223 freeAsmop (IC_RESULT (ic), NULL, ic);
3227 /*-----------------------------------------------------------------*/
3228 /* genMinusDec :- does subtraction with deccrement if possible */
3229 /*-----------------------------------------------------------------*/
3231 genMinusDec (iCode * ic)
3233 unsigned int icount;
3234 unsigned int size = getDataSize (IC_RESULT (ic));
3236 /* will try to generate an increment */
3237 /* if the right side is not a literal we cannot */
3238 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3241 /* if the literal value of the right hand side
3242 is greater than 4 then it is not worth it */
3243 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3246 size = getDataSize (IC_RESULT (ic));
3248 /* if decrement 16 bits in register */
3249 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3250 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3253 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3257 /* If result is a pair */
3258 if (isPair (AOP (IC_RESULT (ic))))
3260 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3262 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3266 /* if increment 16 bits in register */
3267 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3271 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3274 emit2 ("dec %s", _getTempPairName());
3277 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3283 /* if the sizes are greater than 1 then we cannot */
3284 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3285 AOP_SIZE (IC_LEFT (ic)) > 1)
3288 /* we can if the aops of the left & result match or if they are in
3289 registers and the registers are the same */
3290 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3293 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3300 /*-----------------------------------------------------------------*/
3301 /* genMinus - generates code for subtraction */
3302 /*-----------------------------------------------------------------*/
3304 genMinus (iCode * ic)
3306 int size, offset = 0;
3307 unsigned long lit = 0L;
3309 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3310 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3311 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3313 /* special cases :- */
3314 /* if both left & right are in bit space */
3315 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3316 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3318 wassertl (0, "Tried to subtract two bits");
3322 /* if I can do an decrement instead of subtract then GOOD for ME */
3323 if (genMinusDec (ic) == TRUE)
3326 size = getDataSize (IC_RESULT (ic));
3328 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3333 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3337 /* Same logic as genPlus */
3340 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3341 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3342 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3344 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3345 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3346 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3347 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3349 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3350 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3352 if (left == PAIR_INVALID && right == PAIR_INVALID)
3357 else if (right == PAIR_INVALID)
3359 else if (left == PAIR_INVALID)
3362 fetchPair (left, AOP (IC_LEFT (ic)));
3363 /* Order is important. Right may be HL */
3364 fetchPair (right, AOP (IC_RIGHT (ic)));
3366 emit2 ("ld a,%s", _pairs[left].l);
3367 emit2 ("sub a,%s", _pairs[right].l);
3369 emit2 ("ld a,%s", _pairs[left].h);
3370 emit2 ("sbc a,%s", _pairs[right].h);
3372 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3374 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3376 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3382 /* Be paranoid on the GB with 4 byte variables due to how C
3383 can be trashed by lda hl,n(sp).
3385 _gbz80_emitAddSubLong (ic, FALSE);
3390 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3392 /* if literal, add a,#-lit, else normal subb */
3395 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3396 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3400 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3403 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3407 /* first add without previous c */
3409 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3411 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3413 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3416 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3417 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3418 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3420 wassertl (0, "Tried to subtract on a long pointer");
3424 freeAsmop (IC_LEFT (ic), NULL, ic);
3425 freeAsmop (IC_RIGHT (ic), NULL, ic);
3426 freeAsmop (IC_RESULT (ic), NULL, ic);
3429 /*-----------------------------------------------------------------*/
3430 /* genMult - generates code for multiplication */
3431 /*-----------------------------------------------------------------*/
3433 genMult (iCode * ic)
3437 /* If true then the final operation should be a subtract */
3438 bool active = FALSE;
3440 /* Shouldn't occur - all done through function calls */
3441 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3442 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3443 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3445 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3446 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3447 AOP_SIZE (IC_RESULT (ic)) > 2)
3449 wassertl (0, "Multiplication is handled through support function calls");
3452 /* Swap left and right such that right is a literal */
3453 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3455 operand *t = IC_RIGHT (ic);
3456 IC_RIGHT (ic) = IC_LEFT (ic);
3460 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3462 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3463 // wassertl (val > 0, "Multiply must be positive");
3464 wassertl (val != 1, "Can't multiply by 1");
3470 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3472 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3480 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3485 /* Fully unroled version of mul.s. Not the most efficient.
3487 for (count = 0; count < 16; count++)
3489 if (count != 0 && active)
3491 emit2 ("add hl,hl");
3495 if (active == FALSE)
3502 emit2 ("add hl,de");
3516 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3518 freeAsmop (IC_LEFT (ic), NULL, ic);
3519 freeAsmop (IC_RIGHT (ic), NULL, ic);
3520 freeAsmop (IC_RESULT (ic), NULL, ic);
3523 /*-----------------------------------------------------------------*/
3524 /* genDiv - generates code for division */
3525 /*-----------------------------------------------------------------*/
3529 /* Shouldn't occur - all done through function calls */
3530 wassertl (0, "Division is handled through support function calls");
3533 /*-----------------------------------------------------------------*/
3534 /* genMod - generates code for division */
3535 /*-----------------------------------------------------------------*/
3539 /* Shouldn't occur - all done through function calls */
3543 /*-----------------------------------------------------------------*/
3544 /* genIfxJump :- will create a jump depending on the ifx */
3545 /*-----------------------------------------------------------------*/
3547 genIfxJump (iCode * ic, char *jval)
3552 /* if true label then we jump if condition
3556 jlbl = IC_TRUE (ic);
3557 if (!strcmp (jval, "a"))
3561 else if (!strcmp (jval, "c"))
3565 else if (!strcmp (jval, "nc"))
3571 /* The buffer contains the bit on A that we should test */
3577 /* false label is present */
3578 jlbl = IC_FALSE (ic);
3579 if (!strcmp (jval, "a"))
3583 else if (!strcmp (jval, "c"))
3587 else if (!strcmp (jval, "nc"))
3593 /* The buffer contains the bit on A that we should test */
3597 /* Z80 can do a conditional long jump */
3598 if (!strcmp (jval, "a"))
3602 else if (!strcmp (jval, "c"))
3605 else if (!strcmp (jval, "nc"))
3610 emit2 ("bit %s,a", jval);
3612 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3614 /* mark the icode as generated */
3620 _getPairIdName (PAIR_ID id)
3622 return _pairs[id].name;
3626 /** Generic compare for > or <
3629 genCmp (operand * left, operand * right,
3630 operand * result, iCode * ifx, int sign)
3632 int size, offset = 0;
3633 unsigned long lit = 0L;
3634 bool swap_sense = FALSE;
3636 /* if left & right are bit variables */
3637 if (AOP_TYPE (left) == AOP_CRY &&
3638 AOP_TYPE (right) == AOP_CRY)
3640 /* Cant happen on the Z80 */
3641 wassertl (0, "Tried to compare two bits");
3645 /* subtract right from left if at the
3646 end the carry flag is set then we know that
3647 left is greater than right */
3648 size = max (AOP_SIZE (left), AOP_SIZE (right));
3650 /* if unsigned char cmp with lit, just compare */
3652 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3654 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3657 emit2 ("xor a,!immedbyte", 0x80);
3658 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3661 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3663 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3665 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3666 // Pull left into DE and right into HL
3667 aopGet (AOP(left), LSB, FALSE);
3670 aopGet (AOP(right), LSB, FALSE);
3674 if (size == 0 && sign)
3676 // Highest byte when signed needs the bits flipped
3679 emit2 ("ld a,(de)");
3680 emit2 ("xor #0x80");
3682 emit2 ("ld a,(hl)");
3683 emit2 ("xor #0x80");
3687 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3691 emit2 ("ld a,(de)");
3692 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3702 spillPair (PAIR_HL);
3704 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3706 setupPair (PAIR_HL, AOP (left), 0);
3707 aopGet (AOP(right), LSB, FALSE);
3711 if (size == 0 && sign)
3713 // Highest byte when signed needs the bits flipped
3716 emit2 ("ld a,(hl)");
3717 emit2 ("xor #0x80");
3719 emit2 ("ld a,%d(iy)", offset);
3720 emit2 ("xor #0x80");
3724 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3728 emit2 ("ld a,(hl)");
3729 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3738 spillPair (PAIR_HL);
3739 spillPair (PAIR_IY);
3743 if (AOP_TYPE (right) == AOP_LIT)
3745 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3746 /* optimize if(x < 0) or if(x >= 0) */
3751 /* No sign so it's always false */
3756 /* Just load in the top most bit */
3757 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3758 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3760 genIfxJump (ifx, "7");
3772 /* First setup h and l contaning the top most bytes XORed */
3773 bool fDidXor = FALSE;
3774 if (AOP_TYPE (left) == AOP_LIT)
3776 unsigned long lit = (unsigned long)
3777 floatFromVal (AOP (left)->aopu.aop_lit);
3778 emit2 ("ld %s,!immedbyte", _fTmp[0],
3779 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3783 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3784 emit2 ("xor a,!immedbyte", 0x80);
3785 emit2 ("ld %s,a", _fTmp[0]);
3788 if (AOP_TYPE (right) == AOP_LIT)
3790 unsigned long lit = (unsigned long)
3791 floatFromVal (AOP (right)->aopu.aop_lit);
3792 emit2 ("ld %s,!immedbyte", _fTmp[1],
3793 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3797 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3798 emit2 ("xor a,!immedbyte", 0x80);
3799 emit2 ("ld %s,a", _fTmp[1]);
3805 /* Do a long subtract */
3808 _moveA (aopGet (AOP (left), offset, FALSE));
3810 if (sign && size == 0)
3812 emit2 ("ld a,%s", _fTmp[0]);
3813 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3817 /* Subtract through, propagating the carry */
3818 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3826 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3828 outBitCLong (result, swap_sense);
3832 /* if the result is used in the next
3833 ifx conditional branch then generate
3834 code a little differently */
3836 genIfxJump (ifx, swap_sense ? "nc" : "c");
3838 outBitCLong (result, swap_sense);
3839 /* leave the result in acc */
3843 /*-----------------------------------------------------------------*/
3844 /* genCmpGt :- greater than comparison */
3845 /*-----------------------------------------------------------------*/
3847 genCmpGt (iCode * ic, iCode * ifx)
3849 operand *left, *right, *result;
3850 sym_link *letype, *retype;
3853 left = IC_LEFT (ic);
3854 right = IC_RIGHT (ic);
3855 result = IC_RESULT (ic);
3857 letype = getSpec (operandType (left));
3858 retype = getSpec (operandType (right));
3859 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3860 /* assign the amsops */
3861 aopOp (left, ic, FALSE, FALSE);
3862 aopOp (right, ic, FALSE, FALSE);
3863 aopOp (result, ic, TRUE, FALSE);
3865 genCmp (right, left, result, ifx, sign);
3867 freeAsmop (left, NULL, ic);
3868 freeAsmop (right, NULL, ic);
3869 freeAsmop (result, NULL, ic);
3872 /*-----------------------------------------------------------------*/
3873 /* genCmpLt - less than comparisons */
3874 /*-----------------------------------------------------------------*/
3876 genCmpLt (iCode * ic, iCode * ifx)
3878 operand *left, *right, *result;
3879 sym_link *letype, *retype;
3882 left = IC_LEFT (ic);
3883 right = IC_RIGHT (ic);
3884 result = IC_RESULT (ic);
3886 letype = getSpec (operandType (left));
3887 retype = getSpec (operandType (right));
3888 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3890 /* assign the amsops */
3891 aopOp (left, ic, FALSE, FALSE);
3892 aopOp (right, ic, FALSE, FALSE);
3893 aopOp (result, ic, TRUE, FALSE);
3895 genCmp (left, right, result, ifx, sign);
3897 freeAsmop (left, NULL, ic);
3898 freeAsmop (right, NULL, ic);
3899 freeAsmop (result, NULL, ic);
3902 /*-----------------------------------------------------------------*/
3903 /* gencjneshort - compare and jump if not equal */
3904 /*-----------------------------------------------------------------*/
3906 gencjneshort (operand * left, operand * right, symbol * lbl)
3908 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3910 unsigned long lit = 0L;
3912 /* Swap the left and right if it makes the computation easier */
3913 if (AOP_TYPE (left) == AOP_LIT)
3920 if (AOP_TYPE (right) == AOP_LIT)
3921 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3923 /* if the right side is a literal then anything goes */
3924 if (AOP_TYPE (right) == AOP_LIT &&
3925 AOP_TYPE (left) != AOP_DIR)
3929 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3934 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
3941 emit2 ("jp nz,!tlabel", lbl->key + 100);
3947 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3948 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3951 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3952 emit2 ("jp nz,!tlabel", lbl->key + 100);
3957 /* if the right side is in a register or in direct space or
3958 if the left is a pointer register & right is not */
3959 else if (AOP_TYPE (right) == AOP_REG ||
3960 AOP_TYPE (right) == AOP_DIR ||
3961 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3965 _moveA (aopGet (AOP (left), offset, FALSE));
3966 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3967 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3969 emit2 ("jp nz,!tlabel", lbl->key + 100);
3972 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3973 emit2 ("jp nz,!tlabel", lbl->key + 100);
3980 /* right is a pointer reg need both a & b */
3981 /* PENDING: is this required? */
3984 _moveA (aopGet (AOP (right), offset, FALSE));
3985 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3986 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3992 /*-----------------------------------------------------------------*/
3993 /* gencjne - compare and jump if not equal */
3994 /*-----------------------------------------------------------------*/
3996 gencjne (operand * left, operand * right, symbol * lbl)
3998 symbol *tlbl = newiTempLabel (NULL);
4000 gencjneshort (left, right, lbl);
4003 emit2 ("ld a,!one");
4004 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4005 emitLabel (lbl->key + 100);
4007 emitLabel (tlbl->key + 100);
4010 /*-----------------------------------------------------------------*/
4011 /* genCmpEq - generates code for equal to */
4012 /*-----------------------------------------------------------------*/
4014 genCmpEq (iCode * ic, iCode * ifx)
4016 operand *left, *right, *result;
4018 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4019 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4020 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4022 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4024 /* Swap operands if it makes the operation easier. ie if:
4025 1. Left is a literal.
4027 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4029 operand *t = IC_RIGHT (ic);
4030 IC_RIGHT (ic) = IC_LEFT (ic);
4034 if (ifx && !AOP_SIZE (result))
4037 /* if they are both bit variables */
4038 if (AOP_TYPE (left) == AOP_CRY &&
4039 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4041 wassertl (0, "Tried to compare two bits");
4045 tlbl = newiTempLabel (NULL);
4046 gencjneshort (left, right, tlbl);
4049 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4050 emitLabel (tlbl->key + 100);
4054 /* PENDING: do this better */
4055 symbol *lbl = newiTempLabel (NULL);
4056 emit2 ("!shortjp !tlabel", lbl->key + 100);
4057 emitLabel (tlbl->key + 100);
4058 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4059 emitLabel (lbl->key + 100);
4062 /* mark the icode as generated */
4067 /* if they are both bit variables */
4068 if (AOP_TYPE (left) == AOP_CRY &&
4069 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4071 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4075 gencjne (left, right, newiTempLabel (NULL));
4076 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4082 genIfxJump (ifx, "a");
4085 /* if the result is used in an arithmetic operation
4086 then put the result in place */
4087 if (AOP_TYPE (result) != AOP_CRY)
4091 /* leave the result in acc */
4095 freeAsmop (left, NULL, ic);
4096 freeAsmop (right, NULL, ic);
4097 freeAsmop (result, NULL, ic);
4100 /*-----------------------------------------------------------------*/
4101 /* ifxForOp - returns the icode containing the ifx for operand */
4102 /*-----------------------------------------------------------------*/
4104 ifxForOp (operand * op, iCode * ic)
4106 /* if true symbol then needs to be assigned */
4107 if (IS_TRUE_SYMOP (op))
4110 /* if this has register type condition and
4111 the next instruction is ifx with the same operand
4112 and live to of the operand is upto the ifx only then */
4114 ic->next->op == IFX &&
4115 IC_COND (ic->next)->key == op->key &&
4116 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4122 /*-----------------------------------------------------------------*/
4123 /* genAndOp - for && operation */
4124 /*-----------------------------------------------------------------*/
4126 genAndOp (iCode * ic)
4128 operand *left, *right, *result;
4131 /* note here that && operations that are in an if statement are
4132 taken away by backPatchLabels only those used in arthmetic
4133 operations remain */
4134 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4135 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4136 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4138 /* if both are bit variables */
4139 if (AOP_TYPE (left) == AOP_CRY &&
4140 AOP_TYPE (right) == AOP_CRY)
4142 wassertl (0, "Tried to and two bits");
4146 tlbl = newiTempLabel (NULL);
4148 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4150 emitLabel (tlbl->key + 100);
4154 freeAsmop (left, NULL, ic);
4155 freeAsmop (right, NULL, ic);
4156 freeAsmop (result, NULL, ic);
4159 /*-----------------------------------------------------------------*/
4160 /* genOrOp - for || operation */
4161 /*-----------------------------------------------------------------*/
4163 genOrOp (iCode * ic)
4165 operand *left, *right, *result;
4168 /* note here that || operations that are in an
4169 if statement are taken away by backPatchLabels
4170 only those used in arthmetic operations remain */
4171 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4172 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4173 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4175 /* if both are bit variables */
4176 if (AOP_TYPE (left) == AOP_CRY &&
4177 AOP_TYPE (right) == AOP_CRY)
4179 wassertl (0, "Tried to OR two bits");
4183 tlbl = newiTempLabel (NULL);
4185 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4187 emitLabel (tlbl->key + 100);
4191 freeAsmop (left, NULL, ic);
4192 freeAsmop (right, NULL, ic);
4193 freeAsmop (result, NULL, ic);
4196 /*-----------------------------------------------------------------*/
4197 /* isLiteralBit - test if lit == 2^n */
4198 /*-----------------------------------------------------------------*/
4200 isLiteralBit (unsigned long lit)
4202 unsigned long pw[32] =
4203 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4204 0x100L, 0x200L, 0x400L, 0x800L,
4205 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4206 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4207 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4208 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4209 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4212 for (idx = 0; idx < 32; idx++)
4218 /*-----------------------------------------------------------------*/
4219 /* jmpTrueOrFalse - */
4220 /*-----------------------------------------------------------------*/
4222 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4224 // ugly but optimized by peephole
4227 symbol *nlbl = newiTempLabel (NULL);
4228 emit2 ("jp !tlabel", nlbl->key + 100);
4229 emitLabel (tlbl->key + 100);
4230 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4231 emitLabel (nlbl->key + 100);
4235 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4236 emitLabel (tlbl->key + 100);
4241 /*-----------------------------------------------------------------*/
4242 /* genAnd - code for and */
4243 /*-----------------------------------------------------------------*/
4245 genAnd (iCode * ic, iCode * ifx)
4247 operand *left, *right, *result;
4248 int size, offset = 0;
4249 unsigned long lit = 0L;
4252 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4253 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4254 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4256 /* if left is a literal & right is not then exchange them */
4257 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4258 AOP_NEEDSACC (left))
4260 operand *tmp = right;
4265 /* if result = right then exchange them */
4266 if (sameRegs (AOP (result), AOP (right)))
4268 operand *tmp = right;
4273 /* if right is bit then exchange them */
4274 if (AOP_TYPE (right) == AOP_CRY &&
4275 AOP_TYPE (left) != AOP_CRY)
4277 operand *tmp = right;
4281 if (AOP_TYPE (right) == AOP_LIT)
4282 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4284 size = AOP_SIZE (result);
4286 if (AOP_TYPE (left) == AOP_CRY)
4288 wassertl (0, "Tried to perform an AND with a bit as an operand");
4292 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4293 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4294 if ((AOP_TYPE (right) == AOP_LIT) &&
4295 (AOP_TYPE (result) == AOP_CRY) &&
4296 (AOP_TYPE (left) != AOP_CRY))
4298 symbol *tlbl = newiTempLabel (NULL);
4299 int sizel = AOP_SIZE (left);
4302 /* PENDING: Test case for this. */
4307 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4309 _moveA (aopGet (AOP (left), offset, FALSE));
4310 if (bytelit != 0x0FFL)
4312 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4319 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4323 // bit = left & literal
4327 emit2 ("!tlabeldef", tlbl->key + 100);
4329 // if(left & literal)
4334 jmpTrueOrFalse (ifx, tlbl);
4342 /* if left is same as result */
4343 if (sameRegs (AOP (result), AOP (left)))
4345 for (; size--; offset++)
4347 if (AOP_TYPE (right) == AOP_LIT)
4349 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4354 aopPut (AOP (result), "!zero", offset);
4357 _moveA (aopGet (AOP (left), offset, FALSE));
4359 aopGet (AOP (right), offset, FALSE));
4360 aopPut (AOP (left), "a", offset);
4367 if (AOP_TYPE (left) == AOP_ACC)
4369 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4373 _moveA (aopGet (AOP (left), offset, FALSE));
4375 aopGet (AOP (right), offset, FALSE));
4376 aopPut (AOP (left), "a", offset);
4383 // left & result in different registers
4384 if (AOP_TYPE (result) == AOP_CRY)
4386 wassertl (0, "Tried to AND where the result is in carry");
4390 for (; (size--); offset++)
4393 // result = left & right
4394 if (AOP_TYPE (right) == AOP_LIT)
4396 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4398 aopPut (AOP (result),
4399 aopGet (AOP (left), offset, FALSE),
4403 else if (bytelit == 0)
4405 aopPut (AOP (result), "!zero", offset);
4409 // faster than result <- left, anl result,right
4410 // and better if result is SFR
4411 if (AOP_TYPE (left) == AOP_ACC)
4412 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4415 _moveA (aopGet (AOP (left), offset, FALSE));
4417 aopGet (AOP (right), offset, FALSE));
4419 aopPut (AOP (result), "a", offset);
4426 freeAsmop (left, NULL, ic);
4427 freeAsmop (right, NULL, ic);
4428 freeAsmop (result, NULL, ic);
4431 /*-----------------------------------------------------------------*/
4432 /* genOr - code for or */
4433 /*-----------------------------------------------------------------*/
4435 genOr (iCode * ic, iCode * ifx)
4437 operand *left, *right, *result;
4438 int size, offset = 0;
4439 unsigned long lit = 0L;
4442 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4443 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4444 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4446 /* if left is a literal & right is not then exchange them */
4447 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4448 AOP_NEEDSACC (left))
4450 operand *tmp = right;
4455 /* if result = right then exchange them */
4456 if (sameRegs (AOP (result), AOP (right)))
4458 operand *tmp = right;
4463 /* if right is bit then exchange them */
4464 if (AOP_TYPE (right) == AOP_CRY &&
4465 AOP_TYPE (left) != AOP_CRY)
4467 operand *tmp = right;
4471 if (AOP_TYPE (right) == AOP_LIT)
4472 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4474 size = AOP_SIZE (result);
4476 if (AOP_TYPE (left) == AOP_CRY)
4478 wassertl (0, "Tried to OR where left is a bit");
4482 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4483 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4484 if ((AOP_TYPE (right) == AOP_LIT) &&
4485 (AOP_TYPE (result) == AOP_CRY) &&
4486 (AOP_TYPE (left) != AOP_CRY))
4488 symbol *tlbl = newiTempLabel (NULL);
4489 int sizel = AOP_SIZE (left);
4493 wassertl (0, "Result is assigned to a bit");
4495 /* PENDING: Modeled after the AND code which is inefficent. */
4498 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4500 _moveA (aopGet (AOP (left), offset, FALSE));
4501 /* OR with any literal is the same as OR with itself. */
4503 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4509 jmpTrueOrFalse (ifx, tlbl);
4514 /* if left is same as result */
4515 if (sameRegs (AOP (result), AOP (left)))
4517 for (; size--; offset++)
4519 if (AOP_TYPE (right) == AOP_LIT)
4521 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4525 _moveA (aopGet (AOP (left), offset, FALSE));
4527 aopGet (AOP (right), offset, FALSE));
4528 aopPut (AOP (result), "a", offset);
4533 if (AOP_TYPE (left) == AOP_ACC)
4534 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4537 _moveA (aopGet (AOP (left), offset, FALSE));
4539 aopGet (AOP (right), offset, FALSE));
4540 aopPut (AOP (result), "a", offset);
4547 // left & result in different registers
4548 if (AOP_TYPE (result) == AOP_CRY)
4550 wassertl (0, "Result of OR is in a bit");
4553 for (; (size--); offset++)
4556 // result = left & right
4557 if (AOP_TYPE (right) == AOP_LIT)
4559 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4561 aopPut (AOP (result),
4562 aopGet (AOP (left), offset, FALSE),
4567 // faster than result <- left, anl result,right
4568 // and better if result is SFR
4569 if (AOP_TYPE (left) == AOP_ACC)
4570 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4573 _moveA (aopGet (AOP (left), offset, FALSE));
4575 aopGet (AOP (right), offset, FALSE));
4577 aopPut (AOP (result), "a", offset);
4578 /* PENDING: something weird is going on here. Add exception. */
4579 if (AOP_TYPE (result) == AOP_ACC)
4585 freeAsmop (left, NULL, ic);
4586 freeAsmop (right, NULL, ic);
4587 freeAsmop (result, NULL, ic);
4590 /*-----------------------------------------------------------------*/
4591 /* genXor - code for xclusive or */
4592 /*-----------------------------------------------------------------*/
4594 genXor (iCode * ic, iCode * ifx)
4596 operand *left, *right, *result;
4597 int size, offset = 0;
4598 unsigned long lit = 0L;
4600 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4601 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4602 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4604 /* if left is a literal & right is not then exchange them */
4605 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4606 AOP_NEEDSACC (left))
4608 operand *tmp = right;
4613 /* if result = right then exchange them */
4614 if (sameRegs (AOP (result), AOP (right)))
4616 operand *tmp = right;
4621 /* if right is bit then exchange them */
4622 if (AOP_TYPE (right) == AOP_CRY &&
4623 AOP_TYPE (left) != AOP_CRY)
4625 operand *tmp = right;
4629 if (AOP_TYPE (right) == AOP_LIT)
4630 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4632 size = AOP_SIZE (result);
4634 if (AOP_TYPE (left) == AOP_CRY)
4636 wassertl (0, "Tried to XOR a bit");
4640 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4641 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4642 if ((AOP_TYPE (right) == AOP_LIT) &&
4643 (AOP_TYPE (result) == AOP_CRY) &&
4644 (AOP_TYPE (left) != AOP_CRY))
4646 symbol *tlbl = newiTempLabel (NULL);
4647 int sizel = AOP_SIZE (left);
4651 /* PENDING: Test case for this. */
4652 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4656 _moveA (aopGet (AOP (left), offset, FALSE));
4657 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4658 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4663 jmpTrueOrFalse (ifx, tlbl);
4667 wassertl (0, "Result of XOR was destined for a bit");
4672 /* if left is same as result */
4673 if (sameRegs (AOP (result), AOP (left)))
4675 for (; size--; offset++)
4677 if (AOP_TYPE (right) == AOP_LIT)
4679 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4683 _moveA (aopGet (AOP (right), offset, FALSE));
4685 aopGet (AOP (left), offset, FALSE));
4686 aopPut (AOP (result), "a", offset);
4691 if (AOP_TYPE (left) == AOP_ACC)
4693 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4697 _moveA (aopGet (AOP (right), offset, FALSE));
4699 aopGet (AOP (left), offset, FALSE));
4700 aopPut (AOP (result), "a", 0);
4707 // left & result in different registers
4708 if (AOP_TYPE (result) == AOP_CRY)
4710 wassertl (0, "Result of XOR is in a bit");
4713 for (; (size--); offset++)
4716 // result = left & right
4717 if (AOP_TYPE (right) == AOP_LIT)
4719 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4721 aopPut (AOP (result),
4722 aopGet (AOP (left), offset, FALSE),
4727 // faster than result <- left, anl result,right
4728 // and better if result is SFR
4729 if (AOP_TYPE (left) == AOP_ACC)
4731 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4735 _moveA (aopGet (AOP (right), offset, FALSE));
4737 aopGet (AOP (left), offset, FALSE));
4739 aopPut (AOP (result), "a", offset);
4744 freeAsmop (left, NULL, ic);
4745 freeAsmop (right, NULL, ic);
4746 freeAsmop (result, NULL, ic);
4749 /*-----------------------------------------------------------------*/
4750 /* genInline - write the inline code out */
4751 /*-----------------------------------------------------------------*/
4753 genInline (iCode * ic)
4755 char *buffer, *bp, *bp1;
4757 _G.lines.isInline += (!options.asmpeep);
4759 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4760 strcpy (buffer, IC_INLINE (ic));
4762 /* emit each line as a code */
4787 _G.lines.isInline -= (!options.asmpeep);
4791 /*-----------------------------------------------------------------*/
4792 /* genRRC - rotate right with carry */
4793 /*-----------------------------------------------------------------*/
4800 /*-----------------------------------------------------------------*/
4801 /* genRLC - generate code for rotate left with carry */
4802 /*-----------------------------------------------------------------*/
4809 /*-----------------------------------------------------------------*/
4810 /* genGetHbit - generates code get highest order bit */
4811 /*-----------------------------------------------------------------*/
4813 genGetHbit (iCode * ic)
4815 operand *left, *result;
4816 left = IC_LEFT (ic);
4817 result = IC_RESULT (ic);
4818 aopOp (left, ic, FALSE, FALSE);
4819 aopOp (result, ic, FALSE, FALSE);
4821 /* get the highest order byte into a */
4822 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4824 if (AOP_TYPE (result) == AOP_CRY)
4832 /* PENDING: For re-target. */
4838 freeAsmop (left, NULL, ic);
4839 freeAsmop (result, NULL, ic);
4843 emitRsh2 (asmop *aop, int size, int is_signed)
4849 const char *l = aopGet (aop, size, FALSE);
4852 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4862 /*-----------------------------------------------------------------*/
4863 /* shiftR2Left2Result - shift right two bytes from left to result */
4864 /*-----------------------------------------------------------------*/
4866 shiftR2Left2Result (operand * left, int offl,
4867 operand * result, int offr,
4868 int shCount, int is_signed)
4871 symbol *tlbl, *tlbl1;
4873 movLeft2Result (left, offl, result, offr, 0);
4874 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4876 /* if (AOP(result)->type == AOP_REG) { */
4878 tlbl = newiTempLabel (NULL);
4879 tlbl1 = newiTempLabel (NULL);
4881 /* Left is already in result - so now do the shift */
4886 emitRsh2 (AOP (result), size, is_signed);
4891 emit2 ("ld a,!immedbyte+1", shCount);
4892 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4893 emitLabel (tlbl->key + 100);
4895 emitRsh2 (AOP (result), size, is_signed);
4897 emitLabel (tlbl1->key + 100);
4899 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4903 /*-----------------------------------------------------------------*/
4904 /* shiftL2Left2Result - shift left two bytes from left to result */
4905 /*-----------------------------------------------------------------*/
4907 shiftL2Left2Result (operand * left, int offl,
4908 operand * result, int offr, int shCount)
4910 if (sameRegs (AOP (result), AOP (left)) &&
4911 ((offl + MSB16) == offr))
4917 /* Copy left into result */
4918 movLeft2Result (left, offl, result, offr, 0);
4919 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4921 /* PENDING: for now just see if it'll work. */
4922 /*if (AOP(result)->type == AOP_REG) { */
4926 symbol *tlbl, *tlbl1;
4929 tlbl = newiTempLabel (NULL);
4930 tlbl1 = newiTempLabel (NULL);
4932 /* Left is already in result - so now do the shift */
4935 emit2 ("ld a,!immedbyte+1", shCount);
4936 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4937 emitLabel (tlbl->key + 100);
4942 l = aopGet (AOP (result), offset, FALSE);
4946 emit2 ("sla %s", l);
4957 emitLabel (tlbl1->key + 100);
4959 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4964 /*-----------------------------------------------------------------*/
4965 /* AccRol - rotate left accumulator by known count */
4966 /*-----------------------------------------------------------------*/
4968 AccRol (int shCount)
4970 shCount &= 0x0007; // shCount : 0..7
5009 /*-----------------------------------------------------------------*/
5010 /* AccLsh - left shift accumulator by known count */
5011 /*-----------------------------------------------------------------*/
5013 AccLsh (int shCount)
5015 static const unsigned char SLMask[] =
5017 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5026 else if (shCount == 2)
5033 /* rotate left accumulator */
5035 /* and kill the lower order bits */
5036 emit2 ("and a,!immedbyte", SLMask[shCount]);
5041 /*-----------------------------------------------------------------*/
5042 /* shiftL1Left2Result - shift left one byte from left to result */
5043 /*-----------------------------------------------------------------*/
5045 shiftL1Left2Result (operand * left, int offl,
5046 operand * result, int offr, int shCount)
5049 l = aopGet (AOP (left), offl, FALSE);
5051 /* shift left accumulator */
5053 aopPut (AOP (result), "a", offr);
5057 /*-----------------------------------------------------------------*/
5058 /* genlshTwo - left shift two bytes by known amount != 0 */
5059 /*-----------------------------------------------------------------*/
5061 genlshTwo (operand * result, operand * left, int shCount)
5063 int size = AOP_SIZE (result);
5065 wassert (size == 2);
5067 /* if shCount >= 8 */
5075 movLeft2Result (left, LSB, result, MSB16, 0);
5076 aopPut (AOP (result), "!zero", 0);
5077 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5081 movLeft2Result (left, LSB, result, MSB16, 0);
5082 aopPut (AOP (result), "!zero", 0);
5087 aopPut (AOP (result), "!zero", LSB);
5090 /* 1 <= shCount <= 7 */
5099 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5104 /*-----------------------------------------------------------------*/
5105 /* genlshOne - left shift a one byte quantity by known count */
5106 /*-----------------------------------------------------------------*/
5108 genlshOne (operand * result, operand * left, int shCount)
5110 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5113 /*-----------------------------------------------------------------*/
5114 /* genLeftShiftLiteral - left shifting by known count */
5115 /*-----------------------------------------------------------------*/
5117 genLeftShiftLiteral (operand * left,
5122 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5125 freeAsmop (right, NULL, ic);
5127 aopOp (left, ic, FALSE, FALSE);
5128 aopOp (result, ic, FALSE, FALSE);
5130 size = getSize (operandType (result));
5132 /* I suppose that the left size >= result size */
5138 else if (shCount >= (size * 8))
5142 aopPut (AOP (result), "!zero", size);
5150 genlshOne (result, left, shCount);
5153 genlshTwo (result, left, shCount);
5156 wassertl (0, "Shifting of longs is currently unsupported");
5162 freeAsmop (left, NULL, ic);
5163 freeAsmop (result, NULL, ic);
5166 /*-----------------------------------------------------------------*/
5167 /* genLeftShift - generates code for left shifting */
5168 /*-----------------------------------------------------------------*/
5170 genLeftShift (iCode * ic)
5174 symbol *tlbl, *tlbl1;
5175 operand *left, *right, *result;
5177 right = IC_RIGHT (ic);
5178 left = IC_LEFT (ic);
5179 result = IC_RESULT (ic);
5181 aopOp (right, ic, FALSE, FALSE);
5183 /* if the shift count is known then do it
5184 as efficiently as possible */
5185 if (AOP_TYPE (right) == AOP_LIT)
5187 genLeftShiftLiteral (left, right, result, ic);
5191 /* shift count is unknown then we have to form a loop get the loop
5192 count in B : Note: we take only the lower order byte since
5193 shifting more that 32 bits make no sense anyway, ( the largest
5194 size of an object can be only 32 bits ) */
5195 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5197 freeAsmop (right, NULL, ic);
5198 aopOp (left, ic, FALSE, FALSE);
5199 aopOp (result, ic, FALSE, FALSE);
5201 /* now move the left to the result if they are not the
5204 if (!sameRegs (AOP (left), AOP (result)))
5207 size = AOP_SIZE (result);
5211 l = aopGet (AOP (left), offset, FALSE);
5212 aopPut (AOP (result), l, offset);
5217 tlbl = newiTempLabel (NULL);
5218 size = AOP_SIZE (result);
5220 tlbl1 = newiTempLabel (NULL);
5222 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5223 emitLabel (tlbl->key + 100);
5224 l = aopGet (AOP (result), offset, FALSE);
5228 l = aopGet (AOP (result), offset, FALSE);
5232 emit2 ("sla %s", l);
5240 emitLabel (tlbl1->key + 100);
5242 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5244 freeAsmop (left, NULL, ic);
5245 freeAsmop (result, NULL, ic);
5248 /*-----------------------------------------------------------------*/
5249 /* genrshOne - left shift two bytes by known amount != 0 */
5250 /*-----------------------------------------------------------------*/
5252 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5255 int size = AOP_SIZE (result);
5258 wassert (size == 1);
5259 wassert (shCount < 8);
5261 l = aopGet (AOP (left), 0, FALSE);
5263 if (AOP (result)->type == AOP_REG)
5265 aopPut (AOP (result), l, 0);
5266 l = aopGet (AOP (result), 0, FALSE);
5269 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5277 emit2 ("%s a", is_signed ? "sra" : "srl");
5279 aopPut (AOP (result), "a", 0);
5283 /*-----------------------------------------------------------------*/
5284 /* AccRsh - right shift accumulator by known count */
5285 /*-----------------------------------------------------------------*/
5287 AccRsh (int shCount)
5289 static const unsigned char SRMask[] =
5291 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5296 /* rotate right accumulator */
5297 AccRol (8 - shCount);
5298 /* and kill the higher order bits */
5299 emit2 ("and a,!immedbyte", SRMask[shCount]);
5303 /*-----------------------------------------------------------------*/
5304 /* shiftR1Left2Result - shift right one byte from left to result */
5305 /*-----------------------------------------------------------------*/
5307 shiftR1Left2Result (operand * left, int offl,
5308 operand * result, int offr,
5309 int shCount, int sign)
5311 _moveA (aopGet (AOP (left), offl, FALSE));
5316 emit2 ("%s a", sign ? "sra" : "srl");
5323 aopPut (AOP (result), "a", offr);
5326 /*-----------------------------------------------------------------*/
5327 /* genrshTwo - right shift two bytes by known amount != 0 */
5328 /*-----------------------------------------------------------------*/
5330 genrshTwo (operand * result, operand * left,
5331 int shCount, int sign)
5333 /* if shCount >= 8 */
5339 shiftR1Left2Result (left, MSB16, result, LSB,
5344 movLeft2Result (left, MSB16, result, LSB, sign);
5348 /* Sign extend the result */
5349 _moveA(aopGet (AOP (result), 0, FALSE));
5353 aopPut (AOP (result), ACC_NAME, MSB16);
5357 aopPut (AOP (result), "!zero", 1);
5360 /* 1 <= shCount <= 7 */
5363 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5367 /*-----------------------------------------------------------------*/
5368 /* genRightShiftLiteral - left shifting by known count */
5369 /*-----------------------------------------------------------------*/
5371 genRightShiftLiteral (operand * left,
5377 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5380 freeAsmop (right, NULL, ic);
5382 aopOp (left, ic, FALSE, FALSE);
5383 aopOp (result, ic, FALSE, FALSE);
5385 size = getSize (operandType (result));
5387 /* I suppose that the left size >= result size */
5393 else if (shCount >= (size * 8))
5395 aopPut (AOP (result), "!zero", size);
5401 genrshOne (result, left, shCount, sign);
5404 genrshTwo (result, left, shCount, sign);
5407 wassertl (0, "Asked to shift right a long which should be a function call");
5410 wassertl (0, "Entered default case in right shift delegate");
5413 freeAsmop (left, NULL, ic);
5414 freeAsmop (result, NULL, ic);
5417 /*-----------------------------------------------------------------*/
5418 /* genRightShift - generate code for right shifting */
5419 /*-----------------------------------------------------------------*/
5421 genRightShift (iCode * ic)
5423 operand *right, *left, *result;
5425 int size, offset, first = 1;
5429 symbol *tlbl, *tlbl1;
5431 /* if signed then we do it the hard way preserve the
5432 sign bit moving it inwards */
5433 retype = getSpec (operandType (IC_RESULT (ic)));
5435 is_signed = !SPEC_USIGN (retype);
5437 /* signed & unsigned types are treated the same : i.e. the
5438 signed is NOT propagated inwards : quoting from the
5439 ANSI - standard : "for E1 >> E2, is equivalent to division
5440 by 2**E2 if unsigned or if it has a non-negative value,
5441 otherwise the result is implementation defined ", MY definition
5442 is that the sign does not get propagated */
5444 right = IC_RIGHT (ic);
5445 left = IC_LEFT (ic);
5446 result = IC_RESULT (ic);
5448 aopOp (right, ic, FALSE, FALSE);
5450 /* if the shift count is known then do it
5451 as efficiently as possible */
5452 if (AOP_TYPE (right) == AOP_LIT)
5454 genRightShiftLiteral (left, right, result, ic, is_signed);
5458 aopOp (left, ic, FALSE, FALSE);
5459 aopOp (result, ic, FALSE, FALSE);
5461 /* now move the left to the result if they are not the
5463 if (!sameRegs (AOP (left), AOP (result)) &&
5464 AOP_SIZE (result) > 1)
5467 size = AOP_SIZE (result);
5471 l = aopGet (AOP (left), offset, FALSE);
5472 aopPut (AOP (result), l, offset);
5477 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5479 freeAsmop (right, NULL, ic);
5481 tlbl = newiTempLabel (NULL);
5482 tlbl1 = newiTempLabel (NULL);
5483 size = AOP_SIZE (result);
5486 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5487 emitLabel (tlbl->key + 100);
5490 l = aopGet (AOP (result), offset--, FALSE);
5493 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5501 emitLabel (tlbl1->key + 100);
5503 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5505 freeAsmop (left, NULL, ic);
5506 freeAsmop (result, NULL, ic);
5509 /*-----------------------------------------------------------------*/
5510 /* genGenPointerGet - get value from generic pointer space */
5511 /*-----------------------------------------------------------------*/
5513 genGenPointerGet (operand * left,
5514 operand * result, iCode * ic)
5517 sym_link *retype = getSpec (operandType (result));
5523 aopOp (left, ic, FALSE, FALSE);
5524 aopOp (result, ic, FALSE, FALSE);
5526 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5529 if (isPtrPair (AOP (left)))
5531 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5532 aopPut (AOP (result), buffer, 0);
5536 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5537 aopPut (AOP (result), "a", 0);
5539 freeAsmop (left, NULL, ic);
5543 /* For now we always load into IY */
5544 /* if this is remateriazable */
5545 fetchPair (pair, AOP (left));
5547 /* so iy now contains the address */
5548 freeAsmop (left, NULL, ic);
5550 /* if bit then unpack */
5551 if (IS_BITVAR (retype))
5557 size = AOP_SIZE (result);
5562 /* PENDING: make this better */
5563 if (!IS_GB && AOP (result)->type == AOP_REG)
5565 aopPut (AOP (result), "!*hl", offset++);
5569 emit2 ("ld a,!*pair", _pairs[pair].name);
5570 aopPut (AOP (result), "a", offset++);
5574 emit2 ("inc %s", _pairs[pair].name);
5575 _G.pairs[pair].offset++;
5581 freeAsmop (result, NULL, ic);
5584 /*-----------------------------------------------------------------*/
5585 /* genPointerGet - generate code for pointer get */
5586 /*-----------------------------------------------------------------*/
5588 genPointerGet (iCode * ic)
5590 operand *left, *result;
5591 sym_link *type, *etype;
5593 left = IC_LEFT (ic);
5594 result = IC_RESULT (ic);
5596 /* depending on the type of pointer we need to
5597 move it to the correct pointer register */
5598 type = operandType (left);
5599 etype = getSpec (type);
5601 genGenPointerGet (left, result, ic);
5605 isRegOrLit (asmop * aop)
5607 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5612 /*-----------------------------------------------------------------*/
5613 /* genGenPointerSet - stores the value into a pointer location */
5614 /*-----------------------------------------------------------------*/
5616 genGenPointerSet (operand * right,
5617 operand * result, iCode * ic)
5620 sym_link *retype = getSpec (operandType (right));
5621 PAIR_ID pairId = PAIR_HL;
5623 aopOp (result, ic, FALSE, FALSE);
5624 aopOp (right, ic, FALSE, FALSE);
5629 /* Handle the exceptions first */
5630 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5633 const char *l = aopGet (AOP (right), 0, FALSE);
5634 const char *pair = getPairName (AOP (result));
5635 if (canAssignToPtr (l) && isPtr (pair))
5637 emit2 ("ld !*pair,%s", pair, l);
5642 emit2 ("ld !*pair,a", pair);
5647 /* if the operand is already in dptr
5648 then we do nothing else we move the value to dptr */
5649 if (AOP_TYPE (result) != AOP_STR)
5651 fetchPair (pairId, AOP (result));
5653 /* so hl know contains the address */
5654 freeAsmop (result, NULL, ic);
5656 /* if bit then unpack */
5657 if (IS_BITVAR (retype))
5663 size = AOP_SIZE (right);
5668 const char *l = aopGet (AOP (right), offset, FALSE);
5669 if (isRegOrLit (AOP (right)) && !IS_GB)
5671 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5676 emit2 ("ld !*pair,a", _pairs[pairId].name);
5680 emit2 ("inc %s", _pairs[pairId].name);
5681 _G.pairs[pairId].offset++;
5687 freeAsmop (right, NULL, ic);
5690 /*-----------------------------------------------------------------*/
5691 /* genPointerSet - stores the value into a pointer location */
5692 /*-----------------------------------------------------------------*/
5694 genPointerSet (iCode * ic)
5696 operand *right, *result;
5697 sym_link *type, *etype;
5699 right = IC_RIGHT (ic);
5700 result = IC_RESULT (ic);
5702 /* depending on the type of pointer we need to
5703 move it to the correct pointer register */
5704 type = operandType (result);
5705 etype = getSpec (type);
5707 genGenPointerSet (right, result, ic);
5710 /*-----------------------------------------------------------------*/
5711 /* genIfx - generate code for Ifx statement */
5712 /*-----------------------------------------------------------------*/
5714 genIfx (iCode * ic, iCode * popIc)
5716 operand *cond = IC_COND (ic);
5719 aopOp (cond, ic, FALSE, TRUE);
5721 /* get the value into acc */
5722 if (AOP_TYPE (cond) != AOP_CRY)
5726 /* the result is now in the accumulator */
5727 freeAsmop (cond, NULL, ic);
5729 /* if there was something to be popped then do it */
5733 /* if the condition is a bit variable */
5734 if (isbit && IS_ITEMP (cond) &&
5736 genIfxJump (ic, SPIL_LOC (cond)->rname);
5737 else if (isbit && !IS_ITEMP (cond))
5738 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5740 genIfxJump (ic, "a");
5745 /*-----------------------------------------------------------------*/
5746 /* genAddrOf - generates code for address of */
5747 /*-----------------------------------------------------------------*/
5749 genAddrOf (iCode * ic)
5751 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5753 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5755 /* if the operand is on the stack then we
5756 need to get the stack offset of this
5763 if (sym->stack <= 0)
5765 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
5769 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5771 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5775 emit2 ("ld de,!hashedstr", sym->rname);
5776 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
5784 /* if it has an offset then we need to compute it */
5786 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5788 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5789 emit2 ("add hl,sp");
5793 emit2 ("ld hl,#%s", sym->rname);
5795 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5797 freeAsmop (IC_RESULT (ic), NULL, ic);
5800 /*-----------------------------------------------------------------*/
5801 /* genAssign - generate code for assignment */
5802 /*-----------------------------------------------------------------*/
5804 genAssign (iCode * ic)
5806 operand *result, *right;
5808 unsigned long lit = 0L;
5810 result = IC_RESULT (ic);
5811 right = IC_RIGHT (ic);
5813 /* Dont bother assigning if they are the same */
5814 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5816 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5820 aopOp (right, ic, FALSE, FALSE);
5821 aopOp (result, ic, TRUE, FALSE);
5823 /* if they are the same registers */
5824 if (sameRegs (AOP (right), AOP (result)))
5826 emitDebug ("; (registers are the same)");
5830 /* if the result is a bit */
5831 if (AOP_TYPE (result) == AOP_CRY)
5833 wassertl (0, "Tried to assign to a bit");
5837 size = AOP_SIZE (result);
5840 if (AOP_TYPE (right) == AOP_LIT)
5841 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5842 if (isPair (AOP (result)))
5844 fetchPair (getPairId (AOP (result)), AOP (right));
5846 else if ((size > 1) &&
5847 (AOP_TYPE (result) != AOP_REG) &&
5848 (AOP_TYPE (right) == AOP_LIT) &&
5849 !IS_FLOAT (operandType (right)) &&
5852 bool fXored = FALSE;
5854 /* Work from the top down.
5855 Done this way so that we can use the cached copy of 0
5856 in A for a fast clear */
5859 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5861 if (!fXored && size > 1)
5868 aopPut (AOP (result), "a", offset);
5872 aopPut (AOP (result), "!zero", offset);
5876 aopPut (AOP (result),
5877 aopGet (AOP (right), offset, FALSE),
5882 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5884 /* Special case. Load into a and d, then load out. */
5885 _moveA (aopGet (AOP (right), 0, FALSE));
5886 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5887 aopPut (AOP (result), "a", 0);
5888 aopPut (AOP (result), "e", 1);
5890 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5892 /* Special case - simple memcpy */
5893 aopGet (AOP (right), LSB, FALSE);
5896 aopGet (AOP (result), LSB, FALSE);
5900 emit2 ("ld a,(de)");
5901 /* Peephole will optimise this. */
5902 emit2 ("ld (hl),a");
5910 spillPair (PAIR_HL);
5916 /* PENDING: do this check better */
5917 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5919 _moveA (aopGet (AOP (right), offset, FALSE));
5920 aopPut (AOP (result), "a", offset);
5923 aopPut (AOP (result),
5924 aopGet (AOP (right), offset, FALSE),
5931 freeAsmop (right, NULL, ic);
5932 freeAsmop (result, NULL, ic);
5935 /*-----------------------------------------------------------------*/
5936 /* genJumpTab - genrates code for jump table */
5937 /*-----------------------------------------------------------------*/
5939 genJumpTab (iCode * ic)
5944 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5945 /* get the condition into accumulator */
5946 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5949 emit2 ("ld e,%s", l);
5950 emit2 ("ld d,!zero");
5951 jtab = newiTempLabel (NULL);
5953 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5954 emit2 ("add hl,de");
5955 emit2 ("add hl,de");
5956 emit2 ("add hl,de");
5957 freeAsmop (IC_JTCOND (ic), NULL, ic);
5961 emitLabel (jtab->key + 100);
5962 /* now generate the jump labels */
5963 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5964 jtab = setNextItem (IC_JTLABELS (ic)))
5965 emit2 ("jp !tlabel", jtab->key + 100);
5968 /*-----------------------------------------------------------------*/
5969 /* genCast - gen code for casting */
5970 /*-----------------------------------------------------------------*/
5972 genCast (iCode * ic)
5974 operand *result = IC_RESULT (ic);
5975 sym_link *ctype = operandType (IC_LEFT (ic));
5976 operand *right = IC_RIGHT (ic);
5979 /* if they are equivalent then do nothing */
5980 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5983 aopOp (right, ic, FALSE, FALSE);
5984 aopOp (result, ic, FALSE, FALSE);
5986 /* if the result is a bit */
5987 if (AOP_TYPE (result) == AOP_CRY)
5989 wassertl (0, "Tried to cast to a bit");
5992 /* if they are the same size : or less */
5993 if (AOP_SIZE (result) <= AOP_SIZE (right))
5996 /* if they are in the same place */
5997 if (sameRegs (AOP (right), AOP (result)))
6000 /* if they in different places then copy */
6001 size = AOP_SIZE (result);
6005 aopPut (AOP (result),
6006 aopGet (AOP (right), offset, FALSE),
6013 /* So we now know that the size of destination is greater
6014 than the size of the source */
6015 /* we move to result for the size of source */
6016 size = AOP_SIZE (right);
6020 aopPut (AOP (result),
6021 aopGet (AOP (right), offset, FALSE),
6026 /* now depending on the sign of the destination */
6027 size = AOP_SIZE (result) - AOP_SIZE (right);
6028 /* Unsigned or not an integral type - right fill with zeros */
6029 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6032 aopPut (AOP (result), "!zero", offset++);
6036 /* we need to extend the sign :{ */
6037 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6043 aopPut (AOP (result), "a", offset++);
6047 freeAsmop (right, NULL, ic);
6048 freeAsmop (result, NULL, ic);
6051 /*-----------------------------------------------------------------*/
6052 /* genReceive - generate code for a receive iCode */
6053 /*-----------------------------------------------------------------*/
6055 genReceive (iCode * ic)
6057 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6058 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6059 IS_TRUE_SYMOP (IC_RESULT (ic))))
6069 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6070 size = AOP_SIZE(IC_RESULT(ic));
6072 for (i = 0; i < size; i++) {
6073 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6077 freeAsmop (IC_RESULT (ic), NULL, ic);
6082 /** Maximum number of bytes to emit per line. */
6086 /** Context for the byte output chunker. */
6089 unsigned char buffer[DBEMIT_MAX_RUN];
6094 /** Flushes a byte chunker by writing out all in the buffer and
6098 _dbFlush(DBEMITCTX *self)
6105 sprintf(line, ".db 0x%02X", self->buffer[0]);
6107 for (i = 1; i < self->pos; i++)
6109 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6116 /** Write out another byte, buffering until a decent line is
6120 _dbEmit(DBEMITCTX *self, int c)
6122 if (self->pos == DBEMIT_MAX_RUN)
6126 self->buffer[self->pos++] = c;
6129 /** Context for a simple run length encoder. */
6133 unsigned char buffer[128];
6135 /** runLen may be equivalent to pos. */
6141 RLE_CHANGE_COST = 4,
6145 /** Flush the buffer of a run length encoder by writing out the run or
6146 data that it currently contains.
6149 _rleCommit(RLECTX *self)
6155 memset(&db, 0, sizeof(db));
6157 emit2(".db %u", self->pos);
6159 for (i = 0; i < self->pos; i++)
6161 _dbEmit(&db, self->buffer[i]);
6170 Can get either a run or a block of random stuff.
6171 Only want to change state if a good run comes in or a run ends.
6172 Detecting run end is easy.
6175 Say initial state is in run, len zero, last zero. Then if you get a
6176 few zeros then something else then a short run will be output.
6177 Seems OK. While in run mode, keep counting. While in random mode,
6178 keep a count of the run. If run hits margin, output all up to run,
6179 restart, enter run mode.
6182 /** Add another byte into the run length encoder, flushing as
6183 required. The run length encoder uses the Amiga IFF style, where
6184 a block is prefixed by its run length. A positive length means
6185 the next n bytes pass straight through. A negative length means
6186 that the next byte is repeated -n times. A zero terminates the
6190 _rleAppend(RLECTX *self, int c)
6194 if (c != self->last)
6196 /* The run has stopped. See if it is worthwhile writing it out
6197 as a run. Note that the random data comes in as runs of
6200 if (self->runLen > RLE_CHANGE_COST)
6202 /* Yes, worthwhile. */
6203 /* Commit whatever was in the buffer. */
6205 emit2(".db -%u,0x%02X", self->runLen, self->last);
6209 /* Not worthwhile. Append to the end of the random list. */
6210 for (i = 0; i < self->runLen; i++)
6212 if (self->pos >= RLE_MAX_BLOCK)
6217 self->buffer[self->pos++] = self->last;
6225 if (self->runLen >= RLE_MAX_BLOCK)
6227 /* Commit whatever was in the buffer. */
6230 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6238 _rleFlush(RLECTX *self)
6240 _rleAppend(self, -1);
6247 /** genArrayInit - Special code for initialising an array with constant
6251 genArrayInit (iCode * ic)
6255 int elementSize = 0, eIndex, i;
6256 unsigned val, lastVal;
6260 memset(&rle, 0, sizeof(rle));
6262 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6264 _saveRegsForCall(ic, 0);
6266 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6267 emit2 ("call __initrleblock");
6269 type = operandType(IC_LEFT(ic));
6271 if (type && type->next)
6273 elementSize = getSize(type->next);
6277 wassertl (0, "Can't determine element size in genArrayInit.");
6280 iLoop = IC_ARRAYILIST(ic);
6281 lastVal = (unsigned)-1;
6283 /* Feed all the bytes into the run length encoder which will handle
6285 This works well for mixed char data, and for random int and long
6294 for (i = 0; i < ix; i++)
6296 for (eIndex = 0; eIndex < elementSize; eIndex++)
6298 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6299 _rleAppend(&rle, val);
6304 iLoop = iLoop->next;
6308 /* Mark the end of the run. */
6311 _restoreRegsAfterCall();
6315 freeAsmop (IC_LEFT(ic), NULL, ic);
6318 /*-----------------------------------------------------------------*/
6319 /* genZ80Code - generate code for Z80 based controllers */
6320 /*-----------------------------------------------------------------*/
6322 genZ80Code (iCode * lic)
6330 _fReturn = _gbz80_return;
6331 _fTmp = _gbz80_return;
6335 _fReturn = _z80_return;
6336 _fTmp = _z80_return;
6339 _G.lines.head = _G.lines.current = NULL;
6341 for (ic = lic; ic; ic = ic->next)
6344 if (cln != ic->lineno)
6346 emit2 ("; %s %d", ic->filename, ic->lineno);
6349 /* if the result is marked as
6350 spilt and rematerializable or code for
6351 this has already been generated then
6353 if (resultRemat (ic) || ic->generated)
6356 /* depending on the operation */
6360 emitDebug ("; genNot");
6365 emitDebug ("; genCpl");
6370 emitDebug ("; genUminus");
6375 emitDebug ("; genIpush");
6380 /* IPOP happens only when trying to restore a
6381 spilt live range, if there is an ifx statement
6382 following this pop then the if statement might
6383 be using some of the registers being popped which
6384 would destory the contents of the register so
6385 we need to check for this condition and handle it */
6387 ic->next->op == IFX &&
6388 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6390 emitDebug ("; genIfx");
6391 genIfx (ic->next, ic);
6395 emitDebug ("; genIpop");
6401 emitDebug ("; genCall");
6406 emitDebug ("; genPcall");
6411 emitDebug ("; genFunction");
6416 emitDebug ("; genEndFunction");
6417 genEndFunction (ic);
6421 emitDebug ("; genRet");
6426 emitDebug ("; genLabel");
6431 emitDebug ("; genGoto");
6436 emitDebug ("; genPlus");
6441 emitDebug ("; genMinus");
6446 emitDebug ("; genMult");
6451 emitDebug ("; genDiv");
6456 emitDebug ("; genMod");
6461 emitDebug ("; genCmpGt");
6462 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6466 emitDebug ("; genCmpLt");
6467 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6474 /* note these two are xlated by algebraic equivalence
6475 during parsing SDCC.y */
6476 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6477 "got '>=' or '<=' shouldn't have come here");
6481 emitDebug ("; genCmpEq");
6482 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6486 emitDebug ("; genAndOp");
6491 emitDebug ("; genOrOp");
6496 emitDebug ("; genXor");
6497 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6501 emitDebug ("; genOr");
6502 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6506 emitDebug ("; genAnd");
6507 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6511 emitDebug ("; genInline");
6516 emitDebug ("; genRRC");
6521 emitDebug ("; genRLC");
6526 emitDebug ("; genGetHBIT");
6531 emitDebug ("; genLeftShift");
6536 emitDebug ("; genRightShift");
6540 case GET_VALUE_AT_ADDRESS:
6541 emitDebug ("; genPointerGet");
6547 if (POINTER_SET (ic))
6549 emitDebug ("; genAssign (pointer)");
6554 emitDebug ("; genAssign");
6560 emitDebug ("; genIfx");
6565 emitDebug ("; genAddrOf");
6570 emitDebug ("; genJumpTab");
6575 emitDebug ("; genCast");
6580 emitDebug ("; genReceive");
6585 emitDebug ("; addSet");
6586 addSet (&_G.sendSet, ic);
6590 emitDebug ("; genArrayInit");
6600 /* now we are ready to call the
6601 peep hole optimizer */
6602 if (!options.nopeep)
6603 peepHole (&_G.lines.head);
6605 /* This is unfortunate */
6606 /* now do the actual printing */
6608 FILE *fp = codeOutFile;
6609 if (isInHome () && codeOutFile == code->oFile)
6610 codeOutFile = home->oFile;
6611 printLine (_G.lines.head, codeOutFile);
6612 if (_G.flushStatics)
6615 _G.flushStatics = 0;
6620 freeTrace(&_G.lines.trace);
6621 freeTrace(&_G.trace.aops);
6627 _isPairUsed (iCode * ic, PAIR_ID pairId)
6633 if (bitVectBitValue (ic->rMask, D_IDX))
6635 if (bitVectBitValue (ic->rMask, E_IDX))
6645 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6648 value *val = aop->aopu.aop_lit;
6650 wassert (aop->type == AOP_LIT);
6651 wassert (!IS_FLOAT (val->type));
6653 v = (unsigned long) floatFromVal (val);
6661 tsprintf (buffer, "!immedword", v);
6662 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));