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 if (id == PAIR_HL && requiresHL (aop))
1625 aopPut (aop, "a", 0);
1626 aopPut (aop, "d", 1);
1630 aopPut (aop, _pairs[id].l, 0);
1631 aopPut (aop, _pairs[id].h, 1);
1635 /*-----------------------------------------------------------------*/
1636 /* getDataSize - get the operand data size */
1637 /*-----------------------------------------------------------------*/
1639 getDataSize (operand * op)
1642 size = AOP_SIZE (op);
1646 wassertl (0, "Somehow got a three byte data pointer");
1651 /*-----------------------------------------------------------------*/
1652 /* movLeft2Result - move byte from left to result */
1653 /*-----------------------------------------------------------------*/
1655 movLeft2Result (operand * left, int offl,
1656 operand * result, int offr, int sign)
1660 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1662 l = aopGet (AOP (left), offl, FALSE);
1666 aopPut (AOP (result), l, offr);
1670 if (getDataSize (left) == offl + 1)
1672 emit2 ("ld a,%s", l);
1673 aopPut (AOP (result), "a", offr);
1680 movLeft2ResultLong (operand * left, int offl,
1681 operand * result, int offr, int sign,
1686 movLeft2Result (left, offl, result, offr, sign);
1690 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1691 wassertl (size == 2, "Only implemented for two bytes or one");
1693 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1695 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1696 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1701 movLeft2Result (left, offl, result, offr, sign);
1702 movLeft2Result (left, offl+1, result, offr+1, sign);
1707 /** Put Acc into a register set
1710 outAcc (operand * result)
1713 size = getDataSize (result);
1716 aopPut (AOP (result), "a", 0);
1719 /* unsigned or positive */
1722 aopPut (AOP (result), "!zero", offset++);
1727 /** Take the value in carry and put it into a register
1730 outBitCLong (operand * result, bool swap_sense)
1732 /* if the result is bit */
1733 if (AOP_TYPE (result) == AOP_CRY)
1735 wassertl (0, "Tried to write carry to a bit");
1739 emit2 ("ld a,!zero");
1742 emit2 ("xor a,!immedbyte", 1);
1748 outBitC (operand * result)
1750 outBitCLong (result, FALSE);
1753 /*-----------------------------------------------------------------*/
1754 /* toBoolean - emit code for orl a,operator(sizeop) */
1755 /*-----------------------------------------------------------------*/
1757 _toBoolean (operand * oper)
1759 int size = AOP_SIZE (oper);
1763 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1766 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1770 if (AOP (oper)->type != AOP_ACC)
1773 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1778 /*-----------------------------------------------------------------*/
1779 /* genNot - generate code for ! operation */
1780 /*-----------------------------------------------------------------*/
1784 sym_link *optype = operandType (IC_LEFT (ic));
1786 /* assign asmOps to operand & result */
1787 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1788 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1790 /* if in bit space then a special case */
1791 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1793 wassertl (0, "Tried to negate a bit");
1796 /* if type float then do float */
1797 if (IS_FLOAT (optype))
1799 wassertl (0, "Tried to negate a float");
1802 _toBoolean (IC_LEFT (ic));
1807 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1808 emit2 ("sub a,!one");
1809 outBitC (IC_RESULT (ic));
1811 /* release the aops */
1812 freeAsmop (IC_LEFT (ic), NULL, ic);
1813 freeAsmop (IC_RESULT (ic), NULL, ic);
1816 /*-----------------------------------------------------------------*/
1817 /* genCpl - generate code for complement */
1818 /*-----------------------------------------------------------------*/
1826 /* assign asmOps to operand & result */
1827 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1828 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1830 /* if both are in bit space then
1832 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1833 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1835 wassertl (0, "Left and the result are in bit space");
1838 size = AOP_SIZE (IC_RESULT (ic));
1841 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1844 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1847 /* release the aops */
1848 freeAsmop (IC_LEFT (ic), NULL, ic);
1849 freeAsmop (IC_RESULT (ic), NULL, ic);
1853 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1860 store de into result
1865 store de into result
1867 const char *first = isAdd ? "add" : "sub";
1868 const char *later = isAdd ? "adc" : "sbc";
1870 wassertl (IS_GB, "Code is only relevent to the gbz80");
1871 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1873 fetchPair (PAIR_DE, left);
1876 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1879 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1882 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
1883 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
1885 fetchPairLong (PAIR_DE, left, MSB24);
1886 aopGet (right, MSB24, FALSE);
1890 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
1893 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
1895 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
1896 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
1900 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
1902 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
1905 /*-----------------------------------------------------------------*/
1906 /* genUminus - unary minus code generation */
1907 /*-----------------------------------------------------------------*/
1909 genUminus (iCode * ic)
1912 sym_link *optype, *rtype;
1915 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1916 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1918 /* if both in bit space then special
1920 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1921 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1923 wassertl (0, "Left and right are in bit space");
1927 optype = operandType (IC_LEFT (ic));
1928 rtype = operandType (IC_RESULT (ic));
1930 /* if float then do float stuff */
1931 if (IS_FLOAT (optype))
1933 wassertl (0, "Tried to do a unary minus on a float");
1937 /* otherwise subtract from zero */
1938 size = AOP_SIZE (IC_LEFT (ic));
1940 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1942 /* Create a new asmop with value zero */
1943 asmop *azero = newAsmop (AOP_SIMPLELIT);
1944 azero->aopu.aop_simplelit = 0;
1946 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1954 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1955 emit2 ("ld a,!zero");
1956 emit2 ("sbc a,%s", l);
1957 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1960 /* if any remaining bytes in the result */
1961 /* we just need to propagate the sign */
1962 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1967 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1971 /* release the aops */
1972 freeAsmop (IC_LEFT (ic), NULL, ic);
1973 freeAsmop (IC_RESULT (ic), NULL, ic);
1976 /*-----------------------------------------------------------------*/
1977 /* assignResultValue - */
1978 /*-----------------------------------------------------------------*/
1980 assignResultValue (operand * oper)
1982 int size = AOP_SIZE (oper);
1985 wassertl (size <= 4, "Got a result that is bigger than four bytes");
1986 topInA = requiresHL (AOP (oper));
1988 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1990 /* We do it the hard way here. */
1992 aopPut (AOP (oper), _fReturn[0], 0);
1993 aopPut (AOP (oper), _fReturn[1], 1);
1995 aopPut (AOP (oper), _fReturn[0], 2);
1996 aopPut (AOP (oper), _fReturn[1], 3);
2002 aopPut (AOP (oper), _fReturn[size], size);
2007 /** Simple restore that doesn't take into account what is used in the
2011 _restoreRegsAfterCall(void)
2013 if (_G.stack.pushedDE)
2016 _G.stack.pushedDE = FALSE;
2018 if (_G.stack.pushedBC)
2021 _G.stack.pushedBC = FALSE;
2023 _G.saves.saved = FALSE;
2027 _saveRegsForCall(iCode *ic, int sendSetSize)
2030 o Stack parameters are pushed before this function enters
2031 o DE and BC may be used in this function.
2032 o HL and DE may be used to return the result.
2033 o HL and DE may be used to send variables.
2034 o DE and BC may be used to store the result value.
2035 o HL may be used in computing the sent value of DE
2036 o The iPushes for other parameters occur before any addSets
2038 Logic: (to be run inside the first iPush or if none, before sending)
2039 o Compute if DE and/or BC are in use over the call
2040 o Compute if DE is used in the send set
2041 o Compute if DE and/or BC are used to hold the result value
2042 o If (DE is used, or in the send set) and is not used in the result, push.
2043 o If BC is used and is not in the result, push
2045 o If DE is used in the send set, fetch
2046 o If HL is used in the send set, fetch
2050 if (_G.saves.saved == FALSE) {
2051 bool deInUse, bcInUse;
2053 bool bcInRet = FALSE, deInRet = FALSE;
2056 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2058 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2059 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2061 deSending = (sendSetSize > 1);
2063 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2065 if (bcInUse && bcInRet == FALSE) {
2067 _G.stack.pushedBC = TRUE;
2069 if (deInUse && deInRet == FALSE) {
2071 _G.stack.pushedDE = TRUE;
2074 _G.saves.saved = TRUE;
2077 /* Already saved. */
2081 /*-----------------------------------------------------------------*/
2082 /* genIpush - genrate code for pushing this gets a little complex */
2083 /*-----------------------------------------------------------------*/
2085 genIpush (iCode * ic)
2087 int size, offset = 0;
2090 /* if this is not a parm push : ie. it is spill push
2091 and spill push is always done on the local stack */
2094 wassertl(0, "Encountered an unsupported spill push.");
2098 if (_G.saves.saved == FALSE) {
2099 /* Caller saves, and this is the first iPush. */
2100 /* Scan ahead until we find the function that we are pushing parameters to.
2101 Count the number of addSets on the way to figure out what registers
2102 are used in the send set.
2105 iCode *walk = ic->next;
2108 if (walk->op == SEND) {
2111 else if (walk->op == CALL || walk->op == PCALL) {
2120 _saveRegsForCall(walk, nAddSets);
2123 /* Already saved by another iPush. */
2126 /* then do the push */
2127 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2129 size = AOP_SIZE (IC_LEFT (ic));
2131 if (isPair (AOP (IC_LEFT (ic))))
2133 _G.stack.pushed += 2;
2134 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2140 fetchHL (AOP (IC_LEFT (ic)));
2142 spillPair (PAIR_HL);
2143 _G.stack.pushed += 2;
2148 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2150 spillPair (PAIR_HL);
2151 _G.stack.pushed += 2;
2152 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2154 spillPair (PAIR_HL);
2155 _G.stack.pushed += 2;
2161 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2163 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2165 emit2 ("ld a,(%s)", l);
2169 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2170 emit2 ("ld a,%s", l);
2178 freeAsmop (IC_LEFT (ic), NULL, ic);
2181 /*-----------------------------------------------------------------*/
2182 /* genIpop - recover the registers: can happen only for spilling */
2183 /*-----------------------------------------------------------------*/
2185 genIpop (iCode * ic)
2190 /* if the temp was not pushed then */
2191 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2194 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2195 size = AOP_SIZE (IC_LEFT (ic));
2196 offset = (size - 1);
2197 if (isPair (AOP (IC_LEFT (ic))))
2199 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2207 spillPair (PAIR_HL);
2208 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2212 freeAsmop (IC_LEFT (ic), NULL, ic);
2215 /* This is quite unfortunate */
2217 setArea (int inHome)
2220 static int lastArea = 0;
2222 if (_G.in_home != inHome) {
2224 const char *sz = port->mem.code_name;
2225 port->mem.code_name = "HOME";
2226 emit2("!area", CODE_NAME);
2227 port->mem.code_name = sz;
2230 emit2("!area", CODE_NAME); */
2231 _G.in_home = inHome;
2242 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2246 symbol *sym = OP_SYMBOL (op);
2248 if (sym->isspilt || sym->nRegs == 0)
2251 aopOp (op, ic, FALSE, FALSE);
2254 if (aop->type == AOP_REG)
2257 for (i = 0; i < aop->size; i++)
2259 if (pairId == PAIR_DE)
2261 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2262 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2264 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2267 else if (pairId == PAIR_BC)
2269 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2270 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2272 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2282 freeAsmop (IC_LEFT (ic), NULL, ic);
2286 /** Emit the code for a call statement
2289 emitCall (iCode * ic, bool ispcall)
2291 sym_link *dtype = operandType (IC_LEFT (ic));
2293 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2295 /* if caller saves & we have not saved then */
2301 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2303 /* if send set is not empty then assign */
2308 int nSend = elementsInSet(_G.sendSet);
2309 bool swapped = FALSE;
2311 int _z80_sendOrder[] = {
2316 /* Check if the parameters are swapped. If so route through hl instead. */
2317 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2319 sic = setFirstItem(_G.sendSet);
2320 sic = setNextItem(_G.sendSet);
2322 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2323 /* The second send value is loaded from one the one that holds the first
2324 send, i.e. it is overwritten. */
2325 /* Cache the first in HL, and load the second from HL instead. */
2326 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2327 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2333 for (sic = setFirstItem (_G.sendSet); sic;
2334 sic = setNextItem (_G.sendSet))
2337 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2339 size = AOP_SIZE (IC_LEFT (sic));
2340 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2341 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2343 // PENDING: Mild hack
2344 if (swapped == TRUE && send == 1) {
2346 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2349 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2351 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2354 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2358 freeAsmop (IC_LEFT (sic), NULL, sic);
2365 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2367 werror (W_INDIR_BANKED);
2369 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2371 if (isLitWord (AOP (IC_LEFT (ic))))
2373 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2377 symbol *rlbl = newiTempLabel (NULL);
2378 spillPair (PAIR_HL);
2379 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2381 _G.stack.pushed += 2;
2383 fetchHL (AOP (IC_LEFT (ic)));
2385 emit2 ("!tlabeldef", (rlbl->key + 100));
2386 _G.stack.pushed -= 2;
2388 freeAsmop (IC_LEFT (ic), NULL, ic);
2392 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2393 OP_SYMBOL (IC_LEFT (ic))->rname :
2394 OP_SYMBOL (IC_LEFT (ic))->name;
2395 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2397 emit2 ("call banked_call");
2398 emit2 ("!dws", name);
2399 emit2 ("!dw !bankimmeds", name);
2404 emit2 ("call %s", name);
2409 /* Mark the regsiters as restored. */
2410 _G.saves.saved = FALSE;
2412 /* if we need assign a result value */
2413 if ((IS_ITEMP (IC_RESULT (ic)) &&
2414 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2415 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2416 IS_TRUE_SYMOP (IC_RESULT (ic)))
2419 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2421 assignResultValue (IC_RESULT (ic));
2423 freeAsmop (IC_RESULT (ic), NULL, ic);
2426 /* adjust the stack for parameters if required */
2429 int i = ic->parmBytes;
2431 _G.stack.pushed -= i;
2434 emit2 ("!ldaspsp", i);
2441 emit2 ("ld hl,#%d", i);
2442 emit2 ("add hl,sp");
2460 if (_G.stack.pushedDE)
2462 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2463 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2465 if (dInUse && eInUse)
2481 wassertl (0, "Neither D or E were in use but it was pushed.");
2483 _G.stack.pushedDE = FALSE;
2486 if (_G.stack.pushedBC)
2488 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2489 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2491 // If both B and C are used in the return value, then we won't get
2493 if (bInUse && cInUse)
2509 wassertl (0, "Neither B or C were in use but it was pushed.");
2511 _G.stack.pushedBC = FALSE;
2515 /*-----------------------------------------------------------------*/
2516 /* genCall - generates a call statement */
2517 /*-----------------------------------------------------------------*/
2519 genCall (iCode * ic)
2521 emitCall (ic, FALSE);
2524 /*-----------------------------------------------------------------*/
2525 /* genPcall - generates a call by pointer statement */
2526 /*-----------------------------------------------------------------*/
2528 genPcall (iCode * ic)
2530 emitCall (ic, TRUE);
2533 /*-----------------------------------------------------------------*/
2534 /* resultRemat - result is rematerializable */
2535 /*-----------------------------------------------------------------*/
2537 resultRemat (iCode * ic)
2539 if (SKIP_IC (ic) || ic->op == IFX)
2542 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2544 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2545 if (sym->remat && !POINTER_SET (ic))
2552 extern set *publics;
2554 /*-----------------------------------------------------------------*/
2555 /* genFunction - generated code for function entry */
2556 /*-----------------------------------------------------------------*/
2558 genFunction (iCode * ic)
2560 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2564 bool bcInUse = FALSE;
2565 bool deInUse = FALSE;
2568 setArea (IFFUNC_NONBANKED (sym->type));
2570 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2573 _G.receiveOffset = 0;
2575 /* Record the last function name for debugging. */
2576 _G.lastFunctionName = sym->rname;
2578 /* Create the function header */
2579 emit2 ("!functionheader", sym->name);
2580 /* PENDING: portability. */
2581 emit2 ("__%s_start:", sym->rname);
2582 emit2 ("!functionlabeldef", sym->rname);
2584 if (options.profile)
2586 emit2 ("!profileenter");
2589 ftype = operandType (IC_LEFT (ic));
2591 /* if critical function then turn interrupts off */
2592 if (IFFUNC_ISCRITICAL (ftype))
2595 /* if this is an interrupt service routine then save all potentially used registers. */
2596 if (IFFUNC_ISISR (sym->type))
2601 /* PENDING: callee-save etc */
2603 _G.stack.param_offset = 0;
2606 /* Detect which registers are used. */
2610 for (i = 0; i < sym->regsUsed->size; i++)
2612 if (bitVectBitValue (sym->regsUsed, i))
2626 /* Other systems use DE as a temporary. */
2637 _G.stack.param_offset += 2;
2640 _G.stack.pushedBC = bcInUse;
2645 _G.stack.param_offset += 2;
2648 _G.stack.pushedDE = deInUse;
2651 /* adjust the stack for the function */
2652 _G.stack.last = sym->stack;
2654 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2655 emit2 ("!enterxl", sym->stack);
2656 else if (sym->stack)
2657 emit2 ("!enterx", sym->stack);
2660 _G.stack.offset = sym->stack;
2663 /*-----------------------------------------------------------------*/
2664 /* genEndFunction - generates epilogue for functions */
2665 /*-----------------------------------------------------------------*/
2667 genEndFunction (iCode * ic)
2669 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2671 if (IFFUNC_ISISR (sym->type))
2673 wassertl (0, "Tried to close an interrupt support function");
2677 if (IFFUNC_ISCRITICAL (sym->type))
2680 /* PENDING: calleeSave */
2682 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2684 emit2 ("!leavexl", _G.stack.offset);
2686 else if (_G.stack.offset)
2688 emit2 ("!leavex", _G.stack.offset);
2696 if (_G.stack.pushedDE)
2699 _G.stack.pushedDE = FALSE;
2702 if (_G.stack.pushedDE)
2705 _G.stack.pushedDE = FALSE;
2709 if (options.profile)
2711 emit2 ("!profileexit");
2715 /* Both baned and non-banked just ret */
2718 /* PENDING: portability. */
2719 emit2 ("__%s_end:", sym->rname);
2721 _G.flushStatics = 1;
2722 _G.stack.pushed = 0;
2723 _G.stack.offset = 0;
2726 /*-----------------------------------------------------------------*/
2727 /* genRet - generate code for return statement */
2728 /*-----------------------------------------------------------------*/
2733 /* Errk. This is a hack until I can figure out how
2734 to cause dehl to spill on a call */
2735 int size, offset = 0;
2737 /* if we have no return value then
2738 just generate the "ret" */
2742 /* we have something to return then
2743 move the return value into place */
2744 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2745 size = AOP_SIZE (IC_LEFT (ic));
2747 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2751 emit2 ("ld de,%s", l);
2755 emit2 ("ld hl,%s", l);
2760 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2762 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2763 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2769 l = aopGet (AOP (IC_LEFT (ic)), offset,
2771 if (strcmp (_fReturn[offset], l))
2772 emit2 ("ld %s,%s", _fReturn[offset++], l);
2776 freeAsmop (IC_LEFT (ic), NULL, ic);
2779 /* generate a jump to the return label
2780 if the next is not the return statement */
2781 if (!(ic->next && ic->next->op == LABEL &&
2782 IC_LABEL (ic->next) == returnLabel))
2784 emit2 ("jp !tlabel", returnLabel->key + 100);
2787 /*-----------------------------------------------------------------*/
2788 /* genLabel - generates a label */
2789 /*-----------------------------------------------------------------*/
2791 genLabel (iCode * ic)
2793 /* special case never generate */
2794 if (IC_LABEL (ic) == entryLabel)
2797 emitLabel (IC_LABEL (ic)->key + 100);
2800 /*-----------------------------------------------------------------*/
2801 /* genGoto - generates a ljmp */
2802 /*-----------------------------------------------------------------*/
2804 genGoto (iCode * ic)
2806 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2809 /*-----------------------------------------------------------------*/
2810 /* genPlusIncr :- does addition with increment if possible */
2811 /*-----------------------------------------------------------------*/
2813 genPlusIncr (iCode * ic)
2815 unsigned int icount;
2816 unsigned int size = getDataSize (IC_RESULT (ic));
2817 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2819 /* will try to generate an increment */
2820 /* if the right side is not a literal
2822 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2825 emitDebug ("; genPlusIncr");
2827 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2829 /* If result is a pair */
2830 if (resultId != PAIR_INVALID)
2832 if (isLitWord (AOP (IC_LEFT (ic))))
2834 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2837 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2839 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2840 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2846 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2850 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
2854 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2859 /* if the literal value of the right hand side
2860 is greater than 4 then it is not worth it */
2864 /* if increment 16 bits in register */
2865 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2871 symbol *tlbl = NULL;
2872 tlbl = newiTempLabel (NULL);
2875 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2878 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2881 emitLabel (tlbl->key + 100);
2885 /* if the sizes are greater than 1 then we cannot */
2886 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2887 AOP_SIZE (IC_LEFT (ic)) > 1)
2890 /* we can if the aops of the left & result match or
2891 if they are in registers and the registers are the
2893 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2897 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2905 /*-----------------------------------------------------------------*/
2906 /* outBitAcc - output a bit in acc */
2907 /*-----------------------------------------------------------------*/
2909 outBitAcc (operand * result)
2911 symbol *tlbl = newiTempLabel (NULL);
2912 /* if the result is a bit */
2913 if (AOP_TYPE (result) == AOP_CRY)
2915 wassertl (0, "Tried to write A into a bit");
2919 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2920 emit2 ("ld a,!one");
2921 emitLabel (tlbl->key + 100);
2927 couldDestroyCarry (asmop *aop)
2931 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
2940 shiftIntoPair (int idx, asmop *aop)
2942 PAIR_ID id = PAIR_INVALID;
2944 wassertl (IS_Z80, "Only implemented for the Z80");
2945 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
2957 wassertl (0, "Internal error - hit default case");
2960 emitDebug ("; Shift into pair idx %u", idx);
2964 setupPair (PAIR_HL, aop, 0);
2968 setupPair (PAIR_IY, aop, 0);
2970 emit2 ("pop %s", _pairs[id].name);
2973 aop->type = AOP_PAIRPTR;
2974 aop->aopu.aop_pairId = id;
2975 _G.pairs[id].offset = 0;
2976 _G.pairs[id].last_type = aop->type;
2980 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
2982 wassert (left && right);
2986 if (couldDestroyCarry (right) && couldDestroyCarry (result))
2988 shiftIntoPair (0, right);
2989 shiftIntoPair (1, result);
2991 else if (couldDestroyCarry (right))
2993 shiftIntoPair (0, right);
2995 else if (couldDestroyCarry (result))
2997 shiftIntoPair (0, result);
3006 /*-----------------------------------------------------------------*/
3007 /* genPlus - generates code for addition */
3008 /*-----------------------------------------------------------------*/
3010 genPlus (iCode * ic)
3012 int size, offset = 0;
3014 /* special cases :- */
3016 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3017 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3018 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3020 /* Swap the left and right operands if:
3022 if literal, literal on the right or
3023 if left requires ACC or right is already
3026 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3027 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3028 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3030 operand *t = IC_RIGHT (ic);
3031 IC_RIGHT (ic) = IC_LEFT (ic);
3035 /* if both left & right are in bit
3037 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3038 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3041 wassertl (0, "Tried to add two bits");
3044 /* if left in bit space & right literal */
3045 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3046 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3048 /* Can happen I guess */
3049 wassertl (0, "Tried to add a bit to a literal");
3052 /* if I can do an increment instead
3053 of add then GOOD for ME */
3054 if (genPlusIncr (ic) == TRUE)
3057 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3059 size = getDataSize (IC_RESULT (ic));
3061 /* Special case when left and right are constant */
3062 if (isPair (AOP (IC_RESULT (ic))))
3065 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3066 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3068 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3074 sprintf (buffer, "#(%s + %s)", left, right);
3075 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3080 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3082 /* Fetch into HL then do the add */
3083 spillPair (PAIR_HL);
3084 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3085 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3089 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD)
3091 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3092 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3094 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3099 ld hl,sp+n trashes C so we cant afford to do it during an
3100 add with stack based varibles. Worst case is:
3113 So you cant afford to load up hl if either left, right, or result
3114 is on the stack (*sigh*) The alt is:
3122 Combinations in here are:
3123 * If left or right are in bc then the loss is small - trap later
3124 * If the result is in bc then the loss is also small
3128 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3129 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3130 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3132 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3133 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3134 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3135 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3137 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3139 /* Swap left and right */
3140 operand *t = IC_RIGHT (ic);
3141 IC_RIGHT (ic) = IC_LEFT (ic);
3144 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3146 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3147 emit2 ("add hl,bc");
3151 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3152 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3153 emit2 ("add hl,de");
3155 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3161 /* Be paranoid on the GB with 4 byte variables due to how C
3162 can be trashed by lda hl,n(sp).
3164 _gbz80_emitAddSubLong (ic, TRUE);
3169 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3173 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3175 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3178 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3181 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3185 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3188 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3191 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3193 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3197 freeAsmop (IC_LEFT (ic), NULL, ic);
3198 freeAsmop (IC_RIGHT (ic), NULL, ic);
3199 freeAsmop (IC_RESULT (ic), NULL, ic);
3203 /*-----------------------------------------------------------------*/
3204 /* genMinusDec :- does subtraction with deccrement if possible */
3205 /*-----------------------------------------------------------------*/
3207 genMinusDec (iCode * ic)
3209 unsigned int icount;
3210 unsigned int size = getDataSize (IC_RESULT (ic));
3212 /* will try to generate an increment */
3213 /* if the right side is not a literal we cannot */
3214 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3217 /* if the literal value of the right hand side
3218 is greater than 4 then it is not worth it */
3219 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3222 size = getDataSize (IC_RESULT (ic));
3224 /* if decrement 16 bits in register */
3225 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3226 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3229 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3233 /* If result is a pair */
3234 if (isPair (AOP (IC_RESULT (ic))))
3236 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3238 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3242 /* if increment 16 bits in register */
3243 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3247 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3250 emit2 ("dec %s", _getTempPairName());
3253 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3259 /* if the sizes are greater than 1 then we cannot */
3260 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3261 AOP_SIZE (IC_LEFT (ic)) > 1)
3264 /* we can if the aops of the left & result match or if they are in
3265 registers and the registers are the same */
3266 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3269 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3276 /*-----------------------------------------------------------------*/
3277 /* genMinus - generates code for subtraction */
3278 /*-----------------------------------------------------------------*/
3280 genMinus (iCode * ic)
3282 int size, offset = 0;
3283 unsigned long lit = 0L;
3285 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3286 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3287 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3289 /* special cases :- */
3290 /* if both left & right are in bit space */
3291 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3292 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3294 wassertl (0, "Tried to subtract two bits");
3298 /* if I can do an decrement instead of subtract then GOOD for ME */
3299 if (genMinusDec (ic) == TRUE)
3302 size = getDataSize (IC_RESULT (ic));
3304 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3309 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3313 /* Same logic as genPlus */
3316 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3317 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3318 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3320 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3321 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3322 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3323 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3325 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3326 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3328 if (left == PAIR_INVALID && right == PAIR_INVALID)
3333 else if (right == PAIR_INVALID)
3335 else if (left == PAIR_INVALID)
3338 fetchPair (left, AOP (IC_LEFT (ic)));
3339 /* Order is important. Right may be HL */
3340 fetchPair (right, AOP (IC_RIGHT (ic)));
3342 emit2 ("ld a,%s", _pairs[left].l);
3343 emit2 ("sub a,%s", _pairs[right].l);
3345 emit2 ("ld a,%s", _pairs[left].h);
3346 emit2 ("sbc a,%s", _pairs[right].h);
3348 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3350 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3352 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3358 /* Be paranoid on the GB with 4 byte variables due to how C
3359 can be trashed by lda hl,n(sp).
3361 _gbz80_emitAddSubLong (ic, FALSE);
3366 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3368 /* if literal, add a,#-lit, else normal subb */
3371 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3372 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3376 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3379 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3383 /* first add without previous c */
3385 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3387 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3389 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3392 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3393 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3394 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3396 wassertl (0, "Tried to subtract on a long pointer");
3400 freeAsmop (IC_LEFT (ic), NULL, ic);
3401 freeAsmop (IC_RIGHT (ic), NULL, ic);
3402 freeAsmop (IC_RESULT (ic), NULL, ic);
3405 /*-----------------------------------------------------------------*/
3406 /* genMult - generates code for multiplication */
3407 /*-----------------------------------------------------------------*/
3409 genMult (iCode * ic)
3413 /* If true then the final operation should be a subtract */
3414 bool active = FALSE;
3416 /* Shouldn't occur - all done through function calls */
3417 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3418 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3419 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3421 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3422 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3423 AOP_SIZE (IC_RESULT (ic)) > 2)
3425 wassertl (0, "Multiplication is handled through support function calls");
3428 /* Swap left and right such that right is a literal */
3429 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3431 operand *t = IC_RIGHT (ic);
3432 IC_RIGHT (ic) = IC_LEFT (ic);
3436 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3438 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3439 // wassertl (val > 0, "Multiply must be positive");
3440 wassertl (val != 1, "Can't multiply by 1");
3446 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3448 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3456 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3461 /* Fully unroled version of mul.s. Not the most efficient.
3463 for (count = 0; count < 16; count++)
3465 if (count != 0 && active)
3467 emit2 ("add hl,hl");
3471 if (active == FALSE)
3478 emit2 ("add hl,de");
3492 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3494 freeAsmop (IC_LEFT (ic), NULL, ic);
3495 freeAsmop (IC_RIGHT (ic), NULL, ic);
3496 freeAsmop (IC_RESULT (ic), NULL, ic);
3499 /*-----------------------------------------------------------------*/
3500 /* genDiv - generates code for division */
3501 /*-----------------------------------------------------------------*/
3505 /* Shouldn't occur - all done through function calls */
3506 wassertl (0, "Division is handled through support function calls");
3509 /*-----------------------------------------------------------------*/
3510 /* genMod - generates code for division */
3511 /*-----------------------------------------------------------------*/
3515 /* Shouldn't occur - all done through function calls */
3519 /*-----------------------------------------------------------------*/
3520 /* genIfxJump :- will create a jump depending on the ifx */
3521 /*-----------------------------------------------------------------*/
3523 genIfxJump (iCode * ic, char *jval)
3528 /* if true label then we jump if condition
3532 jlbl = IC_TRUE (ic);
3533 if (!strcmp (jval, "a"))
3537 else if (!strcmp (jval, "c"))
3541 else if (!strcmp (jval, "nc"))
3547 /* The buffer contains the bit on A that we should test */
3553 /* false label is present */
3554 jlbl = IC_FALSE (ic);
3555 if (!strcmp (jval, "a"))
3559 else if (!strcmp (jval, "c"))
3563 else if (!strcmp (jval, "nc"))
3569 /* The buffer contains the bit on A that we should test */
3573 /* Z80 can do a conditional long jump */
3574 if (!strcmp (jval, "a"))
3578 else if (!strcmp (jval, "c"))
3581 else if (!strcmp (jval, "nc"))
3586 emit2 ("bit %s,a", jval);
3588 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3590 /* mark the icode as generated */
3596 _getPairIdName (PAIR_ID id)
3598 return _pairs[id].name;
3602 /** Generic compare for > or <
3605 genCmp (operand * left, operand * right,
3606 operand * result, iCode * ifx, int sign)
3608 int size, offset = 0;
3609 unsigned long lit = 0L;
3610 bool swap_sense = FALSE;
3612 /* if left & right are bit variables */
3613 if (AOP_TYPE (left) == AOP_CRY &&
3614 AOP_TYPE (right) == AOP_CRY)
3616 /* Cant happen on the Z80 */
3617 wassertl (0, "Tried to compare two bits");
3621 /* subtract right from left if at the
3622 end the carry flag is set then we know that
3623 left is greater than right */
3624 size = max (AOP_SIZE (left), AOP_SIZE (right));
3626 /* if unsigned char cmp with lit, just compare */
3628 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3630 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3633 emit2 ("xor a,!immedbyte", 0x80);
3634 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3637 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3639 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3641 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3642 // Pull left into DE and right into HL
3643 aopGet (AOP(left), LSB, FALSE);
3646 aopGet (AOP(right), LSB, FALSE);
3650 if (size == 0 && sign)
3652 // Highest byte when signed needs the bits flipped
3655 emit2 ("ld a,(de)");
3656 emit2 ("xor #0x80");
3658 emit2 ("ld a,(hl)");
3659 emit2 ("xor #0x80");
3663 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3667 emit2 ("ld a,(de)");
3668 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3678 spillPair (PAIR_HL);
3680 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3682 setupPair (PAIR_HL, AOP (left), 0);
3683 aopGet (AOP(right), LSB, FALSE);
3687 if (size == 0 && sign)
3689 // Highest byte when signed needs the bits flipped
3692 emit2 ("ld a,(hl)");
3693 emit2 ("xor #0x80");
3695 emit2 ("ld a,%d(iy)", offset);
3696 emit2 ("xor #0x80");
3700 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3704 emit2 ("ld a,(hl)");
3705 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3714 spillPair (PAIR_HL);
3715 spillPair (PAIR_IY);
3719 if (AOP_TYPE (right) == AOP_LIT)
3721 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3722 /* optimize if(x < 0) or if(x >= 0) */
3727 /* No sign so it's always false */
3732 /* Just load in the top most bit */
3733 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3734 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3736 genIfxJump (ifx, "7");
3748 /* First setup h and l contaning the top most bytes XORed */
3749 bool fDidXor = FALSE;
3750 if (AOP_TYPE (left) == AOP_LIT)
3752 unsigned long lit = (unsigned long)
3753 floatFromVal (AOP (left)->aopu.aop_lit);
3754 emit2 ("ld %s,!immedbyte", _fTmp[0],
3755 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3759 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3760 emit2 ("xor a,!immedbyte", 0x80);
3761 emit2 ("ld %s,a", _fTmp[0]);
3764 if (AOP_TYPE (right) == AOP_LIT)
3766 unsigned long lit = (unsigned long)
3767 floatFromVal (AOP (right)->aopu.aop_lit);
3768 emit2 ("ld %s,!immedbyte", _fTmp[1],
3769 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3773 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3774 emit2 ("xor a,!immedbyte", 0x80);
3775 emit2 ("ld %s,a", _fTmp[1]);
3781 /* Do a long subtract */
3784 _moveA (aopGet (AOP (left), offset, FALSE));
3786 if (sign && size == 0)
3788 emit2 ("ld a,%s", _fTmp[0]);
3789 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3793 /* Subtract through, propagating the carry */
3794 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3802 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3804 outBitCLong (result, swap_sense);
3808 /* if the result is used in the next
3809 ifx conditional branch then generate
3810 code a little differently */
3812 genIfxJump (ifx, swap_sense ? "nc" : "c");
3814 outBitCLong (result, swap_sense);
3815 /* leave the result in acc */
3819 /*-----------------------------------------------------------------*/
3820 /* genCmpGt :- greater than comparison */
3821 /*-----------------------------------------------------------------*/
3823 genCmpGt (iCode * ic, iCode * ifx)
3825 operand *left, *right, *result;
3826 sym_link *letype, *retype;
3829 left = IC_LEFT (ic);
3830 right = IC_RIGHT (ic);
3831 result = IC_RESULT (ic);
3833 letype = getSpec (operandType (left));
3834 retype = getSpec (operandType (right));
3835 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3836 /* assign the amsops */
3837 aopOp (left, ic, FALSE, FALSE);
3838 aopOp (right, ic, FALSE, FALSE);
3839 aopOp (result, ic, TRUE, FALSE);
3841 genCmp (right, left, result, ifx, sign);
3843 freeAsmop (left, NULL, ic);
3844 freeAsmop (right, NULL, ic);
3845 freeAsmop (result, NULL, ic);
3848 /*-----------------------------------------------------------------*/
3849 /* genCmpLt - less than comparisons */
3850 /*-----------------------------------------------------------------*/
3852 genCmpLt (iCode * ic, iCode * ifx)
3854 operand *left, *right, *result;
3855 sym_link *letype, *retype;
3858 left = IC_LEFT (ic);
3859 right = IC_RIGHT (ic);
3860 result = IC_RESULT (ic);
3862 letype = getSpec (operandType (left));
3863 retype = getSpec (operandType (right));
3864 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3866 /* assign the amsops */
3867 aopOp (left, ic, FALSE, FALSE);
3868 aopOp (right, ic, FALSE, FALSE);
3869 aopOp (result, ic, TRUE, FALSE);
3871 genCmp (left, right, result, ifx, sign);
3873 freeAsmop (left, NULL, ic);
3874 freeAsmop (right, NULL, ic);
3875 freeAsmop (result, NULL, ic);
3878 /*-----------------------------------------------------------------*/
3879 /* gencjneshort - compare and jump if not equal */
3880 /*-----------------------------------------------------------------*/
3882 gencjneshort (operand * left, operand * right, symbol * lbl)
3884 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3886 unsigned long lit = 0L;
3888 /* Swap the left and right if it makes the computation easier */
3889 if (AOP_TYPE (left) == AOP_LIT)
3896 if (AOP_TYPE (right) == AOP_LIT)
3897 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3899 /* if the right side is a literal then anything goes */
3900 if (AOP_TYPE (right) == AOP_LIT &&
3901 AOP_TYPE (left) != AOP_DIR)
3905 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3910 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
3917 emit2 ("jp nz,!tlabel", lbl->key + 100);
3923 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3924 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3927 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3928 emit2 ("jp nz,!tlabel", lbl->key + 100);
3933 /* if the right side is in a register or in direct space or
3934 if the left is a pointer register & right is not */
3935 else if (AOP_TYPE (right) == AOP_REG ||
3936 AOP_TYPE (right) == AOP_DIR ||
3937 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3941 _moveA (aopGet (AOP (left), offset, FALSE));
3942 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3943 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3945 emit2 ("jp nz,!tlabel", lbl->key + 100);
3948 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3949 emit2 ("jp nz,!tlabel", lbl->key + 100);
3956 /* right is a pointer reg need both a & b */
3957 /* PENDING: is this required? */
3960 _moveA (aopGet (AOP (right), offset, FALSE));
3961 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3962 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3968 /*-----------------------------------------------------------------*/
3969 /* gencjne - compare and jump if not equal */
3970 /*-----------------------------------------------------------------*/
3972 gencjne (operand * left, operand * right, symbol * lbl)
3974 symbol *tlbl = newiTempLabel (NULL);
3976 gencjneshort (left, right, lbl);
3979 emit2 ("ld a,!one");
3980 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3981 emitLabel (lbl->key + 100);
3983 emitLabel (tlbl->key + 100);
3986 /*-----------------------------------------------------------------*/
3987 /* genCmpEq - generates code for equal to */
3988 /*-----------------------------------------------------------------*/
3990 genCmpEq (iCode * ic, iCode * ifx)
3992 operand *left, *right, *result;
3994 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3995 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3996 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3998 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4000 /* Swap operands if it makes the operation easier. ie if:
4001 1. Left is a literal.
4003 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4005 operand *t = IC_RIGHT (ic);
4006 IC_RIGHT (ic) = IC_LEFT (ic);
4010 if (ifx && !AOP_SIZE (result))
4013 /* if they are both bit variables */
4014 if (AOP_TYPE (left) == AOP_CRY &&
4015 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4017 wassertl (0, "Tried to compare two bits");
4021 tlbl = newiTempLabel (NULL);
4022 gencjneshort (left, right, tlbl);
4025 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4026 emitLabel (tlbl->key + 100);
4030 /* PENDING: do this better */
4031 symbol *lbl = newiTempLabel (NULL);
4032 emit2 ("!shortjp !tlabel", lbl->key + 100);
4033 emitLabel (tlbl->key + 100);
4034 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4035 emitLabel (lbl->key + 100);
4038 /* mark the icode as generated */
4043 /* if they are both bit variables */
4044 if (AOP_TYPE (left) == AOP_CRY &&
4045 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4047 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4051 gencjne (left, right, newiTempLabel (NULL));
4052 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4058 genIfxJump (ifx, "a");
4061 /* if the result is used in an arithmetic operation
4062 then put the result in place */
4063 if (AOP_TYPE (result) != AOP_CRY)
4067 /* leave the result in acc */
4071 freeAsmop (left, NULL, ic);
4072 freeAsmop (right, NULL, ic);
4073 freeAsmop (result, NULL, ic);
4076 /*-----------------------------------------------------------------*/
4077 /* ifxForOp - returns the icode containing the ifx for operand */
4078 /*-----------------------------------------------------------------*/
4080 ifxForOp (operand * op, iCode * ic)
4082 /* if true symbol then needs to be assigned */
4083 if (IS_TRUE_SYMOP (op))
4086 /* if this has register type condition and
4087 the next instruction is ifx with the same operand
4088 and live to of the operand is upto the ifx only then */
4090 ic->next->op == IFX &&
4091 IC_COND (ic->next)->key == op->key &&
4092 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4098 /*-----------------------------------------------------------------*/
4099 /* genAndOp - for && operation */
4100 /*-----------------------------------------------------------------*/
4102 genAndOp (iCode * ic)
4104 operand *left, *right, *result;
4107 /* note here that && operations that are in an if statement are
4108 taken away by backPatchLabels only those used in arthmetic
4109 operations remain */
4110 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4111 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4112 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4114 /* if both are bit variables */
4115 if (AOP_TYPE (left) == AOP_CRY &&
4116 AOP_TYPE (right) == AOP_CRY)
4118 wassertl (0, "Tried to and two bits");
4122 tlbl = newiTempLabel (NULL);
4124 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4126 emitLabel (tlbl->key + 100);
4130 freeAsmop (left, NULL, ic);
4131 freeAsmop (right, NULL, ic);
4132 freeAsmop (result, NULL, ic);
4135 /*-----------------------------------------------------------------*/
4136 /* genOrOp - for || operation */
4137 /*-----------------------------------------------------------------*/
4139 genOrOp (iCode * ic)
4141 operand *left, *right, *result;
4144 /* note here that || operations that are in an
4145 if statement are taken away by backPatchLabels
4146 only those used in arthmetic operations remain */
4147 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4148 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4149 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4151 /* if both are bit variables */
4152 if (AOP_TYPE (left) == AOP_CRY &&
4153 AOP_TYPE (right) == AOP_CRY)
4155 wassertl (0, "Tried to OR two bits");
4159 tlbl = newiTempLabel (NULL);
4161 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4163 emitLabel (tlbl->key + 100);
4167 freeAsmop (left, NULL, ic);
4168 freeAsmop (right, NULL, ic);
4169 freeAsmop (result, NULL, ic);
4172 /*-----------------------------------------------------------------*/
4173 /* isLiteralBit - test if lit == 2^n */
4174 /*-----------------------------------------------------------------*/
4176 isLiteralBit (unsigned long lit)
4178 unsigned long pw[32] =
4179 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4180 0x100L, 0x200L, 0x400L, 0x800L,
4181 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4182 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4183 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4184 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4185 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4188 for (idx = 0; idx < 32; idx++)
4194 /*-----------------------------------------------------------------*/
4195 /* jmpTrueOrFalse - */
4196 /*-----------------------------------------------------------------*/
4198 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4200 // ugly but optimized by peephole
4203 symbol *nlbl = newiTempLabel (NULL);
4204 emit2 ("jp !tlabel", nlbl->key + 100);
4205 emitLabel (tlbl->key + 100);
4206 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4207 emitLabel (nlbl->key + 100);
4211 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4212 emitLabel (tlbl->key + 100);
4217 /*-----------------------------------------------------------------*/
4218 /* genAnd - code for and */
4219 /*-----------------------------------------------------------------*/
4221 genAnd (iCode * ic, iCode * ifx)
4223 operand *left, *right, *result;
4224 int size, offset = 0;
4225 unsigned long lit = 0L;
4228 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4229 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4230 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4232 /* if left is a literal & right is not then exchange them */
4233 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4234 AOP_NEEDSACC (left))
4236 operand *tmp = right;
4241 /* if result = right then exchange them */
4242 if (sameRegs (AOP (result), AOP (right)))
4244 operand *tmp = right;
4249 /* if right is bit then exchange them */
4250 if (AOP_TYPE (right) == AOP_CRY &&
4251 AOP_TYPE (left) != AOP_CRY)
4253 operand *tmp = right;
4257 if (AOP_TYPE (right) == AOP_LIT)
4258 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4260 size = AOP_SIZE (result);
4262 if (AOP_TYPE (left) == AOP_CRY)
4264 wassertl (0, "Tried to perform an AND with a bit as an operand");
4268 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4269 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4270 if ((AOP_TYPE (right) == AOP_LIT) &&
4271 (AOP_TYPE (result) == AOP_CRY) &&
4272 (AOP_TYPE (left) != AOP_CRY))
4274 symbol *tlbl = newiTempLabel (NULL);
4275 int sizel = AOP_SIZE (left);
4278 /* PENDING: Test case for this. */
4283 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4285 _moveA (aopGet (AOP (left), offset, FALSE));
4286 if (bytelit != 0x0FFL)
4288 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4295 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4299 // bit = left & literal
4303 emit2 ("!tlabeldef", tlbl->key + 100);
4305 // if(left & literal)
4310 jmpTrueOrFalse (ifx, tlbl);
4318 /* if left is same as result */
4319 if (sameRegs (AOP (result), AOP (left)))
4321 for (; size--; offset++)
4323 if (AOP_TYPE (right) == AOP_LIT)
4325 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4330 aopPut (AOP (result), "!zero", offset);
4333 _moveA (aopGet (AOP (left), offset, FALSE));
4335 aopGet (AOP (right), offset, FALSE));
4336 aopPut (AOP (left), "a", offset);
4343 if (AOP_TYPE (left) == AOP_ACC)
4345 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4349 _moveA (aopGet (AOP (left), offset, FALSE));
4351 aopGet (AOP (right), offset, FALSE));
4352 aopPut (AOP (left), "a", offset);
4359 // left & result in different registers
4360 if (AOP_TYPE (result) == AOP_CRY)
4362 wassertl (0, "Tried to AND where the result is in carry");
4366 for (; (size--); offset++)
4369 // result = left & right
4370 if (AOP_TYPE (right) == AOP_LIT)
4372 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4374 aopPut (AOP (result),
4375 aopGet (AOP (left), offset, FALSE),
4379 else if (bytelit == 0)
4381 aopPut (AOP (result), "!zero", offset);
4385 // faster than result <- left, anl result,right
4386 // and better if result is SFR
4387 if (AOP_TYPE (left) == AOP_ACC)
4388 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4391 _moveA (aopGet (AOP (left), offset, FALSE));
4393 aopGet (AOP (right), offset, FALSE));
4395 aopPut (AOP (result), "a", offset);
4402 freeAsmop (left, NULL, ic);
4403 freeAsmop (right, NULL, ic);
4404 freeAsmop (result, NULL, ic);
4407 /*-----------------------------------------------------------------*/
4408 /* genOr - code for or */
4409 /*-----------------------------------------------------------------*/
4411 genOr (iCode * ic, iCode * ifx)
4413 operand *left, *right, *result;
4414 int size, offset = 0;
4415 unsigned long lit = 0L;
4418 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4419 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4420 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4422 /* if left is a literal & right is not then exchange them */
4423 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4424 AOP_NEEDSACC (left))
4426 operand *tmp = right;
4431 /* if result = right then exchange them */
4432 if (sameRegs (AOP (result), AOP (right)))
4434 operand *tmp = right;
4439 /* if right is bit then exchange them */
4440 if (AOP_TYPE (right) == AOP_CRY &&
4441 AOP_TYPE (left) != AOP_CRY)
4443 operand *tmp = right;
4447 if (AOP_TYPE (right) == AOP_LIT)
4448 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4450 size = AOP_SIZE (result);
4452 if (AOP_TYPE (left) == AOP_CRY)
4454 wassertl (0, "Tried to OR where left is a bit");
4458 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4459 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4460 if ((AOP_TYPE (right) == AOP_LIT) &&
4461 (AOP_TYPE (result) == AOP_CRY) &&
4462 (AOP_TYPE (left) != AOP_CRY))
4464 symbol *tlbl = newiTempLabel (NULL);
4465 int sizel = AOP_SIZE (left);
4469 wassertl (0, "Result is assigned to a bit");
4471 /* PENDING: Modeled after the AND code which is inefficent. */
4474 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4476 _moveA (aopGet (AOP (left), offset, FALSE));
4477 /* OR with any literal is the same as OR with itself. */
4479 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4485 jmpTrueOrFalse (ifx, tlbl);
4490 /* if left is same as result */
4491 if (sameRegs (AOP (result), AOP (left)))
4493 for (; size--; offset++)
4495 if (AOP_TYPE (right) == AOP_LIT)
4497 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4501 _moveA (aopGet (AOP (left), offset, FALSE));
4503 aopGet (AOP (right), offset, FALSE));
4504 aopPut (AOP (result), "a", offset);
4509 if (AOP_TYPE (left) == AOP_ACC)
4510 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4513 _moveA (aopGet (AOP (left), offset, FALSE));
4515 aopGet (AOP (right), offset, FALSE));
4516 aopPut (AOP (result), "a", offset);
4523 // left & result in different registers
4524 if (AOP_TYPE (result) == AOP_CRY)
4526 wassertl (0, "Result of OR is in a bit");
4529 for (; (size--); offset++)
4532 // result = left & right
4533 if (AOP_TYPE (right) == AOP_LIT)
4535 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4537 aopPut (AOP (result),
4538 aopGet (AOP (left), offset, FALSE),
4543 // faster than result <- left, anl result,right
4544 // and better if result is SFR
4545 if (AOP_TYPE (left) == AOP_ACC)
4546 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4549 _moveA (aopGet (AOP (left), offset, FALSE));
4551 aopGet (AOP (right), offset, FALSE));
4553 aopPut (AOP (result), "a", offset);
4554 /* PENDING: something weird is going on here. Add exception. */
4555 if (AOP_TYPE (result) == AOP_ACC)
4561 freeAsmop (left, NULL, ic);
4562 freeAsmop (right, NULL, ic);
4563 freeAsmop (result, NULL, ic);
4566 /*-----------------------------------------------------------------*/
4567 /* genXor - code for xclusive or */
4568 /*-----------------------------------------------------------------*/
4570 genXor (iCode * ic, iCode * ifx)
4572 operand *left, *right, *result;
4573 int size, offset = 0;
4574 unsigned long lit = 0L;
4576 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4577 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4578 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4580 /* if left is a literal & right is not then exchange them */
4581 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4582 AOP_NEEDSACC (left))
4584 operand *tmp = right;
4589 /* if result = right then exchange them */
4590 if (sameRegs (AOP (result), AOP (right)))
4592 operand *tmp = right;
4597 /* if right is bit then exchange them */
4598 if (AOP_TYPE (right) == AOP_CRY &&
4599 AOP_TYPE (left) != AOP_CRY)
4601 operand *tmp = right;
4605 if (AOP_TYPE (right) == AOP_LIT)
4606 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4608 size = AOP_SIZE (result);
4610 if (AOP_TYPE (left) == AOP_CRY)
4612 wassertl (0, "Tried to XOR a bit");
4616 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4617 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4618 if ((AOP_TYPE (right) == AOP_LIT) &&
4619 (AOP_TYPE (result) == AOP_CRY) &&
4620 (AOP_TYPE (left) != AOP_CRY))
4622 symbol *tlbl = newiTempLabel (NULL);
4623 int sizel = AOP_SIZE (left);
4627 /* PENDING: Test case for this. */
4628 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4632 _moveA (aopGet (AOP (left), offset, FALSE));
4633 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4634 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4639 jmpTrueOrFalse (ifx, tlbl);
4643 wassertl (0, "Result of XOR was destined for a bit");
4648 /* if left is same as result */
4649 if (sameRegs (AOP (result), AOP (left)))
4651 for (; size--; offset++)
4653 if (AOP_TYPE (right) == AOP_LIT)
4655 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4659 _moveA (aopGet (AOP (right), offset, FALSE));
4661 aopGet (AOP (left), offset, FALSE));
4662 aopPut (AOP (result), "a", offset);
4667 if (AOP_TYPE (left) == AOP_ACC)
4669 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4673 _moveA (aopGet (AOP (right), offset, FALSE));
4675 aopGet (AOP (left), offset, FALSE));
4676 aopPut (AOP (result), "a", 0);
4683 // left & result in different registers
4684 if (AOP_TYPE (result) == AOP_CRY)
4686 wassertl (0, "Result of XOR is in a bit");
4689 for (; (size--); offset++)
4692 // result = left & right
4693 if (AOP_TYPE (right) == AOP_LIT)
4695 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4697 aopPut (AOP (result),
4698 aopGet (AOP (left), offset, FALSE),
4703 // faster than result <- left, anl result,right
4704 // and better if result is SFR
4705 if (AOP_TYPE (left) == AOP_ACC)
4707 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4711 _moveA (aopGet (AOP (right), offset, FALSE));
4713 aopGet (AOP (left), offset, FALSE));
4715 aopPut (AOP (result), "a", offset);
4720 freeAsmop (left, NULL, ic);
4721 freeAsmop (right, NULL, ic);
4722 freeAsmop (result, NULL, ic);
4725 /*-----------------------------------------------------------------*/
4726 /* genInline - write the inline code out */
4727 /*-----------------------------------------------------------------*/
4729 genInline (iCode * ic)
4731 char *buffer, *bp, *bp1;
4733 _G.lines.isInline += (!options.asmpeep);
4735 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4736 strcpy (buffer, IC_INLINE (ic));
4738 /* emit each line as a code */
4763 _G.lines.isInline -= (!options.asmpeep);
4767 /*-----------------------------------------------------------------*/
4768 /* genRRC - rotate right with carry */
4769 /*-----------------------------------------------------------------*/
4776 /*-----------------------------------------------------------------*/
4777 /* genRLC - generate code for rotate left with carry */
4778 /*-----------------------------------------------------------------*/
4785 /*-----------------------------------------------------------------*/
4786 /* genGetHbit - generates code get highest order bit */
4787 /*-----------------------------------------------------------------*/
4789 genGetHbit (iCode * ic)
4791 operand *left, *result;
4792 left = IC_LEFT (ic);
4793 result = IC_RESULT (ic);
4794 aopOp (left, ic, FALSE, FALSE);
4795 aopOp (result, ic, FALSE, FALSE);
4797 /* get the highest order byte into a */
4798 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4800 if (AOP_TYPE (result) == AOP_CRY)
4808 /* PENDING: For re-target. */
4814 freeAsmop (left, NULL, ic);
4815 freeAsmop (result, NULL, ic);
4819 emitRsh2 (asmop *aop, int size, int is_signed)
4825 const char *l = aopGet (aop, size, FALSE);
4828 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4838 /*-----------------------------------------------------------------*/
4839 /* shiftR2Left2Result - shift right two bytes from left to result */
4840 /*-----------------------------------------------------------------*/
4842 shiftR2Left2Result (operand * left, int offl,
4843 operand * result, int offr,
4844 int shCount, int is_signed)
4847 symbol *tlbl, *tlbl1;
4849 movLeft2Result (left, offl, result, offr, 0);
4850 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4852 /* if (AOP(result)->type == AOP_REG) { */
4854 tlbl = newiTempLabel (NULL);
4855 tlbl1 = newiTempLabel (NULL);
4857 /* Left is already in result - so now do the shift */
4862 emitRsh2 (AOP (result), size, is_signed);
4867 emit2 ("ld a,!immedbyte+1", shCount);
4868 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4869 emitLabel (tlbl->key + 100);
4871 emitRsh2 (AOP (result), size, is_signed);
4873 emitLabel (tlbl1->key + 100);
4875 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4879 /*-----------------------------------------------------------------*/
4880 /* shiftL2Left2Result - shift left two bytes from left to result */
4881 /*-----------------------------------------------------------------*/
4883 shiftL2Left2Result (operand * left, int offl,
4884 operand * result, int offr, int shCount)
4886 if (sameRegs (AOP (result), AOP (left)) &&
4887 ((offl + MSB16) == offr))
4893 /* Copy left into result */
4894 movLeft2Result (left, offl, result, offr, 0);
4895 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4897 /* PENDING: for now just see if it'll work. */
4898 /*if (AOP(result)->type == AOP_REG) { */
4902 symbol *tlbl, *tlbl1;
4905 tlbl = newiTempLabel (NULL);
4906 tlbl1 = newiTempLabel (NULL);
4908 /* Left is already in result - so now do the shift */
4911 emit2 ("ld a,!immedbyte+1", shCount);
4912 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4913 emitLabel (tlbl->key + 100);
4918 l = aopGet (AOP (result), offset, FALSE);
4922 emit2 ("sla %s", l);
4933 emitLabel (tlbl1->key + 100);
4935 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4940 /*-----------------------------------------------------------------*/
4941 /* AccRol - rotate left accumulator by known count */
4942 /*-----------------------------------------------------------------*/
4944 AccRol (int shCount)
4946 shCount &= 0x0007; // shCount : 0..7
4985 /*-----------------------------------------------------------------*/
4986 /* AccLsh - left shift accumulator by known count */
4987 /*-----------------------------------------------------------------*/
4989 AccLsh (int shCount)
4991 static const unsigned char SLMask[] =
4993 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5002 else if (shCount == 2)
5009 /* rotate left accumulator */
5011 /* and kill the lower order bits */
5012 emit2 ("and a,!immedbyte", SLMask[shCount]);
5017 /*-----------------------------------------------------------------*/
5018 /* shiftL1Left2Result - shift left one byte from left to result */
5019 /*-----------------------------------------------------------------*/
5021 shiftL1Left2Result (operand * left, int offl,
5022 operand * result, int offr, int shCount)
5025 l = aopGet (AOP (left), offl, FALSE);
5027 /* shift left accumulator */
5029 aopPut (AOP (result), "a", offr);
5033 /*-----------------------------------------------------------------*/
5034 /* genlshTwo - left shift two bytes by known amount != 0 */
5035 /*-----------------------------------------------------------------*/
5037 genlshTwo (operand * result, operand * left, int shCount)
5039 int size = AOP_SIZE (result);
5041 wassert (size == 2);
5043 /* if shCount >= 8 */
5051 movLeft2Result (left, LSB, result, MSB16, 0);
5052 aopPut (AOP (result), "!zero", 0);
5053 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5057 movLeft2Result (left, LSB, result, MSB16, 0);
5058 aopPut (AOP (result), "!zero", 0);
5063 aopPut (AOP (result), "!zero", LSB);
5066 /* 1 <= shCount <= 7 */
5075 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5080 /*-----------------------------------------------------------------*/
5081 /* genlshOne - left shift a one byte quantity by known count */
5082 /*-----------------------------------------------------------------*/
5084 genlshOne (operand * result, operand * left, int shCount)
5086 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5089 /*-----------------------------------------------------------------*/
5090 /* genLeftShiftLiteral - left shifting by known count */
5091 /*-----------------------------------------------------------------*/
5093 genLeftShiftLiteral (operand * left,
5098 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5101 freeAsmop (right, NULL, ic);
5103 aopOp (left, ic, FALSE, FALSE);
5104 aopOp (result, ic, FALSE, FALSE);
5106 size = getSize (operandType (result));
5108 /* I suppose that the left size >= result size */
5114 else if (shCount >= (size * 8))
5118 aopPut (AOP (result), "!zero", size);
5126 genlshOne (result, left, shCount);
5129 genlshTwo (result, left, shCount);
5132 wassertl (0, "Shifting of longs is currently unsupported");
5138 freeAsmop (left, NULL, ic);
5139 freeAsmop (result, NULL, ic);
5142 /*-----------------------------------------------------------------*/
5143 /* genLeftShift - generates code for left shifting */
5144 /*-----------------------------------------------------------------*/
5146 genLeftShift (iCode * ic)
5150 symbol *tlbl, *tlbl1;
5151 operand *left, *right, *result;
5153 right = IC_RIGHT (ic);
5154 left = IC_LEFT (ic);
5155 result = IC_RESULT (ic);
5157 aopOp (right, ic, FALSE, FALSE);
5159 /* if the shift count is known then do it
5160 as efficiently as possible */
5161 if (AOP_TYPE (right) == AOP_LIT)
5163 genLeftShiftLiteral (left, right, result, ic);
5167 /* shift count is unknown then we have to form a loop get the loop
5168 count in B : Note: we take only the lower order byte since
5169 shifting more that 32 bits make no sense anyway, ( the largest
5170 size of an object can be only 32 bits ) */
5171 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5173 freeAsmop (right, NULL, ic);
5174 aopOp (left, ic, FALSE, FALSE);
5175 aopOp (result, ic, FALSE, FALSE);
5177 /* now move the left to the result if they are not the
5180 if (!sameRegs (AOP (left), AOP (result)))
5183 size = AOP_SIZE (result);
5187 l = aopGet (AOP (left), offset, FALSE);
5188 aopPut (AOP (result), l, offset);
5193 tlbl = newiTempLabel (NULL);
5194 size = AOP_SIZE (result);
5196 tlbl1 = newiTempLabel (NULL);
5198 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5199 emitLabel (tlbl->key + 100);
5200 l = aopGet (AOP (result), offset, FALSE);
5204 l = aopGet (AOP (result), offset, FALSE);
5208 emit2 ("sla %s", l);
5216 emitLabel (tlbl1->key + 100);
5218 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5220 freeAsmop (left, NULL, ic);
5221 freeAsmop (result, NULL, ic);
5224 /*-----------------------------------------------------------------*/
5225 /* genrshOne - left shift two bytes by known amount != 0 */
5226 /*-----------------------------------------------------------------*/
5228 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5231 int size = AOP_SIZE (result);
5234 wassert (size == 1);
5235 wassert (shCount < 8);
5237 l = aopGet (AOP (left), 0, FALSE);
5239 if (AOP (result)->type == AOP_REG)
5241 aopPut (AOP (result), l, 0);
5242 l = aopGet (AOP (result), 0, FALSE);
5245 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5253 emit2 ("%s a", is_signed ? "sra" : "srl");
5255 aopPut (AOP (result), "a", 0);
5259 /*-----------------------------------------------------------------*/
5260 /* AccRsh - right shift accumulator by known count */
5261 /*-----------------------------------------------------------------*/
5263 AccRsh (int shCount)
5265 static const unsigned char SRMask[] =
5267 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5272 /* rotate right accumulator */
5273 AccRol (8 - shCount);
5274 /* and kill the higher order bits */
5275 emit2 ("and a,!immedbyte", SRMask[shCount]);
5279 /*-----------------------------------------------------------------*/
5280 /* shiftR1Left2Result - shift right one byte from left to result */
5281 /*-----------------------------------------------------------------*/
5283 shiftR1Left2Result (operand * left, int offl,
5284 operand * result, int offr,
5285 int shCount, int sign)
5287 _moveA (aopGet (AOP (left), offl, FALSE));
5292 emit2 ("%s a", sign ? "sra" : "srl");
5299 aopPut (AOP (result), "a", offr);
5302 /*-----------------------------------------------------------------*/
5303 /* genrshTwo - right shift two bytes by known amount != 0 */
5304 /*-----------------------------------------------------------------*/
5306 genrshTwo (operand * result, operand * left,
5307 int shCount, int sign)
5309 /* if shCount >= 8 */
5315 shiftR1Left2Result (left, MSB16, result, LSB,
5320 movLeft2Result (left, MSB16, result, LSB, sign);
5324 /* Sign extend the result */
5325 _moveA(aopGet (AOP (result), 0, FALSE));
5329 aopPut (AOP (result), ACC_NAME, MSB16);
5333 aopPut (AOP (result), "!zero", 1);
5336 /* 1 <= shCount <= 7 */
5339 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5343 /*-----------------------------------------------------------------*/
5344 /* genRightShiftLiteral - left shifting by known count */
5345 /*-----------------------------------------------------------------*/
5347 genRightShiftLiteral (operand * left,
5353 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5356 freeAsmop (right, NULL, ic);
5358 aopOp (left, ic, FALSE, FALSE);
5359 aopOp (result, ic, FALSE, FALSE);
5361 size = getSize (operandType (result));
5363 /* I suppose that the left size >= result size */
5369 else if (shCount >= (size * 8))
5371 aopPut (AOP (result), "!zero", size);
5377 genrshOne (result, left, shCount, sign);
5380 genrshTwo (result, left, shCount, sign);
5383 wassertl (0, "Asked to shift right a long which should be a function call");
5386 wassertl (0, "Entered default case in right shift delegate");
5389 freeAsmop (left, NULL, ic);
5390 freeAsmop (result, NULL, ic);
5393 /*-----------------------------------------------------------------*/
5394 /* genRightShift - generate code for right shifting */
5395 /*-----------------------------------------------------------------*/
5397 genRightShift (iCode * ic)
5399 operand *right, *left, *result;
5401 int size, offset, first = 1;
5405 symbol *tlbl, *tlbl1;
5407 /* if signed then we do it the hard way preserve the
5408 sign bit moving it inwards */
5409 retype = getSpec (operandType (IC_RESULT (ic)));
5411 is_signed = !SPEC_USIGN (retype);
5413 /* signed & unsigned types are treated the same : i.e. the
5414 signed is NOT propagated inwards : quoting from the
5415 ANSI - standard : "for E1 >> E2, is equivalent to division
5416 by 2**E2 if unsigned or if it has a non-negative value,
5417 otherwise the result is implementation defined ", MY definition
5418 is that the sign does not get propagated */
5420 right = IC_RIGHT (ic);
5421 left = IC_LEFT (ic);
5422 result = IC_RESULT (ic);
5424 aopOp (right, ic, FALSE, FALSE);
5426 /* if the shift count is known then do it
5427 as efficiently as possible */
5428 if (AOP_TYPE (right) == AOP_LIT)
5430 genRightShiftLiteral (left, right, result, ic, is_signed);
5434 aopOp (left, ic, FALSE, FALSE);
5435 aopOp (result, ic, FALSE, FALSE);
5437 /* now move the left to the result if they are not the
5439 if (!sameRegs (AOP (left), AOP (result)) &&
5440 AOP_SIZE (result) > 1)
5443 size = AOP_SIZE (result);
5447 l = aopGet (AOP (left), offset, FALSE);
5448 aopPut (AOP (result), l, offset);
5453 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5455 freeAsmop (right, NULL, ic);
5457 tlbl = newiTempLabel (NULL);
5458 tlbl1 = newiTempLabel (NULL);
5459 size = AOP_SIZE (result);
5462 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5463 emitLabel (tlbl->key + 100);
5466 l = aopGet (AOP (result), offset--, FALSE);
5469 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5477 emitLabel (tlbl1->key + 100);
5479 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5481 freeAsmop (left, NULL, ic);
5482 freeAsmop (result, NULL, ic);
5485 /*-----------------------------------------------------------------*/
5486 /* genGenPointerGet - get value from generic pointer space */
5487 /*-----------------------------------------------------------------*/
5489 genGenPointerGet (operand * left,
5490 operand * result, iCode * ic)
5493 sym_link *retype = getSpec (operandType (result));
5499 aopOp (left, ic, FALSE, FALSE);
5500 aopOp (result, ic, FALSE, FALSE);
5502 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5505 if (isPtrPair (AOP (left)))
5507 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5508 aopPut (AOP (result), buffer, 0);
5512 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5513 aopPut (AOP (result), "a", 0);
5515 freeAsmop (left, NULL, ic);
5519 /* For now we always load into IY */
5520 /* if this is remateriazable */
5521 fetchPair (pair, AOP (left));
5523 /* so iy now contains the address */
5524 freeAsmop (left, NULL, ic);
5526 /* if bit then unpack */
5527 if (IS_BITVAR (retype))
5533 size = AOP_SIZE (result);
5538 /* PENDING: make this better */
5539 if (!IS_GB && AOP (result)->type == AOP_REG)
5541 aopPut (AOP (result), "!*hl", offset++);
5545 emit2 ("ld a,!*pair", _pairs[pair].name);
5546 aopPut (AOP (result), "a", offset++);
5550 emit2 ("inc %s", _pairs[pair].name);
5551 _G.pairs[pair].offset++;
5557 freeAsmop (result, NULL, ic);
5560 /*-----------------------------------------------------------------*/
5561 /* genPointerGet - generate code for pointer get */
5562 /*-----------------------------------------------------------------*/
5564 genPointerGet (iCode * ic)
5566 operand *left, *result;
5567 sym_link *type, *etype;
5569 left = IC_LEFT (ic);
5570 result = IC_RESULT (ic);
5572 /* depending on the type of pointer we need to
5573 move it to the correct pointer register */
5574 type = operandType (left);
5575 etype = getSpec (type);
5577 genGenPointerGet (left, result, ic);
5581 isRegOrLit (asmop * aop)
5583 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5588 /*-----------------------------------------------------------------*/
5589 /* genGenPointerSet - stores the value into a pointer location */
5590 /*-----------------------------------------------------------------*/
5592 genGenPointerSet (operand * right,
5593 operand * result, iCode * ic)
5596 sym_link *retype = getSpec (operandType (right));
5597 PAIR_ID pairId = PAIR_HL;
5599 aopOp (result, ic, FALSE, FALSE);
5600 aopOp (right, ic, FALSE, FALSE);
5605 /* Handle the exceptions first */
5606 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5609 const char *l = aopGet (AOP (right), 0, FALSE);
5610 const char *pair = getPairName (AOP (result));
5611 if (canAssignToPtr (l) && isPtr (pair))
5613 emit2 ("ld !*pair,%s", pair, l);
5618 emit2 ("ld !*pair,a", pair);
5623 /* if the operand is already in dptr
5624 then we do nothing else we move the value to dptr */
5625 if (AOP_TYPE (result) != AOP_STR)
5627 fetchPair (pairId, AOP (result));
5629 /* so hl know contains the address */
5630 freeAsmop (result, NULL, ic);
5632 /* if bit then unpack */
5633 if (IS_BITVAR (retype))
5639 size = AOP_SIZE (right);
5644 const char *l = aopGet (AOP (right), offset, FALSE);
5645 if (isRegOrLit (AOP (right)) && !IS_GB)
5647 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5652 emit2 ("ld !*pair,a", _pairs[pairId].name);
5656 emit2 ("inc %s", _pairs[pairId].name);
5657 _G.pairs[pairId].offset++;
5663 freeAsmop (right, NULL, ic);
5666 /*-----------------------------------------------------------------*/
5667 /* genPointerSet - stores the value into a pointer location */
5668 /*-----------------------------------------------------------------*/
5670 genPointerSet (iCode * ic)
5672 operand *right, *result;
5673 sym_link *type, *etype;
5675 right = IC_RIGHT (ic);
5676 result = IC_RESULT (ic);
5678 /* depending on the type of pointer we need to
5679 move it to the correct pointer register */
5680 type = operandType (result);
5681 etype = getSpec (type);
5683 genGenPointerSet (right, result, ic);
5686 /*-----------------------------------------------------------------*/
5687 /* genIfx - generate code for Ifx statement */
5688 /*-----------------------------------------------------------------*/
5690 genIfx (iCode * ic, iCode * popIc)
5692 operand *cond = IC_COND (ic);
5695 aopOp (cond, ic, FALSE, TRUE);
5697 /* get the value into acc */
5698 if (AOP_TYPE (cond) != AOP_CRY)
5702 /* the result is now in the accumulator */
5703 freeAsmop (cond, NULL, ic);
5705 /* if there was something to be popped then do it */
5709 /* if the condition is a bit variable */
5710 if (isbit && IS_ITEMP (cond) &&
5712 genIfxJump (ic, SPIL_LOC (cond)->rname);
5713 else if (isbit && !IS_ITEMP (cond))
5714 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5716 genIfxJump (ic, "a");
5721 /*-----------------------------------------------------------------*/
5722 /* genAddrOf - generates code for address of */
5723 /*-----------------------------------------------------------------*/
5725 genAddrOf (iCode * ic)
5727 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5729 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5731 /* if the operand is on the stack then we
5732 need to get the stack offset of this
5739 if (sym->stack <= 0)
5741 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
5745 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5747 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5751 emit2 ("ld de,!hashedstr", sym->rname);
5752 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
5760 /* if it has an offset then we need to compute it */
5762 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5764 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5765 emit2 ("add hl,sp");
5769 emit2 ("ld hl,#%s", sym->rname);
5771 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5773 freeAsmop (IC_RESULT (ic), NULL, ic);
5776 /*-----------------------------------------------------------------*/
5777 /* genAssign - generate code for assignment */
5778 /*-----------------------------------------------------------------*/
5780 genAssign (iCode * ic)
5782 operand *result, *right;
5784 unsigned long lit = 0L;
5786 result = IC_RESULT (ic);
5787 right = IC_RIGHT (ic);
5789 /* Dont bother assigning if they are the same */
5790 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5792 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5796 aopOp (right, ic, FALSE, FALSE);
5797 aopOp (result, ic, TRUE, FALSE);
5799 /* if they are the same registers */
5800 if (sameRegs (AOP (right), AOP (result)))
5802 emitDebug ("; (registers are the same)");
5806 /* if the result is a bit */
5807 if (AOP_TYPE (result) == AOP_CRY)
5809 wassertl (0, "Tried to assign to a bit");
5813 size = AOP_SIZE (result);
5816 if (AOP_TYPE (right) == AOP_LIT)
5817 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5818 if (isPair (AOP (result)))
5820 fetchPair (getPairId (AOP (result)), AOP (right));
5822 else if ((size > 1) &&
5823 (AOP_TYPE (result) != AOP_REG) &&
5824 (AOP_TYPE (right) == AOP_LIT) &&
5825 !IS_FLOAT (operandType (right)) &&
5828 bool fXored = FALSE;
5830 /* Work from the top down.
5831 Done this way so that we can use the cached copy of 0
5832 in A for a fast clear */
5835 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5837 if (!fXored && size > 1)
5844 aopPut (AOP (result), "a", offset);
5848 aopPut (AOP (result), "!zero", offset);
5852 aopPut (AOP (result),
5853 aopGet (AOP (right), offset, FALSE),
5858 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5860 /* Special case. Load into a and d, then load out. */
5861 _moveA (aopGet (AOP (right), 0, FALSE));
5862 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5863 aopPut (AOP (result), "a", 0);
5864 aopPut (AOP (result), "e", 1);
5866 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5868 /* Special case - simple memcpy */
5869 aopGet (AOP (right), LSB, FALSE);
5872 aopGet (AOP (result), LSB, FALSE);
5876 emit2 ("ld a,(de)");
5877 /* Peephole will optimise this. */
5878 emit2 ("ld (hl),a");
5886 spillPair (PAIR_HL);
5892 /* PENDING: do this check better */
5893 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5895 _moveA (aopGet (AOP (right), offset, FALSE));
5896 aopPut (AOP (result), "a", offset);
5899 aopPut (AOP (result),
5900 aopGet (AOP (right), offset, FALSE),
5907 freeAsmop (right, NULL, ic);
5908 freeAsmop (result, NULL, ic);
5911 /*-----------------------------------------------------------------*/
5912 /* genJumpTab - genrates code for jump table */
5913 /*-----------------------------------------------------------------*/
5915 genJumpTab (iCode * ic)
5920 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5921 /* get the condition into accumulator */
5922 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5925 emit2 ("ld e,%s", l);
5926 emit2 ("ld d,!zero");
5927 jtab = newiTempLabel (NULL);
5929 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5930 emit2 ("add hl,de");
5931 emit2 ("add hl,de");
5932 emit2 ("add hl,de");
5933 freeAsmop (IC_JTCOND (ic), NULL, ic);
5937 emitLabel (jtab->key + 100);
5938 /* now generate the jump labels */
5939 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5940 jtab = setNextItem (IC_JTLABELS (ic)))
5941 emit2 ("jp !tlabel", jtab->key + 100);
5944 /*-----------------------------------------------------------------*/
5945 /* genCast - gen code for casting */
5946 /*-----------------------------------------------------------------*/
5948 genCast (iCode * ic)
5950 operand *result = IC_RESULT (ic);
5951 sym_link *ctype = operandType (IC_LEFT (ic));
5952 operand *right = IC_RIGHT (ic);
5955 /* if they are equivalent then do nothing */
5956 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5959 aopOp (right, ic, FALSE, FALSE);
5960 aopOp (result, ic, FALSE, FALSE);
5962 /* if the result is a bit */
5963 if (AOP_TYPE (result) == AOP_CRY)
5965 wassertl (0, "Tried to cast to a bit");
5968 /* if they are the same size : or less */
5969 if (AOP_SIZE (result) <= AOP_SIZE (right))
5972 /* if they are in the same place */
5973 if (sameRegs (AOP (right), AOP (result)))
5976 /* if they in different places then copy */
5977 size = AOP_SIZE (result);
5981 aopPut (AOP (result),
5982 aopGet (AOP (right), offset, FALSE),
5989 /* So we now know that the size of destination is greater
5990 than the size of the source */
5991 /* we move to result for the size of source */
5992 size = AOP_SIZE (right);
5996 aopPut (AOP (result),
5997 aopGet (AOP (right), offset, FALSE),
6002 /* now depending on the sign of the destination */
6003 size = AOP_SIZE (result) - AOP_SIZE (right);
6004 /* Unsigned or not an integral type - right fill with zeros */
6005 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6008 aopPut (AOP (result), "!zero", offset++);
6012 /* we need to extend the sign :{ */
6013 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6019 aopPut (AOP (result), "a", offset++);
6023 freeAsmop (right, NULL, ic);
6024 freeAsmop (result, NULL, ic);
6027 /*-----------------------------------------------------------------*/
6028 /* genReceive - generate code for a receive iCode */
6029 /*-----------------------------------------------------------------*/
6031 genReceive (iCode * ic)
6033 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6034 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6035 IS_TRUE_SYMOP (IC_RESULT (ic))))
6045 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6046 size = AOP_SIZE(IC_RESULT(ic));
6048 for (i = 0; i < size; i++) {
6049 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6053 freeAsmop (IC_RESULT (ic), NULL, ic);
6058 /** Maximum number of bytes to emit per line. */
6062 /** Context for the byte output chunker. */
6065 unsigned char buffer[DBEMIT_MAX_RUN];
6070 /** Flushes a byte chunker by writing out all in the buffer and
6074 _dbFlush(DBEMITCTX *self)
6081 sprintf(line, ".db 0x%02X", self->buffer[0]);
6083 for (i = 1; i < self->pos; i++)
6085 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6092 /** Write out another byte, buffering until a decent line is
6096 _dbEmit(DBEMITCTX *self, int c)
6098 if (self->pos == DBEMIT_MAX_RUN)
6102 self->buffer[self->pos++] = c;
6105 /** Context for a simple run length encoder. */
6109 unsigned char buffer[128];
6111 /** runLen may be equivalent to pos. */
6117 RLE_CHANGE_COST = 4,
6121 /** Flush the buffer of a run length encoder by writing out the run or
6122 data that it currently contains.
6125 _rleCommit(RLECTX *self)
6131 memset(&db, 0, sizeof(db));
6133 emit2(".db %u", self->pos);
6135 for (i = 0; i < self->pos; i++)
6137 _dbEmit(&db, self->buffer[i]);
6146 Can get either a run or a block of random stuff.
6147 Only want to change state if a good run comes in or a run ends.
6148 Detecting run end is easy.
6151 Say initial state is in run, len zero, last zero. Then if you get a
6152 few zeros then something else then a short run will be output.
6153 Seems OK. While in run mode, keep counting. While in random mode,
6154 keep a count of the run. If run hits margin, output all up to run,
6155 restart, enter run mode.
6158 /** Add another byte into the run length encoder, flushing as
6159 required. The run length encoder uses the Amiga IFF style, where
6160 a block is prefixed by its run length. A positive length means
6161 the next n bytes pass straight through. A negative length means
6162 that the next byte is repeated -n times. A zero terminates the
6166 _rleAppend(RLECTX *self, int c)
6170 if (c != self->last)
6172 /* The run has stopped. See if it is worthwhile writing it out
6173 as a run. Note that the random data comes in as runs of
6176 if (self->runLen > RLE_CHANGE_COST)
6178 /* Yes, worthwhile. */
6179 /* Commit whatever was in the buffer. */
6181 emit2(".db -%u,0x%02X", self->runLen, self->last);
6185 /* Not worthwhile. Append to the end of the random list. */
6186 for (i = 0; i < self->runLen; i++)
6188 if (self->pos >= RLE_MAX_BLOCK)
6193 self->buffer[self->pos++] = self->last;
6201 if (self->runLen >= RLE_MAX_BLOCK)
6203 /* Commit whatever was in the buffer. */
6206 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6214 _rleFlush(RLECTX *self)
6216 _rleAppend(self, -1);
6223 /** genArrayInit - Special code for initialising an array with constant
6227 genArrayInit (iCode * ic)
6231 int elementSize = 0, eIndex, i;
6232 unsigned val, lastVal;
6236 memset(&rle, 0, sizeof(rle));
6238 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6240 _saveRegsForCall(ic, 0);
6242 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6243 emit2 ("call __initrleblock");
6245 type = operandType(IC_LEFT(ic));
6247 if (type && type->next)
6249 elementSize = getSize(type->next);
6253 wassertl (0, "Can't determine element size in genArrayInit.");
6256 iLoop = IC_ARRAYILIST(ic);
6257 lastVal = (unsigned)-1;
6259 /* Feed all the bytes into the run length encoder which will handle
6261 This works well for mixed char data, and for random int and long
6270 for (i = 0; i < ix; i++)
6272 for (eIndex = 0; eIndex < elementSize; eIndex++)
6274 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6275 _rleAppend(&rle, val);
6280 iLoop = iLoop->next;
6284 /* Mark the end of the run. */
6287 _restoreRegsAfterCall();
6291 freeAsmop (IC_LEFT(ic), NULL, ic);
6294 /*-----------------------------------------------------------------*/
6295 /* genZ80Code - generate code for Z80 based controllers */
6296 /*-----------------------------------------------------------------*/
6298 genZ80Code (iCode * lic)
6306 _fReturn = _gbz80_return;
6307 _fTmp = _gbz80_return;
6311 _fReturn = _z80_return;
6312 _fTmp = _z80_return;
6315 _G.lines.head = _G.lines.current = NULL;
6317 for (ic = lic; ic; ic = ic->next)
6320 if (cln != ic->lineno)
6322 emit2 ("; %s %d", ic->filename, ic->lineno);
6325 /* if the result is marked as
6326 spilt and rematerializable or code for
6327 this has already been generated then
6329 if (resultRemat (ic) || ic->generated)
6332 /* depending on the operation */
6336 emitDebug ("; genNot");
6341 emitDebug ("; genCpl");
6346 emitDebug ("; genUminus");
6351 emitDebug ("; genIpush");
6356 /* IPOP happens only when trying to restore a
6357 spilt live range, if there is an ifx statement
6358 following this pop then the if statement might
6359 be using some of the registers being popped which
6360 would destory the contents of the register so
6361 we need to check for this condition and handle it */
6363 ic->next->op == IFX &&
6364 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6366 emitDebug ("; genIfx");
6367 genIfx (ic->next, ic);
6371 emitDebug ("; genIpop");
6377 emitDebug ("; genCall");
6382 emitDebug ("; genPcall");
6387 emitDebug ("; genFunction");
6392 emitDebug ("; genEndFunction");
6393 genEndFunction (ic);
6397 emitDebug ("; genRet");
6402 emitDebug ("; genLabel");
6407 emitDebug ("; genGoto");
6412 emitDebug ("; genPlus");
6417 emitDebug ("; genMinus");
6422 emitDebug ("; genMult");
6427 emitDebug ("; genDiv");
6432 emitDebug ("; genMod");
6437 emitDebug ("; genCmpGt");
6438 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6442 emitDebug ("; genCmpLt");
6443 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6450 /* note these two are xlated by algebraic equivalence
6451 during parsing SDCC.y */
6452 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6453 "got '>=' or '<=' shouldn't have come here");
6457 emitDebug ("; genCmpEq");
6458 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6462 emitDebug ("; genAndOp");
6467 emitDebug ("; genOrOp");
6472 emitDebug ("; genXor");
6473 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6477 emitDebug ("; genOr");
6478 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6482 emitDebug ("; genAnd");
6483 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6487 emitDebug ("; genInline");
6492 emitDebug ("; genRRC");
6497 emitDebug ("; genRLC");
6502 emitDebug ("; genGetHBIT");
6507 emitDebug ("; genLeftShift");
6512 emitDebug ("; genRightShift");
6516 case GET_VALUE_AT_ADDRESS:
6517 emitDebug ("; genPointerGet");
6523 if (POINTER_SET (ic))
6525 emitDebug ("; genAssign (pointer)");
6530 emitDebug ("; genAssign");
6536 emitDebug ("; genIfx");
6541 emitDebug ("; genAddrOf");
6546 emitDebug ("; genJumpTab");
6551 emitDebug ("; genCast");
6556 emitDebug ("; genReceive");
6561 emitDebug ("; addSet");
6562 addSet (&_G.sendSet, ic);
6566 emitDebug ("; genArrayInit");
6576 /* now we are ready to call the
6577 peep hole optimizer */
6578 if (!options.nopeep)
6579 peepHole (&_G.lines.head);
6581 /* This is unfortunate */
6582 /* now do the actual printing */
6584 FILE *fp = codeOutFile;
6585 if (isInHome () && codeOutFile == code->oFile)
6586 codeOutFile = home->oFile;
6587 printLine (_G.lines.head, codeOutFile);
6588 if (_G.flushStatics)
6591 _G.flushStatics = 0;
6596 freeTrace(&_G.lines.trace);
6597 freeTrace(&_G.trace.aops);
6603 _isPairUsed (iCode * ic, PAIR_ID pairId)
6609 if (bitVectBitValue (ic->rMask, D_IDX))
6611 if (bitVectBitValue (ic->rMask, E_IDX))
6621 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6624 value *val = aop->aopu.aop_lit;
6626 wassert (aop->type == AOP_LIT);
6627 wassert (!IS_FLOAT (val->type));
6629 v = (unsigned long) floatFromVal (val);
6637 tsprintf (buffer, "!immedword", v);
6638 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));