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
178 /** Code generator persistent data.
182 /** Used to optimised setting up of a pair by remebering what it
183 contains and adjusting instead of reloading where possible.
204 const char *lastFunctionName;
210 /** TRUE if the registers have already been saved. */
228 static const char *aopGet (asmop * aop, int offset, bool bit16);
244 _getTempPairName(void)
246 return _pairs[_getTempPairId()].name;
252 /* Clean up the line so that it is 'prettier' */
253 if (strchr (buf, ':'))
255 /* Is a label - cant do anything */
258 /* Change the first (and probably only) ' ' to a tab so
273 _newLineNode (char *line)
277 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
278 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
284 _vemit2 (const char *szFormat, va_list ap)
288 tvsprintf (buffer, szFormat, ap);
291 _G.lines.current = (_G.lines.current ?
292 connectLine (_G.lines.current, _newLineNode (buffer)) :
293 (_G.lines.head = _newLineNode (buffer)));
295 _G.lines.current->isInline = _G.lines.isInline;
299 emit2 (const char *szFormat,...)
303 va_start (ap, szFormat);
305 _vemit2 (szFormat, ap);
311 emitDebug (const char *szFormat,...)
317 va_start (ap, szFormat);
319 _vemit2 (szFormat, ap);
325 /*-----------------------------------------------------------------*/
326 /* emit2 - writes the code into a file : for now it is simple */
327 /*-----------------------------------------------------------------*/
329 _emit2 (const char *inst, const char *fmt,...)
332 char lb[INITIAL_INLINEASM];
339 sprintf (lb, "%s\t", inst);
340 vsprintf (lb + (strlen (lb)), fmt, ap);
343 vsprintf (lb, fmt, ap);
345 while (isspace (*lbp))
350 _G.lines.current = (_G.lines.current ?
351 connectLine (_G.lines.current, _newLineNode (lb)) :
352 (_G.lines.head = _newLineNode (lb)));
354 _G.lines.current->isInline = _G.lines.isInline;
359 _emitMove(const char *to, const char *from)
361 if (strcasecmp(to, from) != 0)
363 emit2("ld %s,%s", to, from);
368 // Could leave this to the peephole, but sometimes the peephole is inhibited.
373 _moveA(const char *moveFrom)
375 // Let the peephole optimiser take care of redundent loads
376 _emitMove(ACC_NAME, moveFrom);
386 getPairName (asmop * aop)
388 if (aop->type == AOP_REG)
390 switch (aop->aopu.aop_reg[0]->rIdx)
403 else if (aop->type == AOP_STR)
405 switch (*aop->aopu.aop_str[0])
418 wassertl (0, "Tried to get the pair name of something that isn't a pair");
423 getPairId (asmop * aop)
427 if (aop->type == AOP_REG)
429 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
433 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
437 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
442 if (aop->type == AOP_STR)
444 if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
448 if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
452 if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
461 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
465 return (getPairId (aop) != PAIR_INVALID);
469 isPtrPair (asmop * aop)
471 PAIR_ID pairId = getPairId (aop);
482 /** Push a register pair onto the stack */
484 genPairPush (asmop * aop)
486 emit2 ("push %s", getPairName (aop));
490 _push (PAIR_ID pairId)
492 emit2 ("push %s", _pairs[pairId].name);
493 _G.stack.pushed += 2;
497 _pop (PAIR_ID pairId)
499 emit2 ("pop %s", _pairs[pairId].name);
500 _G.stack.pushed -= 2;
503 /*-----------------------------------------------------------------*/
504 /* newAsmop - creates a new asmOp */
505 /*-----------------------------------------------------------------*/
507 newAsmop (short type)
511 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
516 /*-----------------------------------------------------------------*/
517 /* aopForSym - for a true symbol */
518 /*-----------------------------------------------------------------*/
520 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
527 wassert (sym->etype);
529 space = SPEC_OCLS (sym->etype);
531 /* if already has one */
535 /* Assign depending on the storage class */
536 if (sym->onStack || sym->iaccess)
538 /* The pointer that is used depends on how big the offset is.
539 Normally everything is AOP_STK, but for offsets of < -127 or
540 > 128 on the Z80 an extended stack pointer is used.
542 if (IS_Z80 && (sym->stack < -127 || sym->stack > (int)(128-getSize (sym->type))))
544 emitDebug ("; AOP_EXSTK for %s", sym->rname);
545 sym->aop = aop = newAsmop (AOP_EXSTK);
549 emitDebug ("; AOP_STK for %s", sym->rname);
550 sym->aop = aop = newAsmop (AOP_STK);
553 aop->size = getSize (sym->type);
554 aop->aopu.aop_stk = sym->stack;
558 /* special case for a function */
559 if (IS_FUNC (sym->type))
561 sym->aop = aop = newAsmop (AOP_IMMD);
562 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
569 /* if it is in direct space */
570 if (IN_REGSP (space) && !requires_a)
572 sym->aop = aop = newAsmop (AOP_SFR);
573 aop->aopu.aop_dir = sym->rname;
574 aop->size = getSize (sym->type);
575 emitDebug ("; AOP_SFR for %s", sym->rname);
580 /* only remaining is far space */
581 /* in which case DPTR gets the address */
584 emitDebug ("; AOP_HL for %s", sym->rname);
585 sym->aop = aop = newAsmop (AOP_HL);
589 sym->aop = aop = newAsmop (AOP_IY);
591 aop->size = getSize (sym->type);
592 aop->aopu.aop_dir = sym->rname;
594 /* if it is in code space */
595 if (IN_CODESPACE (space))
601 /*-----------------------------------------------------------------*/
602 /* aopForRemat - rematerialzes an object */
603 /*-----------------------------------------------------------------*/
605 aopForRemat (symbol * sym)
608 iCode *ic = sym->rematiCode;
609 asmop *aop = newAsmop (AOP_IMMD);
613 /* if plus or minus print the right hand side */
614 if (ic->op == '+' || ic->op == '-')
616 /* PENDING: for re-target */
617 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
620 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
623 /* we reached the end */
624 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
628 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
632 /*-----------------------------------------------------------------*/
633 /* regsInCommon - two operands have some registers in common */
634 /*-----------------------------------------------------------------*/
636 regsInCommon (operand * op1, operand * op2)
641 /* if they have registers in common */
642 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
645 sym1 = OP_SYMBOL (op1);
646 sym2 = OP_SYMBOL (op2);
648 if (sym1->nRegs == 0 || sym2->nRegs == 0)
651 for (i = 0; i < sym1->nRegs; i++)
657 for (j = 0; j < sym2->nRegs; j++)
662 if (sym2->regs[j] == sym1->regs[i])
670 /*-----------------------------------------------------------------*/
671 /* operandsEqu - equivalent */
672 /*-----------------------------------------------------------------*/
674 operandsEqu (operand * op1, operand * op2)
678 /* if they not symbols */
679 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
682 sym1 = OP_SYMBOL (op1);
683 sym2 = OP_SYMBOL (op2);
685 /* if both are itemps & one is spilt
686 and the other is not then false */
687 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
688 sym1->isspilt != sym2->isspilt)
691 /* if they are the same */
695 if (strcmp (sym1->rname, sym2->rname) == 0)
699 /* if left is a tmp & right is not */
700 if (IS_ITEMP (op1) &&
703 (sym1->usl.spillLoc == sym2))
706 if (IS_ITEMP (op2) &&
710 (sym2->usl.spillLoc == sym1))
716 /*-----------------------------------------------------------------*/
717 /* sameRegs - two asmops have the same registers */
718 /*-----------------------------------------------------------------*/
720 sameRegs (asmop * aop1, asmop * aop2)
724 if (aop1->type == AOP_SFR ||
725 aop2->type == AOP_SFR)
731 if (aop1->type != AOP_REG ||
732 aop2->type != AOP_REG)
735 if (aop1->size != aop2->size)
738 for (i = 0; i < aop1->size; i++)
739 if (aop1->aopu.aop_reg[i] !=
740 aop2->aopu.aop_reg[i])
746 /*-----------------------------------------------------------------*/
747 /* aopOp - allocates an asmop for an operand : */
748 /*-----------------------------------------------------------------*/
750 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
759 /* if this a literal */
760 if (IS_OP_LITERAL (op))
762 op->aop = aop = newAsmop (AOP_LIT);
763 aop->aopu.aop_lit = op->operand.valOperand;
764 aop->size = getSize (operandType (op));
768 /* if already has a asmop then continue */
772 /* if the underlying symbol has a aop */
773 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
775 op->aop = OP_SYMBOL (op)->aop;
779 /* if this is a true symbol */
780 if (IS_TRUE_SYMOP (op))
782 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
786 /* this is a temporary : this has
792 e) can be a return use only */
794 sym = OP_SYMBOL (op);
796 /* if the type is a conditional */
797 if (sym->regType == REG_CND)
799 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
804 /* if it is spilt then two situations
806 b) has a spill location */
807 if (sym->isspilt || sym->nRegs == 0)
809 /* rematerialize it NOW */
812 sym->aop = op->aop = aop =
814 aop->size = getSize (sym->type);
820 if (sym->accuse == ACCUSE_A)
822 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
823 aop->size = getSize (sym->type);
824 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
826 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
828 else if (sym->accuse == ACCUSE_HL)
831 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
832 aop->size = getSize (sym->type);
833 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
834 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
835 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
839 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
847 aop = op->aop = sym->aop = newAsmop (AOP_STR);
848 aop->size = getSize (sym->type);
849 for (i = 0; i < 4; i++)
850 aop->aopu.aop_str[i] = _fReturn[i];
854 /* else spill location */
855 sym->aop = op->aop = aop =
856 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
857 aop->size = getSize (sym->type);
861 /* must be in a register */
862 sym->aop = op->aop = aop = newAsmop (AOP_REG);
863 aop->size = sym->nRegs;
864 for (i = 0; i < sym->nRegs; i++)
865 aop->aopu.aop_reg[i] = sym->regs[i];
868 /*-----------------------------------------------------------------*/
869 /* freeAsmop - free up the asmop given to an operand */
870 /*----------------------------------------------------------------*/
872 freeAsmop (operand * op, asmop * aaop, iCode * ic)
890 /* all other cases just dealloc */
896 OP_SYMBOL (op)->aop = NULL;
897 /* if the symbol has a spill */
899 SPIL_LOC (op)->aop = NULL;
905 isLitWord (asmop * aop)
907 /* if (aop->size != 2)
920 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
925 /* depending on type */
931 /* PENDING: for re-target */
934 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
936 else if (offset == 0)
938 tsprintf (s, "%s", aop->aopu.aop_immd);
942 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
944 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
948 value *val = aop->aopu.aop_lit;
949 /* if it is a float then it gets tricky */
950 /* otherwise it is fairly simple */
951 if (!IS_FLOAT (val->type))
953 unsigned long v = (unsigned long) floatFromVal (val);
959 else if (offset == 0)
965 wassertl(0, "Encountered an invalid offset while fetching a literal");
969 tsprintf (buffer, "!immedword", v);
971 tsprintf (buffer, "!constword", v);
973 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
979 convertFloat (&f, floatFromVal (val));
981 tsprintf (buffer, "!immedword", f.w[offset / 2]);
983 tsprintf (buffer, "!constword", f.w[offset / 2]);
984 rs = Safe_calloc (1, strlen (buffer) + 1);
985 return strcpy (rs, buffer);
994 aopGetWord (asmop * aop, int offset)
996 return aopGetLitWordLong (aop, offset, TRUE);
1000 isPtr (const char *s)
1002 if (!strcmp (s, "hl"))
1004 if (!strcmp (s, "ix"))
1006 if (!strcmp (s, "iy"))
1012 adjustPair (const char *pair, int *pold, int new)
1018 emit2 ("inc %s", pair);
1023 emit2 ("dec %s", pair);
1029 spillPair (PAIR_ID pairId)
1031 _G.pairs[pairId].last_type = AOP_INVALID;
1032 _G.pairs[pairId].base = NULL;
1038 spillPair (PAIR_HL);
1039 spillPair (PAIR_IY);
1043 requiresHL (asmop * aop)
1058 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1060 const char *l, *base;
1061 const char *pair = _pairs[pairId].name;
1062 l = aopGetLitWordLong (left, offset, FALSE);
1063 base = aopGetLitWordLong (left, 0, FALSE);
1064 wassert (l && pair && base);
1068 if (pairId == PAIR_HL || pairId == PAIR_IY)
1070 if (_G.pairs[pairId].last_type == left->type)
1072 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1074 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1076 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1079 if (pairId == PAIR_IY && abs (offset) < 127)
1086 _G.pairs[pairId].last_type = left->type;
1087 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1088 _G.pairs[pairId].offset = offset;
1090 /* Both a lit on the right and a true symbol on the left */
1091 emit2 ("ld %s,!hashedstr", pair, l);
1095 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1097 /* if this is remateriazable */
1098 if (isLitWord (aop)) {
1099 fetchLitPair (pairId, aop, offset);
1102 /* we need to get it byte by byte */
1103 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1104 aopGet (aop, offset, FALSE);
1105 switch (aop->size - offset) {
1107 emit2 ("ld l,!*hl");
1108 emit2 ("ld h,!immedbyte", 0);
1111 // PENDING: Requires that you are only fetching two bytes.
1114 emit2 ("ld h,!*hl");
1118 wassertl (0, "Attempted to fetch too much data into HL");
1122 else if (IS_Z80 && aop->type == AOP_IY) {
1123 /* Instead of fetching relative to IY, just grab directly
1124 from the address IY refers to */
1125 char *l = aopGetLitWordLong (aop, offset, FALSE);
1127 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1129 if (aop->size < 2) {
1130 emit2("ld %s,!zero", _pairs[pairId].h);
1134 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1135 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1137 /* PENDING: check? */
1138 if (pairId == PAIR_HL)
1139 spillPair (PAIR_HL);
1144 fetchPair (PAIR_ID pairId, asmop * aop)
1146 fetchPairLong (pairId, aop, 0);
1150 fetchHL (asmop * aop)
1152 fetchPair (PAIR_HL, aop);
1156 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1158 assert (pairId == PAIR_HL || pairId == PAIR_IY);
1163 wassertl (pairId == PAIR_IY, "AOP_IY must be in IY");
1164 fetchLitPair (pairId, aop, 0);
1168 fetchLitPair (pairId, aop, offset);
1169 _G.pairs[pairId].offset = offset;
1173 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1174 wassertl (pairId == PAIR_IY, "The Z80 extended stack must be in IY");
1177 int offset = aop->aopu.aop_stk + _G.stack.offset;
1179 if (_G.pairs[pairId].last_type == aop->type &&
1180 _G.pairs[pairId].offset == offset)
1186 /* PENDING: Do this better. */
1187 sprintf (buffer, "%d", offset + _G.stack.pushed);
1188 emit2 ("ld iy,!hashedstr", buffer);
1189 emit2 ("add iy,sp");
1190 _G.pairs[pairId].last_type = aop->type;
1191 _G.pairs[pairId].offset = offset;
1198 /* Doesnt include _G.stack.pushed */
1199 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1200 if (aop->aopu.aop_stk > 0)
1202 abso += _G.stack.param_offset;
1204 assert (pairId == PAIR_HL);
1205 /* In some cases we can still inc or dec hl */
1206 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1208 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1212 emit2 ("!ldahlsp", abso + _G.stack.pushed);
1214 _G.pairs[pairId].offset = abso;
1220 _G.pairs[pairId].last_type = aop->type;
1226 emit2 ("!tlabeldef", key);
1230 /*-----------------------------------------------------------------*/
1231 /* aopGet - for fetching value of the aop */
1232 /*-----------------------------------------------------------------*/
1234 aopGet (asmop * aop, int offset, bool bit16)
1238 /* offset is greater than size then zero */
1239 /* PENDING: this seems a bit screwed in some pointer cases. */
1240 if (offset > (aop->size - 1) &&
1241 aop->type != AOP_LIT)
1243 tsprintf (s, "!zero");
1244 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1247 /* depending on type */
1251 /* PENDING: re-target */
1253 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1258 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1261 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1264 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1267 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1270 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1274 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1277 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1281 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1284 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1287 return aop->aopu.aop_reg[offset]->name;
1291 setupPair (PAIR_HL, aop, offset);
1292 tsprintf (s, "!*hl");
1294 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1298 setupPair (PAIR_IY, aop, offset);
1299 tsprintf (s, "!*iyx", offset);
1301 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1305 setupPair (PAIR_IY, aop, offset);
1306 tsprintf (s, "!*iyx", offset, offset);
1308 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1313 setupPair (PAIR_HL, aop, offset);
1314 tsprintf (s, "!*hl");
1318 if (aop->aopu.aop_stk >= 0)
1319 offset += _G.stack.param_offset;
1320 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1323 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1326 wassertl (0, "Tried to fetch from a bit variable");
1335 tsprintf(s, "!zero");
1336 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1340 wassert (offset < 2);
1341 return aop->aopu.aop_str[offset];
1344 return aopLiteral (aop->aopu.aop_lit, offset);
1348 unsigned long v = aop->aopu.aop_simplelit;
1351 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1353 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1357 return aop->aopu.aop_str[offset];
1362 wassertl (0, "aopget got unsupported aop->type");
1367 isRegString (const char *s)
1369 if (!strcmp (s, "b") ||
1381 isConstant (const char *s)
1383 /* This is a bit of a hack... */
1384 return (*s == '#' || *s == '$');
1388 canAssignToPtr (const char *s)
1390 if (isRegString (s))
1397 /*-----------------------------------------------------------------*/
1398 /* aopPut - puts a string for a aop */
1399 /*-----------------------------------------------------------------*/
1401 aopPut (asmop * aop, const char *s, int offset)
1405 if (aop->size && offset > (aop->size - 1))
1407 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1408 "aopPut got offset > aop->size");
1413 tsprintf(buffer2, s);
1416 /* will assign value to value */
1417 /* depending on where it is ofcourse */
1423 if (strcmp (s, "a"))
1424 emit2 ("ld a,%s", s);
1425 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1430 if (strcmp (s, "a"))
1431 emit2 ("ld a,%s", s);
1432 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1436 if (!strcmp (s, "!*hl"))
1437 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1440 aop->aopu.aop_reg[offset]->name, s);
1445 if (!canAssignToPtr (s))
1447 emit2 ("ld a,%s", s);
1448 setupPair (PAIR_IY, aop, offset);
1449 emit2 ("ld !*iyx,a", offset);
1453 setupPair (PAIR_IY, aop, offset);
1454 emit2 ("ld !*iyx,%s", offset, s);
1460 /* PENDING: for re-target */
1461 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1463 emit2 ("ld a,!*hl");
1466 setupPair (PAIR_HL, aop, offset);
1468 emit2 ("ld !*hl,%s", s);
1473 if (!canAssignToPtr (s))
1475 emit2 ("ld a,%s", s);
1476 setupPair (PAIR_IY, aop, offset);
1477 emit2 ("ld !*iyx,a", offset);
1481 setupPair (PAIR_IY, aop, offset);
1482 emit2 ("ld !*iyx,%s", offset, s);
1489 /* PENDING: re-target */
1490 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1492 emit2 ("ld a,!*hl");
1495 setupPair (PAIR_HL, aop, offset);
1496 if (!canAssignToPtr (s))
1498 emit2 ("ld a,%s", s);
1499 emit2 ("ld !*hl,a");
1502 emit2 ("ld !*hl,%s", s);
1506 if (aop->aopu.aop_stk >= 0)
1507 offset += _G.stack.param_offset;
1508 if (!canAssignToPtr (s))
1510 emit2 ("ld a,%s", s);
1511 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1514 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1519 /* if bit variable */
1520 if (!aop->aopu.aop_dir)
1527 /* In bit space but not in C - cant happen */
1528 wassertl (0, "Tried to write into a bit variable");
1534 if (strcmp (aop->aopu.aop_str[offset], s))
1536 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1542 if (!offset && (strcmp (s, "acc") == 0))
1546 wassertl (0, "Tried to access past the end of A");
1550 if (strcmp (aop->aopu.aop_str[offset], s))
1551 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1556 wassert (offset < 2);
1557 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1561 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1562 "aopPut got unsupported aop->type");
1567 #define AOP(op) op->aop
1568 #define AOP_TYPE(op) AOP(op)->type
1569 #define AOP_SIZE(op) AOP(op)->size
1570 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1573 commitPair (asmop * aop, PAIR_ID id)
1575 if (id == PAIR_HL && requiresHL (aop))
1579 aopPut (aop, "a", 0);
1580 aopPut (aop, "d", 1);
1584 aopPut (aop, _pairs[id].l, 0);
1585 aopPut (aop, _pairs[id].h, 1);
1589 /*-----------------------------------------------------------------*/
1590 /* getDataSize - get the operand data size */
1591 /*-----------------------------------------------------------------*/
1593 getDataSize (operand * op)
1596 size = AOP_SIZE (op);
1600 wassertl (0, "Somehow got a three byte data pointer");
1605 /*-----------------------------------------------------------------*/
1606 /* movLeft2Result - move byte from left to result */
1607 /*-----------------------------------------------------------------*/
1609 movLeft2Result (operand * left, int offl,
1610 operand * result, int offr, int sign)
1613 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1615 l = aopGet (AOP (left), offl, FALSE);
1619 aopPut (AOP (result), l, offr);
1623 if (getDataSize (left) == offl + 1)
1625 emit2 ("ld a,%s", l);
1626 aopPut (AOP (result), "a", offr);
1633 /** Put Acc into a register set
1636 outAcc (operand * result)
1639 size = getDataSize (result);
1642 aopPut (AOP (result), "a", 0);
1645 /* unsigned or positive */
1648 aopPut (AOP (result), "!zero", offset++);
1653 /** Take the value in carry and put it into a register
1656 outBitCLong (operand * result, bool swap_sense)
1658 /* if the result is bit */
1659 if (AOP_TYPE (result) == AOP_CRY)
1661 wassertl (0, "Tried to write carry to a bit");
1665 emit2 ("ld a,!zero");
1668 emit2 ("xor a,!immedbyte", 1);
1674 outBitC (operand * result)
1676 outBitCLong (result, FALSE);
1679 /*-----------------------------------------------------------------*/
1680 /* toBoolean - emit code for orl a,operator(sizeop) */
1681 /*-----------------------------------------------------------------*/
1683 _toBoolean (operand * oper)
1685 int size = AOP_SIZE (oper);
1689 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1692 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1696 if (AOP (oper)->type != AOP_ACC)
1699 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1704 /*-----------------------------------------------------------------*/
1705 /* genNot - generate code for ! operation */
1706 /*-----------------------------------------------------------------*/
1710 sym_link *optype = operandType (IC_LEFT (ic));
1712 /* assign asmOps to operand & result */
1713 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1714 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1716 /* if in bit space then a special case */
1717 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1719 wassertl (0, "Tried to negate a bit");
1722 /* if type float then do float */
1723 if (IS_FLOAT (optype))
1725 wassertl (0, "Tried to negate a float");
1728 _toBoolean (IC_LEFT (ic));
1733 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1734 emit2 ("sub a,!one");
1735 outBitC (IC_RESULT (ic));
1737 /* release the aops */
1738 freeAsmop (IC_LEFT (ic), NULL, ic);
1739 freeAsmop (IC_RESULT (ic), NULL, ic);
1742 /*-----------------------------------------------------------------*/
1743 /* genCpl - generate code for complement */
1744 /*-----------------------------------------------------------------*/
1752 /* assign asmOps to operand & result */
1753 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1754 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1756 /* if both are in bit space then
1758 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1759 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1761 wassertl (0, "Left and the result are in bit space");
1764 size = AOP_SIZE (IC_RESULT (ic));
1767 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1770 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1773 /* release the aops */
1774 freeAsmop (IC_LEFT (ic), NULL, ic);
1775 freeAsmop (IC_RESULT (ic), NULL, ic);
1779 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1786 store de into result
1791 store de into result
1793 const char *first = isAdd ? "add" : "sub";
1794 const char *later = isAdd ? "adc" : "sbc";
1796 wassertl (IS_GB, "Code is only relevent to the gbz80");
1797 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1799 fetchPair (PAIR_DE, left);
1802 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1805 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1808 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
1809 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
1811 fetchPairLong (PAIR_DE, left, MSB24);
1812 aopGet (right, MSB24, FALSE);
1816 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
1819 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
1821 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
1822 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
1826 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
1828 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
1831 /*-----------------------------------------------------------------*/
1832 /* genUminus - unary minus code generation */
1833 /*-----------------------------------------------------------------*/
1835 genUminus (iCode * ic)
1838 sym_link *optype, *rtype;
1841 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1842 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1844 /* if both in bit space then special
1846 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1847 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1849 wassertl (0, "Left and right are in bit space");
1853 optype = operandType (IC_LEFT (ic));
1854 rtype = operandType (IC_RESULT (ic));
1856 /* if float then do float stuff */
1857 if (IS_FLOAT (optype))
1859 wassertl (0, "Tried to do a unary minus on a float");
1863 /* otherwise subtract from zero */
1864 size = AOP_SIZE (IC_LEFT (ic));
1866 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1868 /* Create a new asmop with value zero */
1869 asmop *azero = newAsmop (AOP_SIMPLELIT);
1870 azero->aopu.aop_simplelit = 0;
1872 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1880 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1881 emit2 ("ld a,!zero");
1882 emit2 ("sbc a,%s", l);
1883 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1886 /* if any remaining bytes in the result */
1887 /* we just need to propagate the sign */
1888 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1893 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1897 /* release the aops */
1898 freeAsmop (IC_LEFT (ic), NULL, ic);
1899 freeAsmop (IC_RESULT (ic), NULL, ic);
1902 /*-----------------------------------------------------------------*/
1903 /* assignResultValue - */
1904 /*-----------------------------------------------------------------*/
1906 assignResultValue (operand * oper)
1908 int size = AOP_SIZE (oper);
1911 wassertl (size <= 4, "Got a result that is bigger than four bytes");
1912 topInA = requiresHL (AOP (oper));
1914 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1916 /* We do it the hard way here. */
1918 aopPut (AOP (oper), _fReturn[0], 0);
1919 aopPut (AOP (oper), _fReturn[1], 1);
1921 aopPut (AOP (oper), _fReturn[0], 2);
1922 aopPut (AOP (oper), _fReturn[1], 3);
1928 aopPut (AOP (oper), _fReturn[size], size);
1934 _saveRegsForCall(iCode *ic, int sendSetSize)
1937 o Stack parameters are pushed before this function enters
1938 o DE and BC may be used in this function.
1939 o HL and DE may be used to return the result.
1940 o HL and DE may be used to send variables.
1941 o DE and BC may be used to store the result value.
1942 o HL may be used in computing the sent value of DE
1943 o The iPushes for other parameters occur before any addSets
1945 Logic: (to be run inside the first iPush or if none, before sending)
1946 o Compute if DE and/or BC are in use over the call
1947 o Compute if DE is used in the send set
1948 o Compute if DE and/or BC are used to hold the result value
1949 o If (DE is used, or in the send set) and is not used in the result, push.
1950 o If BC is used and is not in the result, push
1952 o If DE is used in the send set, fetch
1953 o If HL is used in the send set, fetch
1957 if (_G.saves.saved == FALSE) {
1958 bool deInUse, bcInUse;
1960 bool bcInRet = FALSE, deInRet = FALSE;
1963 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1965 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1966 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1968 deSending = (sendSetSize > 1);
1970 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1972 if (bcInUse && bcInRet == FALSE) {
1974 _G.stack.pushedBC = TRUE;
1976 if (deInUse && deInRet == FALSE) {
1978 _G.stack.pushedDE = TRUE;
1981 _G.saves.saved = TRUE;
1984 /* Already saved. */
1988 /*-----------------------------------------------------------------*/
1989 /* genIpush - genrate code for pushing this gets a little complex */
1990 /*-----------------------------------------------------------------*/
1992 genIpush (iCode * ic)
1994 int size, offset = 0;
1997 /* if this is not a parm push : ie. it is spill push
1998 and spill push is always done on the local stack */
2001 wassertl(0, "Encountered an unsupported spill push.");
2005 if (_G.saves.saved == FALSE) {
2006 /* Caller saves, and this is the first iPush. */
2007 /* Scan ahead until we find the function that we are pushing parameters to.
2008 Count the number of addSets on the way to figure out what registers
2009 are used in the send set.
2012 iCode *walk = ic->next;
2015 if (walk->op == SEND) {
2018 else if (walk->op == CALL || walk->op == PCALL) {
2027 _saveRegsForCall(walk, nAddSets);
2030 /* Already saved by another iPush. */
2033 /* then do the push */
2034 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2036 size = AOP_SIZE (IC_LEFT (ic));
2038 if (isPair (AOP (IC_LEFT (ic))))
2040 _G.stack.pushed += 2;
2041 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2047 fetchHL (AOP (IC_LEFT (ic)));
2049 spillPair (PAIR_HL);
2050 _G.stack.pushed += 2;
2055 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2057 spillPair (PAIR_HL);
2058 _G.stack.pushed += 2;
2059 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2061 spillPair (PAIR_HL);
2062 _G.stack.pushed += 2;
2068 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2070 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2072 emit2 ("ld a,(%s)", l);
2076 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2077 emit2 ("ld a,%s", l);
2085 freeAsmop (IC_LEFT (ic), NULL, ic);
2088 /*-----------------------------------------------------------------*/
2089 /* genIpop - recover the registers: can happen only for spilling */
2090 /*-----------------------------------------------------------------*/
2092 genIpop (iCode * ic)
2097 /* if the temp was not pushed then */
2098 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2101 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2102 size = AOP_SIZE (IC_LEFT (ic));
2103 offset = (size - 1);
2104 if (isPair (AOP (IC_LEFT (ic))))
2106 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2114 spillPair (PAIR_HL);
2115 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2119 freeAsmop (IC_LEFT (ic), NULL, ic);
2122 /* This is quite unfortunate */
2124 setArea (int inHome)
2127 static int lastArea = 0;
2129 if (_G.in_home != inHome) {
2131 const char *sz = port->mem.code_name;
2132 port->mem.code_name = "HOME";
2133 emit2("!area", CODE_NAME);
2134 port->mem.code_name = sz;
2137 emit2("!area", CODE_NAME); */
2138 _G.in_home = inHome;
2149 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2153 symbol *sym = OP_SYMBOL (op);
2155 if (sym->isspilt || sym->nRegs == 0)
2158 aopOp (op, ic, FALSE, FALSE);
2161 if (aop->type == AOP_REG)
2164 for (i = 0; i < aop->size; i++)
2166 if (pairId == PAIR_DE)
2168 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2169 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2171 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2174 else if (pairId == PAIR_BC)
2176 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2177 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2179 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2189 freeAsmop (IC_LEFT (ic), NULL, ic);
2193 /** Emit the code for a call statement
2196 emitCall (iCode * ic, bool ispcall)
2198 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2200 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2202 /* if caller saves & we have not saved then */
2208 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2210 /* if send set is not empty then assign */
2215 int nSend = elementsInSet(_G.sendSet);
2216 bool swapped = FALSE;
2218 int _z80_sendOrder[] = {
2223 /* Check if the parameters are swapped. If so route through hl instead. */
2224 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2226 sic = setFirstItem(_G.sendSet);
2227 sic = setNextItem(_G.sendSet);
2229 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2230 /* The second send value is loaded from one the one that holds the first
2231 send, i.e. it is overwritten. */
2232 /* Cache the first in HL, and load the second from HL instead. */
2233 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2234 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2240 for (sic = setFirstItem (_G.sendSet); sic;
2241 sic = setNextItem (_G.sendSet))
2244 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2246 size = AOP_SIZE (IC_LEFT (sic));
2247 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2248 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2250 // PENDING: Mild hack
2251 if (swapped == TRUE && send == 1) {
2253 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2256 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2258 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2261 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2265 freeAsmop (IC_LEFT (sic), NULL, sic);
2272 if (IS_BANKEDCALL (detype))
2274 werror (W_INDIR_BANKED);
2276 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2278 if (isLitWord (AOP (IC_LEFT (ic))))
2280 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2284 symbol *rlbl = newiTempLabel (NULL);
2285 spillPair (PAIR_HL);
2286 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2288 _G.stack.pushed += 2;
2290 fetchHL (AOP (IC_LEFT (ic)));
2292 emit2 ("!tlabeldef", (rlbl->key + 100));
2293 _G.stack.pushed -= 2;
2295 freeAsmop (IC_LEFT (ic), NULL, ic);
2299 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2300 OP_SYMBOL (IC_LEFT (ic))->rname :
2301 OP_SYMBOL (IC_LEFT (ic))->name;
2302 if (IS_BANKEDCALL (detype))
2304 emit2 ("call banked_call");
2305 emit2 ("!dws", name);
2306 emit2 ("!dw !bankimmeds", name);
2311 emit2 ("call %s", name);
2316 /* Mark the regsiters as restored. */
2317 _G.saves.saved = FALSE;
2319 /* if we need assign a result value */
2320 if ((IS_ITEMP (IC_RESULT (ic)) &&
2321 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2322 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2323 IS_TRUE_SYMOP (IC_RESULT (ic)))
2326 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2328 assignResultValue (IC_RESULT (ic));
2330 freeAsmop (IC_RESULT (ic), NULL, ic);
2333 /* adjust the stack for parameters if required */
2336 int i = ic->parmBytes;
2338 _G.stack.pushed -= i;
2341 emit2 ("!ldaspsp", i);
2348 emit2 ("ld hl,#%d", i);
2349 emit2 ("add hl,sp");
2366 if (_G.stack.pushedDE)
2368 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2369 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2371 if (dInUse && eInUse)
2387 wassertl (0, "Neither D or E were in use but it was pushed.");
2389 _G.stack.pushedDE = FALSE;
2392 if (_G.stack.pushedBC)
2394 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2395 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2397 // If both B and C are used in the return value, then we won't get
2399 if (bInUse && cInUse)
2415 wassertl (0, "Neither B or C were in use but it was pushed.");
2417 _G.stack.pushedBC = FALSE;
2421 /*-----------------------------------------------------------------*/
2422 /* genCall - generates a call statement */
2423 /*-----------------------------------------------------------------*/
2425 genCall (iCode * ic)
2427 emitCall (ic, FALSE);
2430 /*-----------------------------------------------------------------*/
2431 /* genPcall - generates a call by pointer statement */
2432 /*-----------------------------------------------------------------*/
2434 genPcall (iCode * ic)
2436 emitCall (ic, TRUE);
2439 /*-----------------------------------------------------------------*/
2440 /* resultRemat - result is rematerializable */
2441 /*-----------------------------------------------------------------*/
2443 resultRemat (iCode * ic)
2445 if (SKIP_IC (ic) || ic->op == IFX)
2448 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2450 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2451 if (sym->remat && !POINTER_SET (ic))
2458 extern set *publics;
2460 /*-----------------------------------------------------------------*/
2461 /* genFunction - generated code for function entry */
2462 /*-----------------------------------------------------------------*/
2464 genFunction (iCode * ic)
2466 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2470 bool bcInUse = FALSE;
2471 bool deInUse = FALSE;
2474 setArea (IS_NONBANKED (sym->etype));
2476 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2479 _G.receiveOffset = 0;
2481 /* Record the last function name for debugging. */
2482 _G.lastFunctionName = sym->rname;
2484 /* Create the function header */
2485 emit2 ("!functionheader", sym->name);
2486 /* PENDING: portability. */
2487 emit2 ("__%s_start:", sym->rname);
2488 emit2 ("!functionlabeldef", sym->rname);
2490 if (options.profile)
2492 emit2 ("!profileenter");
2495 fetype = getSpec (operandType (IC_LEFT (ic)));
2497 /* if critical function then turn interrupts off */
2498 if (SPEC_CRTCL (fetype))
2501 /* if this is an interrupt service routine then save all potentially used registers. */
2502 if (IS_ISR (sym->etype))
2507 /* PENDING: callee-save etc */
2509 _G.stack.param_offset = 0;
2512 /* Detect which registers are used. */
2516 for (i = 0; i < sym->regsUsed->size; i++)
2518 if (bitVectBitValue (sym->regsUsed, i))
2532 /* Other systems use DE as a temporary. */
2543 _G.stack.param_offset += 2;
2546 _G.stack.pushedBC = bcInUse;
2551 _G.stack.param_offset += 2;
2554 _G.stack.pushedDE = deInUse;
2557 /* adjust the stack for the function */
2558 _G.stack.last = sym->stack;
2561 emit2 ("!enterx", sym->stack);
2564 _G.stack.offset = sym->stack;
2567 /*-----------------------------------------------------------------*/
2568 /* genEndFunction - generates epilogue for functions */
2569 /*-----------------------------------------------------------------*/
2571 genEndFunction (iCode * ic)
2573 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2575 if (IS_ISR (sym->etype))
2577 wassertl (0, "Tried to close an interrupt support function");
2581 if (SPEC_CRTCL (sym->etype))
2584 /* PENDING: calleeSave */
2586 if (_G.stack.offset)
2588 emit2 ("!leavex", _G.stack.offset);
2596 if (_G.stack.pushedDE)
2599 _G.stack.pushedDE = FALSE;
2602 if (_G.stack.pushedDE)
2605 _G.stack.pushedDE = FALSE;
2609 if (options.profile)
2611 emit2 ("!profileexit");
2615 /* Both baned and non-banked just ret */
2618 /* PENDING: portability. */
2619 emit2 ("__%s_end:", sym->rname);
2621 _G.flushStatics = 1;
2622 _G.stack.pushed = 0;
2623 _G.stack.offset = 0;
2626 /*-----------------------------------------------------------------*/
2627 /* genRet - generate code for return statement */
2628 /*-----------------------------------------------------------------*/
2633 /* Errk. This is a hack until I can figure out how
2634 to cause dehl to spill on a call */
2635 int size, offset = 0;
2637 /* if we have no return value then
2638 just generate the "ret" */
2642 /* we have something to return then
2643 move the return value into place */
2644 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2645 size = AOP_SIZE (IC_LEFT (ic));
2647 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2651 emit2 ("ld de,%s", l);
2655 emit2 ("ld hl,%s", l);
2660 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2662 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2663 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2669 l = aopGet (AOP (IC_LEFT (ic)), offset,
2671 if (strcmp (_fReturn[offset], l))
2672 emit2 ("ld %s,%s", _fReturn[offset++], l);
2676 freeAsmop (IC_LEFT (ic), NULL, ic);
2679 /* generate a jump to the return label
2680 if the next is not the return statement */
2681 if (!(ic->next && ic->next->op == LABEL &&
2682 IC_LABEL (ic->next) == returnLabel))
2684 emit2 ("jp !tlabel", returnLabel->key + 100);
2687 /*-----------------------------------------------------------------*/
2688 /* genLabel - generates a label */
2689 /*-----------------------------------------------------------------*/
2691 genLabel (iCode * ic)
2693 /* special case never generate */
2694 if (IC_LABEL (ic) == entryLabel)
2697 emitLabel (IC_LABEL (ic)->key + 100);
2700 /*-----------------------------------------------------------------*/
2701 /* genGoto - generates a ljmp */
2702 /*-----------------------------------------------------------------*/
2704 genGoto (iCode * ic)
2706 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2709 /*-----------------------------------------------------------------*/
2710 /* genPlusIncr :- does addition with increment if possible */
2711 /*-----------------------------------------------------------------*/
2713 genPlusIncr (iCode * ic)
2715 unsigned int icount;
2716 unsigned int size = getDataSize (IC_RESULT (ic));
2717 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2719 /* will try to generate an increment */
2720 /* if the right side is not a literal
2722 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2725 emitDebug ("; genPlusIncr");
2727 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2729 /* If result is a pair */
2730 if (resultId != PAIR_INVALID)
2732 if (isLitWord (AOP (IC_LEFT (ic))))
2734 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2737 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2739 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2740 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2746 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2750 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2751 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2755 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2760 /* if the literal value of the right hand side
2761 is greater than 4 then it is not worth it */
2765 /* if increment 16 bits in register */
2766 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2772 symbol *tlbl = NULL;
2773 tlbl = newiTempLabel (NULL);
2776 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2779 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2782 emitLabel (tlbl->key + 100);
2786 /* if the sizes are greater than 1 then we cannot */
2787 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2788 AOP_SIZE (IC_LEFT (ic)) > 1)
2791 /* we can if the aops of the left & result match or
2792 if they are in registers and the registers are the
2794 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2798 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2806 /*-----------------------------------------------------------------*/
2807 /* outBitAcc - output a bit in acc */
2808 /*-----------------------------------------------------------------*/
2810 outBitAcc (operand * result)
2812 symbol *tlbl = newiTempLabel (NULL);
2813 /* if the result is a bit */
2814 if (AOP_TYPE (result) == AOP_CRY)
2816 wassertl (0, "Tried to write A into a bit");
2820 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2821 emit2 ("ld a,!one");
2822 emitLabel (tlbl->key + 100);
2827 /*-----------------------------------------------------------------*/
2828 /* genPlus - generates code for addition */
2829 /*-----------------------------------------------------------------*/
2831 genPlus (iCode * ic)
2833 int size, offset = 0;
2835 /* special cases :- */
2837 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2838 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2839 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2841 /* Swap the left and right operands if:
2843 if literal, literal on the right or
2844 if left requires ACC or right is already
2847 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2848 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2849 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2851 operand *t = IC_RIGHT (ic);
2852 IC_RIGHT (ic) = IC_LEFT (ic);
2856 /* if both left & right are in bit
2858 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2859 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2862 wassertl (0, "Tried to add two bits");
2865 /* if left in bit space & right literal */
2866 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2867 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2869 /* Can happen I guess */
2870 wassertl (0, "Tried to add a bit to a literal");
2873 /* if I can do an increment instead
2874 of add then GOOD for ME */
2875 if (genPlusIncr (ic) == TRUE)
2878 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
2880 size = getDataSize (IC_RESULT (ic));
2882 /* Special case when left and right are constant */
2883 if (isPair (AOP (IC_RESULT (ic))))
2886 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2887 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2889 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2895 sprintf (buffer, "#(%s + %s)", left, right);
2896 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2901 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2903 /* Fetch into HL then do the add */
2904 spillPair (PAIR_HL);
2905 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2906 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2911 ld hl,sp+n trashes C so we cant afford to do it during an
2912 add with stack based varibles. Worst case is:
2925 So you cant afford to load up hl if either left, right, or result
2926 is on the stack (*sigh*) The alt is:
2934 Combinations in here are:
2935 * If left or right are in bc then the loss is small - trap later
2936 * If the result is in bc then the loss is also small
2940 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2941 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2942 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2944 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2945 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2946 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2947 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2949 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2951 /* Swap left and right */
2952 operand *t = IC_RIGHT (ic);
2953 IC_RIGHT (ic) = IC_LEFT (ic);
2956 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2958 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2959 emit2 ("add hl,bc");
2963 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2964 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2965 emit2 ("add hl,de");
2967 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2973 /* Be paranoid on the GB with 4 byte variables due to how C
2974 can be trashed by lda hl,n(sp).
2976 _gbz80_emitAddSubLong (ic, TRUE);
2983 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2985 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2988 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2991 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2995 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2998 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3001 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3003 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3007 freeAsmop (IC_LEFT (ic), NULL, ic);
3008 freeAsmop (IC_RIGHT (ic), NULL, ic);
3009 freeAsmop (IC_RESULT (ic), NULL, ic);
3013 /*-----------------------------------------------------------------*/
3014 /* genMinusDec :- does subtraction with deccrement if possible */
3015 /*-----------------------------------------------------------------*/
3017 genMinusDec (iCode * ic)
3019 unsigned int icount;
3020 unsigned int size = getDataSize (IC_RESULT (ic));
3022 /* will try to generate an increment */
3023 /* if the right side is not a literal we cannot */
3024 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3027 /* if the literal value of the right hand side
3028 is greater than 4 then it is not worth it */
3029 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3032 size = getDataSize (IC_RESULT (ic));
3034 /* if decrement 16 bits in register */
3035 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3036 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3039 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3043 /* If result is a pair */
3044 if (isPair (AOP (IC_RESULT (ic))))
3046 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
3047 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
3049 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3053 /* if increment 16 bits in register */
3054 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3058 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3061 emit2 ("dec %s", _getTempPairName());
3064 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3070 /* if the sizes are greater than 1 then we cannot */
3071 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3072 AOP_SIZE (IC_LEFT (ic)) > 1)
3075 /* we can if the aops of the left & result match or if they are in
3076 registers and the registers are the same */
3077 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3080 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3087 /*-----------------------------------------------------------------*/
3088 /* genMinus - generates code for subtraction */
3089 /*-----------------------------------------------------------------*/
3091 genMinus (iCode * ic)
3093 int size, offset = 0;
3094 unsigned long lit = 0L;
3096 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3097 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3098 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3100 /* special cases :- */
3101 /* if both left & right are in bit space */
3102 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3103 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3105 wassertl (0, "Tried to subtract two bits");
3109 /* if I can do an decrement instead of subtract then GOOD for ME */
3110 if (genMinusDec (ic) == TRUE)
3113 size = getDataSize (IC_RESULT (ic));
3115 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3120 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3124 /* Same logic as genPlus */
3127 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3128 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3129 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3131 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3132 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3133 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3134 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3136 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3137 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3139 if (left == PAIR_INVALID && right == PAIR_INVALID)
3144 else if (right == PAIR_INVALID)
3146 else if (left == PAIR_INVALID)
3149 fetchPair (left, AOP (IC_LEFT (ic)));
3150 /* Order is important. Right may be HL */
3151 fetchPair (right, AOP (IC_RIGHT (ic)));
3153 emit2 ("ld a,%s", _pairs[left].l);
3154 emit2 ("sub a,%s", _pairs[right].l);
3156 emit2 ("ld a,%s", _pairs[left].h);
3157 emit2 ("sbc a,%s", _pairs[right].h);
3159 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3160 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3166 /* Be paranoid on the GB with 4 byte variables due to how C
3167 can be trashed by lda hl,n(sp).
3169 _gbz80_emitAddSubLong (ic, FALSE);
3174 /* if literal, add a,#-lit, else normal subb */
3177 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3178 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3182 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3185 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3189 /* first add without previous c */
3191 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3193 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3195 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3198 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3199 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3200 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3202 wassertl (0, "Tried to subtract on a long pointer");
3206 freeAsmop (IC_LEFT (ic), NULL, ic);
3207 freeAsmop (IC_RIGHT (ic), NULL, ic);
3208 freeAsmop (IC_RESULT (ic), NULL, ic);
3211 /*-----------------------------------------------------------------*/
3212 /* genMult - generates code for multiplication */
3213 /*-----------------------------------------------------------------*/
3215 genMult (iCode * ic)
3217 /* Shouldn't occur - all done through function calls */
3218 wassertl (0, "Multiplication is handled through support function calls");
3221 /*-----------------------------------------------------------------*/
3222 /* genDiv - generates code for division */
3223 /*-----------------------------------------------------------------*/
3227 /* Shouldn't occur - all done through function calls */
3228 wassertl (0, "Division is handled through support function calls");
3231 /*-----------------------------------------------------------------*/
3232 /* genMod - generates code for division */
3233 /*-----------------------------------------------------------------*/
3237 /* Shouldn't occur - all done through function calls */
3241 /*-----------------------------------------------------------------*/
3242 /* genIfxJump :- will create a jump depending on the ifx */
3243 /*-----------------------------------------------------------------*/
3245 genIfxJump (iCode * ic, char *jval)
3250 /* if true label then we jump if condition
3254 jlbl = IC_TRUE (ic);
3255 if (!strcmp (jval, "a"))
3259 else if (!strcmp (jval, "c"))
3263 else if (!strcmp (jval, "nc"))
3269 /* The buffer contains the bit on A that we should test */
3275 /* false label is present */
3276 jlbl = IC_FALSE (ic);
3277 if (!strcmp (jval, "a"))
3281 else if (!strcmp (jval, "c"))
3285 else if (!strcmp (jval, "nc"))
3291 /* The buffer contains the bit on A that we should test */
3295 /* Z80 can do a conditional long jump */
3296 if (!strcmp (jval, "a"))
3300 else if (!strcmp (jval, "c"))
3303 else if (!strcmp (jval, "nc"))
3308 emit2 ("bit %s,a", jval);
3310 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3312 /* mark the icode as generated */
3318 _getPairIdName (PAIR_ID id)
3320 return _pairs[id].name;
3324 /** Generic compare for > or <
3327 genCmp (operand * left, operand * right,
3328 operand * result, iCode * ifx, int sign)
3330 int size, offset = 0;
3331 unsigned long lit = 0L;
3332 bool swap_sense = FALSE;
3334 /* if left & right are bit variables */
3335 if (AOP_TYPE (left) == AOP_CRY &&
3336 AOP_TYPE (right) == AOP_CRY)
3338 /* Cant happen on the Z80 */
3339 wassertl (0, "Tried to compare two bits");
3343 /* subtract right from left if at the
3344 end the carry flag is set then we know that
3345 left is greater than right */
3346 size = max (AOP_SIZE (left), AOP_SIZE (right));
3348 /* if unsigned char cmp with lit, just compare */
3350 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3352 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3355 emit2 ("xor a,!immedbyte", 0x80);
3356 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3359 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3361 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3363 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3364 // Pull left into DE and right into HL
3365 aopGet (AOP(left), LSB, FALSE);
3368 aopGet (AOP(right), LSB, FALSE);
3372 if (size == 0 && sign)
3374 // Highest byte when signed needs the bits flipped
3377 emit2 ("ld a,(de)");
3378 emit2 ("xor #0x80");
3380 emit2 ("ld a,(hl)");
3381 emit2 ("xor #0x80");
3385 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3389 emit2 ("ld a,(de)");
3390 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3400 spillPair (PAIR_HL);
3404 if (AOP_TYPE (right) == AOP_LIT)
3406 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3407 /* optimize if(x < 0) or if(x >= 0) */
3412 /* No sign so it's always false */
3417 /* Just load in the top most bit */
3418 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3419 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3421 genIfxJump (ifx, "7");
3432 /* First setup h and l contaning the top most bytes XORed */
3433 bool fDidXor = FALSE;
3434 if (AOP_TYPE (left) == AOP_LIT)
3436 unsigned long lit = (unsigned long)
3437 floatFromVal (AOP (left)->aopu.aop_lit);
3438 emit2 ("ld %s,!immedbyte", _fTmp[0],
3439 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3443 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3444 emit2 ("xor a,!immedbyte", 0x80);
3445 emit2 ("ld %s,a", _fTmp[0]);
3448 if (AOP_TYPE (right) == AOP_LIT)
3450 unsigned long lit = (unsigned long)
3451 floatFromVal (AOP (right)->aopu.aop_lit);
3452 emit2 ("ld %s,!immedbyte", _fTmp[1],
3453 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3457 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3458 emit2 ("xor a,!immedbyte", 0x80);
3459 emit2 ("ld %s,a", _fTmp[1]);
3465 /* Do a long subtract */
3468 _moveA (aopGet (AOP (left), offset, FALSE));
3470 if (sign && size == 0)
3472 emit2 ("ld a,%s", _fTmp[0]);
3473 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3477 /* Subtract through, propagating the carry */
3478 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3486 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3488 outBitCLong (result, swap_sense);
3492 /* if the result is used in the next
3493 ifx conditional branch then generate
3494 code a little differently */
3496 genIfxJump (ifx, swap_sense ? "nc" : "c");
3498 outBitCLong (result, swap_sense);
3499 /* leave the result in acc */
3503 /*-----------------------------------------------------------------*/
3504 /* genCmpGt :- greater than comparison */
3505 /*-----------------------------------------------------------------*/
3507 genCmpGt (iCode * ic, iCode * ifx)
3509 operand *left, *right, *result;
3510 sym_link *letype, *retype;
3513 left = IC_LEFT (ic);
3514 right = IC_RIGHT (ic);
3515 result = IC_RESULT (ic);
3517 letype = getSpec (operandType (left));
3518 retype = getSpec (operandType (right));
3519 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3520 /* assign the amsops */
3521 aopOp (left, ic, FALSE, FALSE);
3522 aopOp (right, ic, FALSE, FALSE);
3523 aopOp (result, ic, TRUE, FALSE);
3525 genCmp (right, left, result, ifx, sign);
3527 freeAsmop (left, NULL, ic);
3528 freeAsmop (right, NULL, ic);
3529 freeAsmop (result, NULL, ic);
3532 /*-----------------------------------------------------------------*/
3533 /* genCmpLt - less than comparisons */
3534 /*-----------------------------------------------------------------*/
3536 genCmpLt (iCode * ic, iCode * ifx)
3538 operand *left, *right, *result;
3539 sym_link *letype, *retype;
3542 left = IC_LEFT (ic);
3543 right = IC_RIGHT (ic);
3544 result = IC_RESULT (ic);
3546 letype = getSpec (operandType (left));
3547 retype = getSpec (operandType (right));
3548 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3550 /* assign the amsops */
3551 aopOp (left, ic, FALSE, FALSE);
3552 aopOp (right, ic, FALSE, FALSE);
3553 aopOp (result, ic, TRUE, FALSE);
3555 genCmp (left, right, result, ifx, sign);
3557 freeAsmop (left, NULL, ic);
3558 freeAsmop (right, NULL, ic);
3559 freeAsmop (result, NULL, ic);
3562 /*-----------------------------------------------------------------*/
3563 /* gencjneshort - compare and jump if not equal */
3564 /*-----------------------------------------------------------------*/
3566 gencjneshort (operand * left, operand * right, symbol * lbl)
3568 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3570 unsigned long lit = 0L;
3572 /* Swap the left and right if it makes the computation easier */
3573 if (AOP_TYPE (left) == AOP_LIT)
3580 if (AOP_TYPE (right) == AOP_LIT)
3581 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3583 /* if the right side is a literal then anything goes */
3584 if (AOP_TYPE (right) == AOP_LIT &&
3585 AOP_TYPE (left) != AOP_DIR)
3589 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3596 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3603 emit2 ("jp nz,!tlabel", lbl->key + 100);
3609 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3610 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3613 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3614 emit2 ("jp nz,!tlabel", lbl->key + 100);
3619 /* if the right side is in a register or in direct space or
3620 if the left is a pointer register & right is not */
3621 else if (AOP_TYPE (right) == AOP_REG ||
3622 AOP_TYPE (right) == AOP_DIR ||
3623 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3627 _moveA (aopGet (AOP (left), offset, FALSE));
3628 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3629 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3631 emit2 ("jp nz,!tlabel", lbl->key + 100);
3634 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3635 emit2 ("jp nz,!tlabel", lbl->key + 100);
3642 /* right is a pointer reg need both a & b */
3643 /* PENDING: is this required? */
3646 _moveA (aopGet (AOP (right), offset, FALSE));
3647 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3648 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3654 /*-----------------------------------------------------------------*/
3655 /* gencjne - compare and jump if not equal */
3656 /*-----------------------------------------------------------------*/
3658 gencjne (operand * left, operand * right, symbol * lbl)
3660 symbol *tlbl = newiTempLabel (NULL);
3662 gencjneshort (left, right, lbl);
3665 emit2 ("ld a,!one");
3666 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3667 emitLabel (lbl->key + 100);
3669 emitLabel (tlbl->key + 100);
3672 /*-----------------------------------------------------------------*/
3673 /* genCmpEq - generates code for equal to */
3674 /*-----------------------------------------------------------------*/
3676 genCmpEq (iCode * ic, iCode * ifx)
3678 operand *left, *right, *result;
3680 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3681 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3682 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3684 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3686 /* Swap operands if it makes the operation easier. ie if:
3687 1. Left is a literal.
3689 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3691 operand *t = IC_RIGHT (ic);
3692 IC_RIGHT (ic) = IC_LEFT (ic);
3696 if (ifx && !AOP_SIZE (result))
3699 /* if they are both bit variables */
3700 if (AOP_TYPE (left) == AOP_CRY &&
3701 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3703 wassertl (0, "Tried to compare two bits");
3707 tlbl = newiTempLabel (NULL);
3708 gencjneshort (left, right, tlbl);
3711 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3712 emitLabel (tlbl->key + 100);
3716 /* PENDING: do this better */
3717 symbol *lbl = newiTempLabel (NULL);
3718 emit2 ("!shortjp !tlabel", lbl->key + 100);
3719 emitLabel (tlbl->key + 100);
3720 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3721 emitLabel (lbl->key + 100);
3724 /* mark the icode as generated */
3729 /* if they are both bit variables */
3730 if (AOP_TYPE (left) == AOP_CRY &&
3731 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3733 wassertl (0, "Tried to compare a bit to either a literal or another bit");
3737 gencjne (left, right, newiTempLabel (NULL));
3738 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3744 genIfxJump (ifx, "a");
3747 /* if the result is used in an arithmetic operation
3748 then put the result in place */
3749 if (AOP_TYPE (result) != AOP_CRY)
3753 /* leave the result in acc */
3757 freeAsmop (left, NULL, ic);
3758 freeAsmop (right, NULL, ic);
3759 freeAsmop (result, NULL, ic);
3762 /*-----------------------------------------------------------------*/
3763 /* ifxForOp - returns the icode containing the ifx for operand */
3764 /*-----------------------------------------------------------------*/
3766 ifxForOp (operand * op, iCode * ic)
3768 /* if true symbol then needs to be assigned */
3769 if (IS_TRUE_SYMOP (op))
3772 /* if this has register type condition and
3773 the next instruction is ifx with the same operand
3774 and live to of the operand is upto the ifx only then */
3776 ic->next->op == IFX &&
3777 IC_COND (ic->next)->key == op->key &&
3778 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3784 /*-----------------------------------------------------------------*/
3785 /* genAndOp - for && operation */
3786 /*-----------------------------------------------------------------*/
3788 genAndOp (iCode * ic)
3790 operand *left, *right, *result;
3793 /* note here that && operations that are in an if statement are
3794 taken away by backPatchLabels only those used in arthmetic
3795 operations remain */
3796 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3797 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3798 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3800 /* if both are bit variables */
3801 if (AOP_TYPE (left) == AOP_CRY &&
3802 AOP_TYPE (right) == AOP_CRY)
3804 wassertl (0, "Tried to and two bits");
3808 tlbl = newiTempLabel (NULL);
3810 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3812 emitLabel (tlbl->key + 100);
3816 freeAsmop (left, NULL, ic);
3817 freeAsmop (right, NULL, ic);
3818 freeAsmop (result, NULL, ic);
3821 /*-----------------------------------------------------------------*/
3822 /* genOrOp - for || operation */
3823 /*-----------------------------------------------------------------*/
3825 genOrOp (iCode * ic)
3827 operand *left, *right, *result;
3830 /* note here that || operations that are in an
3831 if statement are taken away by backPatchLabels
3832 only those used in arthmetic operations remain */
3833 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3834 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3835 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3837 /* if both are bit variables */
3838 if (AOP_TYPE (left) == AOP_CRY &&
3839 AOP_TYPE (right) == AOP_CRY)
3841 wassertl (0, "Tried to OR two bits");
3845 tlbl = newiTempLabel (NULL);
3847 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3849 emitLabel (tlbl->key + 100);
3853 freeAsmop (left, NULL, ic);
3854 freeAsmop (right, NULL, ic);
3855 freeAsmop (result, NULL, ic);
3858 /*-----------------------------------------------------------------*/
3859 /* isLiteralBit - test if lit == 2^n */
3860 /*-----------------------------------------------------------------*/
3862 isLiteralBit (unsigned long lit)
3864 unsigned long pw[32] =
3865 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3866 0x100L, 0x200L, 0x400L, 0x800L,
3867 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3868 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3869 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3870 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3871 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3874 for (idx = 0; idx < 32; idx++)
3880 /*-----------------------------------------------------------------*/
3881 /* jmpTrueOrFalse - */
3882 /*-----------------------------------------------------------------*/
3884 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3886 // ugly but optimized by peephole
3889 symbol *nlbl = newiTempLabel (NULL);
3890 emit2 ("jp !tlabel", nlbl->key + 100);
3891 emitLabel (tlbl->key + 100);
3892 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3893 emitLabel (nlbl->key + 100);
3897 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3898 emitLabel (tlbl->key + 100);
3903 /*-----------------------------------------------------------------*/
3904 /* genAnd - code for and */
3905 /*-----------------------------------------------------------------*/
3907 genAnd (iCode * ic, iCode * ifx)
3909 operand *left, *right, *result;
3910 int size, offset = 0;
3911 unsigned long lit = 0L;
3914 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3915 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3916 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3918 /* if left is a literal & right is not then exchange them */
3919 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3920 AOP_NEEDSACC (left))
3922 operand *tmp = right;
3927 /* if result = right then exchange them */
3928 if (sameRegs (AOP (result), AOP (right)))
3930 operand *tmp = right;
3935 /* if right is bit then exchange them */
3936 if (AOP_TYPE (right) == AOP_CRY &&
3937 AOP_TYPE (left) != AOP_CRY)
3939 operand *tmp = right;
3943 if (AOP_TYPE (right) == AOP_LIT)
3944 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3946 size = AOP_SIZE (result);
3948 if (AOP_TYPE (left) == AOP_CRY)
3950 wassertl (0, "Tried to perform an AND with a bit as an operand");
3954 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3955 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3956 if ((AOP_TYPE (right) == AOP_LIT) &&
3957 (AOP_TYPE (result) == AOP_CRY) &&
3958 (AOP_TYPE (left) != AOP_CRY))
3960 symbol *tlbl = newiTempLabel (NULL);
3961 int sizel = AOP_SIZE (left);
3964 /* PENDING: Test case for this. */
3969 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3971 _moveA (aopGet (AOP (left), offset, FALSE));
3972 if (bytelit != 0x0FFL)
3974 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
3981 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3985 // bit = left & literal
3989 emit2 ("!tlabeldef", tlbl->key + 100);
3991 // if(left & literal)
3996 jmpTrueOrFalse (ifx, tlbl);
4004 /* if left is same as result */
4005 if (sameRegs (AOP (result), AOP (left)))
4007 for (; size--; offset++)
4009 if (AOP_TYPE (right) == AOP_LIT)
4011 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4016 aopPut (AOP (result), "!zero", offset);
4019 _moveA (aopGet (AOP (left), offset, FALSE));
4021 aopGet (AOP (right), offset, FALSE));
4022 aopPut (AOP (left), "a", offset);
4029 if (AOP_TYPE (left) == AOP_ACC)
4031 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4035 _moveA (aopGet (AOP (left), offset, FALSE));
4037 aopGet (AOP (right), offset, FALSE));
4038 aopPut (AOP (left), "a", offset);
4045 // left & result in different registers
4046 if (AOP_TYPE (result) == AOP_CRY)
4048 wassertl (0, "Tried to AND where the result is in carry");
4052 for (; (size--); offset++)
4055 // result = left & right
4056 if (AOP_TYPE (right) == AOP_LIT)
4058 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4060 aopPut (AOP (result),
4061 aopGet (AOP (left), offset, FALSE),
4065 else if (bytelit == 0)
4067 aopPut (AOP (result), "!zero", offset);
4071 // faster than result <- left, anl result,right
4072 // and better if result is SFR
4073 if (AOP_TYPE (left) == AOP_ACC)
4074 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4077 _moveA (aopGet (AOP (left), offset, FALSE));
4079 aopGet (AOP (right), offset, FALSE));
4081 aopPut (AOP (result), "a", offset);
4088 freeAsmop (left, NULL, ic);
4089 freeAsmop (right, NULL, ic);
4090 freeAsmop (result, NULL, ic);
4093 /*-----------------------------------------------------------------*/
4094 /* genOr - code for or */
4095 /*-----------------------------------------------------------------*/
4097 genOr (iCode * ic, iCode * ifx)
4099 operand *left, *right, *result;
4100 int size, offset = 0;
4101 unsigned long lit = 0L;
4104 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4105 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4106 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4108 /* if left is a literal & right is not then exchange them */
4109 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4110 AOP_NEEDSACC (left))
4112 operand *tmp = right;
4117 /* if result = right then exchange them */
4118 if (sameRegs (AOP (result), AOP (right)))
4120 operand *tmp = right;
4125 /* if right is bit then exchange them */
4126 if (AOP_TYPE (right) == AOP_CRY &&
4127 AOP_TYPE (left) != AOP_CRY)
4129 operand *tmp = right;
4133 if (AOP_TYPE (right) == AOP_LIT)
4134 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4136 size = AOP_SIZE (result);
4138 if (AOP_TYPE (left) == AOP_CRY)
4140 wassertl (0, "Tried to OR where left is a bit");
4144 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4145 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4146 if ((AOP_TYPE (right) == AOP_LIT) &&
4147 (AOP_TYPE (result) == AOP_CRY) &&
4148 (AOP_TYPE (left) != AOP_CRY))
4150 symbol *tlbl = newiTempLabel (NULL);
4151 int sizel = AOP_SIZE (left);
4155 wassertl (0, "Result is assigned to a bit");
4157 /* PENDING: Modeled after the AND code which is inefficent. */
4160 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4162 _moveA (aopGet (AOP (left), offset, FALSE));
4163 /* OR with any literal is the same as OR with itself. */
4165 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4171 jmpTrueOrFalse (ifx, tlbl);
4176 /* if left is same as result */
4177 if (sameRegs (AOP (result), AOP (left)))
4179 for (; size--; offset++)
4181 if (AOP_TYPE (right) == AOP_LIT)
4183 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4187 _moveA (aopGet (AOP (left), offset, FALSE));
4189 aopGet (AOP (right), offset, FALSE));
4190 aopPut (AOP (result), "a", offset);
4195 if (AOP_TYPE (left) == AOP_ACC)
4196 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4199 _moveA (aopGet (AOP (left), offset, FALSE));
4201 aopGet (AOP (right), offset, FALSE));
4202 aopPut (AOP (result), "a", offset);
4209 // left & result in different registers
4210 if (AOP_TYPE (result) == AOP_CRY)
4212 wassertl (0, "Result of OR is in a bit");
4215 for (; (size--); offset++)
4218 // result = left & right
4219 if (AOP_TYPE (right) == AOP_LIT)
4221 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4223 aopPut (AOP (result),
4224 aopGet (AOP (left), offset, FALSE),
4229 // faster than result <- left, anl result,right
4230 // and better if result is SFR
4231 if (AOP_TYPE (left) == AOP_ACC)
4232 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4235 _moveA (aopGet (AOP (left), offset, FALSE));
4237 aopGet (AOP (right), offset, FALSE));
4239 aopPut (AOP (result), "a", offset);
4240 /* PENDING: something weird is going on here. Add exception. */
4241 if (AOP_TYPE (result) == AOP_ACC)
4247 freeAsmop (left, NULL, ic);
4248 freeAsmop (right, NULL, ic);
4249 freeAsmop (result, NULL, ic);
4252 /*-----------------------------------------------------------------*/
4253 /* genXor - code for xclusive or */
4254 /*-----------------------------------------------------------------*/
4256 genXor (iCode * ic, iCode * ifx)
4258 operand *left, *right, *result;
4259 int size, offset = 0;
4260 unsigned long lit = 0L;
4262 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4263 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4264 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4266 /* if left is a literal & right is not then exchange them */
4267 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4268 AOP_NEEDSACC (left))
4270 operand *tmp = right;
4275 /* if result = right then exchange them */
4276 if (sameRegs (AOP (result), AOP (right)))
4278 operand *tmp = right;
4283 /* if right is bit then exchange them */
4284 if (AOP_TYPE (right) == AOP_CRY &&
4285 AOP_TYPE (left) != AOP_CRY)
4287 operand *tmp = right;
4291 if (AOP_TYPE (right) == AOP_LIT)
4292 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4294 size = AOP_SIZE (result);
4296 if (AOP_TYPE (left) == AOP_CRY)
4298 wassertl (0, "Tried to XOR a bit");
4302 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4303 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4304 if ((AOP_TYPE (right) == AOP_LIT) &&
4305 (AOP_TYPE (result) == AOP_CRY) &&
4306 (AOP_TYPE (left) != AOP_CRY))
4308 symbol *tlbl = newiTempLabel (NULL);
4309 int sizel = AOP_SIZE (left);
4313 /* PENDING: Test case for this. */
4314 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4318 _moveA (aopGet (AOP (left), offset, FALSE));
4319 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4320 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4325 jmpTrueOrFalse (ifx, tlbl);
4329 wassertl (0, "Result of XOR was destined for a bit");
4334 /* if left is same as result */
4335 if (sameRegs (AOP (result), AOP (left)))
4337 for (; size--; offset++)
4339 if (AOP_TYPE (right) == AOP_LIT)
4341 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4345 _moveA (aopGet (AOP (right), offset, FALSE));
4347 aopGet (AOP (left), offset, FALSE));
4348 aopPut (AOP (result), "a", offset);
4353 if (AOP_TYPE (left) == AOP_ACC)
4355 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4359 _moveA (aopGet (AOP (right), offset, FALSE));
4361 aopGet (AOP (left), offset, FALSE));
4362 aopPut (AOP (result), "a", 0);
4369 // left & result in different registers
4370 if (AOP_TYPE (result) == AOP_CRY)
4372 wassertl (0, "Result of XOR is in a bit");
4375 for (; (size--); offset++)
4378 // result = left & right
4379 if (AOP_TYPE (right) == AOP_LIT)
4381 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4383 aopPut (AOP (result),
4384 aopGet (AOP (left), offset, FALSE),
4389 // faster than result <- left, anl result,right
4390 // and better if result is SFR
4391 if (AOP_TYPE (left) == AOP_ACC)
4393 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4397 _moveA (aopGet (AOP (right), offset, FALSE));
4399 aopGet (AOP (left), offset, FALSE));
4401 aopPut (AOP (result), "a", offset);
4406 freeAsmop (left, NULL, ic);
4407 freeAsmop (right, NULL, ic);
4408 freeAsmop (result, NULL, ic);
4411 /*-----------------------------------------------------------------*/
4412 /* genInline - write the inline code out */
4413 /*-----------------------------------------------------------------*/
4415 genInline (iCode * ic)
4417 char *buffer, *bp, *bp1;
4419 _G.lines.isInline += (!options.asmpeep);
4421 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4422 strcpy (buffer, IC_INLINE (ic));
4424 /* emit each line as a code */
4449 _G.lines.isInline -= (!options.asmpeep);
4453 /*-----------------------------------------------------------------*/
4454 /* genRRC - rotate right with carry */
4455 /*-----------------------------------------------------------------*/
4462 /*-----------------------------------------------------------------*/
4463 /* genRLC - generate code for rotate left with carry */
4464 /*-----------------------------------------------------------------*/
4471 /*-----------------------------------------------------------------*/
4472 /* genGetHbit - generates code get highest order bit */
4473 /*-----------------------------------------------------------------*/
4475 genGetHbit (iCode * ic)
4477 operand *left, *result;
4478 left = IC_LEFT (ic);
4479 result = IC_RESULT (ic);
4480 aopOp (left, ic, FALSE, FALSE);
4481 aopOp (result, ic, FALSE, FALSE);
4483 /* get the highest order byte into a */
4484 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4486 if (AOP_TYPE (result) == AOP_CRY)
4494 /* PENDING: For re-target. */
4500 freeAsmop (left, NULL, ic);
4501 freeAsmop (result, NULL, ic);
4505 emitRsh2 (asmop *aop, int size, int is_signed)
4511 const char *l = aopGet (aop, size, FALSE);
4514 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4524 /*-----------------------------------------------------------------*/
4525 /* shiftR2Left2Result - shift right two bytes from left to result */
4526 /*-----------------------------------------------------------------*/
4528 shiftR2Left2Result (operand * left, int offl,
4529 operand * result, int offr,
4530 int shCount, int is_signed)
4533 symbol *tlbl, *tlbl1;
4535 movLeft2Result (left, offl, result, offr, 0);
4536 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4538 /* if (AOP(result)->type == AOP_REG) { */
4540 tlbl = newiTempLabel (NULL);
4541 tlbl1 = newiTempLabel (NULL);
4543 /* Left is already in result - so now do the shift */
4548 emitRsh2 (AOP (result), size, is_signed);
4553 emit2 ("ld a,!immedbyte+1", shCount);
4554 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4555 emitLabel (tlbl->key + 100);
4557 emitRsh2 (AOP (result), size, is_signed);
4559 emitLabel (tlbl1->key + 100);
4561 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4565 /*-----------------------------------------------------------------*/
4566 /* shiftL2Left2Result - shift left two bytes from left to result */
4567 /*-----------------------------------------------------------------*/
4569 shiftL2Left2Result (operand * left, int offl,
4570 operand * result, int offr, int shCount)
4572 if (sameRegs (AOP (result), AOP (left)) &&
4573 ((offl + MSB16) == offr))
4579 /* Copy left into result */
4580 movLeft2Result (left, offl, result, offr, 0);
4581 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4583 /* PENDING: for now just see if it'll work. */
4584 /*if (AOP(result)->type == AOP_REG) { */
4588 symbol *tlbl, *tlbl1;
4591 tlbl = newiTempLabel (NULL);
4592 tlbl1 = newiTempLabel (NULL);
4594 /* Left is already in result - so now do the shift */
4597 emit2 ("ld a,!immedbyte+1", shCount);
4598 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4599 emitLabel (tlbl->key + 100);
4604 l = aopGet (AOP (result), offset, FALSE);
4608 emit2 ("sla %s", l);
4619 emitLabel (tlbl1->key + 100);
4621 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4626 /*-----------------------------------------------------------------*/
4627 /* AccRol - rotate left accumulator by known count */
4628 /*-----------------------------------------------------------------*/
4630 AccRol (int shCount)
4632 shCount &= 0x0007; // shCount : 0..7
4671 /*-----------------------------------------------------------------*/
4672 /* AccLsh - left shift accumulator by known count */
4673 /*-----------------------------------------------------------------*/
4675 AccLsh (int shCount)
4677 static const unsigned char SLMask[] =
4679 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4688 else if (shCount == 2)
4695 /* rotate left accumulator */
4697 /* and kill the lower order bits */
4698 emit2 ("and a,!immedbyte", SLMask[shCount]);
4703 /*-----------------------------------------------------------------*/
4704 /* shiftL1Left2Result - shift left one byte from left to result */
4705 /*-----------------------------------------------------------------*/
4707 shiftL1Left2Result (operand * left, int offl,
4708 operand * result, int offr, int shCount)
4711 l = aopGet (AOP (left), offl, FALSE);
4713 /* shift left accumulator */
4715 aopPut (AOP (result), "a", offr);
4719 /*-----------------------------------------------------------------*/
4720 /* genlshTwo - left shift two bytes by known amount != 0 */
4721 /*-----------------------------------------------------------------*/
4723 genlshTwo (operand * result, operand * left, int shCount)
4725 int size = AOP_SIZE (result);
4727 wassert (size == 2);
4729 /* if shCount >= 8 */
4737 movLeft2Result (left, LSB, result, MSB16, 0);
4738 aopPut (AOP (result), "!zero", 0);
4739 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
4743 movLeft2Result (left, LSB, result, MSB16, 0);
4744 aopPut (AOP (result), "!zero", 0);
4749 aopPut (AOP (result), "!zero", LSB);
4752 /* 1 <= shCount <= 7 */
4761 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4766 /*-----------------------------------------------------------------*/
4767 /* genlshOne - left shift a one byte quantity by known count */
4768 /*-----------------------------------------------------------------*/
4770 genlshOne (operand * result, operand * left, int shCount)
4772 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4775 /*-----------------------------------------------------------------*/
4776 /* genLeftShiftLiteral - left shifting by known count */
4777 /*-----------------------------------------------------------------*/
4779 genLeftShiftLiteral (operand * left,
4784 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4787 freeAsmop (right, NULL, ic);
4789 aopOp (left, ic, FALSE, FALSE);
4790 aopOp (result, ic, FALSE, FALSE);
4792 size = getSize (operandType (result));
4794 /* I suppose that the left size >= result size */
4800 else if (shCount >= (size * 8))
4804 aopPut (AOP (result), "!zero", size);
4812 genlshOne (result, left, shCount);
4815 genlshTwo (result, left, shCount);
4818 wassertl (0, "Shifting of longs is currently unsupported");
4824 freeAsmop (left, NULL, ic);
4825 freeAsmop (result, NULL, ic);
4828 /*-----------------------------------------------------------------*/
4829 /* genLeftShift - generates code for left shifting */
4830 /*-----------------------------------------------------------------*/
4832 genLeftShift (iCode * ic)
4836 symbol *tlbl, *tlbl1;
4837 operand *left, *right, *result;
4839 right = IC_RIGHT (ic);
4840 left = IC_LEFT (ic);
4841 result = IC_RESULT (ic);
4843 aopOp (right, ic, FALSE, FALSE);
4845 /* if the shift count is known then do it
4846 as efficiently as possible */
4847 if (AOP_TYPE (right) == AOP_LIT)
4849 genLeftShiftLiteral (left, right, result, ic);
4853 /* shift count is unknown then we have to form a loop get the loop
4854 count in B : Note: we take only the lower order byte since
4855 shifting more that 32 bits make no sense anyway, ( the largest
4856 size of an object can be only 32 bits ) */
4857 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4859 freeAsmop (right, NULL, ic);
4860 aopOp (left, ic, FALSE, FALSE);
4861 aopOp (result, ic, FALSE, FALSE);
4863 /* now move the left to the result if they are not the
4866 if (!sameRegs (AOP (left), AOP (result)))
4869 size = AOP_SIZE (result);
4873 l = aopGet (AOP (left), offset, FALSE);
4874 aopPut (AOP (result), l, offset);
4879 tlbl = newiTempLabel (NULL);
4880 size = AOP_SIZE (result);
4882 tlbl1 = newiTempLabel (NULL);
4884 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4885 emitLabel (tlbl->key + 100);
4886 l = aopGet (AOP (result), offset, FALSE);
4890 l = aopGet (AOP (result), offset, FALSE);
4894 emit2 ("sla %s", l);
4902 emitLabel (tlbl1->key + 100);
4904 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4906 freeAsmop (left, NULL, ic);
4907 freeAsmop (result, NULL, ic);
4910 /*-----------------------------------------------------------------*/
4911 /* genrshOne - left shift two bytes by known amount != 0 */
4912 /*-----------------------------------------------------------------*/
4914 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4917 int size = AOP_SIZE (result);
4920 wassert (size == 1);
4921 wassert (shCount < 8);
4923 l = aopGet (AOP (left), 0, FALSE);
4925 if (AOP (result)->type == AOP_REG)
4927 aopPut (AOP (result), l, 0);
4928 l = aopGet (AOP (result), 0, FALSE);
4931 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4939 emit2 ("%s a", is_signed ? "sra" : "srl");
4941 aopPut (AOP (result), "a", 0);
4945 /*-----------------------------------------------------------------*/
4946 /* AccRsh - right shift accumulator by known count */
4947 /*-----------------------------------------------------------------*/
4949 AccRsh (int shCount)
4951 static const unsigned char SRMask[] =
4953 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4958 /* rotate right accumulator */
4959 AccRol (8 - shCount);
4960 /* and kill the higher order bits */
4961 emit2 ("and a,!immedbyte", SRMask[shCount]);
4965 /*-----------------------------------------------------------------*/
4966 /* shiftR1Left2Result - shift right one byte from left to result */
4967 /*-----------------------------------------------------------------*/
4969 shiftR1Left2Result (operand * left, int offl,
4970 operand * result, int offr,
4971 int shCount, int sign)
4973 _moveA (aopGet (AOP (left), offl, FALSE));
4978 emit2 ("%s a", sign ? "sra" : "srl");
4985 aopPut (AOP (result), "a", offr);
4988 /*-----------------------------------------------------------------*/
4989 /* genrshTwo - right shift two bytes by known amount != 0 */
4990 /*-----------------------------------------------------------------*/
4992 genrshTwo (operand * result, operand * left,
4993 int shCount, int sign)
4995 /* if shCount >= 8 */
5001 shiftR1Left2Result (left, MSB16, result, LSB,
5006 movLeft2Result (left, MSB16, result, LSB, sign);
5010 /* Sign extend the result */
5011 _moveA(aopGet (AOP (result), 0, FALSE));
5015 aopPut (AOP (result), ACC_NAME, MSB16);
5019 aopPut (AOP (result), "!zero", 1);
5022 /* 1 <= shCount <= 7 */
5025 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5029 /*-----------------------------------------------------------------*/
5030 /* genRightShiftLiteral - left shifting by known count */
5031 /*-----------------------------------------------------------------*/
5033 genRightShiftLiteral (operand * left,
5039 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5042 freeAsmop (right, NULL, ic);
5044 aopOp (left, ic, FALSE, FALSE);
5045 aopOp (result, ic, FALSE, FALSE);
5047 size = getSize (operandType (result));
5049 /* I suppose that the left size >= result size */
5055 else if (shCount >= (size * 8))
5057 aopPut (AOP (result), "!zero", size);
5063 genrshOne (result, left, shCount, sign);
5066 genrshTwo (result, left, shCount, sign);
5069 wassertl (0, "Asked to shift right a long which should be a function call");
5072 wassertl (0, "Entered default case in right shift delegate");
5075 freeAsmop (left, NULL, ic);
5076 freeAsmop (result, NULL, ic);
5079 /*-----------------------------------------------------------------*/
5080 /* genRightShift - generate code for right shifting */
5081 /*-----------------------------------------------------------------*/
5083 genRightShift (iCode * ic)
5085 operand *right, *left, *result;
5087 int size, offset, first = 1;
5091 symbol *tlbl, *tlbl1;
5093 /* if signed then we do it the hard way preserve the
5094 sign bit moving it inwards */
5095 retype = getSpec (operandType (IC_RESULT (ic)));
5097 is_signed = !SPEC_USIGN (retype);
5099 /* signed & unsigned types are treated the same : i.e. the
5100 signed is NOT propagated inwards : quoting from the
5101 ANSI - standard : "for E1 >> E2, is equivalent to division
5102 by 2**E2 if unsigned or if it has a non-negative value,
5103 otherwise the result is implementation defined ", MY definition
5104 is that the sign does not get propagated */
5106 right = IC_RIGHT (ic);
5107 left = IC_LEFT (ic);
5108 result = IC_RESULT (ic);
5110 aopOp (right, ic, FALSE, FALSE);
5112 /* if the shift count is known then do it
5113 as efficiently as possible */
5114 if (AOP_TYPE (right) == AOP_LIT)
5116 genRightShiftLiteral (left, right, result, ic, is_signed);
5120 aopOp (left, ic, FALSE, FALSE);
5121 aopOp (result, ic, FALSE, FALSE);
5123 /* now move the left to the result if they are not the
5125 if (!sameRegs (AOP (left), AOP (result)) &&
5126 AOP_SIZE (result) > 1)
5129 size = AOP_SIZE (result);
5133 l = aopGet (AOP (left), offset, FALSE);
5134 aopPut (AOP (result), l, offset);
5139 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5141 freeAsmop (right, NULL, ic);
5143 tlbl = newiTempLabel (NULL);
5144 tlbl1 = newiTempLabel (NULL);
5145 size = AOP_SIZE (result);
5148 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5149 emitLabel (tlbl->key + 100);
5152 l = aopGet (AOP (result), offset--, FALSE);
5155 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5163 emitLabel (tlbl1->key + 100);
5165 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5167 freeAsmop (left, NULL, ic);
5168 freeAsmop (result, NULL, ic);
5171 /*-----------------------------------------------------------------*/
5172 /* genGenPointerGet - get value from generic pointer space */
5173 /*-----------------------------------------------------------------*/
5175 genGenPointerGet (operand * left,
5176 operand * result, iCode * ic)
5179 sym_link *retype = getSpec (operandType (result));
5185 aopOp (left, ic, FALSE, FALSE);
5186 aopOp (result, ic, FALSE, FALSE);
5188 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5191 if (isPtrPair (AOP (left)))
5193 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5194 aopPut (AOP (result), buffer, 0);
5198 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5199 aopPut (AOP (result), "a", 0);
5201 freeAsmop (left, NULL, ic);
5205 /* For now we always load into IY */
5206 /* if this is remateriazable */
5207 fetchPair (pair, AOP (left));
5209 /* so iy now contains the address */
5210 freeAsmop (left, NULL, ic);
5212 /* if bit then unpack */
5213 if (IS_BITVAR (retype))
5219 size = AOP_SIZE (result);
5224 /* PENDING: make this better */
5225 if (!IS_GB && AOP (result)->type == AOP_REG)
5227 aopPut (AOP (result), "!*hl", offset++);
5231 emit2 ("ld a,!*pair", _pairs[pair].name);
5232 aopPut (AOP (result), "a", offset++);
5236 emit2 ("inc %s", _pairs[pair].name);
5237 _G.pairs[pair].offset++;
5243 freeAsmop (result, NULL, ic);
5246 /*-----------------------------------------------------------------*/
5247 /* genPointerGet - generate code for pointer get */
5248 /*-----------------------------------------------------------------*/
5250 genPointerGet (iCode * ic)
5252 operand *left, *result;
5253 sym_link *type, *etype;
5255 left = IC_LEFT (ic);
5256 result = IC_RESULT (ic);
5258 /* depending on the type of pointer we need to
5259 move it to the correct pointer register */
5260 type = operandType (left);
5261 etype = getSpec (type);
5263 genGenPointerGet (left, result, ic);
5267 isRegOrLit (asmop * aop)
5269 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5274 /*-----------------------------------------------------------------*/
5275 /* genGenPointerSet - stores the value into a pointer location */
5276 /*-----------------------------------------------------------------*/
5278 genGenPointerSet (operand * right,
5279 operand * result, iCode * ic)
5282 sym_link *retype = getSpec (operandType (right));
5283 PAIR_ID pairId = PAIR_HL;
5285 aopOp (result, ic, FALSE, FALSE);
5286 aopOp (right, ic, FALSE, FALSE);
5291 /* Handle the exceptions first */
5292 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5295 const char *l = aopGet (AOP (right), 0, FALSE);
5296 const char *pair = getPairName (AOP (result));
5297 if (canAssignToPtr (l) && isPtr (pair))
5299 emit2 ("ld !*pair,%s", pair, l);
5304 emit2 ("ld !*pair,a", pair);
5309 /* if the operand is already in dptr
5310 then we do nothing else we move the value to dptr */
5311 if (AOP_TYPE (result) != AOP_STR)
5313 fetchPair (pairId, AOP (result));
5315 /* so hl know contains the address */
5316 freeAsmop (result, NULL, ic);
5318 /* if bit then unpack */
5319 if (IS_BITVAR (retype))
5325 size = AOP_SIZE (right);
5330 const char *l = aopGet (AOP (right), offset, FALSE);
5331 if (isRegOrLit (AOP (right)) && !IS_GB)
5333 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5338 emit2 ("ld !*pair,a", _pairs[pairId].name);
5342 emit2 ("inc %s", _pairs[pairId].name);
5343 _G.pairs[pairId].offset++;
5349 freeAsmop (right, NULL, ic);
5352 /*-----------------------------------------------------------------*/
5353 /* genPointerSet - stores the value into a pointer location */
5354 /*-----------------------------------------------------------------*/
5356 genPointerSet (iCode * ic)
5358 operand *right, *result;
5359 sym_link *type, *etype;
5361 right = IC_RIGHT (ic);
5362 result = IC_RESULT (ic);
5364 /* depending on the type of pointer we need to
5365 move it to the correct pointer register */
5366 type = operandType (result);
5367 etype = getSpec (type);
5369 genGenPointerSet (right, result, ic);
5372 /*-----------------------------------------------------------------*/
5373 /* genIfx - generate code for Ifx statement */
5374 /*-----------------------------------------------------------------*/
5376 genIfx (iCode * ic, iCode * popIc)
5378 operand *cond = IC_COND (ic);
5381 aopOp (cond, ic, FALSE, TRUE);
5383 /* get the value into acc */
5384 if (AOP_TYPE (cond) != AOP_CRY)
5388 /* the result is now in the accumulator */
5389 freeAsmop (cond, NULL, ic);
5391 /* if there was something to be popped then do it */
5395 /* if the condition is a bit variable */
5396 if (isbit && IS_ITEMP (cond) &&
5398 genIfxJump (ic, SPIL_LOC (cond)->rname);
5399 else if (isbit && !IS_ITEMP (cond))
5400 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5402 genIfxJump (ic, "a");
5407 /*-----------------------------------------------------------------*/
5408 /* genAddrOf - generates code for address of */
5409 /*-----------------------------------------------------------------*/
5411 genAddrOf (iCode * ic)
5413 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5415 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5417 /* if the operand is on the stack then we
5418 need to get the stack offset of this
5425 if (sym->stack <= 0)
5427 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5431 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5438 emit2 ("ld de,!hashedstr", sym->rname);
5440 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5441 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5448 /* if it has an offset then we need to compute it */
5450 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5452 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5453 emit2 ("add hl,sp");
5457 emit2 ("ld hl,#%s", sym->rname);
5459 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5460 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5462 freeAsmop (IC_RESULT (ic), NULL, ic);
5465 /*-----------------------------------------------------------------*/
5466 /* genAssign - generate code for assignment */
5467 /*-----------------------------------------------------------------*/
5469 genAssign (iCode * ic)
5471 operand *result, *right;
5473 unsigned long lit = 0L;
5475 result = IC_RESULT (ic);
5476 right = IC_RIGHT (ic);
5478 /* Dont bother assigning if they are the same */
5479 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5481 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5485 aopOp (right, ic, FALSE, FALSE);
5486 aopOp (result, ic, TRUE, FALSE);
5488 /* if they are the same registers */
5489 if (sameRegs (AOP (right), AOP (result)))
5491 emitDebug ("; (registers are the same)");
5495 /* if the result is a bit */
5496 if (AOP_TYPE (result) == AOP_CRY)
5498 wassertl (0, "Tried to assign to a bit");
5502 size = AOP_SIZE (result);
5505 if (AOP_TYPE (right) == AOP_LIT)
5506 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5507 if (isPair (AOP (result)))
5509 fetchPair (getPairId (AOP (result)), AOP (right));
5511 else if ((size > 1) &&
5512 (AOP_TYPE (result) != AOP_REG) &&
5513 (AOP_TYPE (right) == AOP_LIT) &&
5514 !IS_FLOAT (operandType (right)) &&
5517 bool fXored = FALSE;
5519 /* Work from the top down.
5520 Done this way so that we can use the cached copy of 0
5521 in A for a fast clear */
5524 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5526 if (!fXored && size > 1)
5533 aopPut (AOP (result), "a", offset);
5537 aopPut (AOP (result), "!zero", offset);
5541 aopPut (AOP (result),
5542 aopGet (AOP (right), offset, FALSE),
5547 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5549 /* Special case. Load into a and d, then load out. */
5550 _moveA (aopGet (AOP (right), 0, FALSE));
5551 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5552 aopPut (AOP (result), "a", 0);
5553 aopPut (AOP (result), "e", 1);
5555 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5557 /* Special case - simple memcpy */
5558 aopGet (AOP (right), LSB, FALSE);
5561 aopGet (AOP (result), LSB, FALSE);
5565 emit2 ("ld a,(de)");
5566 /* Peephole will optimise this. */
5567 emit2 ("ld (hl),a");
5575 spillPair (PAIR_HL);
5581 /* PENDING: do this check better */
5582 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5584 _moveA (aopGet (AOP (right), offset, FALSE));
5585 aopPut (AOP (result), "a", offset);
5588 aopPut (AOP (result),
5589 aopGet (AOP (right), offset, FALSE),
5596 freeAsmop (right, NULL, ic);
5597 freeAsmop (result, NULL, ic);
5600 /*-----------------------------------------------------------------*/
5601 /* genJumpTab - genrates code for jump table */
5602 /*-----------------------------------------------------------------*/
5604 genJumpTab (iCode * ic)
5609 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5610 /* get the condition into accumulator */
5611 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5614 emit2 ("ld e,%s", l);
5615 emit2 ("ld d,!zero");
5616 jtab = newiTempLabel (NULL);
5618 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5619 emit2 ("add hl,de");
5620 emit2 ("add hl,de");
5621 emit2 ("add hl,de");
5622 freeAsmop (IC_JTCOND (ic), NULL, ic);
5626 emitLabel (jtab->key + 100);
5627 /* now generate the jump labels */
5628 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5629 jtab = setNextItem (IC_JTLABELS (ic)))
5630 emit2 ("jp !tlabel", jtab->key + 100);
5633 /*-----------------------------------------------------------------*/
5634 /* genCast - gen code for casting */
5635 /*-----------------------------------------------------------------*/
5637 genCast (iCode * ic)
5639 operand *result = IC_RESULT (ic);
5640 sym_link *ctype = operandType (IC_LEFT (ic));
5641 operand *right = IC_RIGHT (ic);
5644 /* if they are equivalent then do nothing */
5645 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5648 aopOp (right, ic, FALSE, FALSE);
5649 aopOp (result, ic, FALSE, FALSE);
5651 /* if the result is a bit */
5652 if (AOP_TYPE (result) == AOP_CRY)
5654 wassertl (0, "Tried to cast to a bit");
5657 /* if they are the same size : or less */
5658 if (AOP_SIZE (result) <= AOP_SIZE (right))
5661 /* if they are in the same place */
5662 if (sameRegs (AOP (right), AOP (result)))
5665 /* if they in different places then copy */
5666 size = AOP_SIZE (result);
5670 aopPut (AOP (result),
5671 aopGet (AOP (right), offset, FALSE),
5678 /* So we now know that the size of destination is greater
5679 than the size of the source */
5680 /* we move to result for the size of source */
5681 size = AOP_SIZE (right);
5685 aopPut (AOP (result),
5686 aopGet (AOP (right), offset, FALSE),
5691 /* now depending on the sign of the destination */
5692 size = AOP_SIZE (result) - AOP_SIZE (right);
5693 /* Unsigned or not an integral type - right fill with zeros */
5694 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5697 aopPut (AOP (result), "!zero", offset++);
5701 /* we need to extend the sign :{ */
5702 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5708 aopPut (AOP (result), "a", offset++);
5712 freeAsmop (right, NULL, ic);
5713 freeAsmop (result, NULL, ic);
5716 /*-----------------------------------------------------------------*/
5717 /* genReceive - generate code for a receive iCode */
5718 /*-----------------------------------------------------------------*/
5720 genReceive (iCode * ic)
5722 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5723 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5724 IS_TRUE_SYMOP (IC_RESULT (ic))))
5734 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5735 size = AOP_SIZE(IC_RESULT(ic));
5737 for (i = 0; i < size; i++) {
5738 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5742 freeAsmop (IC_RESULT (ic), NULL, ic);
5747 /** Maximum number of bytes to emit per line. */
5751 /** Context for the byte output chunker. */
5754 unsigned char buffer[DBEMIT_MAX_RUN];
5759 /** Flushes a byte chunker by writing out all in the buffer and
5763 _dbFlush(DBEMITCTX *self)
5770 sprintf(line, ".db 0x%02X", self->buffer[0]);
5772 for (i = 1; i < self->pos; i++)
5774 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5781 /** Write out another byte, buffering until a decent line is
5785 _dbEmit(DBEMITCTX *self, int c)
5787 if (self->pos == DBEMIT_MAX_RUN)
5791 self->buffer[self->pos++] = c;
5794 /** Context for a simple run length encoder. */
5798 unsigned char buffer[128];
5800 /** runLen may be equivalent to pos. */
5806 RLE_CHANGE_COST = 4,
5810 /** Flush the buffer of a run length encoder by writing out the run or
5811 data that it currently contains.
5814 _rleCommit(RLECTX *self)
5820 memset(&db, 0, sizeof(db));
5822 emit2(".db %u", self->pos);
5824 for (i = 0; i < self->pos; i++)
5826 _dbEmit(&db, self->buffer[i]);
5835 Can get either a run or a block of random stuff.
5836 Only want to change state if a good run comes in or a run ends.
5837 Detecting run end is easy.
5840 Say initial state is in run, len zero, last zero. Then if you get a
5841 few zeros then something else then a short run will be output.
5842 Seems OK. While in run mode, keep counting. While in random mode,
5843 keep a count of the run. If run hits margin, output all up to run,
5844 restart, enter run mode.
5847 /** Add another byte into the run length encoder, flushing as
5848 required. The run length encoder uses the Amiga IFF style, where
5849 a block is prefixed by its run length. A positive length means
5850 the next n bytes pass straight through. A negative length means
5851 that the next byte is repeated -n times. A zero terminates the
5855 _rleAppend(RLECTX *self, int c)
5859 if (c != self->last)
5861 /* The run has stopped. See if it is worthwhile writing it out
5862 as a run. Note that the random data comes in as runs of
5865 if (self->runLen > RLE_CHANGE_COST)
5867 /* Yes, worthwhile. */
5868 /* Commit whatever was in the buffer. */
5870 emit2(".db -%u,0x%02X", self->runLen, self->last);
5874 /* Not worthwhile. Append to the end of the random list. */
5875 for (i = 0; i < self->runLen; i++)
5877 if (self->pos >= RLE_MAX_BLOCK)
5882 self->buffer[self->pos++] = self->last;
5890 if (self->runLen >= RLE_MAX_BLOCK)
5892 /* Commit whatever was in the buffer. */
5895 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5903 _rleFlush(RLECTX *self)
5905 _rleAppend(self, -1);
5912 /** genArrayInit - Special code for initialising an array with constant
5916 genArrayInit (iCode * ic)
5920 int elementSize = 0, eIndex, i;
5921 unsigned val, lastVal;
5925 memset(&rle, 0, sizeof(rle));
5927 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5929 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5931 /* Emit the support function call and the destination address. */
5932 emit2("call __initrleblock");
5933 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5937 wassertl (0, "Unexpected operand to genArrayInit.\n");
5940 type = operandType(IC_LEFT(ic));
5942 if (type && type->next)
5944 elementSize = getSize(type->next);
5948 wassertl (0, "Can't determine element size in genArrayInit.");
5951 iLoop = IC_ARRAYILIST(ic);
5952 lastVal = (unsigned)-1;
5954 /* Feed all the bytes into the run length encoder which will handle
5956 This works well for mixed char data, and for random int and long
5965 for (i = 0; i < ix; i++)
5967 for (eIndex = 0; eIndex < elementSize; eIndex++)
5969 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5970 _rleAppend(&rle, val);
5975 iLoop = iLoop->next;
5979 /* Mark the end of the run. */
5982 freeAsmop (IC_LEFT(ic), NULL, ic);
5985 /*-----------------------------------------------------------------*/
5986 /* genZ80Code - generate code for Z80 based controllers */
5987 /*-----------------------------------------------------------------*/
5989 genZ80Code (iCode * lic)
5997 _fReturn = _gbz80_return;
5998 _fTmp = _gbz80_return;
6002 _fReturn = _z80_return;
6003 _fTmp = _z80_return;
6006 _G.lines.head = _G.lines.current = NULL;
6008 for (ic = lic; ic; ic = ic->next)
6011 if (cln != ic->lineno)
6013 emit2 ("; %s %d", ic->filename, ic->lineno);
6016 /* if the result is marked as
6017 spilt and rematerializable or code for
6018 this has already been generated then
6020 if (resultRemat (ic) || ic->generated)
6023 /* depending on the operation */
6027 emitDebug ("; genNot");
6032 emitDebug ("; genCpl");
6037 emitDebug ("; genUminus");
6042 emitDebug ("; genIpush");
6047 /* IPOP happens only when trying to restore a
6048 spilt live range, if there is an ifx statement
6049 following this pop then the if statement might
6050 be using some of the registers being popped which
6051 would destory the contents of the register so
6052 we need to check for this condition and handle it */
6054 ic->next->op == IFX &&
6055 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6057 emitDebug ("; genIfx");
6058 genIfx (ic->next, ic);
6062 emitDebug ("; genIpop");
6068 emitDebug ("; genCall");
6073 emitDebug ("; genPcall");
6078 emitDebug ("; genFunction");
6083 emitDebug ("; genEndFunction");
6084 genEndFunction (ic);
6088 emitDebug ("; genRet");
6093 emitDebug ("; genLabel");
6098 emitDebug ("; genGoto");
6103 emitDebug ("; genPlus");
6108 emitDebug ("; genMinus");
6113 emitDebug ("; genMult");
6118 emitDebug ("; genDiv");
6123 emitDebug ("; genMod");
6128 emitDebug ("; genCmpGt");
6129 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6133 emitDebug ("; genCmpLt");
6134 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6141 /* note these two are xlated by algebraic equivalence
6142 during parsing SDCC.y */
6143 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6144 "got '>=' or '<=' shouldn't have come here");
6148 emitDebug ("; genCmpEq");
6149 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6153 emitDebug ("; genAndOp");
6158 emitDebug ("; genOrOp");
6163 emitDebug ("; genXor");
6164 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6168 emitDebug ("; genOr");
6169 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6173 emitDebug ("; genAnd");
6174 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6178 emitDebug ("; genInline");
6183 emitDebug ("; genRRC");
6188 emitDebug ("; genRLC");
6193 emitDebug ("; genGetHBIT");
6198 emitDebug ("; genLeftShift");
6203 emitDebug ("; genRightShift");
6207 case GET_VALUE_AT_ADDRESS:
6208 emitDebug ("; genPointerGet");
6214 if (POINTER_SET (ic))
6216 emitDebug ("; genAssign (pointer)");
6221 emitDebug ("; genAssign");
6227 emitDebug ("; genIfx");
6232 emitDebug ("; genAddrOf");
6237 emitDebug ("; genJumpTab");
6242 emitDebug ("; genCast");
6247 emitDebug ("; genReceive");
6252 emitDebug ("; addSet");
6253 addSet (&_G.sendSet, ic);
6266 /* now we are ready to call the
6267 peep hole optimizer */
6268 if (!options.nopeep)
6269 peepHole (&_G.lines.head);
6271 /* This is unfortunate */
6272 /* now do the actual printing */
6274 FILE *fp = codeOutFile;
6275 if (isInHome () && codeOutFile == code->oFile)
6276 codeOutFile = home->oFile;
6277 printLine (_G.lines.head, codeOutFile);
6278 if (_G.flushStatics)
6281 _G.flushStatics = 0;
6286 freeTrace(&_G.lines.trace);
6287 freeTrace(&_G.trace.aops);
6293 _isPairUsed (iCode * ic, PAIR_ID pairId)
6299 if (bitVectBitValue (ic->rMask, D_IDX))
6301 if (bitVectBitValue (ic->rMask, E_IDX))
6311 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6314 value *val = aop->aopu.aop_lit;
6316 wassert (aop->type == AOP_LIT);
6317 wassert (!IS_FLOAT (val->type));
6319 v = (unsigned long) floatFromVal (val);
6327 tsprintf (buffer, "!immedword", v);
6328 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));