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 /* If the result is in a register then we can load then increment.
2892 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
2894 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
2897 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
2902 /* we can if the aops of the left & result match or
2903 if they are in registers and the registers are the
2905 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2909 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2917 /*-----------------------------------------------------------------*/
2918 /* outBitAcc - output a bit in acc */
2919 /*-----------------------------------------------------------------*/
2921 outBitAcc (operand * result)
2923 symbol *tlbl = newiTempLabel (NULL);
2924 /* if the result is a bit */
2925 if (AOP_TYPE (result) == AOP_CRY)
2927 wassertl (0, "Tried to write A into a bit");
2931 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2932 emit2 ("ld a,!one");
2933 emitLabel (tlbl->key + 100);
2939 couldDestroyCarry (asmop *aop)
2943 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
2952 shiftIntoPair (int idx, asmop *aop)
2954 PAIR_ID id = PAIR_INVALID;
2956 wassertl (IS_Z80, "Only implemented for the Z80");
2957 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
2969 wassertl (0, "Internal error - hit default case");
2972 emitDebug ("; Shift into pair idx %u", idx);
2976 setupPair (PAIR_HL, aop, 0);
2980 setupPair (PAIR_IY, aop, 0);
2982 emit2 ("pop %s", _pairs[id].name);
2985 aop->type = AOP_PAIRPTR;
2986 aop->aopu.aop_pairId = id;
2987 _G.pairs[id].offset = 0;
2988 _G.pairs[id].last_type = aop->type;
2992 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
2994 wassert (left && right);
2998 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3000 shiftIntoPair (0, right);
3001 shiftIntoPair (1, result);
3003 else if (couldDestroyCarry (right))
3005 shiftIntoPair (0, right);
3007 else if (couldDestroyCarry (result))
3009 shiftIntoPair (0, result);
3018 /*-----------------------------------------------------------------*/
3019 /* genPlus - generates code for addition */
3020 /*-----------------------------------------------------------------*/
3022 genPlus (iCode * ic)
3024 int size, offset = 0;
3026 /* special cases :- */
3028 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3029 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3030 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3032 /* Swap the left and right operands if:
3034 if literal, literal on the right or
3035 if left requires ACC or right is already
3038 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3039 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3040 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3042 operand *t = IC_RIGHT (ic);
3043 IC_RIGHT (ic) = IC_LEFT (ic);
3047 /* if both left & right are in bit
3049 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3050 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3053 wassertl (0, "Tried to add two bits");
3056 /* if left in bit space & right literal */
3057 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3058 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3060 /* Can happen I guess */
3061 wassertl (0, "Tried to add a bit to a literal");
3064 /* if I can do an increment instead
3065 of add then GOOD for ME */
3066 if (genPlusIncr (ic) == TRUE)
3069 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3071 size = getDataSize (IC_RESULT (ic));
3073 /* Special case when left and right are constant */
3074 if (isPair (AOP (IC_RESULT (ic))))
3077 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3078 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3080 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3086 sprintf (buffer, "#(%s + %s)", left, right);
3087 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3092 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3094 /* Fetch into HL then do the add */
3095 spillPair (PAIR_HL);
3096 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3097 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3101 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD)
3103 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3104 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3106 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3111 ld hl,sp+n trashes C so we cant afford to do it during an
3112 add with stack based varibles. Worst case is:
3125 So you cant afford to load up hl if either left, right, or result
3126 is on the stack (*sigh*) The alt is:
3134 Combinations in here are:
3135 * If left or right are in bc then the loss is small - trap later
3136 * If the result is in bc then the loss is also small
3140 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3141 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3142 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3144 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3145 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3146 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3147 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3149 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3151 /* Swap left and right */
3152 operand *t = IC_RIGHT (ic);
3153 IC_RIGHT (ic) = IC_LEFT (ic);
3156 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3158 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3159 emit2 ("add hl,bc");
3163 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3164 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3165 emit2 ("add hl,de");
3167 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3173 /* Be paranoid on the GB with 4 byte variables due to how C
3174 can be trashed by lda hl,n(sp).
3176 _gbz80_emitAddSubLong (ic, TRUE);
3181 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3185 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3187 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3190 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3193 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3197 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3200 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3203 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3205 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3209 freeAsmop (IC_LEFT (ic), NULL, ic);
3210 freeAsmop (IC_RIGHT (ic), NULL, ic);
3211 freeAsmop (IC_RESULT (ic), NULL, ic);
3215 /*-----------------------------------------------------------------*/
3216 /* genMinusDec :- does subtraction with deccrement if possible */
3217 /*-----------------------------------------------------------------*/
3219 genMinusDec (iCode * ic)
3221 unsigned int icount;
3222 unsigned int size = getDataSize (IC_RESULT (ic));
3224 /* will try to generate an increment */
3225 /* if the right side is not a literal we cannot */
3226 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3229 /* if the literal value of the right hand side
3230 is greater than 4 then it is not worth it */
3231 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3234 size = getDataSize (IC_RESULT (ic));
3236 /* if decrement 16 bits in register */
3237 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3238 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3241 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3245 /* If result is a pair */
3246 if (isPair (AOP (IC_RESULT (ic))))
3248 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3250 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3254 /* if increment 16 bits in register */
3255 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3259 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3262 emit2 ("dec %s", _getTempPairName());
3265 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3271 /* if the sizes are greater than 1 then we cannot */
3272 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3273 AOP_SIZE (IC_LEFT (ic)) > 1)
3276 /* we can if the aops of the left & result match or if they are in
3277 registers and the registers are the same */
3278 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3281 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3288 /*-----------------------------------------------------------------*/
3289 /* genMinus - generates code for subtraction */
3290 /*-----------------------------------------------------------------*/
3292 genMinus (iCode * ic)
3294 int size, offset = 0;
3295 unsigned long lit = 0L;
3297 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3298 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3299 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3301 /* special cases :- */
3302 /* if both left & right are in bit space */
3303 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3304 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3306 wassertl (0, "Tried to subtract two bits");
3310 /* if I can do an decrement instead of subtract then GOOD for ME */
3311 if (genMinusDec (ic) == TRUE)
3314 size = getDataSize (IC_RESULT (ic));
3316 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3321 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3325 /* Same logic as genPlus */
3328 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3329 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3330 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3332 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3333 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3334 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3335 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3337 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3338 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3340 if (left == PAIR_INVALID && right == PAIR_INVALID)
3345 else if (right == PAIR_INVALID)
3347 else if (left == PAIR_INVALID)
3350 fetchPair (left, AOP (IC_LEFT (ic)));
3351 /* Order is important. Right may be HL */
3352 fetchPair (right, AOP (IC_RIGHT (ic)));
3354 emit2 ("ld a,%s", _pairs[left].l);
3355 emit2 ("sub a,%s", _pairs[right].l);
3357 emit2 ("ld a,%s", _pairs[left].h);
3358 emit2 ("sbc a,%s", _pairs[right].h);
3360 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3362 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3364 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3370 /* Be paranoid on the GB with 4 byte variables due to how C
3371 can be trashed by lda hl,n(sp).
3373 _gbz80_emitAddSubLong (ic, FALSE);
3378 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3380 /* if literal, add a,#-lit, else normal subb */
3383 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3384 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3388 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3391 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3395 /* first add without previous c */
3397 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3399 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3401 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3404 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3405 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3406 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3408 wassertl (0, "Tried to subtract on a long pointer");
3412 freeAsmop (IC_LEFT (ic), NULL, ic);
3413 freeAsmop (IC_RIGHT (ic), NULL, ic);
3414 freeAsmop (IC_RESULT (ic), NULL, ic);
3417 /*-----------------------------------------------------------------*/
3418 /* genMult - generates code for multiplication */
3419 /*-----------------------------------------------------------------*/
3421 genMult (iCode * ic)
3425 /* If true then the final operation should be a subtract */
3426 bool active = FALSE;
3428 /* Shouldn't occur - all done through function calls */
3429 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3430 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3431 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3433 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3434 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3435 AOP_SIZE (IC_RESULT (ic)) > 2)
3437 wassertl (0, "Multiplication is handled through support function calls");
3440 /* Swap left and right such that right is a literal */
3441 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3443 operand *t = IC_RIGHT (ic);
3444 IC_RIGHT (ic) = IC_LEFT (ic);
3448 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3450 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3451 // wassertl (val > 0, "Multiply must be positive");
3452 wassertl (val != 1, "Can't multiply by 1");
3458 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3460 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3468 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3473 /* Fully unroled version of mul.s. Not the most efficient.
3475 for (count = 0; count < 16; count++)
3477 if (count != 0 && active)
3479 emit2 ("add hl,hl");
3483 if (active == FALSE)
3490 emit2 ("add hl,de");
3504 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3506 freeAsmop (IC_LEFT (ic), NULL, ic);
3507 freeAsmop (IC_RIGHT (ic), NULL, ic);
3508 freeAsmop (IC_RESULT (ic), NULL, ic);
3511 /*-----------------------------------------------------------------*/
3512 /* genDiv - generates code for division */
3513 /*-----------------------------------------------------------------*/
3517 /* Shouldn't occur - all done through function calls */
3518 wassertl (0, "Division is handled through support function calls");
3521 /*-----------------------------------------------------------------*/
3522 /* genMod - generates code for division */
3523 /*-----------------------------------------------------------------*/
3527 /* Shouldn't occur - all done through function calls */
3531 /*-----------------------------------------------------------------*/
3532 /* genIfxJump :- will create a jump depending on the ifx */
3533 /*-----------------------------------------------------------------*/
3535 genIfxJump (iCode * ic, char *jval)
3540 /* if true label then we jump if condition
3544 jlbl = IC_TRUE (ic);
3545 if (!strcmp (jval, "a"))
3549 else if (!strcmp (jval, "c"))
3553 else if (!strcmp (jval, "nc"))
3559 /* The buffer contains the bit on A that we should test */
3565 /* false label is present */
3566 jlbl = IC_FALSE (ic);
3567 if (!strcmp (jval, "a"))
3571 else if (!strcmp (jval, "c"))
3575 else if (!strcmp (jval, "nc"))
3581 /* The buffer contains the bit on A that we should test */
3585 /* Z80 can do a conditional long jump */
3586 if (!strcmp (jval, "a"))
3590 else if (!strcmp (jval, "c"))
3593 else if (!strcmp (jval, "nc"))
3598 emit2 ("bit %s,a", jval);
3600 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3602 /* mark the icode as generated */
3608 _getPairIdName (PAIR_ID id)
3610 return _pairs[id].name;
3614 /** Generic compare for > or <
3617 genCmp (operand * left, operand * right,
3618 operand * result, iCode * ifx, int sign)
3620 int size, offset = 0;
3621 unsigned long lit = 0L;
3622 bool swap_sense = FALSE;
3624 /* if left & right are bit variables */
3625 if (AOP_TYPE (left) == AOP_CRY &&
3626 AOP_TYPE (right) == AOP_CRY)
3628 /* Cant happen on the Z80 */
3629 wassertl (0, "Tried to compare two bits");
3633 /* subtract right from left if at the
3634 end the carry flag is set then we know that
3635 left is greater than right */
3636 size = max (AOP_SIZE (left), AOP_SIZE (right));
3638 /* if unsigned char cmp with lit, just compare */
3640 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3642 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3645 emit2 ("xor a,!immedbyte", 0x80);
3646 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3649 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3651 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3653 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3654 // Pull left into DE and right into HL
3655 aopGet (AOP(left), LSB, FALSE);
3658 aopGet (AOP(right), LSB, FALSE);
3662 if (size == 0 && sign)
3664 // Highest byte when signed needs the bits flipped
3667 emit2 ("ld a,(de)");
3668 emit2 ("xor #0x80");
3670 emit2 ("ld a,(hl)");
3671 emit2 ("xor #0x80");
3675 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3679 emit2 ("ld a,(de)");
3680 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3690 spillPair (PAIR_HL);
3692 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3694 setupPair (PAIR_HL, AOP (left), 0);
3695 aopGet (AOP(right), LSB, FALSE);
3699 if (size == 0 && sign)
3701 // Highest byte when signed needs the bits flipped
3704 emit2 ("ld a,(hl)");
3705 emit2 ("xor #0x80");
3707 emit2 ("ld a,%d(iy)", offset);
3708 emit2 ("xor #0x80");
3712 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3716 emit2 ("ld a,(hl)");
3717 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3726 spillPair (PAIR_HL);
3727 spillPair (PAIR_IY);
3731 if (AOP_TYPE (right) == AOP_LIT)
3733 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3734 /* optimize if(x < 0) or if(x >= 0) */
3739 /* No sign so it's always false */
3744 /* Just load in the top most bit */
3745 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3746 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3748 genIfxJump (ifx, "7");
3760 /* First setup h and l contaning the top most bytes XORed */
3761 bool fDidXor = FALSE;
3762 if (AOP_TYPE (left) == AOP_LIT)
3764 unsigned long lit = (unsigned long)
3765 floatFromVal (AOP (left)->aopu.aop_lit);
3766 emit2 ("ld %s,!immedbyte", _fTmp[0],
3767 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3771 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3772 emit2 ("xor a,!immedbyte", 0x80);
3773 emit2 ("ld %s,a", _fTmp[0]);
3776 if (AOP_TYPE (right) == AOP_LIT)
3778 unsigned long lit = (unsigned long)
3779 floatFromVal (AOP (right)->aopu.aop_lit);
3780 emit2 ("ld %s,!immedbyte", _fTmp[1],
3781 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3785 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3786 emit2 ("xor a,!immedbyte", 0x80);
3787 emit2 ("ld %s,a", _fTmp[1]);
3793 /* Do a long subtract */
3796 _moveA (aopGet (AOP (left), offset, FALSE));
3798 if (sign && size == 0)
3800 emit2 ("ld a,%s", _fTmp[0]);
3801 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3805 /* Subtract through, propagating the carry */
3806 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3814 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3816 outBitCLong (result, swap_sense);
3820 /* if the result is used in the next
3821 ifx conditional branch then generate
3822 code a little differently */
3824 genIfxJump (ifx, swap_sense ? "nc" : "c");
3826 outBitCLong (result, swap_sense);
3827 /* leave the result in acc */
3831 /*-----------------------------------------------------------------*/
3832 /* genCmpGt :- greater than comparison */
3833 /*-----------------------------------------------------------------*/
3835 genCmpGt (iCode * ic, iCode * ifx)
3837 operand *left, *right, *result;
3838 sym_link *letype, *retype;
3841 left = IC_LEFT (ic);
3842 right = IC_RIGHT (ic);
3843 result = IC_RESULT (ic);
3845 letype = getSpec (operandType (left));
3846 retype = getSpec (operandType (right));
3847 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3848 /* assign the amsops */
3849 aopOp (left, ic, FALSE, FALSE);
3850 aopOp (right, ic, FALSE, FALSE);
3851 aopOp (result, ic, TRUE, FALSE);
3853 genCmp (right, left, result, ifx, sign);
3855 freeAsmop (left, NULL, ic);
3856 freeAsmop (right, NULL, ic);
3857 freeAsmop (result, NULL, ic);
3860 /*-----------------------------------------------------------------*/
3861 /* genCmpLt - less than comparisons */
3862 /*-----------------------------------------------------------------*/
3864 genCmpLt (iCode * ic, iCode * ifx)
3866 operand *left, *right, *result;
3867 sym_link *letype, *retype;
3870 left = IC_LEFT (ic);
3871 right = IC_RIGHT (ic);
3872 result = IC_RESULT (ic);
3874 letype = getSpec (operandType (left));
3875 retype = getSpec (operandType (right));
3876 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3878 /* assign the amsops */
3879 aopOp (left, ic, FALSE, FALSE);
3880 aopOp (right, ic, FALSE, FALSE);
3881 aopOp (result, ic, TRUE, FALSE);
3883 genCmp (left, right, result, ifx, sign);
3885 freeAsmop (left, NULL, ic);
3886 freeAsmop (right, NULL, ic);
3887 freeAsmop (result, NULL, ic);
3890 /*-----------------------------------------------------------------*/
3891 /* gencjneshort - compare and jump if not equal */
3892 /*-----------------------------------------------------------------*/
3894 gencjneshort (operand * left, operand * right, symbol * lbl)
3896 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3898 unsigned long lit = 0L;
3900 /* Swap the left and right if it makes the computation easier */
3901 if (AOP_TYPE (left) == AOP_LIT)
3908 if (AOP_TYPE (right) == AOP_LIT)
3909 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3911 /* if the right side is a literal then anything goes */
3912 if (AOP_TYPE (right) == AOP_LIT &&
3913 AOP_TYPE (left) != AOP_DIR)
3917 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3922 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
3929 emit2 ("jp nz,!tlabel", lbl->key + 100);
3935 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3936 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3939 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3940 emit2 ("jp nz,!tlabel", lbl->key + 100);
3945 /* if the right side is in a register or in direct space or
3946 if the left is a pointer register & right is not */
3947 else if (AOP_TYPE (right) == AOP_REG ||
3948 AOP_TYPE (right) == AOP_DIR ||
3949 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3953 _moveA (aopGet (AOP (left), offset, FALSE));
3954 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3955 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3957 emit2 ("jp nz,!tlabel", lbl->key + 100);
3960 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3961 emit2 ("jp nz,!tlabel", lbl->key + 100);
3968 /* right is a pointer reg need both a & b */
3969 /* PENDING: is this required? */
3972 _moveA (aopGet (AOP (right), offset, FALSE));
3973 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3974 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3980 /*-----------------------------------------------------------------*/
3981 /* gencjne - compare and jump if not equal */
3982 /*-----------------------------------------------------------------*/
3984 gencjne (operand * left, operand * right, symbol * lbl)
3986 symbol *tlbl = newiTempLabel (NULL);
3988 gencjneshort (left, right, lbl);
3991 emit2 ("ld a,!one");
3992 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3993 emitLabel (lbl->key + 100);
3995 emitLabel (tlbl->key + 100);
3998 /*-----------------------------------------------------------------*/
3999 /* genCmpEq - generates code for equal to */
4000 /*-----------------------------------------------------------------*/
4002 genCmpEq (iCode * ic, iCode * ifx)
4004 operand *left, *right, *result;
4006 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4007 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4008 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4010 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4012 /* Swap operands if it makes the operation easier. ie if:
4013 1. Left is a literal.
4015 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4017 operand *t = IC_RIGHT (ic);
4018 IC_RIGHT (ic) = IC_LEFT (ic);
4022 if (ifx && !AOP_SIZE (result))
4025 /* if they are both bit variables */
4026 if (AOP_TYPE (left) == AOP_CRY &&
4027 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4029 wassertl (0, "Tried to compare two bits");
4033 tlbl = newiTempLabel (NULL);
4034 gencjneshort (left, right, tlbl);
4037 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4038 emitLabel (tlbl->key + 100);
4042 /* PENDING: do this better */
4043 symbol *lbl = newiTempLabel (NULL);
4044 emit2 ("!shortjp !tlabel", lbl->key + 100);
4045 emitLabel (tlbl->key + 100);
4046 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4047 emitLabel (lbl->key + 100);
4050 /* mark the icode as generated */
4055 /* if they are both bit variables */
4056 if (AOP_TYPE (left) == AOP_CRY &&
4057 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4059 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4063 gencjne (left, right, newiTempLabel (NULL));
4064 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4070 genIfxJump (ifx, "a");
4073 /* if the result is used in an arithmetic operation
4074 then put the result in place */
4075 if (AOP_TYPE (result) != AOP_CRY)
4079 /* leave the result in acc */
4083 freeAsmop (left, NULL, ic);
4084 freeAsmop (right, NULL, ic);
4085 freeAsmop (result, NULL, ic);
4088 /*-----------------------------------------------------------------*/
4089 /* ifxForOp - returns the icode containing the ifx for operand */
4090 /*-----------------------------------------------------------------*/
4092 ifxForOp (operand * op, iCode * ic)
4094 /* if true symbol then needs to be assigned */
4095 if (IS_TRUE_SYMOP (op))
4098 /* if this has register type condition and
4099 the next instruction is ifx with the same operand
4100 and live to of the operand is upto the ifx only then */
4102 ic->next->op == IFX &&
4103 IC_COND (ic->next)->key == op->key &&
4104 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4110 /*-----------------------------------------------------------------*/
4111 /* genAndOp - for && operation */
4112 /*-----------------------------------------------------------------*/
4114 genAndOp (iCode * ic)
4116 operand *left, *right, *result;
4119 /* note here that && operations that are in an if statement are
4120 taken away by backPatchLabels only those used in arthmetic
4121 operations remain */
4122 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4123 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4124 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4126 /* if both are bit variables */
4127 if (AOP_TYPE (left) == AOP_CRY &&
4128 AOP_TYPE (right) == AOP_CRY)
4130 wassertl (0, "Tried to and two bits");
4134 tlbl = newiTempLabel (NULL);
4136 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4138 emitLabel (tlbl->key + 100);
4142 freeAsmop (left, NULL, ic);
4143 freeAsmop (right, NULL, ic);
4144 freeAsmop (result, NULL, ic);
4147 /*-----------------------------------------------------------------*/
4148 /* genOrOp - for || operation */
4149 /*-----------------------------------------------------------------*/
4151 genOrOp (iCode * ic)
4153 operand *left, *right, *result;
4156 /* note here that || operations that are in an
4157 if statement are taken away by backPatchLabels
4158 only those used in arthmetic operations remain */
4159 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4160 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4161 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4163 /* if both are bit variables */
4164 if (AOP_TYPE (left) == AOP_CRY &&
4165 AOP_TYPE (right) == AOP_CRY)
4167 wassertl (0, "Tried to OR two bits");
4171 tlbl = newiTempLabel (NULL);
4173 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4175 emitLabel (tlbl->key + 100);
4179 freeAsmop (left, NULL, ic);
4180 freeAsmop (right, NULL, ic);
4181 freeAsmop (result, NULL, ic);
4184 /*-----------------------------------------------------------------*/
4185 /* isLiteralBit - test if lit == 2^n */
4186 /*-----------------------------------------------------------------*/
4188 isLiteralBit (unsigned long lit)
4190 unsigned long pw[32] =
4191 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4192 0x100L, 0x200L, 0x400L, 0x800L,
4193 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4194 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4195 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4196 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4197 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4200 for (idx = 0; idx < 32; idx++)
4206 /*-----------------------------------------------------------------*/
4207 /* jmpTrueOrFalse - */
4208 /*-----------------------------------------------------------------*/
4210 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4212 // ugly but optimized by peephole
4215 symbol *nlbl = newiTempLabel (NULL);
4216 emit2 ("jp !tlabel", nlbl->key + 100);
4217 emitLabel (tlbl->key + 100);
4218 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4219 emitLabel (nlbl->key + 100);
4223 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4224 emitLabel (tlbl->key + 100);
4229 /*-----------------------------------------------------------------*/
4230 /* genAnd - code for and */
4231 /*-----------------------------------------------------------------*/
4233 genAnd (iCode * ic, iCode * ifx)
4235 operand *left, *right, *result;
4236 int size, offset = 0;
4237 unsigned long lit = 0L;
4240 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4241 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4242 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4244 /* if left is a literal & right is not then exchange them */
4245 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4246 AOP_NEEDSACC (left))
4248 operand *tmp = right;
4253 /* if result = right then exchange them */
4254 if (sameRegs (AOP (result), AOP (right)))
4256 operand *tmp = right;
4261 /* if right is bit then exchange them */
4262 if (AOP_TYPE (right) == AOP_CRY &&
4263 AOP_TYPE (left) != AOP_CRY)
4265 operand *tmp = right;
4269 if (AOP_TYPE (right) == AOP_LIT)
4270 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4272 size = AOP_SIZE (result);
4274 if (AOP_TYPE (left) == AOP_CRY)
4276 wassertl (0, "Tried to perform an AND with a bit as an operand");
4280 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4281 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4282 if ((AOP_TYPE (right) == AOP_LIT) &&
4283 (AOP_TYPE (result) == AOP_CRY) &&
4284 (AOP_TYPE (left) != AOP_CRY))
4286 symbol *tlbl = newiTempLabel (NULL);
4287 int sizel = AOP_SIZE (left);
4290 /* PENDING: Test case for this. */
4295 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4297 _moveA (aopGet (AOP (left), offset, FALSE));
4298 if (bytelit != 0x0FFL)
4300 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4307 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4311 // bit = left & literal
4315 emit2 ("!tlabeldef", tlbl->key + 100);
4317 // if(left & literal)
4322 jmpTrueOrFalse (ifx, tlbl);
4330 /* if left is same as result */
4331 if (sameRegs (AOP (result), AOP (left)))
4333 for (; size--; offset++)
4335 if (AOP_TYPE (right) == AOP_LIT)
4337 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4342 aopPut (AOP (result), "!zero", offset);
4345 _moveA (aopGet (AOP (left), offset, FALSE));
4347 aopGet (AOP (right), offset, FALSE));
4348 aopPut (AOP (left), "a", offset);
4355 if (AOP_TYPE (left) == AOP_ACC)
4357 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4361 _moveA (aopGet (AOP (left), offset, FALSE));
4363 aopGet (AOP (right), offset, FALSE));
4364 aopPut (AOP (left), "a", offset);
4371 // left & result in different registers
4372 if (AOP_TYPE (result) == AOP_CRY)
4374 wassertl (0, "Tried to AND where the result is in carry");
4378 for (; (size--); offset++)
4381 // result = left & right
4382 if (AOP_TYPE (right) == AOP_LIT)
4384 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4386 aopPut (AOP (result),
4387 aopGet (AOP (left), offset, FALSE),
4391 else if (bytelit == 0)
4393 aopPut (AOP (result), "!zero", offset);
4397 // faster than result <- left, anl result,right
4398 // and better if result is SFR
4399 if (AOP_TYPE (left) == AOP_ACC)
4400 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4403 _moveA (aopGet (AOP (left), offset, FALSE));
4405 aopGet (AOP (right), offset, FALSE));
4407 aopPut (AOP (result), "a", offset);
4414 freeAsmop (left, NULL, ic);
4415 freeAsmop (right, NULL, ic);
4416 freeAsmop (result, NULL, ic);
4419 /*-----------------------------------------------------------------*/
4420 /* genOr - code for or */
4421 /*-----------------------------------------------------------------*/
4423 genOr (iCode * ic, iCode * ifx)
4425 operand *left, *right, *result;
4426 int size, offset = 0;
4427 unsigned long lit = 0L;
4430 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4431 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4432 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4434 /* if left is a literal & right is not then exchange them */
4435 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4436 AOP_NEEDSACC (left))
4438 operand *tmp = right;
4443 /* if result = right then exchange them */
4444 if (sameRegs (AOP (result), AOP (right)))
4446 operand *tmp = right;
4451 /* if right is bit then exchange them */
4452 if (AOP_TYPE (right) == AOP_CRY &&
4453 AOP_TYPE (left) != AOP_CRY)
4455 operand *tmp = right;
4459 if (AOP_TYPE (right) == AOP_LIT)
4460 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4462 size = AOP_SIZE (result);
4464 if (AOP_TYPE (left) == AOP_CRY)
4466 wassertl (0, "Tried to OR where left is a bit");
4470 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4471 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4472 if ((AOP_TYPE (right) == AOP_LIT) &&
4473 (AOP_TYPE (result) == AOP_CRY) &&
4474 (AOP_TYPE (left) != AOP_CRY))
4476 symbol *tlbl = newiTempLabel (NULL);
4477 int sizel = AOP_SIZE (left);
4481 wassertl (0, "Result is assigned to a bit");
4483 /* PENDING: Modeled after the AND code which is inefficent. */
4486 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4488 _moveA (aopGet (AOP (left), offset, FALSE));
4489 /* OR with any literal is the same as OR with itself. */
4491 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4497 jmpTrueOrFalse (ifx, tlbl);
4502 /* if left is same as result */
4503 if (sameRegs (AOP (result), AOP (left)))
4505 for (; size--; offset++)
4507 if (AOP_TYPE (right) == AOP_LIT)
4509 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4513 _moveA (aopGet (AOP (left), offset, FALSE));
4515 aopGet (AOP (right), offset, FALSE));
4516 aopPut (AOP (result), "a", offset);
4521 if (AOP_TYPE (left) == AOP_ACC)
4522 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4525 _moveA (aopGet (AOP (left), offset, FALSE));
4527 aopGet (AOP (right), offset, FALSE));
4528 aopPut (AOP (result), "a", offset);
4535 // left & result in different registers
4536 if (AOP_TYPE (result) == AOP_CRY)
4538 wassertl (0, "Result of OR is in a bit");
4541 for (; (size--); offset++)
4544 // result = left & right
4545 if (AOP_TYPE (right) == AOP_LIT)
4547 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4549 aopPut (AOP (result),
4550 aopGet (AOP (left), offset, FALSE),
4555 // faster than result <- left, anl result,right
4556 // and better if result is SFR
4557 if (AOP_TYPE (left) == AOP_ACC)
4558 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4561 _moveA (aopGet (AOP (left), offset, FALSE));
4563 aopGet (AOP (right), offset, FALSE));
4565 aopPut (AOP (result), "a", offset);
4566 /* PENDING: something weird is going on here. Add exception. */
4567 if (AOP_TYPE (result) == AOP_ACC)
4573 freeAsmop (left, NULL, ic);
4574 freeAsmop (right, NULL, ic);
4575 freeAsmop (result, NULL, ic);
4578 /*-----------------------------------------------------------------*/
4579 /* genXor - code for xclusive or */
4580 /*-----------------------------------------------------------------*/
4582 genXor (iCode * ic, iCode * ifx)
4584 operand *left, *right, *result;
4585 int size, offset = 0;
4586 unsigned long lit = 0L;
4588 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4589 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4590 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4592 /* if left is a literal & right is not then exchange them */
4593 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4594 AOP_NEEDSACC (left))
4596 operand *tmp = right;
4601 /* if result = right then exchange them */
4602 if (sameRegs (AOP (result), AOP (right)))
4604 operand *tmp = right;
4609 /* if right is bit then exchange them */
4610 if (AOP_TYPE (right) == AOP_CRY &&
4611 AOP_TYPE (left) != AOP_CRY)
4613 operand *tmp = right;
4617 if (AOP_TYPE (right) == AOP_LIT)
4618 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4620 size = AOP_SIZE (result);
4622 if (AOP_TYPE (left) == AOP_CRY)
4624 wassertl (0, "Tried to XOR a bit");
4628 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4629 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4630 if ((AOP_TYPE (right) == AOP_LIT) &&
4631 (AOP_TYPE (result) == AOP_CRY) &&
4632 (AOP_TYPE (left) != AOP_CRY))
4634 symbol *tlbl = newiTempLabel (NULL);
4635 int sizel = AOP_SIZE (left);
4639 /* PENDING: Test case for this. */
4640 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4644 _moveA (aopGet (AOP (left), offset, FALSE));
4645 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4646 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4651 jmpTrueOrFalse (ifx, tlbl);
4655 wassertl (0, "Result of XOR was destined for a bit");
4660 /* if left is same as result */
4661 if (sameRegs (AOP (result), AOP (left)))
4663 for (; size--; offset++)
4665 if (AOP_TYPE (right) == AOP_LIT)
4667 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4671 _moveA (aopGet (AOP (right), offset, FALSE));
4673 aopGet (AOP (left), offset, FALSE));
4674 aopPut (AOP (result), "a", offset);
4679 if (AOP_TYPE (left) == AOP_ACC)
4681 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4685 _moveA (aopGet (AOP (right), offset, FALSE));
4687 aopGet (AOP (left), offset, FALSE));
4688 aopPut (AOP (result), "a", 0);
4695 // left & result in different registers
4696 if (AOP_TYPE (result) == AOP_CRY)
4698 wassertl (0, "Result of XOR is in a bit");
4701 for (; (size--); offset++)
4704 // result = left & right
4705 if (AOP_TYPE (right) == AOP_LIT)
4707 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4709 aopPut (AOP (result),
4710 aopGet (AOP (left), offset, FALSE),
4715 // faster than result <- left, anl result,right
4716 // and better if result is SFR
4717 if (AOP_TYPE (left) == AOP_ACC)
4719 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4723 _moveA (aopGet (AOP (right), offset, FALSE));
4725 aopGet (AOP (left), offset, FALSE));
4727 aopPut (AOP (result), "a", offset);
4732 freeAsmop (left, NULL, ic);
4733 freeAsmop (right, NULL, ic);
4734 freeAsmop (result, NULL, ic);
4737 /*-----------------------------------------------------------------*/
4738 /* genInline - write the inline code out */
4739 /*-----------------------------------------------------------------*/
4741 genInline (iCode * ic)
4743 char *buffer, *bp, *bp1;
4745 _G.lines.isInline += (!options.asmpeep);
4747 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4748 strcpy (buffer, IC_INLINE (ic));
4750 /* emit each line as a code */
4775 _G.lines.isInline -= (!options.asmpeep);
4779 /*-----------------------------------------------------------------*/
4780 /* genRRC - rotate right with carry */
4781 /*-----------------------------------------------------------------*/
4788 /*-----------------------------------------------------------------*/
4789 /* genRLC - generate code for rotate left with carry */
4790 /*-----------------------------------------------------------------*/
4797 /*-----------------------------------------------------------------*/
4798 /* genGetHbit - generates code get highest order bit */
4799 /*-----------------------------------------------------------------*/
4801 genGetHbit (iCode * ic)
4803 operand *left, *result;
4804 left = IC_LEFT (ic);
4805 result = IC_RESULT (ic);
4806 aopOp (left, ic, FALSE, FALSE);
4807 aopOp (result, ic, FALSE, FALSE);
4809 /* get the highest order byte into a */
4810 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4812 if (AOP_TYPE (result) == AOP_CRY)
4820 /* PENDING: For re-target. */
4826 freeAsmop (left, NULL, ic);
4827 freeAsmop (result, NULL, ic);
4831 emitRsh2 (asmop *aop, int size, int is_signed)
4837 const char *l = aopGet (aop, size, FALSE);
4840 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4850 /*-----------------------------------------------------------------*/
4851 /* shiftR2Left2Result - shift right two bytes from left to result */
4852 /*-----------------------------------------------------------------*/
4854 shiftR2Left2Result (operand * left, int offl,
4855 operand * result, int offr,
4856 int shCount, int is_signed)
4859 symbol *tlbl, *tlbl1;
4861 movLeft2Result (left, offl, result, offr, 0);
4862 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4864 /* if (AOP(result)->type == AOP_REG) { */
4866 tlbl = newiTempLabel (NULL);
4867 tlbl1 = newiTempLabel (NULL);
4869 /* Left is already in result - so now do the shift */
4874 emitRsh2 (AOP (result), size, is_signed);
4879 emit2 ("ld a,!immedbyte+1", shCount);
4880 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4881 emitLabel (tlbl->key + 100);
4883 emitRsh2 (AOP (result), size, is_signed);
4885 emitLabel (tlbl1->key + 100);
4887 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4891 /*-----------------------------------------------------------------*/
4892 /* shiftL2Left2Result - shift left two bytes from left to result */
4893 /*-----------------------------------------------------------------*/
4895 shiftL2Left2Result (operand * left, int offl,
4896 operand * result, int offr, int shCount)
4898 if (sameRegs (AOP (result), AOP (left)) &&
4899 ((offl + MSB16) == offr))
4905 /* Copy left into result */
4906 movLeft2Result (left, offl, result, offr, 0);
4907 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4909 /* PENDING: for now just see if it'll work. */
4910 /*if (AOP(result)->type == AOP_REG) { */
4914 symbol *tlbl, *tlbl1;
4917 tlbl = newiTempLabel (NULL);
4918 tlbl1 = newiTempLabel (NULL);
4920 /* Left is already in result - so now do the shift */
4923 emit2 ("ld a,!immedbyte+1", shCount);
4924 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4925 emitLabel (tlbl->key + 100);
4930 l = aopGet (AOP (result), offset, FALSE);
4934 emit2 ("sla %s", l);
4945 emitLabel (tlbl1->key + 100);
4947 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4952 /*-----------------------------------------------------------------*/
4953 /* AccRol - rotate left accumulator by known count */
4954 /*-----------------------------------------------------------------*/
4956 AccRol (int shCount)
4958 shCount &= 0x0007; // shCount : 0..7
4997 /*-----------------------------------------------------------------*/
4998 /* AccLsh - left shift accumulator by known count */
4999 /*-----------------------------------------------------------------*/
5001 AccLsh (int shCount)
5003 static const unsigned char SLMask[] =
5005 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5014 else if (shCount == 2)
5021 /* rotate left accumulator */
5023 /* and kill the lower order bits */
5024 emit2 ("and a,!immedbyte", SLMask[shCount]);
5029 /*-----------------------------------------------------------------*/
5030 /* shiftL1Left2Result - shift left one byte from left to result */
5031 /*-----------------------------------------------------------------*/
5033 shiftL1Left2Result (operand * left, int offl,
5034 operand * result, int offr, int shCount)
5037 l = aopGet (AOP (left), offl, FALSE);
5039 /* shift left accumulator */
5041 aopPut (AOP (result), "a", offr);
5045 /*-----------------------------------------------------------------*/
5046 /* genlshTwo - left shift two bytes by known amount != 0 */
5047 /*-----------------------------------------------------------------*/
5049 genlshTwo (operand * result, operand * left, int shCount)
5051 int size = AOP_SIZE (result);
5053 wassert (size == 2);
5055 /* if shCount >= 8 */
5063 movLeft2Result (left, LSB, result, MSB16, 0);
5064 aopPut (AOP (result), "!zero", 0);
5065 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5069 movLeft2Result (left, LSB, result, MSB16, 0);
5070 aopPut (AOP (result), "!zero", 0);
5075 aopPut (AOP (result), "!zero", LSB);
5078 /* 1 <= shCount <= 7 */
5087 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5092 /*-----------------------------------------------------------------*/
5093 /* genlshOne - left shift a one byte quantity by known count */
5094 /*-----------------------------------------------------------------*/
5096 genlshOne (operand * result, operand * left, int shCount)
5098 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5101 /*-----------------------------------------------------------------*/
5102 /* genLeftShiftLiteral - left shifting by known count */
5103 /*-----------------------------------------------------------------*/
5105 genLeftShiftLiteral (operand * left,
5110 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5113 freeAsmop (right, NULL, ic);
5115 aopOp (left, ic, FALSE, FALSE);
5116 aopOp (result, ic, FALSE, FALSE);
5118 size = getSize (operandType (result));
5120 /* I suppose that the left size >= result size */
5126 else if (shCount >= (size * 8))
5130 aopPut (AOP (result), "!zero", size);
5138 genlshOne (result, left, shCount);
5141 genlshTwo (result, left, shCount);
5144 wassertl (0, "Shifting of longs is currently unsupported");
5150 freeAsmop (left, NULL, ic);
5151 freeAsmop (result, NULL, ic);
5154 /*-----------------------------------------------------------------*/
5155 /* genLeftShift - generates code for left shifting */
5156 /*-----------------------------------------------------------------*/
5158 genLeftShift (iCode * ic)
5162 symbol *tlbl, *tlbl1;
5163 operand *left, *right, *result;
5165 right = IC_RIGHT (ic);
5166 left = IC_LEFT (ic);
5167 result = IC_RESULT (ic);
5169 aopOp (right, ic, FALSE, FALSE);
5171 /* if the shift count is known then do it
5172 as efficiently as possible */
5173 if (AOP_TYPE (right) == AOP_LIT)
5175 genLeftShiftLiteral (left, right, result, ic);
5179 /* shift count is unknown then we have to form a loop get the loop
5180 count in B : Note: we take only the lower order byte since
5181 shifting more that 32 bits make no sense anyway, ( the largest
5182 size of an object can be only 32 bits ) */
5183 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5185 freeAsmop (right, NULL, ic);
5186 aopOp (left, ic, FALSE, FALSE);
5187 aopOp (result, ic, FALSE, FALSE);
5189 /* now move the left to the result if they are not the
5192 if (!sameRegs (AOP (left), AOP (result)))
5195 size = AOP_SIZE (result);
5199 l = aopGet (AOP (left), offset, FALSE);
5200 aopPut (AOP (result), l, offset);
5205 tlbl = newiTempLabel (NULL);
5206 size = AOP_SIZE (result);
5208 tlbl1 = newiTempLabel (NULL);
5210 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5211 emitLabel (tlbl->key + 100);
5212 l = aopGet (AOP (result), offset, FALSE);
5216 l = aopGet (AOP (result), offset, FALSE);
5220 emit2 ("sla %s", l);
5228 emitLabel (tlbl1->key + 100);
5230 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5232 freeAsmop (left, NULL, ic);
5233 freeAsmop (result, NULL, ic);
5236 /*-----------------------------------------------------------------*/
5237 /* genrshOne - left shift two bytes by known amount != 0 */
5238 /*-----------------------------------------------------------------*/
5240 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5243 int size = AOP_SIZE (result);
5246 wassert (size == 1);
5247 wassert (shCount < 8);
5249 l = aopGet (AOP (left), 0, FALSE);
5251 if (AOP (result)->type == AOP_REG)
5253 aopPut (AOP (result), l, 0);
5254 l = aopGet (AOP (result), 0, FALSE);
5257 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5265 emit2 ("%s a", is_signed ? "sra" : "srl");
5267 aopPut (AOP (result), "a", 0);
5271 /*-----------------------------------------------------------------*/
5272 /* AccRsh - right shift accumulator by known count */
5273 /*-----------------------------------------------------------------*/
5275 AccRsh (int shCount)
5277 static const unsigned char SRMask[] =
5279 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5284 /* rotate right accumulator */
5285 AccRol (8 - shCount);
5286 /* and kill the higher order bits */
5287 emit2 ("and a,!immedbyte", SRMask[shCount]);
5291 /*-----------------------------------------------------------------*/
5292 /* shiftR1Left2Result - shift right one byte from left to result */
5293 /*-----------------------------------------------------------------*/
5295 shiftR1Left2Result (operand * left, int offl,
5296 operand * result, int offr,
5297 int shCount, int sign)
5299 _moveA (aopGet (AOP (left), offl, FALSE));
5304 emit2 ("%s a", sign ? "sra" : "srl");
5311 aopPut (AOP (result), "a", offr);
5314 /*-----------------------------------------------------------------*/
5315 /* genrshTwo - right shift two bytes by known amount != 0 */
5316 /*-----------------------------------------------------------------*/
5318 genrshTwo (operand * result, operand * left,
5319 int shCount, int sign)
5321 /* if shCount >= 8 */
5327 shiftR1Left2Result (left, MSB16, result, LSB,
5332 movLeft2Result (left, MSB16, result, LSB, sign);
5336 /* Sign extend the result */
5337 _moveA(aopGet (AOP (result), 0, FALSE));
5341 aopPut (AOP (result), ACC_NAME, MSB16);
5345 aopPut (AOP (result), "!zero", 1);
5348 /* 1 <= shCount <= 7 */
5351 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5355 /*-----------------------------------------------------------------*/
5356 /* genRightShiftLiteral - left shifting by known count */
5357 /*-----------------------------------------------------------------*/
5359 genRightShiftLiteral (operand * left,
5365 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5368 freeAsmop (right, NULL, ic);
5370 aopOp (left, ic, FALSE, FALSE);
5371 aopOp (result, ic, FALSE, FALSE);
5373 size = getSize (operandType (result));
5375 /* I suppose that the left size >= result size */
5381 else if (shCount >= (size * 8))
5383 aopPut (AOP (result), "!zero", size);
5389 genrshOne (result, left, shCount, sign);
5392 genrshTwo (result, left, shCount, sign);
5395 wassertl (0, "Asked to shift right a long which should be a function call");
5398 wassertl (0, "Entered default case in right shift delegate");
5401 freeAsmop (left, NULL, ic);
5402 freeAsmop (result, NULL, ic);
5405 /*-----------------------------------------------------------------*/
5406 /* genRightShift - generate code for right shifting */
5407 /*-----------------------------------------------------------------*/
5409 genRightShift (iCode * ic)
5411 operand *right, *left, *result;
5413 int size, offset, first = 1;
5417 symbol *tlbl, *tlbl1;
5419 /* if signed then we do it the hard way preserve the
5420 sign bit moving it inwards */
5421 retype = getSpec (operandType (IC_RESULT (ic)));
5423 is_signed = !SPEC_USIGN (retype);
5425 /* signed & unsigned types are treated the same : i.e. the
5426 signed is NOT propagated inwards : quoting from the
5427 ANSI - standard : "for E1 >> E2, is equivalent to division
5428 by 2**E2 if unsigned or if it has a non-negative value,
5429 otherwise the result is implementation defined ", MY definition
5430 is that the sign does not get propagated */
5432 right = IC_RIGHT (ic);
5433 left = IC_LEFT (ic);
5434 result = IC_RESULT (ic);
5436 aopOp (right, ic, FALSE, FALSE);
5438 /* if the shift count is known then do it
5439 as efficiently as possible */
5440 if (AOP_TYPE (right) == AOP_LIT)
5442 genRightShiftLiteral (left, right, result, ic, is_signed);
5446 aopOp (left, ic, FALSE, FALSE);
5447 aopOp (result, ic, FALSE, FALSE);
5449 /* now move the left to the result if they are not the
5451 if (!sameRegs (AOP (left), AOP (result)) &&
5452 AOP_SIZE (result) > 1)
5455 size = AOP_SIZE (result);
5459 l = aopGet (AOP (left), offset, FALSE);
5460 aopPut (AOP (result), l, offset);
5465 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5467 freeAsmop (right, NULL, ic);
5469 tlbl = newiTempLabel (NULL);
5470 tlbl1 = newiTempLabel (NULL);
5471 size = AOP_SIZE (result);
5474 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5475 emitLabel (tlbl->key + 100);
5478 l = aopGet (AOP (result), offset--, FALSE);
5481 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5489 emitLabel (tlbl1->key + 100);
5491 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5493 freeAsmop (left, NULL, ic);
5494 freeAsmop (result, NULL, ic);
5497 /*-----------------------------------------------------------------*/
5498 /* genGenPointerGet - get value from generic pointer space */
5499 /*-----------------------------------------------------------------*/
5501 genGenPointerGet (operand * left,
5502 operand * result, iCode * ic)
5505 sym_link *retype = getSpec (operandType (result));
5511 aopOp (left, ic, FALSE, FALSE);
5512 aopOp (result, ic, FALSE, FALSE);
5514 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5517 if (isPtrPair (AOP (left)))
5519 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5520 aopPut (AOP (result), buffer, 0);
5524 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5525 aopPut (AOP (result), "a", 0);
5527 freeAsmop (left, NULL, ic);
5531 /* For now we always load into IY */
5532 /* if this is remateriazable */
5533 fetchPair (pair, AOP (left));
5535 /* so iy now contains the address */
5536 freeAsmop (left, NULL, ic);
5538 /* if bit then unpack */
5539 if (IS_BITVAR (retype))
5545 size = AOP_SIZE (result);
5550 /* PENDING: make this better */
5551 if (!IS_GB && AOP (result)->type == AOP_REG)
5553 aopPut (AOP (result), "!*hl", offset++);
5557 emit2 ("ld a,!*pair", _pairs[pair].name);
5558 aopPut (AOP (result), "a", offset++);
5562 emit2 ("inc %s", _pairs[pair].name);
5563 _G.pairs[pair].offset++;
5569 freeAsmop (result, NULL, ic);
5572 /*-----------------------------------------------------------------*/
5573 /* genPointerGet - generate code for pointer get */
5574 /*-----------------------------------------------------------------*/
5576 genPointerGet (iCode * ic)
5578 operand *left, *result;
5579 sym_link *type, *etype;
5581 left = IC_LEFT (ic);
5582 result = IC_RESULT (ic);
5584 /* depending on the type of pointer we need to
5585 move it to the correct pointer register */
5586 type = operandType (left);
5587 etype = getSpec (type);
5589 genGenPointerGet (left, result, ic);
5593 isRegOrLit (asmop * aop)
5595 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5600 /*-----------------------------------------------------------------*/
5601 /* genGenPointerSet - stores the value into a pointer location */
5602 /*-----------------------------------------------------------------*/
5604 genGenPointerSet (operand * right,
5605 operand * result, iCode * ic)
5608 sym_link *retype = getSpec (operandType (right));
5609 PAIR_ID pairId = PAIR_HL;
5611 aopOp (result, ic, FALSE, FALSE);
5612 aopOp (right, ic, FALSE, FALSE);
5617 /* Handle the exceptions first */
5618 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5621 const char *l = aopGet (AOP (right), 0, FALSE);
5622 const char *pair = getPairName (AOP (result));
5623 if (canAssignToPtr (l) && isPtr (pair))
5625 emit2 ("ld !*pair,%s", pair, l);
5630 emit2 ("ld !*pair,a", pair);
5635 /* if the operand is already in dptr
5636 then we do nothing else we move the value to dptr */
5637 if (AOP_TYPE (result) != AOP_STR)
5639 fetchPair (pairId, AOP (result));
5641 /* so hl know contains the address */
5642 freeAsmop (result, NULL, ic);
5644 /* if bit then unpack */
5645 if (IS_BITVAR (retype))
5651 size = AOP_SIZE (right);
5656 const char *l = aopGet (AOP (right), offset, FALSE);
5657 if (isRegOrLit (AOP (right)) && !IS_GB)
5659 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5664 emit2 ("ld !*pair,a", _pairs[pairId].name);
5668 emit2 ("inc %s", _pairs[pairId].name);
5669 _G.pairs[pairId].offset++;
5675 freeAsmop (right, NULL, ic);
5678 /*-----------------------------------------------------------------*/
5679 /* genPointerSet - stores the value into a pointer location */
5680 /*-----------------------------------------------------------------*/
5682 genPointerSet (iCode * ic)
5684 operand *right, *result;
5685 sym_link *type, *etype;
5687 right = IC_RIGHT (ic);
5688 result = IC_RESULT (ic);
5690 /* depending on the type of pointer we need to
5691 move it to the correct pointer register */
5692 type = operandType (result);
5693 etype = getSpec (type);
5695 genGenPointerSet (right, result, ic);
5698 /*-----------------------------------------------------------------*/
5699 /* genIfx - generate code for Ifx statement */
5700 /*-----------------------------------------------------------------*/
5702 genIfx (iCode * ic, iCode * popIc)
5704 operand *cond = IC_COND (ic);
5707 aopOp (cond, ic, FALSE, TRUE);
5709 /* get the value into acc */
5710 if (AOP_TYPE (cond) != AOP_CRY)
5714 /* the result is now in the accumulator */
5715 freeAsmop (cond, NULL, ic);
5717 /* if there was something to be popped then do it */
5721 /* if the condition is a bit variable */
5722 if (isbit && IS_ITEMP (cond) &&
5724 genIfxJump (ic, SPIL_LOC (cond)->rname);
5725 else if (isbit && !IS_ITEMP (cond))
5726 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5728 genIfxJump (ic, "a");
5733 /*-----------------------------------------------------------------*/
5734 /* genAddrOf - generates code for address of */
5735 /*-----------------------------------------------------------------*/
5737 genAddrOf (iCode * ic)
5739 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5741 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5743 /* if the operand is on the stack then we
5744 need to get the stack offset of this
5751 if (sym->stack <= 0)
5753 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
5757 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5759 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5763 emit2 ("ld de,!hashedstr", sym->rname);
5764 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
5772 /* if it has an offset then we need to compute it */
5774 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5776 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5777 emit2 ("add hl,sp");
5781 emit2 ("ld hl,#%s", sym->rname);
5783 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5785 freeAsmop (IC_RESULT (ic), NULL, ic);
5788 /*-----------------------------------------------------------------*/
5789 /* genAssign - generate code for assignment */
5790 /*-----------------------------------------------------------------*/
5792 genAssign (iCode * ic)
5794 operand *result, *right;
5796 unsigned long lit = 0L;
5798 result = IC_RESULT (ic);
5799 right = IC_RIGHT (ic);
5801 /* Dont bother assigning if they are the same */
5802 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5804 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5808 aopOp (right, ic, FALSE, FALSE);
5809 aopOp (result, ic, TRUE, FALSE);
5811 /* if they are the same registers */
5812 if (sameRegs (AOP (right), AOP (result)))
5814 emitDebug ("; (registers are the same)");
5818 /* if the result is a bit */
5819 if (AOP_TYPE (result) == AOP_CRY)
5821 wassertl (0, "Tried to assign to a bit");
5825 size = AOP_SIZE (result);
5828 if (AOP_TYPE (right) == AOP_LIT)
5829 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5830 if (isPair (AOP (result)))
5832 fetchPair (getPairId (AOP (result)), AOP (right));
5834 else if ((size > 1) &&
5835 (AOP_TYPE (result) != AOP_REG) &&
5836 (AOP_TYPE (right) == AOP_LIT) &&
5837 !IS_FLOAT (operandType (right)) &&
5840 bool fXored = FALSE;
5842 /* Work from the top down.
5843 Done this way so that we can use the cached copy of 0
5844 in A for a fast clear */
5847 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5849 if (!fXored && size > 1)
5856 aopPut (AOP (result), "a", offset);
5860 aopPut (AOP (result), "!zero", offset);
5864 aopPut (AOP (result),
5865 aopGet (AOP (right), offset, FALSE),
5870 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5872 /* Special case. Load into a and d, then load out. */
5873 _moveA (aopGet (AOP (right), 0, FALSE));
5874 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5875 aopPut (AOP (result), "a", 0);
5876 aopPut (AOP (result), "e", 1);
5878 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5880 /* Special case - simple memcpy */
5881 aopGet (AOP (right), LSB, FALSE);
5884 aopGet (AOP (result), LSB, FALSE);
5888 emit2 ("ld a,(de)");
5889 /* Peephole will optimise this. */
5890 emit2 ("ld (hl),a");
5898 spillPair (PAIR_HL);
5904 /* PENDING: do this check better */
5905 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5907 _moveA (aopGet (AOP (right), offset, FALSE));
5908 aopPut (AOP (result), "a", offset);
5911 aopPut (AOP (result),
5912 aopGet (AOP (right), offset, FALSE),
5919 freeAsmop (right, NULL, ic);
5920 freeAsmop (result, NULL, ic);
5923 /*-----------------------------------------------------------------*/
5924 /* genJumpTab - genrates code for jump table */
5925 /*-----------------------------------------------------------------*/
5927 genJumpTab (iCode * ic)
5932 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5933 /* get the condition into accumulator */
5934 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5937 emit2 ("ld e,%s", l);
5938 emit2 ("ld d,!zero");
5939 jtab = newiTempLabel (NULL);
5941 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5942 emit2 ("add hl,de");
5943 emit2 ("add hl,de");
5944 emit2 ("add hl,de");
5945 freeAsmop (IC_JTCOND (ic), NULL, ic);
5949 emitLabel (jtab->key + 100);
5950 /* now generate the jump labels */
5951 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5952 jtab = setNextItem (IC_JTLABELS (ic)))
5953 emit2 ("jp !tlabel", jtab->key + 100);
5956 /*-----------------------------------------------------------------*/
5957 /* genCast - gen code for casting */
5958 /*-----------------------------------------------------------------*/
5960 genCast (iCode * ic)
5962 operand *result = IC_RESULT (ic);
5963 sym_link *ctype = operandType (IC_LEFT (ic));
5964 operand *right = IC_RIGHT (ic);
5967 /* if they are equivalent then do nothing */
5968 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5971 aopOp (right, ic, FALSE, FALSE);
5972 aopOp (result, ic, FALSE, FALSE);
5974 /* if the result is a bit */
5975 if (AOP_TYPE (result) == AOP_CRY)
5977 wassertl (0, "Tried to cast to a bit");
5980 /* if they are the same size : or less */
5981 if (AOP_SIZE (result) <= AOP_SIZE (right))
5984 /* if they are in the same place */
5985 if (sameRegs (AOP (right), AOP (result)))
5988 /* if they in different places then copy */
5989 size = AOP_SIZE (result);
5993 aopPut (AOP (result),
5994 aopGet (AOP (right), offset, FALSE),
6001 /* So we now know that the size of destination is greater
6002 than the size of the source */
6003 /* we move to result for the size of source */
6004 size = AOP_SIZE (right);
6008 aopPut (AOP (result),
6009 aopGet (AOP (right), offset, FALSE),
6014 /* now depending on the sign of the destination */
6015 size = AOP_SIZE (result) - AOP_SIZE (right);
6016 /* Unsigned or not an integral type - right fill with zeros */
6017 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6020 aopPut (AOP (result), "!zero", offset++);
6024 /* we need to extend the sign :{ */
6025 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6031 aopPut (AOP (result), "a", offset++);
6035 freeAsmop (right, NULL, ic);
6036 freeAsmop (result, NULL, ic);
6039 /*-----------------------------------------------------------------*/
6040 /* genReceive - generate code for a receive iCode */
6041 /*-----------------------------------------------------------------*/
6043 genReceive (iCode * ic)
6045 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6046 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6047 IS_TRUE_SYMOP (IC_RESULT (ic))))
6057 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6058 size = AOP_SIZE(IC_RESULT(ic));
6060 for (i = 0; i < size; i++) {
6061 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6065 freeAsmop (IC_RESULT (ic), NULL, ic);
6070 /** Maximum number of bytes to emit per line. */
6074 /** Context for the byte output chunker. */
6077 unsigned char buffer[DBEMIT_MAX_RUN];
6082 /** Flushes a byte chunker by writing out all in the buffer and
6086 _dbFlush(DBEMITCTX *self)
6093 sprintf(line, ".db 0x%02X", self->buffer[0]);
6095 for (i = 1; i < self->pos; i++)
6097 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6104 /** Write out another byte, buffering until a decent line is
6108 _dbEmit(DBEMITCTX *self, int c)
6110 if (self->pos == DBEMIT_MAX_RUN)
6114 self->buffer[self->pos++] = c;
6117 /** Context for a simple run length encoder. */
6121 unsigned char buffer[128];
6123 /** runLen may be equivalent to pos. */
6129 RLE_CHANGE_COST = 4,
6133 /** Flush the buffer of a run length encoder by writing out the run or
6134 data that it currently contains.
6137 _rleCommit(RLECTX *self)
6143 memset(&db, 0, sizeof(db));
6145 emit2(".db %u", self->pos);
6147 for (i = 0; i < self->pos; i++)
6149 _dbEmit(&db, self->buffer[i]);
6158 Can get either a run or a block of random stuff.
6159 Only want to change state if a good run comes in or a run ends.
6160 Detecting run end is easy.
6163 Say initial state is in run, len zero, last zero. Then if you get a
6164 few zeros then something else then a short run will be output.
6165 Seems OK. While in run mode, keep counting. While in random mode,
6166 keep a count of the run. If run hits margin, output all up to run,
6167 restart, enter run mode.
6170 /** Add another byte into the run length encoder, flushing as
6171 required. The run length encoder uses the Amiga IFF style, where
6172 a block is prefixed by its run length. A positive length means
6173 the next n bytes pass straight through. A negative length means
6174 that the next byte is repeated -n times. A zero terminates the
6178 _rleAppend(RLECTX *self, int c)
6182 if (c != self->last)
6184 /* The run has stopped. See if it is worthwhile writing it out
6185 as a run. Note that the random data comes in as runs of
6188 if (self->runLen > RLE_CHANGE_COST)
6190 /* Yes, worthwhile. */
6191 /* Commit whatever was in the buffer. */
6193 emit2(".db -%u,0x%02X", self->runLen, self->last);
6197 /* Not worthwhile. Append to the end of the random list. */
6198 for (i = 0; i < self->runLen; i++)
6200 if (self->pos >= RLE_MAX_BLOCK)
6205 self->buffer[self->pos++] = self->last;
6213 if (self->runLen >= RLE_MAX_BLOCK)
6215 /* Commit whatever was in the buffer. */
6218 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6226 _rleFlush(RLECTX *self)
6228 _rleAppend(self, -1);
6235 /** genArrayInit - Special code for initialising an array with constant
6239 genArrayInit (iCode * ic)
6243 int elementSize = 0, eIndex, i;
6244 unsigned val, lastVal;
6248 memset(&rle, 0, sizeof(rle));
6250 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6252 _saveRegsForCall(ic, 0);
6254 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6255 emit2 ("call __initrleblock");
6257 type = operandType(IC_LEFT(ic));
6259 if (type && type->next)
6261 elementSize = getSize(type->next);
6265 wassertl (0, "Can't determine element size in genArrayInit.");
6268 iLoop = IC_ARRAYILIST(ic);
6269 lastVal = (unsigned)-1;
6271 /* Feed all the bytes into the run length encoder which will handle
6273 This works well for mixed char data, and for random int and long
6282 for (i = 0; i < ix; i++)
6284 for (eIndex = 0; eIndex < elementSize; eIndex++)
6286 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6287 _rleAppend(&rle, val);
6292 iLoop = iLoop->next;
6296 /* Mark the end of the run. */
6299 _restoreRegsAfterCall();
6303 freeAsmop (IC_LEFT(ic), NULL, ic);
6306 /*-----------------------------------------------------------------*/
6307 /* genZ80Code - generate code for Z80 based controllers */
6308 /*-----------------------------------------------------------------*/
6310 genZ80Code (iCode * lic)
6318 _fReturn = _gbz80_return;
6319 _fTmp = _gbz80_return;
6323 _fReturn = _z80_return;
6324 _fTmp = _z80_return;
6327 _G.lines.head = _G.lines.current = NULL;
6329 for (ic = lic; ic; ic = ic->next)
6332 if (cln != ic->lineno)
6334 emit2 ("; %s %d", ic->filename, ic->lineno);
6337 /* if the result is marked as
6338 spilt and rematerializable or code for
6339 this has already been generated then
6341 if (resultRemat (ic) || ic->generated)
6344 /* depending on the operation */
6348 emitDebug ("; genNot");
6353 emitDebug ("; genCpl");
6358 emitDebug ("; genUminus");
6363 emitDebug ("; genIpush");
6368 /* IPOP happens only when trying to restore a
6369 spilt live range, if there is an ifx statement
6370 following this pop then the if statement might
6371 be using some of the registers being popped which
6372 would destory the contents of the register so
6373 we need to check for this condition and handle it */
6375 ic->next->op == IFX &&
6376 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6378 emitDebug ("; genIfx");
6379 genIfx (ic->next, ic);
6383 emitDebug ("; genIpop");
6389 emitDebug ("; genCall");
6394 emitDebug ("; genPcall");
6399 emitDebug ("; genFunction");
6404 emitDebug ("; genEndFunction");
6405 genEndFunction (ic);
6409 emitDebug ("; genRet");
6414 emitDebug ("; genLabel");
6419 emitDebug ("; genGoto");
6424 emitDebug ("; genPlus");
6429 emitDebug ("; genMinus");
6434 emitDebug ("; genMult");
6439 emitDebug ("; genDiv");
6444 emitDebug ("; genMod");
6449 emitDebug ("; genCmpGt");
6450 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6454 emitDebug ("; genCmpLt");
6455 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6462 /* note these two are xlated by algebraic equivalence
6463 during parsing SDCC.y */
6464 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6465 "got '>=' or '<=' shouldn't have come here");
6469 emitDebug ("; genCmpEq");
6470 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6474 emitDebug ("; genAndOp");
6479 emitDebug ("; genOrOp");
6484 emitDebug ("; genXor");
6485 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6489 emitDebug ("; genOr");
6490 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6494 emitDebug ("; genAnd");
6495 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6499 emitDebug ("; genInline");
6504 emitDebug ("; genRRC");
6509 emitDebug ("; genRLC");
6514 emitDebug ("; genGetHBIT");
6519 emitDebug ("; genLeftShift");
6524 emitDebug ("; genRightShift");
6528 case GET_VALUE_AT_ADDRESS:
6529 emitDebug ("; genPointerGet");
6535 if (POINTER_SET (ic))
6537 emitDebug ("; genAssign (pointer)");
6542 emitDebug ("; genAssign");
6548 emitDebug ("; genIfx");
6553 emitDebug ("; genAddrOf");
6558 emitDebug ("; genJumpTab");
6563 emitDebug ("; genCast");
6568 emitDebug ("; genReceive");
6573 emitDebug ("; addSet");
6574 addSet (&_G.sendSet, ic);
6578 emitDebug ("; genArrayInit");
6588 /* now we are ready to call the
6589 peep hole optimizer */
6590 if (!options.nopeep)
6591 peepHole (&_G.lines.head);
6593 /* This is unfortunate */
6594 /* now do the actual printing */
6596 FILE *fp = codeOutFile;
6597 if (isInHome () && codeOutFile == code->oFile)
6598 codeOutFile = home->oFile;
6599 printLine (_G.lines.head, codeOutFile);
6600 if (_G.flushStatics)
6603 _G.flushStatics = 0;
6608 freeTrace(&_G.lines.trace);
6609 freeTrace(&_G.trace.aops);
6615 _isPairUsed (iCode * ic, PAIR_ID pairId)
6621 if (bitVectBitValue (ic->rMask, D_IDX))
6623 if (bitVectBitValue (ic->rMask, E_IDX))
6633 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6636 value *val = aop->aopu.aop_lit;
6638 wassert (aop->type == AOP_LIT);
6639 wassert (!IS_FLOAT (val->type));
6641 v = (unsigned long) floatFromVal (val);
6649 tsprintf (buffer, "!immedword", v);
6650 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));