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;
138 /** Enum covering all the possible register pairs.
157 } _pairs[NUM_PAIRS] = {
158 { "??1", "?2", "?3" },
163 { "iy", "iy.l?", "iy.h?" },
164 { "ix", "ix.l?", "ix.h?" }
168 #define ACC_NAME _pairs[PAIR_AF].h
170 #define RESULTONSTACK(x) \
171 (IC_RESULT(x) && IC_RESULT(x)->aop && \
172 IC_RESULT(x)->aop->type == AOP_STK )
182 /** Code generator persistent data.
186 /** Used to optimised setting up of a pair by remebering what it
187 contains and adjusting instead of reloading where possible.
208 const char *lastFunctionName;
214 /** TRUE if the registers have already been saved. */
232 static const char *aopGet (asmop * aop, int offset, bool bit16);
248 _getTempPairName(void)
250 return _pairs[_getTempPairId()].name;
256 /* Clean up the line so that it is 'prettier' */
257 if (strchr (buf, ':'))
259 /* Is a label - cant do anything */
262 /* Change the first (and probably only) ' ' to a tab so
277 _newLineNode (char *line)
281 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
282 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
288 _vemit2 (const char *szFormat, va_list ap)
292 tvsprintf (buffer, szFormat, ap);
295 _G.lines.current = (_G.lines.current ?
296 connectLine (_G.lines.current, _newLineNode (buffer)) :
297 (_G.lines.head = _newLineNode (buffer)));
299 _G.lines.current->isInline = _G.lines.isInline;
303 emit2 (const char *szFormat,...)
307 va_start (ap, szFormat);
309 _vemit2 (szFormat, ap);
315 emitDebug (const char *szFormat,...)
321 va_start (ap, szFormat);
323 _vemit2 (szFormat, ap);
329 /*-----------------------------------------------------------------*/
330 /* emit2 - writes the code into a file : for now it is simple */
331 /*-----------------------------------------------------------------*/
333 _emit2 (const char *inst, const char *fmt,...)
336 char lb[INITIAL_INLINEASM];
343 sprintf (lb, "%s\t", inst);
344 vsprintf (lb + (strlen (lb)), fmt, ap);
347 vsprintf (lb, fmt, ap);
349 while (isspace (*lbp))
354 _G.lines.current = (_G.lines.current ?
355 connectLine (_G.lines.current, _newLineNode (lb)) :
356 (_G.lines.head = _newLineNode (lb)));
358 _G.lines.current->isInline = _G.lines.isInline;
363 _emitMove(const char *to, const char *from)
365 if (strcasecmp(to, from) != 0)
367 emit2("ld %s,%s", to, from);
372 // Could leave this to the peephole, but sometimes the peephole is inhibited.
377 _moveA(const char *moveFrom)
379 // Let the peephole optimiser take care of redundent loads
380 _emitMove(ACC_NAME, moveFrom);
390 getPairName (asmop * aop)
392 if (aop->type == AOP_REG)
394 switch (aop->aopu.aop_reg[0]->rIdx)
407 else if (aop->type == AOP_STR)
409 switch (*aop->aopu.aop_str[0])
422 wassertl (0, "Tried to get the pair name of something that isn't a pair");
427 getPairId (asmop * aop)
431 if (aop->type == AOP_REG)
433 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
437 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
441 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
446 if (aop->type == AOP_STR)
448 if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
452 if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
456 if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
465 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
469 return (getPairId (aop) != PAIR_INVALID);
473 isPtrPair (asmop * aop)
475 PAIR_ID pairId = getPairId (aop);
486 /** Push a register pair onto the stack */
488 genPairPush (asmop * aop)
490 emit2 ("push %s", getPairName (aop));
494 _push (PAIR_ID pairId)
496 emit2 ("push %s", _pairs[pairId].name);
497 _G.stack.pushed += 2;
501 _pop (PAIR_ID pairId)
503 emit2 ("pop %s", _pairs[pairId].name);
504 _G.stack.pushed -= 2;
507 /*-----------------------------------------------------------------*/
508 /* newAsmop - creates a new asmOp */
509 /*-----------------------------------------------------------------*/
511 newAsmop (short type)
515 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
520 /*-----------------------------------------------------------------*/
521 /* aopForSym - for a true symbol */
522 /*-----------------------------------------------------------------*/
524 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
531 wassert (sym->etype);
533 space = SPEC_OCLS (sym->etype);
535 /* if already has one */
539 /* Assign depending on the storage class */
540 if (sym->onStack || sym->iaccess)
542 emitDebug ("; AOP_STK for %s", sym->rname);
543 sym->aop = aop = newAsmop (AOP_STK);
544 aop->size = getSize (sym->type);
545 aop->aopu.aop_stk = sym->stack;
549 /* special case for a function */
550 if (IS_FUNC (sym->type))
552 sym->aop = aop = newAsmop (AOP_IMMD);
553 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
560 /* if it is in direct space */
561 if (IN_REGSP (space) && !requires_a)
563 sym->aop = aop = newAsmop (AOP_SFR);
564 aop->aopu.aop_dir = sym->rname;
565 aop->size = getSize (sym->type);
566 emitDebug ("; AOP_SFR for %s", sym->rname);
571 /* only remaining is far space */
572 /* in which case DPTR gets the address */
575 emitDebug ("; AOP_HL for %s", sym->rname);
576 sym->aop = aop = newAsmop (AOP_HL);
580 sym->aop = aop = newAsmop (AOP_IY);
582 aop->size = getSize (sym->type);
583 aop->aopu.aop_dir = sym->rname;
585 /* if it is in code space */
586 if (IN_CODESPACE (space))
592 /*-----------------------------------------------------------------*/
593 /* aopForRemat - rematerialzes an object */
594 /*-----------------------------------------------------------------*/
596 aopForRemat (symbol * sym)
599 iCode *ic = sym->rematiCode;
600 asmop *aop = newAsmop (AOP_IMMD);
604 /* if plus or minus print the right hand side */
605 if (ic->op == '+' || ic->op == '-')
607 /* PENDING: for re-target */
608 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
611 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
614 /* we reached the end */
615 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
619 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
623 /*-----------------------------------------------------------------*/
624 /* regsInCommon - two operands have some registers in common */
625 /*-----------------------------------------------------------------*/
627 regsInCommon (operand * op1, operand * op2)
632 /* if they have registers in common */
633 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
636 sym1 = OP_SYMBOL (op1);
637 sym2 = OP_SYMBOL (op2);
639 if (sym1->nRegs == 0 || sym2->nRegs == 0)
642 for (i = 0; i < sym1->nRegs; i++)
648 for (j = 0; j < sym2->nRegs; j++)
653 if (sym2->regs[j] == sym1->regs[i])
661 /*-----------------------------------------------------------------*/
662 /* operandsEqu - equivalent */
663 /*-----------------------------------------------------------------*/
665 operandsEqu (operand * op1, operand * op2)
669 /* if they not symbols */
670 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
673 sym1 = OP_SYMBOL (op1);
674 sym2 = OP_SYMBOL (op2);
676 /* if both are itemps & one is spilt
677 and the other is not then false */
678 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
679 sym1->isspilt != sym2->isspilt)
682 /* if they are the same */
686 if (strcmp (sym1->rname, sym2->rname) == 0)
690 /* if left is a tmp & right is not */
691 if (IS_ITEMP (op1) &&
694 (sym1->usl.spillLoc == sym2))
697 if (IS_ITEMP (op2) &&
701 (sym2->usl.spillLoc == sym1))
707 /*-----------------------------------------------------------------*/
708 /* sameRegs - two asmops have the same registers */
709 /*-----------------------------------------------------------------*/
711 sameRegs (asmop * aop1, asmop * aop2)
715 if (aop1->type == AOP_SFR ||
716 aop2->type == AOP_SFR)
722 if (aop1->type != AOP_REG ||
723 aop2->type != AOP_REG)
726 if (aop1->size != aop2->size)
729 for (i = 0; i < aop1->size; i++)
730 if (aop1->aopu.aop_reg[i] !=
731 aop2->aopu.aop_reg[i])
737 /*-----------------------------------------------------------------*/
738 /* aopOp - allocates an asmop for an operand : */
739 /*-----------------------------------------------------------------*/
741 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
750 /* if this a literal */
751 if (IS_OP_LITERAL (op))
753 op->aop = aop = newAsmop (AOP_LIT);
754 aop->aopu.aop_lit = op->operand.valOperand;
755 aop->size = getSize (operandType (op));
759 /* if already has a asmop then continue */
763 /* if the underlying symbol has a aop */
764 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
766 op->aop = OP_SYMBOL (op)->aop;
770 /* if this is a true symbol */
771 if (IS_TRUE_SYMOP (op))
773 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
777 /* this is a temporary : this has
783 e) can be a return use only */
785 sym = OP_SYMBOL (op);
787 /* if the type is a conditional */
788 if (sym->regType == REG_CND)
790 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
795 /* if it is spilt then two situations
797 b) has a spill location */
798 if (sym->isspilt || sym->nRegs == 0)
800 /* rematerialize it NOW */
803 sym->aop = op->aop = aop =
805 aop->size = getSize (sym->type);
811 if (sym->accuse == ACCUSE_A)
813 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
814 aop->size = getSize (sym->type);
815 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
817 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
819 else if (sym->accuse == ACCUSE_HL)
822 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
823 aop->size = getSize (sym->type);
824 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
825 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
826 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
830 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
838 aop = op->aop = sym->aop = newAsmop (AOP_STR);
839 aop->size = getSize (sym->type);
840 for (i = 0; i < 4; i++)
841 aop->aopu.aop_str[i] = _fReturn[i];
845 /* else spill location */
846 sym->aop = op->aop = aop =
847 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
848 aop->size = getSize (sym->type);
852 /* must be in a register */
853 sym->aop = op->aop = aop = newAsmop (AOP_REG);
854 aop->size = sym->nRegs;
855 for (i = 0; i < sym->nRegs; i++)
856 aop->aopu.aop_reg[i] = sym->regs[i];
859 /*-----------------------------------------------------------------*/
860 /* freeAsmop - free up the asmop given to an operand */
861 /*----------------------------------------------------------------*/
863 freeAsmop (operand * op, asmop * aaop, iCode * ic)
881 /* all other cases just dealloc */
887 OP_SYMBOL (op)->aop = NULL;
888 /* if the symbol has a spill */
890 SPIL_LOC (op)->aop = NULL;
896 isLitWord (asmop * aop)
898 /* if (aop->size != 2)
911 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
916 /* depending on type */
922 /* PENDING: for re-target */
925 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
927 else if (offset == 0)
929 tsprintf (s, "%s", aop->aopu.aop_immd);
933 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
935 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
939 value *val = aop->aopu.aop_lit;
940 /* if it is a float then it gets tricky */
941 /* otherwise it is fairly simple */
942 if (!IS_FLOAT (val->type))
944 unsigned long v = (unsigned long) floatFromVal (val);
950 else if (offset == 0)
956 wassertl(0, "Encountered an invalid offset while fetching a literal");
960 tsprintf (buffer, "!immedword", v);
962 tsprintf (buffer, "!constword", v);
964 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
970 convertFloat (&f, floatFromVal (val));
972 tsprintf (buffer, "!immedword", f.w[offset / 2]);
974 tsprintf (buffer, "!constword", f.w[offset / 2]);
975 rs = Safe_calloc (1, strlen (buffer) + 1);
976 return strcpy (rs, buffer);
985 aopGetWord (asmop * aop, int offset)
987 return aopGetLitWordLong (aop, offset, TRUE);
991 isPtr (const char *s)
993 if (!strcmp (s, "hl"))
995 if (!strcmp (s, "ix"))
997 if (!strcmp (s, "iy"))
1003 adjustPair (const char *pair, int *pold, int new)
1009 emit2 ("inc %s", pair);
1014 emit2 ("dec %s", pair);
1020 spillPair (PAIR_ID pairId)
1022 _G.pairs[pairId].last_type = AOP_INVALID;
1023 _G.pairs[pairId].base = NULL;
1029 spillPair (PAIR_HL);
1030 spillPair (PAIR_IY);
1034 requiresHL (asmop * aop)
1048 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1050 const char *l, *base;
1051 const char *pair = _pairs[pairId].name;
1052 l = aopGetLitWordLong (left, offset, FALSE);
1053 base = aopGetLitWordLong (left, 0, FALSE);
1054 wassert (l && pair && base);
1058 if (pairId == PAIR_HL || pairId == PAIR_IY)
1060 if (_G.pairs[pairId].last_type == left->type)
1062 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1064 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1066 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1069 if (pairId == PAIR_IY && abs (offset) < 127)
1076 _G.pairs[pairId].last_type = left->type;
1077 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1078 _G.pairs[pairId].offset = offset;
1080 /* Both a lit on the right and a true symbol on the left */
1081 emit2 ("ld %s,!hashedstr", pair, l);
1085 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1087 /* if this is remateriazable */
1088 if (isLitWord (aop)) {
1089 fetchLitPair (pairId, aop, offset);
1092 /* we need to get it byte by byte */
1093 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1094 aopGet (aop, offset, FALSE);
1095 switch (aop->size - offset) {
1097 emit2 ("ld l,!*hl");
1098 emit2 ("ld h,!immedbyte", 0);
1101 // PENDING: Requires that you are only fetching two bytes.
1104 emit2 ("ld h,!*hl");
1108 wassertl (0, "Attempted to fetch too much data into HL");
1112 else if (IS_Z80 && aop->type == AOP_IY) {
1113 /* Instead of fetching relative to IY, just grab directly
1114 from the address IY refers to */
1115 char *l = aopGetLitWordLong (aop, offset, FALSE);
1117 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1119 if (aop->size < 2) {
1120 emit2("ld %s,!zero", _pairs[pairId].h);
1124 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1125 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1127 /* PENDING: check? */
1128 if (pairId == PAIR_HL)
1129 spillPair (PAIR_HL);
1134 fetchPair (PAIR_ID pairId, asmop * aop)
1136 fetchPairLong (pairId, aop, 0);
1140 fetchHL (asmop * aop)
1142 fetchPair (PAIR_HL, aop);
1146 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1148 assert (pairId == PAIR_HL || pairId == PAIR_IY);
1153 fetchLitPair (pairId, aop, 0);
1156 fetchLitPair (pairId, aop, offset);
1157 _G.pairs[pairId].offset = offset;
1161 /* Doesnt include _G.stack.pushed */
1162 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1163 if (aop->aopu.aop_stk > 0)
1165 abso += _G.stack.param_offset;
1167 assert (pairId == PAIR_HL);
1168 /* In some cases we can still inc or dec hl */
1169 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1171 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1175 emit2 ("!ldahlsp", abso + _G.stack.pushed);
1177 _G.pairs[pairId].offset = abso;
1183 _G.pairs[pairId].last_type = aop->type;
1189 emit2 ("!tlabeldef", key);
1193 /*-----------------------------------------------------------------*/
1194 /* aopGet - for fetching value of the aop */
1195 /*-----------------------------------------------------------------*/
1197 aopGet (asmop * aop, int offset, bool bit16)
1201 /* offset is greater than size then zero */
1202 /* PENDING: this seems a bit screwed in some pointer cases. */
1203 if (offset > (aop->size - 1) &&
1204 aop->type != AOP_LIT)
1206 tsprintf (s, "!zero");
1207 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1210 /* depending on type */
1214 /* PENDING: re-target */
1216 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1221 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1224 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1227 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1230 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1233 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1237 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1240 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1244 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1247 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1250 return aop->aopu.aop_reg[offset]->name;
1254 setupPair (PAIR_HL, aop, offset);
1255 tsprintf (s, "!*hl");
1257 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1261 setupPair (PAIR_IY, aop, offset);
1262 tsprintf (s, "!*iyx", offset);
1264 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1269 setupPair (PAIR_HL, aop, offset);
1270 tsprintf (s, "!*hl");
1274 if (aop->aopu.aop_stk >= 0)
1275 offset += _G.stack.param_offset;
1276 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1279 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1282 wassertl (0, "Tried to fetch from a bit variable");
1291 tsprintf(s, "!zero");
1292 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1296 wassert (offset < 2);
1297 return aop->aopu.aop_str[offset];
1300 return aopLiteral (aop->aopu.aop_lit, offset);
1304 unsigned long v = aop->aopu.aop_simplelit;
1307 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1309 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1313 return aop->aopu.aop_str[offset];
1318 wassertl (0, "aopget got unsupported aop->type");
1323 isRegString (const char *s)
1325 if (!strcmp (s, "b") ||
1337 isConstant (const char *s)
1339 /* This is a bit of a hack... */
1340 return (*s == '#' || *s == '$');
1344 canAssignToPtr (const char *s)
1346 if (isRegString (s))
1353 /*-----------------------------------------------------------------*/
1354 /* aopPut - puts a string for a aop */
1355 /*-----------------------------------------------------------------*/
1357 aopPut (asmop * aop, const char *s, int offset)
1361 if (aop->size && offset > (aop->size - 1))
1363 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1364 "aopPut got offset > aop->size");
1369 tsprintf(buffer2, s);
1372 /* will assign value to value */
1373 /* depending on where it is ofcourse */
1379 if (strcmp (s, "a"))
1380 emit2 ("ld a,%s", s);
1381 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1386 if (strcmp (s, "a"))
1387 emit2 ("ld a,%s", s);
1388 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1392 if (!strcmp (s, "!*hl"))
1393 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1396 aop->aopu.aop_reg[offset]->name, s);
1401 setupPair (PAIR_IY, aop, offset);
1402 if (!canAssignToPtr (s))
1404 emit2 ("ld a,%s", s);
1405 emit2 ("ld !*iyx,a", offset);
1408 emit2 ("ld !*iyx,%s", offset, s);
1413 /* PENDING: for re-target */
1414 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1416 emit2 ("ld a,!*hl");
1419 setupPair (PAIR_HL, aop, offset);
1421 emit2 ("ld !*hl,%s", s);
1427 /* PENDING: re-target */
1428 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1430 emit2 ("ld a,!*hl");
1433 setupPair (PAIR_HL, aop, offset);
1434 if (!canAssignToPtr (s))
1436 emit2 ("ld a,%s", s);
1437 emit2 ("ld !*hl,a");
1440 emit2 ("ld !*hl,%s", s);
1444 if (aop->aopu.aop_stk >= 0)
1445 offset += _G.stack.param_offset;
1446 if (!canAssignToPtr (s))
1448 emit2 ("ld a,%s", s);
1449 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1452 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1457 /* if bit variable */
1458 if (!aop->aopu.aop_dir)
1465 /* In bit space but not in C - cant happen */
1466 wassertl (0, "Tried to write into a bit variable");
1472 if (strcmp (aop->aopu.aop_str[offset], s))
1474 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1480 if (!offset && (strcmp (s, "acc") == 0))
1484 wassertl (0, "Tried to access past the end of A");
1488 if (strcmp (aop->aopu.aop_str[offset], s))
1489 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1494 wassert (offset < 2);
1495 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1499 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1500 "aopPut got unsupported aop->type");
1505 #define AOP(op) op->aop
1506 #define AOP_TYPE(op) AOP(op)->type
1507 #define AOP_SIZE(op) AOP(op)->size
1508 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1511 commitPair (asmop * aop, PAIR_ID id)
1513 if (id == PAIR_HL && requiresHL (aop))
1517 aopPut (aop, "a", 0);
1518 aopPut (aop, "d", 1);
1522 aopPut (aop, _pairs[id].l, 0);
1523 aopPut (aop, _pairs[id].h, 1);
1527 /*-----------------------------------------------------------------*/
1528 /* getDataSize - get the operand data size */
1529 /*-----------------------------------------------------------------*/
1531 getDataSize (operand * op)
1534 size = AOP_SIZE (op);
1538 wassertl (0, "Somehow got a three byte data pointer");
1543 /*-----------------------------------------------------------------*/
1544 /* movLeft2Result - move byte from left to result */
1545 /*-----------------------------------------------------------------*/
1547 movLeft2Result (operand * left, int offl,
1548 operand * result, int offr, int sign)
1551 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1553 l = aopGet (AOP (left), offl, FALSE);
1557 aopPut (AOP (result), l, offr);
1561 if (getDataSize (left) == offl + 1)
1563 emit2 ("ld a,%s", l);
1564 aopPut (AOP (result), "a", offr);
1571 /** Put Acc into a register set
1574 outAcc (operand * result)
1577 size = getDataSize (result);
1580 aopPut (AOP (result), "a", 0);
1583 /* unsigned or positive */
1586 aopPut (AOP (result), "!zero", offset++);
1591 /** Take the value in carry and put it into a register
1594 outBitCLong (operand * result, bool swap_sense)
1596 /* if the result is bit */
1597 if (AOP_TYPE (result) == AOP_CRY)
1599 wassertl (0, "Tried to write carry to a bit");
1603 emit2 ("ld a,!zero");
1606 emit2 ("xor a,!immedbyte", 1);
1612 outBitC (operand * result)
1614 outBitCLong (result, FALSE);
1617 /*-----------------------------------------------------------------*/
1618 /* toBoolean - emit code for orl a,operator(sizeop) */
1619 /*-----------------------------------------------------------------*/
1621 _toBoolean (operand * oper)
1623 int size = AOP_SIZE (oper);
1627 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1630 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1634 if (AOP (oper)->type != AOP_ACC)
1637 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1642 /*-----------------------------------------------------------------*/
1643 /* genNot - generate code for ! operation */
1644 /*-----------------------------------------------------------------*/
1648 sym_link *optype = operandType (IC_LEFT (ic));
1650 /* assign asmOps to operand & result */
1651 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1652 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1654 /* if in bit space then a special case */
1655 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1657 wassertl (0, "Tried to negate a bit");
1660 /* if type float then do float */
1661 if (IS_FLOAT (optype))
1663 wassertl (0, "Tried to negate a float");
1666 _toBoolean (IC_LEFT (ic));
1671 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1672 emit2 ("sub a,!one");
1673 outBitC (IC_RESULT (ic));
1675 /* release the aops */
1676 freeAsmop (IC_LEFT (ic), NULL, ic);
1677 freeAsmop (IC_RESULT (ic), NULL, ic);
1680 /*-----------------------------------------------------------------*/
1681 /* genCpl - generate code for complement */
1682 /*-----------------------------------------------------------------*/
1690 /* assign asmOps to operand & result */
1691 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1692 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1694 /* if both are in bit space then
1696 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1697 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1699 wassertl (0, "Left and the result are in bit space");
1702 size = AOP_SIZE (IC_RESULT (ic));
1705 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1708 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1711 /* release the aops */
1712 freeAsmop (IC_LEFT (ic), NULL, ic);
1713 freeAsmop (IC_RESULT (ic), NULL, ic);
1717 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1724 store de into result
1729 store de into result
1731 const char *first = isAdd ? "add" : "sub";
1732 const char *later = isAdd ? "adc" : "sbc";
1734 wassertl (IS_GB, "Code is only relevent to the gbz80");
1735 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1737 fetchPair (PAIR_DE, left);
1740 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1743 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1746 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
1747 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
1749 fetchPairLong (PAIR_DE, left, MSB24);
1750 aopGet (right, MSB24, FALSE);
1754 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
1757 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
1759 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
1760 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
1764 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
1766 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
1769 /*-----------------------------------------------------------------*/
1770 /* genUminus - unary minus code generation */
1771 /*-----------------------------------------------------------------*/
1773 genUminus (iCode * ic)
1776 sym_link *optype, *rtype;
1779 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1780 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1782 /* if both in bit space then special
1784 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1785 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1787 wassertl (0, "Left and right are in bit space");
1791 optype = operandType (IC_LEFT (ic));
1792 rtype = operandType (IC_RESULT (ic));
1794 /* if float then do float stuff */
1795 if (IS_FLOAT (optype))
1797 wassertl (0, "Tried to do a unary minus on a float");
1801 /* otherwise subtract from zero */
1802 size = AOP_SIZE (IC_LEFT (ic));
1804 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1806 /* Create a new asmop with value zero */
1807 asmop *azero = newAsmop (AOP_SIMPLELIT);
1808 azero->aopu.aop_simplelit = 0;
1810 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1818 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1819 emit2 ("ld a,!zero");
1820 emit2 ("sbc a,%s", l);
1821 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1824 /* if any remaining bytes in the result */
1825 /* we just need to propagate the sign */
1826 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1831 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1835 /* release the aops */
1836 freeAsmop (IC_LEFT (ic), NULL, ic);
1837 freeAsmop (IC_RESULT (ic), NULL, ic);
1840 /*-----------------------------------------------------------------*/
1841 /* assignResultValue - */
1842 /*-----------------------------------------------------------------*/
1844 assignResultValue (operand * oper)
1846 int size = AOP_SIZE (oper);
1849 wassertl (size <= 4, "Got a result that is bigger than four bytes");
1850 topInA = requiresHL (AOP (oper));
1852 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1854 /* We do it the hard way here. */
1856 aopPut (AOP (oper), _fReturn[0], 0);
1857 aopPut (AOP (oper), _fReturn[1], 1);
1859 aopPut (AOP (oper), _fReturn[0], 2);
1860 aopPut (AOP (oper), _fReturn[1], 3);
1866 aopPut (AOP (oper), _fReturn[size], size);
1872 _saveRegsForCall(iCode *ic, int sendSetSize)
1875 o Stack parameters are pushed before this function enters
1876 o DE and BC may be used in this function.
1877 o HL and DE may be used to return the result.
1878 o HL and DE may be used to send variables.
1879 o DE and BC may be used to store the result value.
1880 o HL may be used in computing the sent value of DE
1881 o The iPushes for other parameters occur before any addSets
1883 Logic: (to be run inside the first iPush or if none, before sending)
1884 o Compute if DE and/or BC are in use over the call
1885 o Compute if DE is used in the send set
1886 o Compute if DE and/or BC are used to hold the result value
1887 o If (DE is used, or in the send set) and is not used in the result, push.
1888 o If BC is used and is not in the result, push
1890 o If DE is used in the send set, fetch
1891 o If HL is used in the send set, fetch
1895 if (_G.saves.saved == FALSE) {
1896 bool deInUse, bcInUse;
1898 bool bcInRet = FALSE, deInRet = FALSE;
1901 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1903 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1904 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1906 deSending = (sendSetSize > 1);
1908 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1910 if (bcInUse && bcInRet == FALSE) {
1912 _G.stack.pushedBC = TRUE;
1914 if (deInUse && deInRet == FALSE) {
1916 _G.stack.pushedDE = TRUE;
1919 _G.saves.saved = TRUE;
1922 /* Already saved. */
1926 /*-----------------------------------------------------------------*/
1927 /* genIpush - genrate code for pushing this gets a little complex */
1928 /*-----------------------------------------------------------------*/
1930 genIpush (iCode * ic)
1932 int size, offset = 0;
1935 /* if this is not a parm push : ie. it is spill push
1936 and spill push is always done on the local stack */
1939 wassertl(0, "Encountered an unsupported spill push.");
1943 if (_G.saves.saved == FALSE) {
1944 /* Caller saves, and this is the first iPush. */
1945 /* Scan ahead until we find the function that we are pushing parameters to.
1946 Count the number of addSets on the way to figure out what registers
1947 are used in the send set.
1950 iCode *walk = ic->next;
1953 if (walk->op == SEND) {
1956 else if (walk->op == CALL || walk->op == PCALL) {
1965 _saveRegsForCall(walk, nAddSets);
1968 /* Already saved by another iPush. */
1971 /* then do the push */
1972 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1974 size = AOP_SIZE (IC_LEFT (ic));
1976 if (isPair (AOP (IC_LEFT (ic))))
1978 _G.stack.pushed += 2;
1979 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1985 fetchHL (AOP (IC_LEFT (ic)));
1987 spillPair (PAIR_HL);
1988 _G.stack.pushed += 2;
1993 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
1995 spillPair (PAIR_HL);
1996 _G.stack.pushed += 2;
1997 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
1999 spillPair (PAIR_HL);
2000 _G.stack.pushed += 2;
2006 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2008 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2010 emit2 ("ld a,(%s)", l);
2014 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2015 emit2 ("ld a,%s", l);
2023 freeAsmop (IC_LEFT (ic), NULL, ic);
2026 /*-----------------------------------------------------------------*/
2027 /* genIpop - recover the registers: can happen only for spilling */
2028 /*-----------------------------------------------------------------*/
2030 genIpop (iCode * ic)
2035 /* if the temp was not pushed then */
2036 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2039 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2040 size = AOP_SIZE (IC_LEFT (ic));
2041 offset = (size - 1);
2042 if (isPair (AOP (IC_LEFT (ic))))
2044 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2052 spillPair (PAIR_HL);
2053 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2057 freeAsmop (IC_LEFT (ic), NULL, ic);
2060 /* This is quite unfortunate */
2062 setArea (int inHome)
2065 static int lastArea = 0;
2067 if (_G.in_home != inHome) {
2069 const char *sz = port->mem.code_name;
2070 port->mem.code_name = "HOME";
2071 emit2("!area", CODE_NAME);
2072 port->mem.code_name = sz;
2075 emit2("!area", CODE_NAME); */
2076 _G.in_home = inHome;
2087 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2091 symbol *sym = OP_SYMBOL (op);
2093 if (sym->isspilt || sym->nRegs == 0)
2096 aopOp (op, ic, FALSE, FALSE);
2099 if (aop->type == AOP_REG)
2102 for (i = 0; i < aop->size; i++)
2104 if (pairId == PAIR_DE)
2106 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2107 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2109 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2112 else if (pairId == PAIR_BC)
2114 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2115 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2117 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2127 freeAsmop (IC_LEFT (ic), NULL, ic);
2131 /** Emit the code for a call statement
2134 emitCall (iCode * ic, bool ispcall)
2136 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2138 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2140 /* if caller saves & we have not saved then */
2146 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2148 /* if send set is not empty then assign */
2153 int nSend = elementsInSet(_G.sendSet);
2154 bool swapped = FALSE;
2156 int _z80_sendOrder[] = {
2161 /* Check if the parameters are swapped. If so route through hl instead. */
2162 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2164 sic = setFirstItem(_G.sendSet);
2165 sic = setNextItem(_G.sendSet);
2167 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2168 /* The second send value is loaded from one the one that holds the first
2169 send, i.e. it is overwritten. */
2170 /* Cache the first in HL, and load the second from HL instead. */
2171 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2172 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2178 for (sic = setFirstItem (_G.sendSet); sic;
2179 sic = setNextItem (_G.sendSet))
2182 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2184 size = AOP_SIZE (IC_LEFT (sic));
2185 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2186 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2188 // PENDING: Mild hack
2189 if (swapped == TRUE && send == 1) {
2191 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2194 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2196 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2199 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2203 freeAsmop (IC_LEFT (sic), NULL, sic);
2210 if (IS_BANKEDCALL (detype))
2212 werror (W_INDIR_BANKED);
2214 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2216 if (isLitWord (AOP (IC_LEFT (ic))))
2218 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2222 symbol *rlbl = newiTempLabel (NULL);
2223 spillPair (PAIR_HL);
2224 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2226 _G.stack.pushed += 2;
2228 fetchHL (AOP (IC_LEFT (ic)));
2230 emit2 ("!tlabeldef", (rlbl->key + 100));
2231 _G.stack.pushed -= 2;
2233 freeAsmop (IC_LEFT (ic), NULL, ic);
2237 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2238 OP_SYMBOL (IC_LEFT (ic))->rname :
2239 OP_SYMBOL (IC_LEFT (ic))->name;
2240 if (IS_BANKEDCALL (detype))
2242 emit2 ("call banked_call");
2243 emit2 ("!dws", name);
2244 emit2 ("!dw !bankimmeds", name);
2249 emit2 ("call %s", name);
2254 /* Mark the regsiters as restored. */
2255 _G.saves.saved = FALSE;
2257 /* if we need assign a result value */
2258 if ((IS_ITEMP (IC_RESULT (ic)) &&
2259 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2260 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2261 IS_TRUE_SYMOP (IC_RESULT (ic)))
2264 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2266 assignResultValue (IC_RESULT (ic));
2268 freeAsmop (IC_RESULT (ic), NULL, ic);
2271 /* adjust the stack for parameters if required */
2274 int i = ic->parmBytes;
2276 _G.stack.pushed -= i;
2279 emit2 ("!ldaspsp", i);
2286 emit2 ("ld hl,#%d", i);
2287 emit2 ("add hl,sp");
2304 if (_G.stack.pushedDE)
2306 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2307 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2309 if (dInUse && eInUse)
2325 wassertl (0, "Neither D or E were in use but it was pushed.");
2327 _G.stack.pushedDE = FALSE;
2330 if (_G.stack.pushedBC)
2332 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2333 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2335 // If both B and C are used in the return value, then we won't get
2337 if (bInUse && cInUse)
2353 wassertl (0, "Neither B or C were in use but it was pushed.");
2355 _G.stack.pushedBC = FALSE;
2359 /*-----------------------------------------------------------------*/
2360 /* genCall - generates a call statement */
2361 /*-----------------------------------------------------------------*/
2363 genCall (iCode * ic)
2365 emitCall (ic, FALSE);
2368 /*-----------------------------------------------------------------*/
2369 /* genPcall - generates a call by pointer statement */
2370 /*-----------------------------------------------------------------*/
2372 genPcall (iCode * ic)
2374 emitCall (ic, TRUE);
2377 /*-----------------------------------------------------------------*/
2378 /* resultRemat - result is rematerializable */
2379 /*-----------------------------------------------------------------*/
2381 resultRemat (iCode * ic)
2383 if (SKIP_IC (ic) || ic->op == IFX)
2386 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2388 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2389 if (sym->remat && !POINTER_SET (ic))
2396 extern set *publics;
2398 /*-----------------------------------------------------------------*/
2399 /* genFunction - generated code for function entry */
2400 /*-----------------------------------------------------------------*/
2402 genFunction (iCode * ic)
2404 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2408 bool bcInUse = FALSE;
2409 bool deInUse = FALSE;
2412 setArea (IS_NONBANKED (sym->etype));
2414 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2417 _G.receiveOffset = 0;
2419 /* Record the last function name for debugging. */
2420 _G.lastFunctionName = sym->rname;
2422 /* Create the function header */
2423 emit2 ("!functionheader", sym->name);
2424 /* PENDING: portability. */
2425 emit2 ("__%s_start:", sym->rname);
2426 emit2 ("!functionlabeldef", sym->rname);
2428 if (options.profile)
2430 emit2 ("!profileenter");
2433 fetype = getSpec (operandType (IC_LEFT (ic)));
2435 /* if critical function then turn interrupts off */
2436 if (SPEC_CRTCL (fetype))
2439 /* if this is an interrupt service routine then save all potentially used registers. */
2440 if (IS_ISR (sym->etype))
2445 /* PENDING: callee-save etc */
2447 _G.stack.param_offset = 0;
2450 /* Detect which registers are used. */
2454 for (i = 0; i < sym->regsUsed->size; i++)
2456 if (bitVectBitValue (sym->regsUsed, i))
2470 /* Other systems use DE as a temporary. */
2481 _G.stack.param_offset += 2;
2484 _G.stack.pushedBC = bcInUse;
2489 _G.stack.param_offset += 2;
2492 _G.stack.pushedDE = deInUse;
2495 /* adjust the stack for the function */
2496 _G.stack.last = sym->stack;
2499 emit2 ("!enterx", sym->stack);
2502 _G.stack.offset = sym->stack;
2505 /*-----------------------------------------------------------------*/
2506 /* genEndFunction - generates epilogue for functions */
2507 /*-----------------------------------------------------------------*/
2509 genEndFunction (iCode * ic)
2511 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2513 if (IS_ISR (sym->etype))
2515 wassertl (0, "Tried to close an interrupt support function");
2519 if (SPEC_CRTCL (sym->etype))
2522 /* PENDING: calleeSave */
2524 if (_G.stack.offset)
2526 emit2 ("!leavex", _G.stack.offset);
2534 if (_G.stack.pushedDE)
2537 _G.stack.pushedDE = FALSE;
2540 if (_G.stack.pushedDE)
2543 _G.stack.pushedDE = FALSE;
2547 if (options.profile)
2549 emit2 ("!profileexit");
2553 /* Both baned and non-banked just ret */
2556 /* PENDING: portability. */
2557 emit2 ("__%s_end:", sym->rname);
2559 _G.flushStatics = 1;
2560 _G.stack.pushed = 0;
2561 _G.stack.offset = 0;
2564 /*-----------------------------------------------------------------*/
2565 /* genRet - generate code for return statement */
2566 /*-----------------------------------------------------------------*/
2571 /* Errk. This is a hack until I can figure out how
2572 to cause dehl to spill on a call */
2573 int size, offset = 0;
2575 /* if we have no return value then
2576 just generate the "ret" */
2580 /* we have something to return then
2581 move the return value into place */
2582 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2583 size = AOP_SIZE (IC_LEFT (ic));
2585 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2589 emit2 ("ld de,%s", l);
2593 emit2 ("ld hl,%s", l);
2598 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2600 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2601 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2607 l = aopGet (AOP (IC_LEFT (ic)), offset,
2609 if (strcmp (_fReturn[offset], l))
2610 emit2 ("ld %s,%s", _fReturn[offset++], l);
2614 freeAsmop (IC_LEFT (ic), NULL, ic);
2617 /* generate a jump to the return label
2618 if the next is not the return statement */
2619 if (!(ic->next && ic->next->op == LABEL &&
2620 IC_LABEL (ic->next) == returnLabel))
2622 emit2 ("jp !tlabel", returnLabel->key + 100);
2625 /*-----------------------------------------------------------------*/
2626 /* genLabel - generates a label */
2627 /*-----------------------------------------------------------------*/
2629 genLabel (iCode * ic)
2631 /* special case never generate */
2632 if (IC_LABEL (ic) == entryLabel)
2635 emitLabel (IC_LABEL (ic)->key + 100);
2638 /*-----------------------------------------------------------------*/
2639 /* genGoto - generates a ljmp */
2640 /*-----------------------------------------------------------------*/
2642 genGoto (iCode * ic)
2644 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2647 /*-----------------------------------------------------------------*/
2648 /* genPlusIncr :- does addition with increment if possible */
2649 /*-----------------------------------------------------------------*/
2651 genPlusIncr (iCode * ic)
2653 unsigned int icount;
2654 unsigned int size = getDataSize (IC_RESULT (ic));
2655 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2657 /* will try to generate an increment */
2658 /* if the right side is not a literal
2660 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2663 emitDebug ("; genPlusIncr");
2665 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2667 /* If result is a pair */
2668 if (resultId != PAIR_INVALID)
2670 if (isLitWord (AOP (IC_LEFT (ic))))
2672 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2675 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2677 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2678 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2684 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2688 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2689 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2693 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2698 /* if the literal value of the right hand side
2699 is greater than 4 then it is not worth it */
2703 /* if increment 16 bits in register */
2704 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2710 symbol *tlbl = NULL;
2711 tlbl = newiTempLabel (NULL);
2714 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2717 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2720 emitLabel (tlbl->key + 100);
2724 /* if the sizes are greater than 1 then we cannot */
2725 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2726 AOP_SIZE (IC_LEFT (ic)) > 1)
2729 /* we can if the aops of the left & result match or
2730 if they are in registers and the registers are the
2732 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2736 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2744 /*-----------------------------------------------------------------*/
2745 /* outBitAcc - output a bit in acc */
2746 /*-----------------------------------------------------------------*/
2748 outBitAcc (operand * result)
2750 symbol *tlbl = newiTempLabel (NULL);
2751 /* if the result is a bit */
2752 if (AOP_TYPE (result) == AOP_CRY)
2754 wassertl (0, "Tried to write A into a bit");
2758 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2759 emit2 ("ld a,!one");
2760 emitLabel (tlbl->key + 100);
2765 /*-----------------------------------------------------------------*/
2766 /* genPlus - generates code for addition */
2767 /*-----------------------------------------------------------------*/
2769 genPlus (iCode * ic)
2771 int size, offset = 0;
2773 /* special cases :- */
2775 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2776 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2777 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2779 /* Swap the left and right operands if:
2781 if literal, literal on the right or
2782 if left requires ACC or right is already
2785 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2786 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2787 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2789 operand *t = IC_RIGHT (ic);
2790 IC_RIGHT (ic) = IC_LEFT (ic);
2794 /* if both left & right are in bit
2796 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2797 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2800 wassertl (0, "Tried to add two bits");
2803 /* if left in bit space & right literal */
2804 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2805 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2807 /* Can happen I guess */
2808 wassertl (0, "Tried to add a bit to a literal");
2811 /* if I can do an increment instead
2812 of add then GOOD for ME */
2813 if (genPlusIncr (ic) == TRUE)
2816 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
2818 size = getDataSize (IC_RESULT (ic));
2820 /* Special case when left and right are constant */
2821 if (isPair (AOP (IC_RESULT (ic))))
2824 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2825 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2827 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2833 sprintf (buffer, "#(%s + %s)", left, right);
2834 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2839 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2841 /* Fetch into HL then do the add */
2842 spillPair (PAIR_HL);
2843 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2844 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2849 ld hl,sp+n trashes C so we cant afford to do it during an
2850 add with stack based varibles. Worst case is:
2863 So you cant afford to load up hl if either left, right, or result
2864 is on the stack (*sigh*) The alt is:
2872 Combinations in here are:
2873 * If left or right are in bc then the loss is small - trap later
2874 * If the result is in bc then the loss is also small
2878 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2879 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2880 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2882 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2883 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2884 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2885 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2887 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2889 /* Swap left and right */
2890 operand *t = IC_RIGHT (ic);
2891 IC_RIGHT (ic) = IC_LEFT (ic);
2894 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2896 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2897 emit2 ("add hl,bc");
2901 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2902 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2903 emit2 ("add hl,de");
2905 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2911 /* Be paranoid on the GB with 4 byte variables due to how C
2912 can be trashed by lda hl,n(sp).
2914 _gbz80_emitAddSubLong (ic, TRUE);
2921 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2923 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2926 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2929 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2933 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2936 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2939 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2941 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2945 freeAsmop (IC_LEFT (ic), NULL, ic);
2946 freeAsmop (IC_RIGHT (ic), NULL, ic);
2947 freeAsmop (IC_RESULT (ic), NULL, ic);
2951 /*-----------------------------------------------------------------*/
2952 /* genMinusDec :- does subtraction with deccrement if possible */
2953 /*-----------------------------------------------------------------*/
2955 genMinusDec (iCode * ic)
2957 unsigned int icount;
2958 unsigned int size = getDataSize (IC_RESULT (ic));
2960 /* will try to generate an increment */
2961 /* if the right side is not a literal we cannot */
2962 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2965 /* if the literal value of the right hand side
2966 is greater than 4 then it is not worth it */
2967 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2970 size = getDataSize (IC_RESULT (ic));
2972 /* if decrement 16 bits in register */
2973 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2974 (size > 1) && isPair (AOP (IC_RESULT (ic))))
2977 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2981 /* If result is a pair */
2982 if (isPair (AOP (IC_RESULT (ic))))
2984 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2985 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2987 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2991 /* if increment 16 bits in register */
2992 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2996 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
2999 emit2 ("dec %s", _getTempPairName());
3002 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3008 /* if the sizes are greater than 1 then we cannot */
3009 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3010 AOP_SIZE (IC_LEFT (ic)) > 1)
3013 /* we can if the aops of the left & result match or if they are in
3014 registers and the registers are the same */
3015 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3018 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3025 /*-----------------------------------------------------------------*/
3026 /* genMinus - generates code for subtraction */
3027 /*-----------------------------------------------------------------*/
3029 genMinus (iCode * ic)
3031 int size, offset = 0;
3032 unsigned long lit = 0L;
3034 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3035 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3036 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3038 /* special cases :- */
3039 /* if both left & right are in bit space */
3040 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3041 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3043 wassertl (0, "Tried to subtract two bits");
3047 /* if I can do an decrement instead of subtract then GOOD for ME */
3048 if (genMinusDec (ic) == TRUE)
3051 size = getDataSize (IC_RESULT (ic));
3053 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3058 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3062 /* Same logic as genPlus */
3065 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3066 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3067 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3069 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3070 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3071 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3072 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3074 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3075 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3077 if (left == PAIR_INVALID && right == PAIR_INVALID)
3082 else if (right == PAIR_INVALID)
3084 else if (left == PAIR_INVALID)
3087 fetchPair (left, AOP (IC_LEFT (ic)));
3088 /* Order is important. Right may be HL */
3089 fetchPair (right, AOP (IC_RIGHT (ic)));
3091 emit2 ("ld a,%s", _pairs[left].l);
3092 emit2 ("sub a,%s", _pairs[right].l);
3094 emit2 ("ld a,%s", _pairs[left].h);
3095 emit2 ("sbc a,%s", _pairs[right].h);
3097 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3098 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3104 /* Be paranoid on the GB with 4 byte variables due to how C
3105 can be trashed by lda hl,n(sp).
3107 _gbz80_emitAddSubLong (ic, FALSE);
3112 /* if literal, add a,#-lit, else normal subb */
3115 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3116 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3120 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3123 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3127 /* first add without previous c */
3129 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3131 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3133 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3136 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3137 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3138 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3140 wassertl (0, "Tried to subtract on a long pointer");
3144 freeAsmop (IC_LEFT (ic), NULL, ic);
3145 freeAsmop (IC_RIGHT (ic), NULL, ic);
3146 freeAsmop (IC_RESULT (ic), NULL, ic);
3149 /*-----------------------------------------------------------------*/
3150 /* genMult - generates code for multiplication */
3151 /*-----------------------------------------------------------------*/
3153 genMult (iCode * ic)
3155 /* Shouldn't occur - all done through function calls */
3156 wassertl (0, "Multiplication is handled through support function calls");
3159 /*-----------------------------------------------------------------*/
3160 /* genDiv - generates code for division */
3161 /*-----------------------------------------------------------------*/
3165 /* Shouldn't occur - all done through function calls */
3166 wassertl (0, "Division is handled through support function calls");
3169 /*-----------------------------------------------------------------*/
3170 /* genMod - generates code for division */
3171 /*-----------------------------------------------------------------*/
3175 /* Shouldn't occur - all done through function calls */
3179 /*-----------------------------------------------------------------*/
3180 /* genIfxJump :- will create a jump depending on the ifx */
3181 /*-----------------------------------------------------------------*/
3183 genIfxJump (iCode * ic, char *jval)
3188 /* if true label then we jump if condition
3192 jlbl = IC_TRUE (ic);
3193 if (!strcmp (jval, "a"))
3197 else if (!strcmp (jval, "c"))
3201 else if (!strcmp (jval, "nc"))
3207 /* The buffer contains the bit on A that we should test */
3213 /* false label is present */
3214 jlbl = IC_FALSE (ic);
3215 if (!strcmp (jval, "a"))
3219 else if (!strcmp (jval, "c"))
3223 else if (!strcmp (jval, "nc"))
3229 /* The buffer contains the bit on A that we should test */
3233 /* Z80 can do a conditional long jump */
3234 if (!strcmp (jval, "a"))
3238 else if (!strcmp (jval, "c"))
3241 else if (!strcmp (jval, "nc"))
3246 emit2 ("bit %s,a", jval);
3248 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3250 /* mark the icode as generated */
3256 _getPairIdName (PAIR_ID id)
3258 return _pairs[id].name;
3262 /** Generic compare for > or <
3265 genCmp (operand * left, operand * right,
3266 operand * result, iCode * ifx, int sign)
3268 int size, offset = 0;
3269 unsigned long lit = 0L;
3270 bool swap_sense = FALSE;
3272 /* if left & right are bit variables */
3273 if (AOP_TYPE (left) == AOP_CRY &&
3274 AOP_TYPE (right) == AOP_CRY)
3276 /* Cant happen on the Z80 */
3277 wassertl (0, "Tried to compare two bits");
3281 /* subtract right from left if at the
3282 end the carry flag is set then we know that
3283 left is greater than right */
3284 size = max (AOP_SIZE (left), AOP_SIZE (right));
3286 /* if unsigned char cmp with lit, just compare */
3288 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3290 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3293 emit2 ("xor a,!immedbyte", 0x80);
3294 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3297 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3299 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3301 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3302 // Pull left into DE and right into HL
3303 aopGet (AOP(left), LSB, FALSE);
3306 aopGet (AOP(right), LSB, FALSE);
3310 if (size == 0 && sign)
3312 // Highest byte when signed needs the bits flipped
3315 emit2 ("ld a,(de)");
3316 emit2 ("xor #0x80");
3318 emit2 ("ld a,(hl)");
3319 emit2 ("xor #0x80");
3323 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3327 emit2 ("ld a,(de)");
3328 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3338 spillPair (PAIR_HL);
3342 if (AOP_TYPE (right) == AOP_LIT)
3344 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3345 /* optimize if(x < 0) or if(x >= 0) */
3350 /* No sign so it's always false */
3355 /* Just load in the top most bit */
3356 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3357 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3359 genIfxJump (ifx, "7");
3370 /* First setup h and l contaning the top most bytes XORed */
3371 bool fDidXor = FALSE;
3372 if (AOP_TYPE (left) == AOP_LIT)
3374 unsigned long lit = (unsigned long)
3375 floatFromVal (AOP (left)->aopu.aop_lit);
3376 emit2 ("ld %s,!immedbyte", _fTmp[0],
3377 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3381 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3382 emit2 ("xor a,!immedbyte", 0x80);
3383 emit2 ("ld %s,a", _fTmp[0]);
3386 if (AOP_TYPE (right) == AOP_LIT)
3388 unsigned long lit = (unsigned long)
3389 floatFromVal (AOP (right)->aopu.aop_lit);
3390 emit2 ("ld %s,!immedbyte", _fTmp[1],
3391 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3395 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3396 emit2 ("xor a,!immedbyte", 0x80);
3397 emit2 ("ld %s,a", _fTmp[1]);
3403 /* Do a long subtract */
3406 _moveA (aopGet (AOP (left), offset, FALSE));
3408 if (sign && size == 0)
3410 emit2 ("ld a,%s", _fTmp[0]);
3411 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3415 /* Subtract through, propagating the carry */
3416 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3424 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3426 outBitCLong (result, swap_sense);
3430 /* if the result is used in the next
3431 ifx conditional branch then generate
3432 code a little differently */
3434 genIfxJump (ifx, swap_sense ? "nc" : "c");
3436 outBitCLong (result, swap_sense);
3437 /* leave the result in acc */
3441 /*-----------------------------------------------------------------*/
3442 /* genCmpGt :- greater than comparison */
3443 /*-----------------------------------------------------------------*/
3445 genCmpGt (iCode * ic, iCode * ifx)
3447 operand *left, *right, *result;
3448 sym_link *letype, *retype;
3451 left = IC_LEFT (ic);
3452 right = IC_RIGHT (ic);
3453 result = IC_RESULT (ic);
3455 letype = getSpec (operandType (left));
3456 retype = getSpec (operandType (right));
3457 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3458 /* assign the amsops */
3459 aopOp (left, ic, FALSE, FALSE);
3460 aopOp (right, ic, FALSE, FALSE);
3461 aopOp (result, ic, TRUE, FALSE);
3463 genCmp (right, left, result, ifx, sign);
3465 freeAsmop (left, NULL, ic);
3466 freeAsmop (right, NULL, ic);
3467 freeAsmop (result, NULL, ic);
3470 /*-----------------------------------------------------------------*/
3471 /* genCmpLt - less than comparisons */
3472 /*-----------------------------------------------------------------*/
3474 genCmpLt (iCode * ic, iCode * ifx)
3476 operand *left, *right, *result;
3477 sym_link *letype, *retype;
3480 left = IC_LEFT (ic);
3481 right = IC_RIGHT (ic);
3482 result = IC_RESULT (ic);
3484 letype = getSpec (operandType (left));
3485 retype = getSpec (operandType (right));
3486 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3488 /* assign the amsops */
3489 aopOp (left, ic, FALSE, FALSE);
3490 aopOp (right, ic, FALSE, FALSE);
3491 aopOp (result, ic, TRUE, FALSE);
3493 genCmp (left, right, result, ifx, sign);
3495 freeAsmop (left, NULL, ic);
3496 freeAsmop (right, NULL, ic);
3497 freeAsmop (result, NULL, ic);
3500 /*-----------------------------------------------------------------*/
3501 /* gencjneshort - compare and jump if not equal */
3502 /*-----------------------------------------------------------------*/
3504 gencjneshort (operand * left, operand * right, symbol * lbl)
3506 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3508 unsigned long lit = 0L;
3510 /* Swap the left and right if it makes the computation easier */
3511 if (AOP_TYPE (left) == AOP_LIT)
3518 if (AOP_TYPE (right) == AOP_LIT)
3519 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3521 /* if the right side is a literal then anything goes */
3522 if (AOP_TYPE (right) == AOP_LIT &&
3523 AOP_TYPE (left) != AOP_DIR)
3527 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3534 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3541 emit2 ("jp nz,!tlabel", lbl->key + 100);
3547 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3548 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3551 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3552 emit2 ("jp nz,!tlabel", lbl->key + 100);
3557 /* if the right side is in a register or in direct space or
3558 if the left is a pointer register & right is not */
3559 else if (AOP_TYPE (right) == AOP_REG ||
3560 AOP_TYPE (right) == AOP_DIR ||
3561 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3565 _moveA (aopGet (AOP (left), offset, FALSE));
3566 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3567 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3569 emit2 ("jp nz,!tlabel", lbl->key + 100);
3572 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3573 emit2 ("jp nz,!tlabel", lbl->key + 100);
3580 /* right is a pointer reg need both a & b */
3581 /* PENDING: is this required? */
3584 _moveA (aopGet (AOP (right), offset, FALSE));
3585 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3586 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3592 /*-----------------------------------------------------------------*/
3593 /* gencjne - compare and jump if not equal */
3594 /*-----------------------------------------------------------------*/
3596 gencjne (operand * left, operand * right, symbol * lbl)
3598 symbol *tlbl = newiTempLabel (NULL);
3600 gencjneshort (left, right, lbl);
3603 emit2 ("ld a,!one");
3604 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3605 emitLabel (lbl->key + 100);
3607 emitLabel (tlbl->key + 100);
3610 /*-----------------------------------------------------------------*/
3611 /* genCmpEq - generates code for equal to */
3612 /*-----------------------------------------------------------------*/
3614 genCmpEq (iCode * ic, iCode * ifx)
3616 operand *left, *right, *result;
3618 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3619 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3620 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3622 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3624 /* Swap operands if it makes the operation easier. ie if:
3625 1. Left is a literal.
3627 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3629 operand *t = IC_RIGHT (ic);
3630 IC_RIGHT (ic) = IC_LEFT (ic);
3634 if (ifx && !AOP_SIZE (result))
3637 /* if they are both bit variables */
3638 if (AOP_TYPE (left) == AOP_CRY &&
3639 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3641 wassertl (0, "Tried to compare two bits");
3645 tlbl = newiTempLabel (NULL);
3646 gencjneshort (left, right, tlbl);
3649 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3650 emitLabel (tlbl->key + 100);
3654 /* PENDING: do this better */
3655 symbol *lbl = newiTempLabel (NULL);
3656 emit2 ("!shortjp !tlabel", lbl->key + 100);
3657 emitLabel (tlbl->key + 100);
3658 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3659 emitLabel (lbl->key + 100);
3662 /* mark the icode as generated */
3667 /* if they are both bit variables */
3668 if (AOP_TYPE (left) == AOP_CRY &&
3669 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3671 wassertl (0, "Tried to compare a bit to either a literal or another bit");
3675 gencjne (left, right, newiTempLabel (NULL));
3676 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3682 genIfxJump (ifx, "a");
3685 /* if the result is used in an arithmetic operation
3686 then put the result in place */
3687 if (AOP_TYPE (result) != AOP_CRY)
3691 /* leave the result in acc */
3695 freeAsmop (left, NULL, ic);
3696 freeAsmop (right, NULL, ic);
3697 freeAsmop (result, NULL, ic);
3700 /*-----------------------------------------------------------------*/
3701 /* ifxForOp - returns the icode containing the ifx for operand */
3702 /*-----------------------------------------------------------------*/
3704 ifxForOp (operand * op, iCode * ic)
3706 /* if true symbol then needs to be assigned */
3707 if (IS_TRUE_SYMOP (op))
3710 /* if this has register type condition and
3711 the next instruction is ifx with the same operand
3712 and live to of the operand is upto the ifx only then */
3714 ic->next->op == IFX &&
3715 IC_COND (ic->next)->key == op->key &&
3716 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3722 /*-----------------------------------------------------------------*/
3723 /* genAndOp - for && operation */
3724 /*-----------------------------------------------------------------*/
3726 genAndOp (iCode * ic)
3728 operand *left, *right, *result;
3731 /* note here that && operations that are in an if statement are
3732 taken away by backPatchLabels only those used in arthmetic
3733 operations remain */
3734 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3735 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3736 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3738 /* if both are bit variables */
3739 if (AOP_TYPE (left) == AOP_CRY &&
3740 AOP_TYPE (right) == AOP_CRY)
3742 wassertl (0, "Tried to and two bits");
3746 tlbl = newiTempLabel (NULL);
3748 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3750 emitLabel (tlbl->key + 100);
3754 freeAsmop (left, NULL, ic);
3755 freeAsmop (right, NULL, ic);
3756 freeAsmop (result, NULL, ic);
3759 /*-----------------------------------------------------------------*/
3760 /* genOrOp - for || operation */
3761 /*-----------------------------------------------------------------*/
3763 genOrOp (iCode * ic)
3765 operand *left, *right, *result;
3768 /* note here that || operations that are in an
3769 if statement are taken away by backPatchLabels
3770 only those used in arthmetic operations remain */
3771 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3772 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3773 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3775 /* if both are bit variables */
3776 if (AOP_TYPE (left) == AOP_CRY &&
3777 AOP_TYPE (right) == AOP_CRY)
3779 wassertl (0, "Tried to OR two bits");
3783 tlbl = newiTempLabel (NULL);
3785 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3787 emitLabel (tlbl->key + 100);
3791 freeAsmop (left, NULL, ic);
3792 freeAsmop (right, NULL, ic);
3793 freeAsmop (result, NULL, ic);
3796 /*-----------------------------------------------------------------*/
3797 /* isLiteralBit - test if lit == 2^n */
3798 /*-----------------------------------------------------------------*/
3800 isLiteralBit (unsigned long lit)
3802 unsigned long pw[32] =
3803 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3804 0x100L, 0x200L, 0x400L, 0x800L,
3805 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3806 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3807 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3808 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3809 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3812 for (idx = 0; idx < 32; idx++)
3818 /*-----------------------------------------------------------------*/
3819 /* jmpTrueOrFalse - */
3820 /*-----------------------------------------------------------------*/
3822 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3824 // ugly but optimized by peephole
3827 symbol *nlbl = newiTempLabel (NULL);
3828 emit2 ("jp !tlabel", nlbl->key + 100);
3829 emitLabel (tlbl->key + 100);
3830 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3831 emitLabel (nlbl->key + 100);
3835 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3836 emitLabel (tlbl->key + 100);
3841 /*-----------------------------------------------------------------*/
3842 /* genAnd - code for and */
3843 /*-----------------------------------------------------------------*/
3845 genAnd (iCode * ic, iCode * ifx)
3847 operand *left, *right, *result;
3848 int size, offset = 0;
3849 unsigned long lit = 0L;
3852 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3853 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3854 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3856 /* if left is a literal & right is not then exchange them */
3857 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3858 AOP_NEEDSACC (left))
3860 operand *tmp = right;
3865 /* if result = right then exchange them */
3866 if (sameRegs (AOP (result), AOP (right)))
3868 operand *tmp = right;
3873 /* if right is bit then exchange them */
3874 if (AOP_TYPE (right) == AOP_CRY &&
3875 AOP_TYPE (left) != AOP_CRY)
3877 operand *tmp = right;
3881 if (AOP_TYPE (right) == AOP_LIT)
3882 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3884 size = AOP_SIZE (result);
3886 if (AOP_TYPE (left) == AOP_CRY)
3888 wassertl (0, "Tried to perform an AND with a bit as an operand");
3892 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3893 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3894 if ((AOP_TYPE (right) == AOP_LIT) &&
3895 (AOP_TYPE (result) == AOP_CRY) &&
3896 (AOP_TYPE (left) != AOP_CRY))
3898 symbol *tlbl = newiTempLabel (NULL);
3899 int sizel = AOP_SIZE (left);
3902 /* PENDING: Test case for this. */
3907 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3909 _moveA (aopGet (AOP (left), offset, FALSE));
3910 if (bytelit != 0x0FFL)
3912 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
3919 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3923 // bit = left & literal
3927 emit2 ("!tlabeldef", tlbl->key + 100);
3929 // if(left & literal)
3934 jmpTrueOrFalse (ifx, tlbl);
3942 /* if left is same as result */
3943 if (sameRegs (AOP (result), AOP (left)))
3945 for (; size--; offset++)
3947 if (AOP_TYPE (right) == AOP_LIT)
3949 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3954 aopPut (AOP (result), "!zero", offset);
3957 _moveA (aopGet (AOP (left), offset, FALSE));
3959 aopGet (AOP (right), offset, FALSE));
3960 aopPut (AOP (left), "a", offset);
3967 if (AOP_TYPE (left) == AOP_ACC)
3969 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
3973 _moveA (aopGet (AOP (left), offset, FALSE));
3975 aopGet (AOP (right), offset, FALSE));
3976 aopPut (AOP (left), "a", offset);
3983 // left & result in different registers
3984 if (AOP_TYPE (result) == AOP_CRY)
3986 wassertl (0, "Tried to AND where the result is in carry");
3990 for (; (size--); offset++)
3993 // result = left & right
3994 if (AOP_TYPE (right) == AOP_LIT)
3996 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3998 aopPut (AOP (result),
3999 aopGet (AOP (left), offset, FALSE),
4003 else if (bytelit == 0)
4005 aopPut (AOP (result), "!zero", offset);
4009 // faster than result <- left, anl result,right
4010 // and better if result is SFR
4011 if (AOP_TYPE (left) == AOP_ACC)
4012 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4015 _moveA (aopGet (AOP (left), offset, FALSE));
4017 aopGet (AOP (right), offset, FALSE));
4019 aopPut (AOP (result), "a", offset);
4026 freeAsmop (left, NULL, ic);
4027 freeAsmop (right, NULL, ic);
4028 freeAsmop (result, NULL, ic);
4031 /*-----------------------------------------------------------------*/
4032 /* genOr - code for or */
4033 /*-----------------------------------------------------------------*/
4035 genOr (iCode * ic, iCode * ifx)
4037 operand *left, *right, *result;
4038 int size, offset = 0;
4039 unsigned long lit = 0L;
4042 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4043 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4044 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4046 /* if left is a literal & right is not then exchange them */
4047 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4048 AOP_NEEDSACC (left))
4050 operand *tmp = right;
4055 /* if result = right then exchange them */
4056 if (sameRegs (AOP (result), AOP (right)))
4058 operand *tmp = right;
4063 /* if right is bit then exchange them */
4064 if (AOP_TYPE (right) == AOP_CRY &&
4065 AOP_TYPE (left) != AOP_CRY)
4067 operand *tmp = right;
4071 if (AOP_TYPE (right) == AOP_LIT)
4072 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4074 size = AOP_SIZE (result);
4076 if (AOP_TYPE (left) == AOP_CRY)
4078 wassertl (0, "Tried to OR where left is a bit");
4082 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4083 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4084 if ((AOP_TYPE (right) == AOP_LIT) &&
4085 (AOP_TYPE (result) == AOP_CRY) &&
4086 (AOP_TYPE (left) != AOP_CRY))
4088 symbol *tlbl = newiTempLabel (NULL);
4089 int sizel = AOP_SIZE (left);
4093 wassertl (0, "Result is assigned to a bit");
4095 /* PENDING: Modeled after the AND code which is inefficent. */
4098 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4100 _moveA (aopGet (AOP (left), offset, FALSE));
4101 /* OR with any literal is the same as OR with itself. */
4103 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4109 jmpTrueOrFalse (ifx, tlbl);
4114 /* if left is same as result */
4115 if (sameRegs (AOP (result), AOP (left)))
4117 for (; size--; offset++)
4119 if (AOP_TYPE (right) == AOP_LIT)
4121 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4125 _moveA (aopGet (AOP (left), offset, FALSE));
4127 aopGet (AOP (right), offset, FALSE));
4128 aopPut (AOP (result), "a", offset);
4133 if (AOP_TYPE (left) == AOP_ACC)
4134 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4137 _moveA (aopGet (AOP (left), offset, FALSE));
4139 aopGet (AOP (right), offset, FALSE));
4140 aopPut (AOP (result), "a", offset);
4147 // left & result in different registers
4148 if (AOP_TYPE (result) == AOP_CRY)
4150 wassertl (0, "Result of OR is in a bit");
4153 for (; (size--); offset++)
4156 // result = left & right
4157 if (AOP_TYPE (right) == AOP_LIT)
4159 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4161 aopPut (AOP (result),
4162 aopGet (AOP (left), offset, FALSE),
4167 // faster than result <- left, anl result,right
4168 // and better if result is SFR
4169 if (AOP_TYPE (left) == AOP_ACC)
4170 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4173 _moveA (aopGet (AOP (left), offset, FALSE));
4175 aopGet (AOP (right), offset, FALSE));
4177 aopPut (AOP (result), "a", offset);
4178 /* PENDING: something weird is going on here. Add exception. */
4179 if (AOP_TYPE (result) == AOP_ACC)
4185 freeAsmop (left, NULL, ic);
4186 freeAsmop (right, NULL, ic);
4187 freeAsmop (result, NULL, ic);
4190 /*-----------------------------------------------------------------*/
4191 /* genXor - code for xclusive or */
4192 /*-----------------------------------------------------------------*/
4194 genXor (iCode * ic, iCode * ifx)
4196 operand *left, *right, *result;
4197 int size, offset = 0;
4198 unsigned long lit = 0L;
4200 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4201 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4202 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4204 /* if left is a literal & right is not then exchange them */
4205 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4206 AOP_NEEDSACC (left))
4208 operand *tmp = right;
4213 /* if result = right then exchange them */
4214 if (sameRegs (AOP (result), AOP (right)))
4216 operand *tmp = right;
4221 /* if right is bit then exchange them */
4222 if (AOP_TYPE (right) == AOP_CRY &&
4223 AOP_TYPE (left) != AOP_CRY)
4225 operand *tmp = right;
4229 if (AOP_TYPE (right) == AOP_LIT)
4230 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4232 size = AOP_SIZE (result);
4234 if (AOP_TYPE (left) == AOP_CRY)
4236 wassertl (0, "Tried to XOR a bit");
4240 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4241 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4242 if ((AOP_TYPE (right) == AOP_LIT) &&
4243 (AOP_TYPE (result) == AOP_CRY) &&
4244 (AOP_TYPE (left) != AOP_CRY))
4246 symbol *tlbl = newiTempLabel (NULL);
4247 int sizel = AOP_SIZE (left);
4251 /* PENDING: Test case for this. */
4252 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4256 _moveA (aopGet (AOP (left), offset, FALSE));
4257 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4258 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4263 jmpTrueOrFalse (ifx, tlbl);
4267 wassertl (0, "Result of XOR was destined for a bit");
4272 /* if left is same as result */
4273 if (sameRegs (AOP (result), AOP (left)))
4275 for (; size--; offset++)
4277 if (AOP_TYPE (right) == AOP_LIT)
4279 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4283 _moveA (aopGet (AOP (right), offset, FALSE));
4285 aopGet (AOP (left), offset, FALSE));
4286 aopPut (AOP (result), "a", offset);
4291 if (AOP_TYPE (left) == AOP_ACC)
4293 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4297 _moveA (aopGet (AOP (right), offset, FALSE));
4299 aopGet (AOP (left), offset, FALSE));
4300 aopPut (AOP (result), "a", 0);
4307 // left & result in different registers
4308 if (AOP_TYPE (result) == AOP_CRY)
4310 wassertl (0, "Result of XOR is in a bit");
4313 for (; (size--); offset++)
4316 // result = left & right
4317 if (AOP_TYPE (right) == AOP_LIT)
4319 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4321 aopPut (AOP (result),
4322 aopGet (AOP (left), offset, FALSE),
4327 // faster than result <- left, anl result,right
4328 // and better if result is SFR
4329 if (AOP_TYPE (left) == AOP_ACC)
4331 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4335 _moveA (aopGet (AOP (right), offset, FALSE));
4337 aopGet (AOP (left), offset, FALSE));
4339 aopPut (AOP (result), "a", offset);
4344 freeAsmop (left, NULL, ic);
4345 freeAsmop (right, NULL, ic);
4346 freeAsmop (result, NULL, ic);
4349 /*-----------------------------------------------------------------*/
4350 /* genInline - write the inline code out */
4351 /*-----------------------------------------------------------------*/
4353 genInline (iCode * ic)
4355 char *buffer, *bp, *bp1;
4357 _G.lines.isInline += (!options.asmpeep);
4359 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4360 strcpy (buffer, IC_INLINE (ic));
4362 /* emit each line as a code */
4387 _G.lines.isInline -= (!options.asmpeep);
4391 /*-----------------------------------------------------------------*/
4392 /* genRRC - rotate right with carry */
4393 /*-----------------------------------------------------------------*/
4400 /*-----------------------------------------------------------------*/
4401 /* genRLC - generate code for rotate left with carry */
4402 /*-----------------------------------------------------------------*/
4409 /*-----------------------------------------------------------------*/
4410 /* genGetHbit - generates code get highest order bit */
4411 /*-----------------------------------------------------------------*/
4413 genGetHbit (iCode * ic)
4415 operand *left, *result;
4416 left = IC_LEFT (ic);
4417 result = IC_RESULT (ic);
4418 aopOp (left, ic, FALSE, FALSE);
4419 aopOp (result, ic, FALSE, FALSE);
4421 /* get the highest order byte into a */
4422 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4424 if (AOP_TYPE (result) == AOP_CRY)
4432 /* PENDING: For re-target. */
4438 freeAsmop (left, NULL, ic);
4439 freeAsmop (result, NULL, ic);
4443 emitRsh2 (asmop *aop, int size, int is_signed)
4449 const char *l = aopGet (aop, size, FALSE);
4452 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4462 /*-----------------------------------------------------------------*/
4463 /* shiftR2Left2Result - shift right two bytes from left to result */
4464 /*-----------------------------------------------------------------*/
4466 shiftR2Left2Result (operand * left, int offl,
4467 operand * result, int offr,
4468 int shCount, int is_signed)
4471 symbol *tlbl, *tlbl1;
4473 movLeft2Result (left, offl, result, offr, 0);
4474 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4476 /* if (AOP(result)->type == AOP_REG) { */
4478 tlbl = newiTempLabel (NULL);
4479 tlbl1 = newiTempLabel (NULL);
4481 /* Left is already in result - so now do the shift */
4486 emitRsh2 (AOP (result), size, is_signed);
4491 emit2 ("ld a,!immedbyte+1", shCount);
4492 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4493 emitLabel (tlbl->key + 100);
4495 emitRsh2 (AOP (result), size, is_signed);
4497 emitLabel (tlbl1->key + 100);
4499 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4503 /*-----------------------------------------------------------------*/
4504 /* shiftL2Left2Result - shift left two bytes from left to result */
4505 /*-----------------------------------------------------------------*/
4507 shiftL2Left2Result (operand * left, int offl,
4508 operand * result, int offr, int shCount)
4510 if (sameRegs (AOP (result), AOP (left)) &&
4511 ((offl + MSB16) == offr))
4517 /* Copy left into result */
4518 movLeft2Result (left, offl, result, offr, 0);
4519 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4521 /* PENDING: for now just see if it'll work. */
4522 /*if (AOP(result)->type == AOP_REG) { */
4526 symbol *tlbl, *tlbl1;
4529 tlbl = newiTempLabel (NULL);
4530 tlbl1 = newiTempLabel (NULL);
4532 /* Left is already in result - so now do the shift */
4535 emit2 ("ld a,!immedbyte+1", shCount);
4536 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4537 emitLabel (tlbl->key + 100);
4542 l = aopGet (AOP (result), offset, FALSE);
4546 emit2 ("sla %s", l);
4557 emitLabel (tlbl1->key + 100);
4559 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4564 /*-----------------------------------------------------------------*/
4565 /* AccRol - rotate left accumulator by known count */
4566 /*-----------------------------------------------------------------*/
4568 AccRol (int shCount)
4570 shCount &= 0x0007; // shCount : 0..7
4609 /*-----------------------------------------------------------------*/
4610 /* AccLsh - left shift accumulator by known count */
4611 /*-----------------------------------------------------------------*/
4613 AccLsh (int shCount)
4615 static const unsigned char SLMask[] =
4617 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4626 else if (shCount == 2)
4633 /* rotate left accumulator */
4635 /* and kill the lower order bits */
4636 emit2 ("and a,!immedbyte", SLMask[shCount]);
4641 /*-----------------------------------------------------------------*/
4642 /* shiftL1Left2Result - shift left one byte from left to result */
4643 /*-----------------------------------------------------------------*/
4645 shiftL1Left2Result (operand * left, int offl,
4646 operand * result, int offr, int shCount)
4649 l = aopGet (AOP (left), offl, FALSE);
4651 /* shift left accumulator */
4653 aopPut (AOP (result), "a", offr);
4657 /*-----------------------------------------------------------------*/
4658 /* genlshTwo - left shift two bytes by known amount != 0 */
4659 /*-----------------------------------------------------------------*/
4661 genlshTwo (operand * result, operand * left, int shCount)
4663 int size = AOP_SIZE (result);
4665 wassert (size == 2);
4667 /* if shCount >= 8 */
4675 movLeft2Result (left, LSB, result, MSB16, 0);
4676 aopPut (AOP (result), "!zero", 0);
4677 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
4681 movLeft2Result (left, LSB, result, MSB16, 0);
4682 aopPut (AOP (result), "!zero", 0);
4687 aopPut (AOP (result), "!zero", LSB);
4690 /* 1 <= shCount <= 7 */
4699 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4704 /*-----------------------------------------------------------------*/
4705 /* genlshOne - left shift a one byte quantity by known count */
4706 /*-----------------------------------------------------------------*/
4708 genlshOne (operand * result, operand * left, int shCount)
4710 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4713 /*-----------------------------------------------------------------*/
4714 /* genLeftShiftLiteral - left shifting by known count */
4715 /*-----------------------------------------------------------------*/
4717 genLeftShiftLiteral (operand * left,
4722 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4725 freeAsmop (right, NULL, ic);
4727 aopOp (left, ic, FALSE, FALSE);
4728 aopOp (result, ic, FALSE, FALSE);
4730 size = getSize (operandType (result));
4732 /* I suppose that the left size >= result size */
4738 else if (shCount >= (size * 8))
4742 aopPut (AOP (result), "!zero", size);
4750 genlshOne (result, left, shCount);
4753 genlshTwo (result, left, shCount);
4756 wassertl (0, "Shifting of longs is currently unsupported");
4762 freeAsmop (left, NULL, ic);
4763 freeAsmop (result, NULL, ic);
4766 /*-----------------------------------------------------------------*/
4767 /* genLeftShift - generates code for left shifting */
4768 /*-----------------------------------------------------------------*/
4770 genLeftShift (iCode * ic)
4774 symbol *tlbl, *tlbl1;
4775 operand *left, *right, *result;
4777 right = IC_RIGHT (ic);
4778 left = IC_LEFT (ic);
4779 result = IC_RESULT (ic);
4781 aopOp (right, ic, FALSE, FALSE);
4783 /* if the shift count is known then do it
4784 as efficiently as possible */
4785 if (AOP_TYPE (right) == AOP_LIT)
4787 genLeftShiftLiteral (left, right, result, ic);
4791 /* shift count is unknown then we have to form a loop get the loop
4792 count in B : Note: we take only the lower order byte since
4793 shifting more that 32 bits make no sense anyway, ( the largest
4794 size of an object can be only 32 bits ) */
4795 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4797 freeAsmop (right, NULL, ic);
4798 aopOp (left, ic, FALSE, FALSE);
4799 aopOp (result, ic, FALSE, FALSE);
4801 /* now move the left to the result if they are not the
4804 if (!sameRegs (AOP (left), AOP (result)))
4807 size = AOP_SIZE (result);
4811 l = aopGet (AOP (left), offset, FALSE);
4812 aopPut (AOP (result), l, offset);
4817 tlbl = newiTempLabel (NULL);
4818 size = AOP_SIZE (result);
4820 tlbl1 = newiTempLabel (NULL);
4822 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4823 emitLabel (tlbl->key + 100);
4824 l = aopGet (AOP (result), offset, FALSE);
4828 l = aopGet (AOP (result), offset, FALSE);
4832 emit2 ("sla %s", l);
4840 emitLabel (tlbl1->key + 100);
4842 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4844 freeAsmop (left, NULL, ic);
4845 freeAsmop (result, NULL, ic);
4848 /*-----------------------------------------------------------------*/
4849 /* genrshOne - left shift two bytes by known amount != 0 */
4850 /*-----------------------------------------------------------------*/
4852 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4855 int size = AOP_SIZE (result);
4858 wassert (size == 1);
4859 wassert (shCount < 8);
4861 l = aopGet (AOP (left), 0, FALSE);
4863 if (AOP (result)->type == AOP_REG)
4865 aopPut (AOP (result), l, 0);
4866 l = aopGet (AOP (result), 0, FALSE);
4869 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4877 emit2 ("%s a", is_signed ? "sra" : "srl");
4879 aopPut (AOP (result), "a", 0);
4883 /*-----------------------------------------------------------------*/
4884 /* AccRsh - right shift accumulator by known count */
4885 /*-----------------------------------------------------------------*/
4887 AccRsh (int shCount)
4889 static const unsigned char SRMask[] =
4891 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4896 /* rotate right accumulator */
4897 AccRol (8 - shCount);
4898 /* and kill the higher order bits */
4899 emit2 ("and a,!immedbyte", SRMask[shCount]);
4903 /*-----------------------------------------------------------------*/
4904 /* shiftR1Left2Result - shift right one byte from left to result */
4905 /*-----------------------------------------------------------------*/
4907 shiftR1Left2Result (operand * left, int offl,
4908 operand * result, int offr,
4909 int shCount, int sign)
4911 _moveA (aopGet (AOP (left), offl, FALSE));
4916 emit2 ("%s a", sign ? "sra" : "srl");
4923 aopPut (AOP (result), "a", offr);
4926 /*-----------------------------------------------------------------*/
4927 /* genrshTwo - right shift two bytes by known amount != 0 */
4928 /*-----------------------------------------------------------------*/
4930 genrshTwo (operand * result, operand * left,
4931 int shCount, int sign)
4933 /* if shCount >= 8 */
4939 shiftR1Left2Result (left, MSB16, result, LSB,
4944 movLeft2Result (left, MSB16, result, LSB, sign);
4948 /* Sign extend the result */
4949 _moveA(aopGet (AOP (result), 0, FALSE));
4953 aopPut (AOP (result), ACC_NAME, MSB16);
4957 aopPut (AOP (result), "!zero", 1);
4960 /* 1 <= shCount <= 7 */
4963 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4967 /*-----------------------------------------------------------------*/
4968 /* genRightShiftLiteral - left shifting by known count */
4969 /*-----------------------------------------------------------------*/
4971 genRightShiftLiteral (operand * left,
4977 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4980 freeAsmop (right, NULL, ic);
4982 aopOp (left, ic, FALSE, FALSE);
4983 aopOp (result, ic, FALSE, FALSE);
4985 size = getSize (operandType (result));
4987 /* I suppose that the left size >= result size */
4993 else if (shCount >= (size * 8))
4995 aopPut (AOP (result), "!zero", size);
5001 genrshOne (result, left, shCount, sign);
5004 genrshTwo (result, left, shCount, sign);
5007 wassertl (0, "Asked to shift right a long which should be a function call");
5010 wassertl (0, "Entered default case in right shift delegate");
5013 freeAsmop (left, NULL, ic);
5014 freeAsmop (result, NULL, ic);
5017 /*-----------------------------------------------------------------*/
5018 /* genRightShift - generate code for right shifting */
5019 /*-----------------------------------------------------------------*/
5021 genRightShift (iCode * ic)
5023 operand *right, *left, *result;
5025 int size, offset, first = 1;
5029 symbol *tlbl, *tlbl1;
5031 /* if signed then we do it the hard way preserve the
5032 sign bit moving it inwards */
5033 retype = getSpec (operandType (IC_RESULT (ic)));
5035 is_signed = !SPEC_USIGN (retype);
5037 /* signed & unsigned types are treated the same : i.e. the
5038 signed is NOT propagated inwards : quoting from the
5039 ANSI - standard : "for E1 >> E2, is equivalent to division
5040 by 2**E2 if unsigned or if it has a non-negative value,
5041 otherwise the result is implementation defined ", MY definition
5042 is that the sign does not get propagated */
5044 right = IC_RIGHT (ic);
5045 left = IC_LEFT (ic);
5046 result = IC_RESULT (ic);
5048 aopOp (right, ic, FALSE, FALSE);
5050 /* if the shift count is known then do it
5051 as efficiently as possible */
5052 if (AOP_TYPE (right) == AOP_LIT)
5054 genRightShiftLiteral (left, right, result, ic, is_signed);
5058 aopOp (left, ic, FALSE, FALSE);
5059 aopOp (result, ic, FALSE, FALSE);
5061 /* now move the left to the result if they are not the
5063 if (!sameRegs (AOP (left), AOP (result)) &&
5064 AOP_SIZE (result) > 1)
5067 size = AOP_SIZE (result);
5071 l = aopGet (AOP (left), offset, FALSE);
5072 aopPut (AOP (result), l, offset);
5077 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5079 freeAsmop (right, NULL, ic);
5081 tlbl = newiTempLabel (NULL);
5082 tlbl1 = newiTempLabel (NULL);
5083 size = AOP_SIZE (result);
5086 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5087 emitLabel (tlbl->key + 100);
5090 l = aopGet (AOP (result), offset--, FALSE);
5093 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5101 emitLabel (tlbl1->key + 100);
5103 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5105 freeAsmop (left, NULL, ic);
5106 freeAsmop (result, NULL, ic);
5109 /*-----------------------------------------------------------------*/
5110 /* genGenPointerGet - get value from generic pointer space */
5111 /*-----------------------------------------------------------------*/
5113 genGenPointerGet (operand * left,
5114 operand * result, iCode * ic)
5117 sym_link *retype = getSpec (operandType (result));
5123 aopOp (left, ic, FALSE, FALSE);
5124 aopOp (result, ic, FALSE, FALSE);
5126 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5129 if (isPtrPair (AOP (left)))
5131 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5132 aopPut (AOP (result), buffer, 0);
5136 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5137 aopPut (AOP (result), "a", 0);
5139 freeAsmop (left, NULL, ic);
5143 /* For now we always load into IY */
5144 /* if this is remateriazable */
5145 fetchPair (pair, AOP (left));
5147 /* so iy now contains the address */
5148 freeAsmop (left, NULL, ic);
5150 /* if bit then unpack */
5151 if (IS_BITVAR (retype))
5157 size = AOP_SIZE (result);
5162 /* PENDING: make this better */
5163 if (!IS_GB && AOP (result)->type == AOP_REG)
5165 aopPut (AOP (result), "!*hl", offset++);
5169 emit2 ("ld a,!*pair", _pairs[pair].name);
5170 aopPut (AOP (result), "a", offset++);
5174 emit2 ("inc %s", _pairs[pair].name);
5175 _G.pairs[pair].offset++;
5181 freeAsmop (result, NULL, ic);
5184 /*-----------------------------------------------------------------*/
5185 /* genPointerGet - generate code for pointer get */
5186 /*-----------------------------------------------------------------*/
5188 genPointerGet (iCode * ic)
5190 operand *left, *result;
5191 sym_link *type, *etype;
5193 left = IC_LEFT (ic);
5194 result = IC_RESULT (ic);
5196 /* depending on the type of pointer we need to
5197 move it to the correct pointer register */
5198 type = operandType (left);
5199 etype = getSpec (type);
5201 genGenPointerGet (left, result, ic);
5205 isRegOrLit (asmop * aop)
5207 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5212 /*-----------------------------------------------------------------*/
5213 /* genGenPointerSet - stores the value into a pointer location */
5214 /*-----------------------------------------------------------------*/
5216 genGenPointerSet (operand * right,
5217 operand * result, iCode * ic)
5220 sym_link *retype = getSpec (operandType (right));
5221 PAIR_ID pairId = PAIR_HL;
5223 aopOp (result, ic, FALSE, FALSE);
5224 aopOp (right, ic, FALSE, FALSE);
5229 /* Handle the exceptions first */
5230 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5233 const char *l = aopGet (AOP (right), 0, FALSE);
5234 const char *pair = getPairName (AOP (result));
5235 if (canAssignToPtr (l) && isPtr (pair))
5237 emit2 ("ld !*pair,%s", pair, l);
5242 emit2 ("ld !*pair,a", pair);
5247 /* if the operand is already in dptr
5248 then we do nothing else we move the value to dptr */
5249 if (AOP_TYPE (result) != AOP_STR)
5251 fetchPair (pairId, AOP (result));
5253 /* so hl know contains the address */
5254 freeAsmop (result, NULL, ic);
5256 /* if bit then unpack */
5257 if (IS_BITVAR (retype))
5263 size = AOP_SIZE (right);
5268 const char *l = aopGet (AOP (right), offset, FALSE);
5269 if (isRegOrLit (AOP (right)) && !IS_GB)
5271 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5276 emit2 ("ld !*pair,a", _pairs[pairId].name);
5280 emit2 ("inc %s", _pairs[pairId].name);
5281 _G.pairs[pairId].offset++;
5287 freeAsmop (right, NULL, ic);
5290 /*-----------------------------------------------------------------*/
5291 /* genPointerSet - stores the value into a pointer location */
5292 /*-----------------------------------------------------------------*/
5294 genPointerSet (iCode * ic)
5296 operand *right, *result;
5297 sym_link *type, *etype;
5299 right = IC_RIGHT (ic);
5300 result = IC_RESULT (ic);
5302 /* depending on the type of pointer we need to
5303 move it to the correct pointer register */
5304 type = operandType (result);
5305 etype = getSpec (type);
5307 genGenPointerSet (right, result, ic);
5310 /*-----------------------------------------------------------------*/
5311 /* genIfx - generate code for Ifx statement */
5312 /*-----------------------------------------------------------------*/
5314 genIfx (iCode * ic, iCode * popIc)
5316 operand *cond = IC_COND (ic);
5319 aopOp (cond, ic, FALSE, TRUE);
5321 /* get the value into acc */
5322 if (AOP_TYPE (cond) != AOP_CRY)
5326 /* the result is now in the accumulator */
5327 freeAsmop (cond, NULL, ic);
5329 /* if there was something to be popped then do it */
5333 /* if the condition is a bit variable */
5334 if (isbit && IS_ITEMP (cond) &&
5336 genIfxJump (ic, SPIL_LOC (cond)->rname);
5337 else if (isbit && !IS_ITEMP (cond))
5338 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5340 genIfxJump (ic, "a");
5345 /*-----------------------------------------------------------------*/
5346 /* genAddrOf - generates code for address of */
5347 /*-----------------------------------------------------------------*/
5349 genAddrOf (iCode * ic)
5351 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5353 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5355 /* if the operand is on the stack then we
5356 need to get the stack offset of this
5363 if (sym->stack <= 0)
5365 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5369 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5376 emit2 ("ld de,!hashedstr", sym->rname);
5378 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5379 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5386 /* if it has an offset then we need to compute it */
5388 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5390 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5391 emit2 ("add hl,sp");
5395 emit2 ("ld hl,#%s", sym->rname);
5397 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5398 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5400 freeAsmop (IC_RESULT (ic), NULL, ic);
5403 /*-----------------------------------------------------------------*/
5404 /* genAssign - generate code for assignment */
5405 /*-----------------------------------------------------------------*/
5407 genAssign (iCode * ic)
5409 operand *result, *right;
5411 unsigned long lit = 0L;
5413 result = IC_RESULT (ic);
5414 right = IC_RIGHT (ic);
5416 /* Dont bother assigning if they are the same */
5417 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5419 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5423 aopOp (right, ic, FALSE, FALSE);
5424 aopOp (result, ic, TRUE, FALSE);
5426 /* if they are the same registers */
5427 if (sameRegs (AOP (right), AOP (result)))
5429 emitDebug ("; (registers are the same)");
5433 /* if the result is a bit */
5434 if (AOP_TYPE (result) == AOP_CRY)
5436 wassertl (0, "Tried to assign to a bit");
5440 size = AOP_SIZE (result);
5443 if (AOP_TYPE (right) == AOP_LIT)
5444 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5445 if (isPair (AOP (result)))
5447 fetchPair (getPairId (AOP (result)), AOP (right));
5449 else if ((size > 1) &&
5450 (AOP_TYPE (result) != AOP_REG) &&
5451 (AOP_TYPE (right) == AOP_LIT) &&
5452 !IS_FLOAT (operandType (right)) &&
5455 bool fXored = FALSE;
5457 /* Work from the top down.
5458 Done this way so that we can use the cached copy of 0
5459 in A for a fast clear */
5462 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5464 if (!fXored && size > 1)
5471 aopPut (AOP (result), "a", offset);
5475 aopPut (AOP (result), "!zero", offset);
5479 aopPut (AOP (result),
5480 aopGet (AOP (right), offset, FALSE),
5485 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5487 /* Special case. Load into a and d, then load out. */
5488 _moveA (aopGet (AOP (right), 0, FALSE));
5489 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5490 aopPut (AOP (result), "a", 0);
5491 aopPut (AOP (result), "e", 1);
5493 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5495 /* Special case - simple memcpy */
5496 aopGet (AOP (right), LSB, FALSE);
5499 aopGet (AOP (result), LSB, FALSE);
5503 emit2 ("ld a,(de)");
5504 /* Peephole will optimise this. */
5505 emit2 ("ld (hl),a");
5513 spillPair (PAIR_HL);
5519 /* PENDING: do this check better */
5520 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5522 _moveA (aopGet (AOP (right), offset, FALSE));
5523 aopPut (AOP (result), "a", offset);
5526 aopPut (AOP (result),
5527 aopGet (AOP (right), offset, FALSE),
5534 freeAsmop (right, NULL, ic);
5535 freeAsmop (result, NULL, ic);
5538 /*-----------------------------------------------------------------*/
5539 /* genJumpTab - genrates code for jump table */
5540 /*-----------------------------------------------------------------*/
5542 genJumpTab (iCode * ic)
5547 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5548 /* get the condition into accumulator */
5549 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5552 emit2 ("ld e,%s", l);
5553 emit2 ("ld d,!zero");
5554 jtab = newiTempLabel (NULL);
5556 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5557 emit2 ("add hl,de");
5558 emit2 ("add hl,de");
5559 emit2 ("add hl,de");
5560 freeAsmop (IC_JTCOND (ic), NULL, ic);
5564 emitLabel (jtab->key + 100);
5565 /* now generate the jump labels */
5566 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5567 jtab = setNextItem (IC_JTLABELS (ic)))
5568 emit2 ("jp !tlabel", jtab->key + 100);
5571 /*-----------------------------------------------------------------*/
5572 /* genCast - gen code for casting */
5573 /*-----------------------------------------------------------------*/
5575 genCast (iCode * ic)
5577 operand *result = IC_RESULT (ic);
5578 sym_link *ctype = operandType (IC_LEFT (ic));
5579 operand *right = IC_RIGHT (ic);
5582 /* if they are equivalent then do nothing */
5583 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5586 aopOp (right, ic, FALSE, FALSE);
5587 aopOp (result, ic, FALSE, FALSE);
5589 /* if the result is a bit */
5590 if (AOP_TYPE (result) == AOP_CRY)
5592 wassertl (0, "Tried to cast to a bit");
5595 /* if they are the same size : or less */
5596 if (AOP_SIZE (result) <= AOP_SIZE (right))
5599 /* if they are in the same place */
5600 if (sameRegs (AOP (right), AOP (result)))
5603 /* if they in different places then copy */
5604 size = AOP_SIZE (result);
5608 aopPut (AOP (result),
5609 aopGet (AOP (right), offset, FALSE),
5616 /* So we now know that the size of destination is greater
5617 than the size of the source */
5618 /* we move to result for the size of source */
5619 size = AOP_SIZE (right);
5623 aopPut (AOP (result),
5624 aopGet (AOP (right), offset, FALSE),
5629 /* now depending on the sign of the destination */
5630 size = AOP_SIZE (result) - AOP_SIZE (right);
5631 /* Unsigned or not an integral type - right fill with zeros */
5632 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5635 aopPut (AOP (result), "!zero", offset++);
5639 /* we need to extend the sign :{ */
5640 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5646 aopPut (AOP (result), "a", offset++);
5650 freeAsmop (right, NULL, ic);
5651 freeAsmop (result, NULL, ic);
5654 /*-----------------------------------------------------------------*/
5655 /* genReceive - generate code for a receive iCode */
5656 /*-----------------------------------------------------------------*/
5658 genReceive (iCode * ic)
5660 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5661 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5662 IS_TRUE_SYMOP (IC_RESULT (ic))))
5672 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5673 size = AOP_SIZE(IC_RESULT(ic));
5675 for (i = 0; i < size; i++) {
5676 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5680 freeAsmop (IC_RESULT (ic), NULL, ic);
5685 /** Maximum number of bytes to emit per line. */
5689 /** Context for the byte output chunker. */
5692 unsigned char buffer[DBEMIT_MAX_RUN];
5697 /** Flushes a byte chunker by writing out all in the buffer and
5701 _dbFlush(DBEMITCTX *self)
5708 sprintf(line, ".db 0x%02X", self->buffer[0]);
5710 for (i = 1; i < self->pos; i++)
5712 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5719 /** Write out another byte, buffering until a decent line is
5723 _dbEmit(DBEMITCTX *self, int c)
5725 if (self->pos == DBEMIT_MAX_RUN)
5729 self->buffer[self->pos++] = c;
5732 /** Context for a simple run length encoder. */
5736 unsigned char buffer[128];
5738 /** runLen may be equivalent to pos. */
5744 RLE_CHANGE_COST = 4,
5748 /** Flush the buffer of a run length encoder by writing out the run or
5749 data that it currently contains.
5752 _rleCommit(RLECTX *self)
5758 memset(&db, 0, sizeof(db));
5760 emit2(".db %u", self->pos);
5762 for (i = 0; i < self->pos; i++)
5764 _dbEmit(&db, self->buffer[i]);
5773 Can get either a run or a block of random stuff.
5774 Only want to change state if a good run comes in or a run ends.
5775 Detecting run end is easy.
5778 Say initial state is in run, len zero, last zero. Then if you get a
5779 few zeros then something else then a short run will be output.
5780 Seems OK. While in run mode, keep counting. While in random mode,
5781 keep a count of the run. If run hits margin, output all up to run,
5782 restart, enter run mode.
5785 /** Add another byte into the run length encoder, flushing as
5786 required. The run length encoder uses the Amiga IFF style, where
5787 a block is prefixed by its run length. A positive length means
5788 the next n bytes pass straight through. A negative length means
5789 that the next byte is repeated -n times. A zero terminates the
5793 _rleAppend(RLECTX *self, int c)
5797 if (c != self->last)
5799 /* The run has stopped. See if it is worthwhile writing it out
5800 as a run. Note that the random data comes in as runs of
5803 if (self->runLen > RLE_CHANGE_COST)
5805 /* Yes, worthwhile. */
5806 /* Commit whatever was in the buffer. */
5808 emit2(".db -%u,0x%02X", self->runLen, self->last);
5812 /* Not worthwhile. Append to the end of the random list. */
5813 for (i = 0; i < self->runLen; i++)
5815 if (self->pos >= RLE_MAX_BLOCK)
5820 self->buffer[self->pos++] = self->last;
5828 if (self->runLen >= RLE_MAX_BLOCK)
5830 /* Commit whatever was in the buffer. */
5833 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5841 _rleFlush(RLECTX *self)
5843 _rleAppend(self, -1);
5850 /** genArrayInit - Special code for initialising an array with constant
5854 genArrayInit (iCode * ic)
5858 int elementSize = 0, eIndex, i;
5859 unsigned val, lastVal;
5863 memset(&rle, 0, sizeof(rle));
5865 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5867 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5869 /* Emit the support function call and the destination address. */
5870 emit2("call __initrleblock");
5871 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5875 wassertl (0, "Unexpected operand to genArrayInit.\n");
5878 type = operandType(IC_LEFT(ic));
5880 if (type && type->next)
5882 elementSize = getSize(type->next);
5886 wassertl (0, "Can't determine element size in genArrayInit.");
5889 iLoop = IC_ARRAYILIST(ic);
5890 lastVal = (unsigned)-1;
5892 /* Feed all the bytes into the run length encoder which will handle
5894 This works well for mixed char data, and for random int and long
5903 for (i = 0; i < ix; i++)
5905 for (eIndex = 0; eIndex < elementSize; eIndex++)
5907 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5908 _rleAppend(&rle, val);
5913 iLoop = iLoop->next;
5917 /* Mark the end of the run. */
5920 freeAsmop (IC_LEFT(ic), NULL, ic);
5923 /*-----------------------------------------------------------------*/
5924 /* genZ80Code - generate code for Z80 based controllers */
5925 /*-----------------------------------------------------------------*/
5927 genZ80Code (iCode * lic)
5935 _fReturn = _gbz80_return;
5936 _fTmp = _gbz80_return;
5940 _fReturn = _z80_return;
5941 _fTmp = _z80_return;
5944 _G.lines.head = _G.lines.current = NULL;
5946 for (ic = lic; ic; ic = ic->next)
5949 if (cln != ic->lineno)
5951 emit2 ("; %s %d", ic->filename, ic->lineno);
5954 /* if the result is marked as
5955 spilt and rematerializable or code for
5956 this has already been generated then
5958 if (resultRemat (ic) || ic->generated)
5961 /* depending on the operation */
5965 emitDebug ("; genNot");
5970 emitDebug ("; genCpl");
5975 emitDebug ("; genUminus");
5980 emitDebug ("; genIpush");
5985 /* IPOP happens only when trying to restore a
5986 spilt live range, if there is an ifx statement
5987 following this pop then the if statement might
5988 be using some of the registers being popped which
5989 would destory the contents of the register so
5990 we need to check for this condition and handle it */
5992 ic->next->op == IFX &&
5993 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5995 emitDebug ("; genIfx");
5996 genIfx (ic->next, ic);
6000 emitDebug ("; genIpop");
6006 emitDebug ("; genCall");
6011 emitDebug ("; genPcall");
6016 emitDebug ("; genFunction");
6021 emitDebug ("; genEndFunction");
6022 genEndFunction (ic);
6026 emitDebug ("; genRet");
6031 emitDebug ("; genLabel");
6036 emitDebug ("; genGoto");
6041 emitDebug ("; genPlus");
6046 emitDebug ("; genMinus");
6051 emitDebug ("; genMult");
6056 emitDebug ("; genDiv");
6061 emitDebug ("; genMod");
6066 emitDebug ("; genCmpGt");
6067 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6071 emitDebug ("; genCmpLt");
6072 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6079 /* note these two are xlated by algebraic equivalence
6080 during parsing SDCC.y */
6081 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6082 "got '>=' or '<=' shouldn't have come here");
6086 emitDebug ("; genCmpEq");
6087 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6091 emitDebug ("; genAndOp");
6096 emitDebug ("; genOrOp");
6101 emitDebug ("; genXor");
6102 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6106 emitDebug ("; genOr");
6107 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6111 emitDebug ("; genAnd");
6112 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6116 emitDebug ("; genInline");
6121 emitDebug ("; genRRC");
6126 emitDebug ("; genRLC");
6131 emitDebug ("; genGetHBIT");
6136 emitDebug ("; genLeftShift");
6141 emitDebug ("; genRightShift");
6145 case GET_VALUE_AT_ADDRESS:
6146 emitDebug ("; genPointerGet");
6152 if (POINTER_SET (ic))
6154 emitDebug ("; genAssign (pointer)");
6159 emitDebug ("; genAssign");
6165 emitDebug ("; genIfx");
6170 emitDebug ("; genAddrOf");
6175 emitDebug ("; genJumpTab");
6180 emitDebug ("; genCast");
6185 emitDebug ("; genReceive");
6190 emitDebug ("; addSet");
6191 addSet (&_G.sendSet, ic);
6204 /* now we are ready to call the
6205 peep hole optimizer */
6206 if (!options.nopeep)
6207 peepHole (&_G.lines.head);
6209 /* This is unfortunate */
6210 /* now do the actual printing */
6212 FILE *fp = codeOutFile;
6213 if (isInHome () && codeOutFile == code->oFile)
6214 codeOutFile = home->oFile;
6215 printLine (_G.lines.head, codeOutFile);
6216 if (_G.flushStatics)
6219 _G.flushStatics = 0;
6224 freeTrace(&_G.lines.trace);
6225 freeTrace(&_G.trace.aops);
6231 _isPairUsed (iCode * ic, PAIR_ID pairId)
6237 if (bitVectBitValue (ic->rMask, D_IDX))
6239 if (bitVectBitValue (ic->rMask, E_IDX))
6249 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6252 value *val = aop->aopu.aop_lit;
6254 wassert (aop->type == AOP_LIT);
6255 wassert (!IS_FLOAT (val->type));
6257 v = (unsigned long) floatFromVal (val);
6265 tsprintf (buffer, "!immedword", v);
6266 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));