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 && (options.ommitFramePtr || 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)
889 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
891 _pop (aop->aopu.aop_pairId);
895 /* all other cases just dealloc */
901 OP_SYMBOL (op)->aop = NULL;
902 /* if the symbol has a spill */
904 SPIL_LOC (op)->aop = NULL;
911 isLitWord (asmop * aop)
913 /* if (aop->size != 2)
926 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
931 /* depending on type */
937 /* PENDING: for re-target */
940 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
942 else if (offset == 0)
944 tsprintf (s, "%s", aop->aopu.aop_immd);
948 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
950 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
954 value *val = aop->aopu.aop_lit;
955 /* if it is a float then it gets tricky */
956 /* otherwise it is fairly simple */
957 if (!IS_FLOAT (val->type))
959 unsigned long v = (unsigned long) floatFromVal (val);
965 else if (offset == 0)
971 wassertl(0, "Encountered an invalid offset while fetching a literal");
975 tsprintf (buffer, "!immedword", v);
977 tsprintf (buffer, "!constword", v);
979 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
985 convertFloat (&f, floatFromVal (val));
987 tsprintf (buffer, "!immedword", f.w[offset / 2]);
989 tsprintf (buffer, "!constword", f.w[offset / 2]);
990 rs = Safe_calloc (1, strlen (buffer) + 1);
991 return strcpy (rs, buffer);
1000 aopGetWord (asmop * aop, int offset)
1002 return aopGetLitWordLong (aop, offset, TRUE);
1006 isPtr (const char *s)
1008 if (!strcmp (s, "hl"))
1010 if (!strcmp (s, "ix"))
1012 if (!strcmp (s, "iy"))
1018 adjustPair (const char *pair, int *pold, int new)
1024 emit2 ("inc %s", pair);
1029 emit2 ("dec %s", pair);
1035 spillPair (PAIR_ID pairId)
1037 _G.pairs[pairId].last_type = AOP_INVALID;
1038 _G.pairs[pairId].base = NULL;
1044 spillPair (PAIR_HL);
1045 spillPair (PAIR_IY);
1049 requiresHL (asmop * aop)
1064 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1066 const char *l, *base;
1067 const char *pair = _pairs[pairId].name;
1068 l = aopGetLitWordLong (left, offset, FALSE);
1069 base = aopGetLitWordLong (left, 0, FALSE);
1070 wassert (l && pair && base);
1074 if (pairId == PAIR_HL || pairId == PAIR_IY)
1076 if (_G.pairs[pairId].last_type == left->type)
1078 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1080 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1082 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1085 if (pairId == PAIR_IY && abs (offset) < 127)
1092 _G.pairs[pairId].last_type = left->type;
1093 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1094 _G.pairs[pairId].offset = offset;
1096 /* Both a lit on the right and a true symbol on the left */
1097 emit2 ("ld %s,!hashedstr", pair, l);
1101 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1103 /* if this is remateriazable */
1104 if (isLitWord (aop)) {
1105 fetchLitPair (pairId, aop, offset);
1108 /* we need to get it byte by byte */
1109 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1110 aopGet (aop, offset, FALSE);
1111 switch (aop->size - offset) {
1113 emit2 ("ld l,!*hl");
1114 emit2 ("ld h,!immedbyte", 0);
1117 // PENDING: Requires that you are only fetching two bytes.
1120 emit2 ("ld h,!*hl");
1124 wassertl (0, "Attempted to fetch too much data into HL");
1128 else if (IS_Z80 && aop->type == AOP_IY) {
1129 /* Instead of fetching relative to IY, just grab directly
1130 from the address IY refers to */
1131 char *l = aopGetLitWordLong (aop, offset, FALSE);
1133 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1135 if (aop->size < 2) {
1136 emit2("ld %s,!zero", _pairs[pairId].h);
1140 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1141 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1143 /* PENDING: check? */
1144 if (pairId == PAIR_HL)
1145 spillPair (PAIR_HL);
1150 fetchPair (PAIR_ID pairId, asmop * aop)
1152 fetchPairLong (pairId, aop, 0);
1156 fetchHL (asmop * aop)
1158 fetchPair (PAIR_HL, aop);
1162 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1167 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1168 fetchLitPair (pairId, aop, 0);
1172 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1174 fetchLitPair (pairId, aop, offset);
1175 _G.pairs[pairId].offset = offset;
1179 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1180 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1183 int offset = aop->aopu.aop_stk + _G.stack.offset;
1185 if (_G.pairs[pairId].last_type == aop->type &&
1186 _G.pairs[pairId].offset == offset)
1192 /* PENDING: Do this better. */
1193 sprintf (buffer, "%d", offset + _G.stack.pushed);
1194 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1195 emit2 ("add %s,sp", _pairs[pairId].name);
1196 _G.pairs[pairId].last_type = aop->type;
1197 _G.pairs[pairId].offset = offset;
1204 /* Doesnt include _G.stack.pushed */
1205 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1206 if (aop->aopu.aop_stk > 0)
1208 abso += _G.stack.param_offset;
1210 assert (pairId == PAIR_HL);
1211 /* In some cases we can still inc or dec hl */
1212 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1214 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1218 emit2 ("!ldahlsp", abso + _G.stack.pushed);
1220 _G.pairs[pairId].offset = abso;
1225 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1231 _G.pairs[pairId].last_type = aop->type;
1237 emit2 ("!tlabeldef", key);
1241 /*-----------------------------------------------------------------*/
1242 /* aopGet - for fetching value of the aop */
1243 /*-----------------------------------------------------------------*/
1245 aopGet (asmop * aop, int offset, bool bit16)
1249 /* offset is greater than size then zero */
1250 /* PENDING: this seems a bit screwed in some pointer cases. */
1251 if (offset > (aop->size - 1) &&
1252 aop->type != AOP_LIT)
1254 tsprintf (s, "!zero");
1255 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1258 /* depending on type */
1262 /* PENDING: re-target */
1264 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1269 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1272 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1275 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1278 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1281 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1285 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1288 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1292 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1295 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1298 return aop->aopu.aop_reg[offset]->name;
1302 setupPair (PAIR_HL, aop, offset);
1303 tsprintf (s, "!*hl");
1305 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1309 setupPair (PAIR_IY, aop, offset);
1310 tsprintf (s, "!*iyx", offset);
1312 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1316 setupPair (PAIR_IY, aop, offset);
1317 tsprintf (s, "!*iyx", offset, offset);
1319 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1324 setupPair (PAIR_HL, aop, offset);
1325 tsprintf (s, "!*hl");
1329 if (aop->aopu.aop_stk >= 0)
1330 offset += _G.stack.param_offset;
1331 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1334 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1337 wassertl (0, "Tried to fetch from a bit variable");
1346 tsprintf(s, "!zero");
1347 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1351 wassert (offset < 2);
1352 return aop->aopu.aop_str[offset];
1355 return aopLiteral (aop->aopu.aop_lit, offset);
1359 unsigned long v = aop->aopu.aop_simplelit;
1362 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1364 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1368 return aop->aopu.aop_str[offset];
1371 setupPair (aop->aopu.aop_pairId, aop, offset);
1372 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1374 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1379 wassertl (0, "aopget got unsupported aop->type");
1384 isRegString (const char *s)
1386 if (!strcmp (s, "b") ||
1398 isConstant (const char *s)
1400 /* This is a bit of a hack... */
1401 return (*s == '#' || *s == '$');
1405 canAssignToPtr (const char *s)
1407 if (isRegString (s))
1414 /*-----------------------------------------------------------------*/
1415 /* aopPut - puts a string for a aop */
1416 /*-----------------------------------------------------------------*/
1418 aopPut (asmop * aop, const char *s, int offset)
1422 if (aop->size && offset > (aop->size - 1))
1424 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1425 "aopPut got offset > aop->size");
1430 tsprintf(buffer2, s);
1433 /* will assign value to value */
1434 /* depending on where it is ofcourse */
1440 if (strcmp (s, "a"))
1441 emit2 ("ld a,%s", s);
1442 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1447 if (strcmp (s, "a"))
1448 emit2 ("ld a,%s", s);
1449 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1453 if (!strcmp (s, "!*hl"))
1454 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1457 aop->aopu.aop_reg[offset]->name, s);
1462 if (!canAssignToPtr (s))
1464 emit2 ("ld a,%s", s);
1465 setupPair (PAIR_IY, aop, offset);
1466 emit2 ("ld !*iyx,a", offset);
1470 setupPair (PAIR_IY, aop, offset);
1471 emit2 ("ld !*iyx,%s", offset, s);
1477 /* PENDING: for re-target */
1478 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1480 emit2 ("ld a,!*hl");
1483 setupPair (PAIR_HL, aop, offset);
1485 emit2 ("ld !*hl,%s", s);
1490 if (!canAssignToPtr (s))
1492 emit2 ("ld a,%s", s);
1493 setupPair (PAIR_IY, aop, offset);
1494 emit2 ("ld !*iyx,a", offset);
1498 setupPair (PAIR_IY, aop, offset);
1499 emit2 ("ld !*iyx,%s", offset, s);
1506 /* PENDING: re-target */
1507 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1509 emit2 ("ld a,!*hl");
1512 setupPair (PAIR_HL, aop, offset);
1513 if (!canAssignToPtr (s))
1515 emit2 ("ld a,%s", s);
1516 emit2 ("ld !*hl,a");
1519 emit2 ("ld !*hl,%s", s);
1523 if (aop->aopu.aop_stk >= 0)
1524 offset += _G.stack.param_offset;
1525 if (!canAssignToPtr (s))
1527 emit2 ("ld a,%s", s);
1528 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1531 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1536 /* if bit variable */
1537 if (!aop->aopu.aop_dir)
1544 /* In bit space but not in C - cant happen */
1545 wassertl (0, "Tried to write into a bit variable");
1551 if (strcmp (aop->aopu.aop_str[offset], s))
1553 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1559 if (!offset && (strcmp (s, "acc") == 0))
1563 wassertl (0, "Tried to access past the end of A");
1567 if (strcmp (aop->aopu.aop_str[offset], s))
1568 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1573 wassert (offset < 2);
1574 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1578 setupPair (aop->aopu.aop_pairId, aop, offset);
1579 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1583 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1584 "aopPut got unsupported aop->type");
1589 #define AOP(op) op->aop
1590 #define AOP_TYPE(op) AOP(op)->type
1591 #define AOP_SIZE(op) AOP(op)->size
1592 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1595 commitPair (asmop * aop, PAIR_ID id)
1597 if (id == PAIR_HL && requiresHL (aop))
1601 aopPut (aop, "a", 0);
1602 aopPut (aop, "d", 1);
1606 aopPut (aop, _pairs[id].l, 0);
1607 aopPut (aop, _pairs[id].h, 1);
1611 /*-----------------------------------------------------------------*/
1612 /* getDataSize - get the operand data size */
1613 /*-----------------------------------------------------------------*/
1615 getDataSize (operand * op)
1618 size = AOP_SIZE (op);
1622 wassertl (0, "Somehow got a three byte data pointer");
1627 /*-----------------------------------------------------------------*/
1628 /* movLeft2Result - move byte from left to result */
1629 /*-----------------------------------------------------------------*/
1631 movLeft2Result (operand * left, int offl,
1632 operand * result, int offr, int sign)
1635 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1637 l = aopGet (AOP (left), offl, FALSE);
1641 aopPut (AOP (result), l, offr);
1645 if (getDataSize (left) == offl + 1)
1647 emit2 ("ld a,%s", l);
1648 aopPut (AOP (result), "a", offr);
1655 /** Put Acc into a register set
1658 outAcc (operand * result)
1661 size = getDataSize (result);
1664 aopPut (AOP (result), "a", 0);
1667 /* unsigned or positive */
1670 aopPut (AOP (result), "!zero", offset++);
1675 /** Take the value in carry and put it into a register
1678 outBitCLong (operand * result, bool swap_sense)
1680 /* if the result is bit */
1681 if (AOP_TYPE (result) == AOP_CRY)
1683 wassertl (0, "Tried to write carry to a bit");
1687 emit2 ("ld a,!zero");
1690 emit2 ("xor a,!immedbyte", 1);
1696 outBitC (operand * result)
1698 outBitCLong (result, FALSE);
1701 /*-----------------------------------------------------------------*/
1702 /* toBoolean - emit code for orl a,operator(sizeop) */
1703 /*-----------------------------------------------------------------*/
1705 _toBoolean (operand * oper)
1707 int size = AOP_SIZE (oper);
1711 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1714 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1718 if (AOP (oper)->type != AOP_ACC)
1721 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1726 /*-----------------------------------------------------------------*/
1727 /* genNot - generate code for ! operation */
1728 /*-----------------------------------------------------------------*/
1732 sym_link *optype = operandType (IC_LEFT (ic));
1734 /* assign asmOps to operand & result */
1735 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1736 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1738 /* if in bit space then a special case */
1739 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1741 wassertl (0, "Tried to negate a bit");
1744 /* if type float then do float */
1745 if (IS_FLOAT (optype))
1747 wassertl (0, "Tried to negate a float");
1750 _toBoolean (IC_LEFT (ic));
1755 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1756 emit2 ("sub a,!one");
1757 outBitC (IC_RESULT (ic));
1759 /* release the aops */
1760 freeAsmop (IC_LEFT (ic), NULL, ic);
1761 freeAsmop (IC_RESULT (ic), NULL, ic);
1764 /*-----------------------------------------------------------------*/
1765 /* genCpl - generate code for complement */
1766 /*-----------------------------------------------------------------*/
1774 /* assign asmOps to operand & result */
1775 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1776 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1778 /* if both are in bit space then
1780 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1781 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1783 wassertl (0, "Left and the result are in bit space");
1786 size = AOP_SIZE (IC_RESULT (ic));
1789 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1792 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1795 /* release the aops */
1796 freeAsmop (IC_LEFT (ic), NULL, ic);
1797 freeAsmop (IC_RESULT (ic), NULL, ic);
1801 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1808 store de into result
1813 store de into result
1815 const char *first = isAdd ? "add" : "sub";
1816 const char *later = isAdd ? "adc" : "sbc";
1818 wassertl (IS_GB, "Code is only relevent to the gbz80");
1819 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1821 fetchPair (PAIR_DE, left);
1824 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1827 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1830 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
1831 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
1833 fetchPairLong (PAIR_DE, left, MSB24);
1834 aopGet (right, MSB24, FALSE);
1838 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
1841 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
1843 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
1844 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
1848 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
1850 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
1853 /*-----------------------------------------------------------------*/
1854 /* genUminus - unary minus code generation */
1855 /*-----------------------------------------------------------------*/
1857 genUminus (iCode * ic)
1860 sym_link *optype, *rtype;
1863 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1864 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1866 /* if both in bit space then special
1868 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1869 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1871 wassertl (0, "Left and right are in bit space");
1875 optype = operandType (IC_LEFT (ic));
1876 rtype = operandType (IC_RESULT (ic));
1878 /* if float then do float stuff */
1879 if (IS_FLOAT (optype))
1881 wassertl (0, "Tried to do a unary minus on a float");
1885 /* otherwise subtract from zero */
1886 size = AOP_SIZE (IC_LEFT (ic));
1888 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1890 /* Create a new asmop with value zero */
1891 asmop *azero = newAsmop (AOP_SIMPLELIT);
1892 azero->aopu.aop_simplelit = 0;
1894 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1902 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1903 emit2 ("ld a,!zero");
1904 emit2 ("sbc a,%s", l);
1905 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1908 /* if any remaining bytes in the result */
1909 /* we just need to propagate the sign */
1910 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1915 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1919 /* release the aops */
1920 freeAsmop (IC_LEFT (ic), NULL, ic);
1921 freeAsmop (IC_RESULT (ic), NULL, ic);
1924 /*-----------------------------------------------------------------*/
1925 /* assignResultValue - */
1926 /*-----------------------------------------------------------------*/
1928 assignResultValue (operand * oper)
1930 int size = AOP_SIZE (oper);
1933 wassertl (size <= 4, "Got a result that is bigger than four bytes");
1934 topInA = requiresHL (AOP (oper));
1936 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1938 /* We do it the hard way here. */
1940 aopPut (AOP (oper), _fReturn[0], 0);
1941 aopPut (AOP (oper), _fReturn[1], 1);
1943 aopPut (AOP (oper), _fReturn[0], 2);
1944 aopPut (AOP (oper), _fReturn[1], 3);
1950 aopPut (AOP (oper), _fReturn[size], size);
1956 _saveRegsForCall(iCode *ic, int sendSetSize)
1959 o Stack parameters are pushed before this function enters
1960 o DE and BC may be used in this function.
1961 o HL and DE may be used to return the result.
1962 o HL and DE may be used to send variables.
1963 o DE and BC may be used to store the result value.
1964 o HL may be used in computing the sent value of DE
1965 o The iPushes for other parameters occur before any addSets
1967 Logic: (to be run inside the first iPush or if none, before sending)
1968 o Compute if DE and/or BC are in use over the call
1969 o Compute if DE is used in the send set
1970 o Compute if DE and/or BC are used to hold the result value
1971 o If (DE is used, or in the send set) and is not used in the result, push.
1972 o If BC is used and is not in the result, push
1974 o If DE is used in the send set, fetch
1975 o If HL is used in the send set, fetch
1979 if (_G.saves.saved == FALSE) {
1980 bool deInUse, bcInUse;
1982 bool bcInRet = FALSE, deInRet = FALSE;
1985 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1987 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1988 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1990 deSending = (sendSetSize > 1);
1992 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1994 if (bcInUse && bcInRet == FALSE) {
1996 _G.stack.pushedBC = TRUE;
1998 if (deInUse && deInRet == FALSE) {
2000 _G.stack.pushedDE = TRUE;
2003 _G.saves.saved = TRUE;
2006 /* Already saved. */
2010 /*-----------------------------------------------------------------*/
2011 /* genIpush - genrate code for pushing this gets a little complex */
2012 /*-----------------------------------------------------------------*/
2014 genIpush (iCode * ic)
2016 int size, offset = 0;
2019 /* if this is not a parm push : ie. it is spill push
2020 and spill push is always done on the local stack */
2023 wassertl(0, "Encountered an unsupported spill push.");
2027 if (_G.saves.saved == FALSE) {
2028 /* Caller saves, and this is the first iPush. */
2029 /* Scan ahead until we find the function that we are pushing parameters to.
2030 Count the number of addSets on the way to figure out what registers
2031 are used in the send set.
2034 iCode *walk = ic->next;
2037 if (walk->op == SEND) {
2040 else if (walk->op == CALL || walk->op == PCALL) {
2049 _saveRegsForCall(walk, nAddSets);
2052 /* Already saved by another iPush. */
2055 /* then do the push */
2056 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2058 size = AOP_SIZE (IC_LEFT (ic));
2060 if (isPair (AOP (IC_LEFT (ic))))
2062 _G.stack.pushed += 2;
2063 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2069 fetchHL (AOP (IC_LEFT (ic)));
2071 spillPair (PAIR_HL);
2072 _G.stack.pushed += 2;
2077 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2079 spillPair (PAIR_HL);
2080 _G.stack.pushed += 2;
2081 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2083 spillPair (PAIR_HL);
2084 _G.stack.pushed += 2;
2090 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2092 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2094 emit2 ("ld a,(%s)", l);
2098 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2099 emit2 ("ld a,%s", l);
2107 freeAsmop (IC_LEFT (ic), NULL, ic);
2110 /*-----------------------------------------------------------------*/
2111 /* genIpop - recover the registers: can happen only for spilling */
2112 /*-----------------------------------------------------------------*/
2114 genIpop (iCode * ic)
2119 /* if the temp was not pushed then */
2120 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2123 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2124 size = AOP_SIZE (IC_LEFT (ic));
2125 offset = (size - 1);
2126 if (isPair (AOP (IC_LEFT (ic))))
2128 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2136 spillPair (PAIR_HL);
2137 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2141 freeAsmop (IC_LEFT (ic), NULL, ic);
2144 /* This is quite unfortunate */
2146 setArea (int inHome)
2149 static int lastArea = 0;
2151 if (_G.in_home != inHome) {
2153 const char *sz = port->mem.code_name;
2154 port->mem.code_name = "HOME";
2155 emit2("!area", CODE_NAME);
2156 port->mem.code_name = sz;
2159 emit2("!area", CODE_NAME); */
2160 _G.in_home = inHome;
2171 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2175 symbol *sym = OP_SYMBOL (op);
2177 if (sym->isspilt || sym->nRegs == 0)
2180 aopOp (op, ic, FALSE, FALSE);
2183 if (aop->type == AOP_REG)
2186 for (i = 0; i < aop->size; i++)
2188 if (pairId == PAIR_DE)
2190 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2191 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2193 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2196 else if (pairId == PAIR_BC)
2198 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2199 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2201 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2211 freeAsmop (IC_LEFT (ic), NULL, ic);
2215 /** Emit the code for a call statement
2218 emitCall (iCode * ic, bool ispcall)
2220 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2222 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2224 /* if caller saves & we have not saved then */
2230 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2232 /* if send set is not empty then assign */
2237 int nSend = elementsInSet(_G.sendSet);
2238 bool swapped = FALSE;
2240 int _z80_sendOrder[] = {
2245 /* Check if the parameters are swapped. If so route through hl instead. */
2246 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2248 sic = setFirstItem(_G.sendSet);
2249 sic = setNextItem(_G.sendSet);
2251 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2252 /* The second send value is loaded from one the one that holds the first
2253 send, i.e. it is overwritten. */
2254 /* Cache the first in HL, and load the second from HL instead. */
2255 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2256 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2262 for (sic = setFirstItem (_G.sendSet); sic;
2263 sic = setNextItem (_G.sendSet))
2266 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2268 size = AOP_SIZE (IC_LEFT (sic));
2269 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2270 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2272 // PENDING: Mild hack
2273 if (swapped == TRUE && send == 1) {
2275 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2278 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2280 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2283 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2287 freeAsmop (IC_LEFT (sic), NULL, sic);
2294 if (IS_BANKEDCALL (detype))
2296 werror (W_INDIR_BANKED);
2298 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2300 if (isLitWord (AOP (IC_LEFT (ic))))
2302 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2306 symbol *rlbl = newiTempLabel (NULL);
2307 spillPair (PAIR_HL);
2308 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2310 _G.stack.pushed += 2;
2312 fetchHL (AOP (IC_LEFT (ic)));
2314 emit2 ("!tlabeldef", (rlbl->key + 100));
2315 _G.stack.pushed -= 2;
2317 freeAsmop (IC_LEFT (ic), NULL, ic);
2321 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2322 OP_SYMBOL (IC_LEFT (ic))->rname :
2323 OP_SYMBOL (IC_LEFT (ic))->name;
2324 if (IS_BANKEDCALL (detype))
2326 emit2 ("call banked_call");
2327 emit2 ("!dws", name);
2328 emit2 ("!dw !bankimmeds", name);
2333 emit2 ("call %s", name);
2338 /* Mark the regsiters as restored. */
2339 _G.saves.saved = FALSE;
2341 /* if we need assign a result value */
2342 if ((IS_ITEMP (IC_RESULT (ic)) &&
2343 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2344 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2345 IS_TRUE_SYMOP (IC_RESULT (ic)))
2348 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2350 assignResultValue (IC_RESULT (ic));
2352 freeAsmop (IC_RESULT (ic), NULL, ic);
2355 /* adjust the stack for parameters if required */
2358 int i = ic->parmBytes;
2360 _G.stack.pushed -= i;
2363 emit2 ("!ldaspsp", i);
2370 emit2 ("ld hl,#%d", i);
2371 emit2 ("add hl,sp");
2388 if (_G.stack.pushedDE)
2390 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2391 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2393 if (dInUse && eInUse)
2409 wassertl (0, "Neither D or E were in use but it was pushed.");
2411 _G.stack.pushedDE = FALSE;
2414 if (_G.stack.pushedBC)
2416 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2417 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2419 // If both B and C are used in the return value, then we won't get
2421 if (bInUse && cInUse)
2437 wassertl (0, "Neither B or C were in use but it was pushed.");
2439 _G.stack.pushedBC = FALSE;
2443 /*-----------------------------------------------------------------*/
2444 /* genCall - generates a call statement */
2445 /*-----------------------------------------------------------------*/
2447 genCall (iCode * ic)
2449 emitCall (ic, FALSE);
2452 /*-----------------------------------------------------------------*/
2453 /* genPcall - generates a call by pointer statement */
2454 /*-----------------------------------------------------------------*/
2456 genPcall (iCode * ic)
2458 emitCall (ic, TRUE);
2461 /*-----------------------------------------------------------------*/
2462 /* resultRemat - result is rematerializable */
2463 /*-----------------------------------------------------------------*/
2465 resultRemat (iCode * ic)
2467 if (SKIP_IC (ic) || ic->op == IFX)
2470 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2472 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2473 if (sym->remat && !POINTER_SET (ic))
2480 extern set *publics;
2482 /*-----------------------------------------------------------------*/
2483 /* genFunction - generated code for function entry */
2484 /*-----------------------------------------------------------------*/
2486 genFunction (iCode * ic)
2488 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2492 bool bcInUse = FALSE;
2493 bool deInUse = FALSE;
2496 setArea (IS_NONBANKED (sym->etype));
2498 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2501 _G.receiveOffset = 0;
2503 /* Record the last function name for debugging. */
2504 _G.lastFunctionName = sym->rname;
2506 /* Create the function header */
2507 emit2 ("!functionheader", sym->name);
2508 /* PENDING: portability. */
2509 emit2 ("__%s_start:", sym->rname);
2510 emit2 ("!functionlabeldef", sym->rname);
2512 if (options.profile)
2514 emit2 ("!profileenter");
2517 fetype = getSpec (operandType (IC_LEFT (ic)));
2519 /* if critical function then turn interrupts off */
2520 if (SPEC_CRTCL (fetype))
2523 /* if this is an interrupt service routine then save all potentially used registers. */
2524 if (IS_ISR (sym->etype))
2529 /* PENDING: callee-save etc */
2531 _G.stack.param_offset = 0;
2534 /* Detect which registers are used. */
2538 for (i = 0; i < sym->regsUsed->size; i++)
2540 if (bitVectBitValue (sym->regsUsed, i))
2554 /* Other systems use DE as a temporary. */
2565 _G.stack.param_offset += 2;
2568 _G.stack.pushedBC = bcInUse;
2573 _G.stack.param_offset += 2;
2576 _G.stack.pushedDE = deInUse;
2579 /* adjust the stack for the function */
2580 _G.stack.last = sym->stack;
2583 emit2 ("!enterx", sym->stack);
2586 _G.stack.offset = sym->stack;
2589 /*-----------------------------------------------------------------*/
2590 /* genEndFunction - generates epilogue for functions */
2591 /*-----------------------------------------------------------------*/
2593 genEndFunction (iCode * ic)
2595 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2597 if (IS_ISR (sym->etype))
2599 wassertl (0, "Tried to close an interrupt support function");
2603 if (SPEC_CRTCL (sym->etype))
2606 /* PENDING: calleeSave */
2608 if (_G.stack.offset)
2610 emit2 ("!leavex", _G.stack.offset);
2618 if (_G.stack.pushedDE)
2621 _G.stack.pushedDE = FALSE;
2624 if (_G.stack.pushedDE)
2627 _G.stack.pushedDE = FALSE;
2631 if (options.profile)
2633 emit2 ("!profileexit");
2637 /* Both baned and non-banked just ret */
2640 /* PENDING: portability. */
2641 emit2 ("__%s_end:", sym->rname);
2643 _G.flushStatics = 1;
2644 _G.stack.pushed = 0;
2645 _G.stack.offset = 0;
2648 /*-----------------------------------------------------------------*/
2649 /* genRet - generate code for return statement */
2650 /*-----------------------------------------------------------------*/
2655 /* Errk. This is a hack until I can figure out how
2656 to cause dehl to spill on a call */
2657 int size, offset = 0;
2659 /* if we have no return value then
2660 just generate the "ret" */
2664 /* we have something to return then
2665 move the return value into place */
2666 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2667 size = AOP_SIZE (IC_LEFT (ic));
2669 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2673 emit2 ("ld de,%s", l);
2677 emit2 ("ld hl,%s", l);
2682 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2684 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2685 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2691 l = aopGet (AOP (IC_LEFT (ic)), offset,
2693 if (strcmp (_fReturn[offset], l))
2694 emit2 ("ld %s,%s", _fReturn[offset++], l);
2698 freeAsmop (IC_LEFT (ic), NULL, ic);
2701 /* generate a jump to the return label
2702 if the next is not the return statement */
2703 if (!(ic->next && ic->next->op == LABEL &&
2704 IC_LABEL (ic->next) == returnLabel))
2706 emit2 ("jp !tlabel", returnLabel->key + 100);
2709 /*-----------------------------------------------------------------*/
2710 /* genLabel - generates a label */
2711 /*-----------------------------------------------------------------*/
2713 genLabel (iCode * ic)
2715 /* special case never generate */
2716 if (IC_LABEL (ic) == entryLabel)
2719 emitLabel (IC_LABEL (ic)->key + 100);
2722 /*-----------------------------------------------------------------*/
2723 /* genGoto - generates a ljmp */
2724 /*-----------------------------------------------------------------*/
2726 genGoto (iCode * ic)
2728 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2731 /*-----------------------------------------------------------------*/
2732 /* genPlusIncr :- does addition with increment if possible */
2733 /*-----------------------------------------------------------------*/
2735 genPlusIncr (iCode * ic)
2737 unsigned int icount;
2738 unsigned int size = getDataSize (IC_RESULT (ic));
2739 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2741 /* will try to generate an increment */
2742 /* if the right side is not a literal
2744 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2747 emitDebug ("; genPlusIncr");
2749 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2751 /* If result is a pair */
2752 if (resultId != PAIR_INVALID)
2754 if (isLitWord (AOP (IC_LEFT (ic))))
2756 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2759 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2761 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2762 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2768 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2772 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2773 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2777 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2782 /* if the literal value of the right hand side
2783 is greater than 4 then it is not worth it */
2787 /* if increment 16 bits in register */
2788 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2794 symbol *tlbl = NULL;
2795 tlbl = newiTempLabel (NULL);
2798 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2801 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2804 emitLabel (tlbl->key + 100);
2808 /* if the sizes are greater than 1 then we cannot */
2809 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2810 AOP_SIZE (IC_LEFT (ic)) > 1)
2813 /* we can if the aops of the left & result match or
2814 if they are in registers and the registers are the
2816 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2820 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2828 /*-----------------------------------------------------------------*/
2829 /* outBitAcc - output a bit in acc */
2830 /*-----------------------------------------------------------------*/
2832 outBitAcc (operand * result)
2834 symbol *tlbl = newiTempLabel (NULL);
2835 /* if the result is a bit */
2836 if (AOP_TYPE (result) == AOP_CRY)
2838 wassertl (0, "Tried to write A into a bit");
2842 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2843 emit2 ("ld a,!one");
2844 emitLabel (tlbl->key + 100);
2850 couldDestroyCarry (asmop *aop)
2854 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
2863 shiftIntoPair (int idx, asmop *aop)
2865 PAIR_ID id = PAIR_INVALID;
2867 wassertl (IS_Z80, "Only implemented for the Z80");
2868 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
2880 wassertl (0, "Internal error - hit default case");
2883 emitDebug ("; Shift into pair idx %u", idx);
2887 setupPair (PAIR_HL, aop, 0);
2891 setupPair (PAIR_IY, aop, 0);
2893 emit2 ("pop %s", _pairs[id].name);
2896 aop->type = AOP_PAIRPTR;
2897 aop->aopu.aop_pairId = id;
2898 _G.pairs[id].offset = 0;
2899 _G.pairs[id].last_type = aop->type;
2903 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
2905 wassert (left && right);
2909 if (couldDestroyCarry (right) && couldDestroyCarry (result))
2911 shiftIntoPair (0, right);
2912 shiftIntoPair (1, result);
2914 else if (couldDestroyCarry (right))
2916 shiftIntoPair (0, right);
2918 else if (couldDestroyCarry (result))
2920 shiftIntoPair (0, result);
2929 /*-----------------------------------------------------------------*/
2930 /* genPlus - generates code for addition */
2931 /*-----------------------------------------------------------------*/
2933 genPlus (iCode * ic)
2935 int size, offset = 0;
2937 /* special cases :- */
2939 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2940 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2941 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2943 /* Swap the left and right operands if:
2945 if literal, literal on the right or
2946 if left requires ACC or right is already
2949 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2950 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2951 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2953 operand *t = IC_RIGHT (ic);
2954 IC_RIGHT (ic) = IC_LEFT (ic);
2958 /* if both left & right are in bit
2960 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2961 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2964 wassertl (0, "Tried to add two bits");
2967 /* if left in bit space & right literal */
2968 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2969 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2971 /* Can happen I guess */
2972 wassertl (0, "Tried to add a bit to a literal");
2975 /* if I can do an increment instead
2976 of add then GOOD for ME */
2977 if (genPlusIncr (ic) == TRUE)
2980 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
2982 size = getDataSize (IC_RESULT (ic));
2984 /* Special case when left and right are constant */
2985 if (isPair (AOP (IC_RESULT (ic))))
2988 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2989 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2991 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2997 sprintf (buffer, "#(%s + %s)", left, right);
2998 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3003 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3005 /* Fetch into HL then do the add */
3006 spillPair (PAIR_HL);
3007 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3008 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3013 ld hl,sp+n trashes C so we cant afford to do it during an
3014 add with stack based varibles. Worst case is:
3027 So you cant afford to load up hl if either left, right, or result
3028 is on the stack (*sigh*) The alt is:
3036 Combinations in here are:
3037 * If left or right are in bc then the loss is small - trap later
3038 * If the result is in bc then the loss is also small
3042 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3043 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3044 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3046 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3047 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3048 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3049 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3051 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3053 /* Swap left and right */
3054 operand *t = IC_RIGHT (ic);
3055 IC_RIGHT (ic) = IC_LEFT (ic);
3058 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3060 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3061 emit2 ("add hl,bc");
3065 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3066 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3067 emit2 ("add hl,de");
3069 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3075 /* Be paranoid on the GB with 4 byte variables due to how C
3076 can be trashed by lda hl,n(sp).
3078 _gbz80_emitAddSubLong (ic, TRUE);
3083 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3087 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3089 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3092 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3095 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3099 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3102 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3105 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3107 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3111 freeAsmop (IC_LEFT (ic), NULL, ic);
3112 freeAsmop (IC_RIGHT (ic), NULL, ic);
3113 freeAsmop (IC_RESULT (ic), NULL, ic);
3117 /*-----------------------------------------------------------------*/
3118 /* genMinusDec :- does subtraction with deccrement if possible */
3119 /*-----------------------------------------------------------------*/
3121 genMinusDec (iCode * ic)
3123 unsigned int icount;
3124 unsigned int size = getDataSize (IC_RESULT (ic));
3126 /* will try to generate an increment */
3127 /* if the right side is not a literal we cannot */
3128 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3131 /* if the literal value of the right hand side
3132 is greater than 4 then it is not worth it */
3133 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3136 size = getDataSize (IC_RESULT (ic));
3138 /* if decrement 16 bits in register */
3139 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3140 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3143 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3147 /* If result is a pair */
3148 if (isPair (AOP (IC_RESULT (ic))))
3150 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
3151 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
3153 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3157 /* if increment 16 bits in register */
3158 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3162 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3165 emit2 ("dec %s", _getTempPairName());
3168 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3174 /* if the sizes are greater than 1 then we cannot */
3175 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3176 AOP_SIZE (IC_LEFT (ic)) > 1)
3179 /* we can if the aops of the left & result match or if they are in
3180 registers and the registers are the same */
3181 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3184 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3191 /*-----------------------------------------------------------------*/
3192 /* genMinus - generates code for subtraction */
3193 /*-----------------------------------------------------------------*/
3195 genMinus (iCode * ic)
3197 int size, offset = 0;
3198 unsigned long lit = 0L;
3200 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3201 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3202 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3204 /* special cases :- */
3205 /* if both left & right are in bit space */
3206 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3207 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3209 wassertl (0, "Tried to subtract two bits");
3213 /* if I can do an decrement instead of subtract then GOOD for ME */
3214 if (genMinusDec (ic) == TRUE)
3217 size = getDataSize (IC_RESULT (ic));
3219 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3224 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3228 /* Same logic as genPlus */
3231 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3232 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3233 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3235 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3236 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3237 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3238 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3240 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3241 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3243 if (left == PAIR_INVALID && right == PAIR_INVALID)
3248 else if (right == PAIR_INVALID)
3250 else if (left == PAIR_INVALID)
3253 fetchPair (left, AOP (IC_LEFT (ic)));
3254 /* Order is important. Right may be HL */
3255 fetchPair (right, AOP (IC_RIGHT (ic)));
3257 emit2 ("ld a,%s", _pairs[left].l);
3258 emit2 ("sub a,%s", _pairs[right].l);
3260 emit2 ("ld a,%s", _pairs[left].h);
3261 emit2 ("sbc a,%s", _pairs[right].h);
3263 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3264 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3270 /* Be paranoid on the GB with 4 byte variables due to how C
3271 can be trashed by lda hl,n(sp).
3273 _gbz80_emitAddSubLong (ic, FALSE);
3278 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3280 /* if literal, add a,#-lit, else normal subb */
3283 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3284 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3288 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3291 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3295 /* first add without previous c */
3297 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3299 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3301 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3304 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3305 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3306 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3308 wassertl (0, "Tried to subtract on a long pointer");
3312 freeAsmop (IC_LEFT (ic), NULL, ic);
3313 freeAsmop (IC_RIGHT (ic), NULL, ic);
3314 freeAsmop (IC_RESULT (ic), NULL, ic);
3317 /*-----------------------------------------------------------------*/
3318 /* genMult - generates code for multiplication */
3319 /*-----------------------------------------------------------------*/
3321 genMult (iCode * ic)
3323 /* Shouldn't occur - all done through function calls */
3324 wassertl (0, "Multiplication is handled through support function calls");
3327 /*-----------------------------------------------------------------*/
3328 /* genDiv - generates code for division */
3329 /*-----------------------------------------------------------------*/
3333 /* Shouldn't occur - all done through function calls */
3334 wassertl (0, "Division is handled through support function calls");
3337 /*-----------------------------------------------------------------*/
3338 /* genMod - generates code for division */
3339 /*-----------------------------------------------------------------*/
3343 /* Shouldn't occur - all done through function calls */
3347 /*-----------------------------------------------------------------*/
3348 /* genIfxJump :- will create a jump depending on the ifx */
3349 /*-----------------------------------------------------------------*/
3351 genIfxJump (iCode * ic, char *jval)
3356 /* if true label then we jump if condition
3360 jlbl = IC_TRUE (ic);
3361 if (!strcmp (jval, "a"))
3365 else if (!strcmp (jval, "c"))
3369 else if (!strcmp (jval, "nc"))
3375 /* The buffer contains the bit on A that we should test */
3381 /* false label is present */
3382 jlbl = IC_FALSE (ic);
3383 if (!strcmp (jval, "a"))
3387 else if (!strcmp (jval, "c"))
3391 else if (!strcmp (jval, "nc"))
3397 /* The buffer contains the bit on A that we should test */
3401 /* Z80 can do a conditional long jump */
3402 if (!strcmp (jval, "a"))
3406 else if (!strcmp (jval, "c"))
3409 else if (!strcmp (jval, "nc"))
3414 emit2 ("bit %s,a", jval);
3416 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3418 /* mark the icode as generated */
3424 _getPairIdName (PAIR_ID id)
3426 return _pairs[id].name;
3430 /** Generic compare for > or <
3433 genCmp (operand * left, operand * right,
3434 operand * result, iCode * ifx, int sign)
3436 int size, offset = 0;
3437 unsigned long lit = 0L;
3438 bool swap_sense = FALSE;
3440 /* if left & right are bit variables */
3441 if (AOP_TYPE (left) == AOP_CRY &&
3442 AOP_TYPE (right) == AOP_CRY)
3444 /* Cant happen on the Z80 */
3445 wassertl (0, "Tried to compare two bits");
3449 /* subtract right from left if at the
3450 end the carry flag is set then we know that
3451 left is greater than right */
3452 size = max (AOP_SIZE (left), AOP_SIZE (right));
3454 /* if unsigned char cmp with lit, just compare */
3456 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3458 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3461 emit2 ("xor a,!immedbyte", 0x80);
3462 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3465 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3467 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3469 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3470 // Pull left into DE and right into HL
3471 aopGet (AOP(left), LSB, FALSE);
3474 aopGet (AOP(right), LSB, FALSE);
3478 if (size == 0 && sign)
3480 // Highest byte when signed needs the bits flipped
3483 emit2 ("ld a,(de)");
3484 emit2 ("xor #0x80");
3486 emit2 ("ld a,(hl)");
3487 emit2 ("xor #0x80");
3491 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3495 emit2 ("ld a,(de)");
3496 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3506 spillPair (PAIR_HL);
3508 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3510 setupPair (PAIR_HL, AOP (left), 0);
3511 aopGet (AOP(right), LSB, FALSE);
3515 if (size == 0 && sign)
3517 // Highest byte when signed needs the bits flipped
3520 emit2 ("ld a,(hl)");
3521 emit2 ("xor #0x80");
3523 emit2 ("ld a,%d(iy)", offset);
3524 emit2 ("xor #0x80");
3528 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3532 emit2 ("ld a,(hl)");
3533 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3542 spillPair (PAIR_HL);
3543 spillPair (PAIR_IY);
3547 if (AOP_TYPE (right) == AOP_LIT)
3549 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3550 /* optimize if(x < 0) or if(x >= 0) */
3555 /* No sign so it's always false */
3560 /* Just load in the top most bit */
3561 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3562 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3564 genIfxJump (ifx, "7");
3576 /* First setup h and l contaning the top most bytes XORed */
3577 bool fDidXor = FALSE;
3578 if (AOP_TYPE (left) == AOP_LIT)
3580 unsigned long lit = (unsigned long)
3581 floatFromVal (AOP (left)->aopu.aop_lit);
3582 emit2 ("ld %s,!immedbyte", _fTmp[0],
3583 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3587 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3588 emit2 ("xor a,!immedbyte", 0x80);
3589 emit2 ("ld %s,a", _fTmp[0]);
3592 if (AOP_TYPE (right) == AOP_LIT)
3594 unsigned long lit = (unsigned long)
3595 floatFromVal (AOP (right)->aopu.aop_lit);
3596 emit2 ("ld %s,!immedbyte", _fTmp[1],
3597 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3601 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3602 emit2 ("xor a,!immedbyte", 0x80);
3603 emit2 ("ld %s,a", _fTmp[1]);
3609 /* Do a long subtract */
3612 _moveA (aopGet (AOP (left), offset, FALSE));
3614 if (sign && size == 0)
3616 emit2 ("ld a,%s", _fTmp[0]);
3617 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3621 /* Subtract through, propagating the carry */
3622 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3630 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3632 outBitCLong (result, swap_sense);
3636 /* if the result is used in the next
3637 ifx conditional branch then generate
3638 code a little differently */
3640 genIfxJump (ifx, swap_sense ? "nc" : "c");
3642 outBitCLong (result, swap_sense);
3643 /* leave the result in acc */
3647 /*-----------------------------------------------------------------*/
3648 /* genCmpGt :- greater than comparison */
3649 /*-----------------------------------------------------------------*/
3651 genCmpGt (iCode * ic, iCode * ifx)
3653 operand *left, *right, *result;
3654 sym_link *letype, *retype;
3657 left = IC_LEFT (ic);
3658 right = IC_RIGHT (ic);
3659 result = IC_RESULT (ic);
3661 letype = getSpec (operandType (left));
3662 retype = getSpec (operandType (right));
3663 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3664 /* assign the amsops */
3665 aopOp (left, ic, FALSE, FALSE);
3666 aopOp (right, ic, FALSE, FALSE);
3667 aopOp (result, ic, TRUE, FALSE);
3669 genCmp (right, left, result, ifx, sign);
3671 freeAsmop (left, NULL, ic);
3672 freeAsmop (right, NULL, ic);
3673 freeAsmop (result, NULL, ic);
3676 /*-----------------------------------------------------------------*/
3677 /* genCmpLt - less than comparisons */
3678 /*-----------------------------------------------------------------*/
3680 genCmpLt (iCode * ic, iCode * ifx)
3682 operand *left, *right, *result;
3683 sym_link *letype, *retype;
3686 left = IC_LEFT (ic);
3687 right = IC_RIGHT (ic);
3688 result = IC_RESULT (ic);
3690 letype = getSpec (operandType (left));
3691 retype = getSpec (operandType (right));
3692 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3694 /* assign the amsops */
3695 aopOp (left, ic, FALSE, FALSE);
3696 aopOp (right, ic, FALSE, FALSE);
3697 aopOp (result, ic, TRUE, FALSE);
3699 genCmp (left, right, result, ifx, sign);
3701 freeAsmop (left, NULL, ic);
3702 freeAsmop (right, NULL, ic);
3703 freeAsmop (result, NULL, ic);
3706 /*-----------------------------------------------------------------*/
3707 /* gencjneshort - compare and jump if not equal */
3708 /*-----------------------------------------------------------------*/
3710 gencjneshort (operand * left, operand * right, symbol * lbl)
3712 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3714 unsigned long lit = 0L;
3716 /* Swap the left and right if it makes the computation easier */
3717 if (AOP_TYPE (left) == AOP_LIT)
3724 if (AOP_TYPE (right) == AOP_LIT)
3725 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3727 /* if the right side is a literal then anything goes */
3728 if (AOP_TYPE (right) == AOP_LIT &&
3729 AOP_TYPE (left) != AOP_DIR)
3733 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3738 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
3745 emit2 ("jp nz,!tlabel", lbl->key + 100);
3751 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3752 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3755 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3756 emit2 ("jp nz,!tlabel", lbl->key + 100);
3761 /* if the right side is in a register or in direct space or
3762 if the left is a pointer register & right is not */
3763 else if (AOP_TYPE (right) == AOP_REG ||
3764 AOP_TYPE (right) == AOP_DIR ||
3765 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3769 _moveA (aopGet (AOP (left), offset, FALSE));
3770 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3771 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3773 emit2 ("jp nz,!tlabel", lbl->key + 100);
3776 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3777 emit2 ("jp nz,!tlabel", lbl->key + 100);
3784 /* right is a pointer reg need both a & b */
3785 /* PENDING: is this required? */
3788 _moveA (aopGet (AOP (right), offset, FALSE));
3789 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3790 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3796 /*-----------------------------------------------------------------*/
3797 /* gencjne - compare and jump if not equal */
3798 /*-----------------------------------------------------------------*/
3800 gencjne (operand * left, operand * right, symbol * lbl)
3802 symbol *tlbl = newiTempLabel (NULL);
3804 gencjneshort (left, right, lbl);
3807 emit2 ("ld a,!one");
3808 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3809 emitLabel (lbl->key + 100);
3811 emitLabel (tlbl->key + 100);
3814 /*-----------------------------------------------------------------*/
3815 /* genCmpEq - generates code for equal to */
3816 /*-----------------------------------------------------------------*/
3818 genCmpEq (iCode * ic, iCode * ifx)
3820 operand *left, *right, *result;
3822 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3823 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3824 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3826 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3828 /* Swap operands if it makes the operation easier. ie if:
3829 1. Left is a literal.
3831 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3833 operand *t = IC_RIGHT (ic);
3834 IC_RIGHT (ic) = IC_LEFT (ic);
3838 if (ifx && !AOP_SIZE (result))
3841 /* if they are both bit variables */
3842 if (AOP_TYPE (left) == AOP_CRY &&
3843 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3845 wassertl (0, "Tried to compare two bits");
3849 tlbl = newiTempLabel (NULL);
3850 gencjneshort (left, right, tlbl);
3853 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3854 emitLabel (tlbl->key + 100);
3858 /* PENDING: do this better */
3859 symbol *lbl = newiTempLabel (NULL);
3860 emit2 ("!shortjp !tlabel", lbl->key + 100);
3861 emitLabel (tlbl->key + 100);
3862 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3863 emitLabel (lbl->key + 100);
3866 /* mark the icode as generated */
3871 /* if they are both bit variables */
3872 if (AOP_TYPE (left) == AOP_CRY &&
3873 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3875 wassertl (0, "Tried to compare a bit to either a literal or another bit");
3879 gencjne (left, right, newiTempLabel (NULL));
3880 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3886 genIfxJump (ifx, "a");
3889 /* if the result is used in an arithmetic operation
3890 then put the result in place */
3891 if (AOP_TYPE (result) != AOP_CRY)
3895 /* leave the result in acc */
3899 freeAsmop (left, NULL, ic);
3900 freeAsmop (right, NULL, ic);
3901 freeAsmop (result, NULL, ic);
3904 /*-----------------------------------------------------------------*/
3905 /* ifxForOp - returns the icode containing the ifx for operand */
3906 /*-----------------------------------------------------------------*/
3908 ifxForOp (operand * op, iCode * ic)
3910 /* if true symbol then needs to be assigned */
3911 if (IS_TRUE_SYMOP (op))
3914 /* if this has register type condition and
3915 the next instruction is ifx with the same operand
3916 and live to of the operand is upto the ifx only then */
3918 ic->next->op == IFX &&
3919 IC_COND (ic->next)->key == op->key &&
3920 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3926 /*-----------------------------------------------------------------*/
3927 /* genAndOp - for && operation */
3928 /*-----------------------------------------------------------------*/
3930 genAndOp (iCode * ic)
3932 operand *left, *right, *result;
3935 /* note here that && operations that are in an if statement are
3936 taken away by backPatchLabels only those used in arthmetic
3937 operations remain */
3938 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3939 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3940 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3942 /* if both are bit variables */
3943 if (AOP_TYPE (left) == AOP_CRY &&
3944 AOP_TYPE (right) == AOP_CRY)
3946 wassertl (0, "Tried to and two bits");
3950 tlbl = newiTempLabel (NULL);
3952 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3954 emitLabel (tlbl->key + 100);
3958 freeAsmop (left, NULL, ic);
3959 freeAsmop (right, NULL, ic);
3960 freeAsmop (result, NULL, ic);
3963 /*-----------------------------------------------------------------*/
3964 /* genOrOp - for || operation */
3965 /*-----------------------------------------------------------------*/
3967 genOrOp (iCode * ic)
3969 operand *left, *right, *result;
3972 /* note here that || operations that are in an
3973 if statement are taken away by backPatchLabels
3974 only those used in arthmetic operations remain */
3975 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3976 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3977 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3979 /* if both are bit variables */
3980 if (AOP_TYPE (left) == AOP_CRY &&
3981 AOP_TYPE (right) == AOP_CRY)
3983 wassertl (0, "Tried to OR two bits");
3987 tlbl = newiTempLabel (NULL);
3989 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3991 emitLabel (tlbl->key + 100);
3995 freeAsmop (left, NULL, ic);
3996 freeAsmop (right, NULL, ic);
3997 freeAsmop (result, NULL, ic);
4000 /*-----------------------------------------------------------------*/
4001 /* isLiteralBit - test if lit == 2^n */
4002 /*-----------------------------------------------------------------*/
4004 isLiteralBit (unsigned long lit)
4006 unsigned long pw[32] =
4007 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4008 0x100L, 0x200L, 0x400L, 0x800L,
4009 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4010 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4011 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4012 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4013 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4016 for (idx = 0; idx < 32; idx++)
4022 /*-----------------------------------------------------------------*/
4023 /* jmpTrueOrFalse - */
4024 /*-----------------------------------------------------------------*/
4026 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4028 // ugly but optimized by peephole
4031 symbol *nlbl = newiTempLabel (NULL);
4032 emit2 ("jp !tlabel", nlbl->key + 100);
4033 emitLabel (tlbl->key + 100);
4034 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4035 emitLabel (nlbl->key + 100);
4039 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4040 emitLabel (tlbl->key + 100);
4045 /*-----------------------------------------------------------------*/
4046 /* genAnd - code for and */
4047 /*-----------------------------------------------------------------*/
4049 genAnd (iCode * ic, iCode * ifx)
4051 operand *left, *right, *result;
4052 int size, offset = 0;
4053 unsigned long lit = 0L;
4056 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4057 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4058 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4060 /* if left is a literal & right is not then exchange them */
4061 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4062 AOP_NEEDSACC (left))
4064 operand *tmp = right;
4069 /* if result = right then exchange them */
4070 if (sameRegs (AOP (result), AOP (right)))
4072 operand *tmp = right;
4077 /* if right is bit then exchange them */
4078 if (AOP_TYPE (right) == AOP_CRY &&
4079 AOP_TYPE (left) != AOP_CRY)
4081 operand *tmp = right;
4085 if (AOP_TYPE (right) == AOP_LIT)
4086 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4088 size = AOP_SIZE (result);
4090 if (AOP_TYPE (left) == AOP_CRY)
4092 wassertl (0, "Tried to perform an AND with a bit as an operand");
4096 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4097 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4098 if ((AOP_TYPE (right) == AOP_LIT) &&
4099 (AOP_TYPE (result) == AOP_CRY) &&
4100 (AOP_TYPE (left) != AOP_CRY))
4102 symbol *tlbl = newiTempLabel (NULL);
4103 int sizel = AOP_SIZE (left);
4106 /* PENDING: Test case for this. */
4111 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4113 _moveA (aopGet (AOP (left), offset, FALSE));
4114 if (bytelit != 0x0FFL)
4116 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4123 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4127 // bit = left & literal
4131 emit2 ("!tlabeldef", tlbl->key + 100);
4133 // if(left & literal)
4138 jmpTrueOrFalse (ifx, tlbl);
4146 /* if left is same as result */
4147 if (sameRegs (AOP (result), AOP (left)))
4149 for (; size--; offset++)
4151 if (AOP_TYPE (right) == AOP_LIT)
4153 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4158 aopPut (AOP (result), "!zero", offset);
4161 _moveA (aopGet (AOP (left), offset, FALSE));
4163 aopGet (AOP (right), offset, FALSE));
4164 aopPut (AOP (left), "a", offset);
4171 if (AOP_TYPE (left) == AOP_ACC)
4173 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4177 _moveA (aopGet (AOP (left), offset, FALSE));
4179 aopGet (AOP (right), offset, FALSE));
4180 aopPut (AOP (left), "a", offset);
4187 // left & result in different registers
4188 if (AOP_TYPE (result) == AOP_CRY)
4190 wassertl (0, "Tried to AND where the result is in carry");
4194 for (; (size--); offset++)
4197 // result = left & right
4198 if (AOP_TYPE (right) == AOP_LIT)
4200 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4202 aopPut (AOP (result),
4203 aopGet (AOP (left), offset, FALSE),
4207 else if (bytelit == 0)
4209 aopPut (AOP (result), "!zero", offset);
4213 // faster than result <- left, anl result,right
4214 // and better if result is SFR
4215 if (AOP_TYPE (left) == AOP_ACC)
4216 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4219 _moveA (aopGet (AOP (left), offset, FALSE));
4221 aopGet (AOP (right), offset, FALSE));
4223 aopPut (AOP (result), "a", offset);
4230 freeAsmop (left, NULL, ic);
4231 freeAsmop (right, NULL, ic);
4232 freeAsmop (result, NULL, ic);
4235 /*-----------------------------------------------------------------*/
4236 /* genOr - code for or */
4237 /*-----------------------------------------------------------------*/
4239 genOr (iCode * ic, iCode * ifx)
4241 operand *left, *right, *result;
4242 int size, offset = 0;
4243 unsigned long lit = 0L;
4246 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4247 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4248 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4250 /* if left is a literal & right is not then exchange them */
4251 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4252 AOP_NEEDSACC (left))
4254 operand *tmp = right;
4259 /* if result = right then exchange them */
4260 if (sameRegs (AOP (result), AOP (right)))
4262 operand *tmp = right;
4267 /* if right is bit then exchange them */
4268 if (AOP_TYPE (right) == AOP_CRY &&
4269 AOP_TYPE (left) != AOP_CRY)
4271 operand *tmp = right;
4275 if (AOP_TYPE (right) == AOP_LIT)
4276 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4278 size = AOP_SIZE (result);
4280 if (AOP_TYPE (left) == AOP_CRY)
4282 wassertl (0, "Tried to OR where left is a bit");
4286 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4287 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4288 if ((AOP_TYPE (right) == AOP_LIT) &&
4289 (AOP_TYPE (result) == AOP_CRY) &&
4290 (AOP_TYPE (left) != AOP_CRY))
4292 symbol *tlbl = newiTempLabel (NULL);
4293 int sizel = AOP_SIZE (left);
4297 wassertl (0, "Result is assigned to a bit");
4299 /* PENDING: Modeled after the AND code which is inefficent. */
4302 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4304 _moveA (aopGet (AOP (left), offset, FALSE));
4305 /* OR with any literal is the same as OR with itself. */
4307 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4313 jmpTrueOrFalse (ifx, tlbl);
4318 /* if left is same as result */
4319 if (sameRegs (AOP (result), AOP (left)))
4321 for (; size--; offset++)
4323 if (AOP_TYPE (right) == AOP_LIT)
4325 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4329 _moveA (aopGet (AOP (left), offset, FALSE));
4331 aopGet (AOP (right), offset, FALSE));
4332 aopPut (AOP (result), "a", offset);
4337 if (AOP_TYPE (left) == AOP_ACC)
4338 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4341 _moveA (aopGet (AOP (left), offset, FALSE));
4343 aopGet (AOP (right), offset, FALSE));
4344 aopPut (AOP (result), "a", offset);
4351 // left & result in different registers
4352 if (AOP_TYPE (result) == AOP_CRY)
4354 wassertl (0, "Result of OR is in a bit");
4357 for (; (size--); offset++)
4360 // result = left & right
4361 if (AOP_TYPE (right) == AOP_LIT)
4363 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4365 aopPut (AOP (result),
4366 aopGet (AOP (left), offset, FALSE),
4371 // faster than result <- left, anl result,right
4372 // and better if result is SFR
4373 if (AOP_TYPE (left) == AOP_ACC)
4374 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4377 _moveA (aopGet (AOP (left), offset, FALSE));
4379 aopGet (AOP (right), offset, FALSE));
4381 aopPut (AOP (result), "a", offset);
4382 /* PENDING: something weird is going on here. Add exception. */
4383 if (AOP_TYPE (result) == AOP_ACC)
4389 freeAsmop (left, NULL, ic);
4390 freeAsmop (right, NULL, ic);
4391 freeAsmop (result, NULL, ic);
4394 /*-----------------------------------------------------------------*/
4395 /* genXor - code for xclusive or */
4396 /*-----------------------------------------------------------------*/
4398 genXor (iCode * ic, iCode * ifx)
4400 operand *left, *right, *result;
4401 int size, offset = 0;
4402 unsigned long lit = 0L;
4404 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4405 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4406 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4408 /* if left is a literal & right is not then exchange them */
4409 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4410 AOP_NEEDSACC (left))
4412 operand *tmp = right;
4417 /* if result = right then exchange them */
4418 if (sameRegs (AOP (result), AOP (right)))
4420 operand *tmp = right;
4425 /* if right is bit then exchange them */
4426 if (AOP_TYPE (right) == AOP_CRY &&
4427 AOP_TYPE (left) != AOP_CRY)
4429 operand *tmp = right;
4433 if (AOP_TYPE (right) == AOP_LIT)
4434 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4436 size = AOP_SIZE (result);
4438 if (AOP_TYPE (left) == AOP_CRY)
4440 wassertl (0, "Tried to XOR a bit");
4444 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4445 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4446 if ((AOP_TYPE (right) == AOP_LIT) &&
4447 (AOP_TYPE (result) == AOP_CRY) &&
4448 (AOP_TYPE (left) != AOP_CRY))
4450 symbol *tlbl = newiTempLabel (NULL);
4451 int sizel = AOP_SIZE (left);
4455 /* PENDING: Test case for this. */
4456 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4460 _moveA (aopGet (AOP (left), offset, FALSE));
4461 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4462 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4467 jmpTrueOrFalse (ifx, tlbl);
4471 wassertl (0, "Result of XOR was destined for a bit");
4476 /* if left is same as result */
4477 if (sameRegs (AOP (result), AOP (left)))
4479 for (; size--; offset++)
4481 if (AOP_TYPE (right) == AOP_LIT)
4483 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4487 _moveA (aopGet (AOP (right), offset, FALSE));
4489 aopGet (AOP (left), offset, FALSE));
4490 aopPut (AOP (result), "a", offset);
4495 if (AOP_TYPE (left) == AOP_ACC)
4497 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4501 _moveA (aopGet (AOP (right), offset, FALSE));
4503 aopGet (AOP (left), offset, FALSE));
4504 aopPut (AOP (result), "a", 0);
4511 // left & result in different registers
4512 if (AOP_TYPE (result) == AOP_CRY)
4514 wassertl (0, "Result of XOR is in a bit");
4517 for (; (size--); offset++)
4520 // result = left & right
4521 if (AOP_TYPE (right) == AOP_LIT)
4523 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4525 aopPut (AOP (result),
4526 aopGet (AOP (left), offset, FALSE),
4531 // faster than result <- left, anl result,right
4532 // and better if result is SFR
4533 if (AOP_TYPE (left) == AOP_ACC)
4535 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4539 _moveA (aopGet (AOP (right), offset, FALSE));
4541 aopGet (AOP (left), offset, FALSE));
4543 aopPut (AOP (result), "a", offset);
4548 freeAsmop (left, NULL, ic);
4549 freeAsmop (right, NULL, ic);
4550 freeAsmop (result, NULL, ic);
4553 /*-----------------------------------------------------------------*/
4554 /* genInline - write the inline code out */
4555 /*-----------------------------------------------------------------*/
4557 genInline (iCode * ic)
4559 char *buffer, *bp, *bp1;
4561 _G.lines.isInline += (!options.asmpeep);
4563 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4564 strcpy (buffer, IC_INLINE (ic));
4566 /* emit each line as a code */
4591 _G.lines.isInline -= (!options.asmpeep);
4595 /*-----------------------------------------------------------------*/
4596 /* genRRC - rotate right with carry */
4597 /*-----------------------------------------------------------------*/
4604 /*-----------------------------------------------------------------*/
4605 /* genRLC - generate code for rotate left with carry */
4606 /*-----------------------------------------------------------------*/
4613 /*-----------------------------------------------------------------*/
4614 /* genGetHbit - generates code get highest order bit */
4615 /*-----------------------------------------------------------------*/
4617 genGetHbit (iCode * ic)
4619 operand *left, *result;
4620 left = IC_LEFT (ic);
4621 result = IC_RESULT (ic);
4622 aopOp (left, ic, FALSE, FALSE);
4623 aopOp (result, ic, FALSE, FALSE);
4625 /* get the highest order byte into a */
4626 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4628 if (AOP_TYPE (result) == AOP_CRY)
4636 /* PENDING: For re-target. */
4642 freeAsmop (left, NULL, ic);
4643 freeAsmop (result, NULL, ic);
4647 emitRsh2 (asmop *aop, int size, int is_signed)
4653 const char *l = aopGet (aop, size, FALSE);
4656 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4666 /*-----------------------------------------------------------------*/
4667 /* shiftR2Left2Result - shift right two bytes from left to result */
4668 /*-----------------------------------------------------------------*/
4670 shiftR2Left2Result (operand * left, int offl,
4671 operand * result, int offr,
4672 int shCount, int is_signed)
4675 symbol *tlbl, *tlbl1;
4677 movLeft2Result (left, offl, result, offr, 0);
4678 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4680 /* if (AOP(result)->type == AOP_REG) { */
4682 tlbl = newiTempLabel (NULL);
4683 tlbl1 = newiTempLabel (NULL);
4685 /* Left is already in result - so now do the shift */
4690 emitRsh2 (AOP (result), size, is_signed);
4695 emit2 ("ld a,!immedbyte+1", shCount);
4696 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4697 emitLabel (tlbl->key + 100);
4699 emitRsh2 (AOP (result), size, is_signed);
4701 emitLabel (tlbl1->key + 100);
4703 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4707 /*-----------------------------------------------------------------*/
4708 /* shiftL2Left2Result - shift left two bytes from left to result */
4709 /*-----------------------------------------------------------------*/
4711 shiftL2Left2Result (operand * left, int offl,
4712 operand * result, int offr, int shCount)
4714 if (sameRegs (AOP (result), AOP (left)) &&
4715 ((offl + MSB16) == offr))
4721 /* Copy left into result */
4722 movLeft2Result (left, offl, result, offr, 0);
4723 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4725 /* PENDING: for now just see if it'll work. */
4726 /*if (AOP(result)->type == AOP_REG) { */
4730 symbol *tlbl, *tlbl1;
4733 tlbl = newiTempLabel (NULL);
4734 tlbl1 = newiTempLabel (NULL);
4736 /* Left is already in result - so now do the shift */
4739 emit2 ("ld a,!immedbyte+1", shCount);
4740 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4741 emitLabel (tlbl->key + 100);
4746 l = aopGet (AOP (result), offset, FALSE);
4750 emit2 ("sla %s", l);
4761 emitLabel (tlbl1->key + 100);
4763 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4768 /*-----------------------------------------------------------------*/
4769 /* AccRol - rotate left accumulator by known count */
4770 /*-----------------------------------------------------------------*/
4772 AccRol (int shCount)
4774 shCount &= 0x0007; // shCount : 0..7
4813 /*-----------------------------------------------------------------*/
4814 /* AccLsh - left shift accumulator by known count */
4815 /*-----------------------------------------------------------------*/
4817 AccLsh (int shCount)
4819 static const unsigned char SLMask[] =
4821 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4830 else if (shCount == 2)
4837 /* rotate left accumulator */
4839 /* and kill the lower order bits */
4840 emit2 ("and a,!immedbyte", SLMask[shCount]);
4845 /*-----------------------------------------------------------------*/
4846 /* shiftL1Left2Result - shift left one byte from left to result */
4847 /*-----------------------------------------------------------------*/
4849 shiftL1Left2Result (operand * left, int offl,
4850 operand * result, int offr, int shCount)
4853 l = aopGet (AOP (left), offl, FALSE);
4855 /* shift left accumulator */
4857 aopPut (AOP (result), "a", offr);
4861 /*-----------------------------------------------------------------*/
4862 /* genlshTwo - left shift two bytes by known amount != 0 */
4863 /*-----------------------------------------------------------------*/
4865 genlshTwo (operand * result, operand * left, int shCount)
4867 int size = AOP_SIZE (result);
4869 wassert (size == 2);
4871 /* if shCount >= 8 */
4879 movLeft2Result (left, LSB, result, MSB16, 0);
4880 aopPut (AOP (result), "!zero", 0);
4881 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
4885 movLeft2Result (left, LSB, result, MSB16, 0);
4886 aopPut (AOP (result), "!zero", 0);
4891 aopPut (AOP (result), "!zero", LSB);
4894 /* 1 <= shCount <= 7 */
4903 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4908 /*-----------------------------------------------------------------*/
4909 /* genlshOne - left shift a one byte quantity by known count */
4910 /*-----------------------------------------------------------------*/
4912 genlshOne (operand * result, operand * left, int shCount)
4914 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4917 /*-----------------------------------------------------------------*/
4918 /* genLeftShiftLiteral - left shifting by known count */
4919 /*-----------------------------------------------------------------*/
4921 genLeftShiftLiteral (operand * left,
4926 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4929 freeAsmop (right, NULL, ic);
4931 aopOp (left, ic, FALSE, FALSE);
4932 aopOp (result, ic, FALSE, FALSE);
4934 size = getSize (operandType (result));
4936 /* I suppose that the left size >= result size */
4942 else if (shCount >= (size * 8))
4946 aopPut (AOP (result), "!zero", size);
4954 genlshOne (result, left, shCount);
4957 genlshTwo (result, left, shCount);
4960 wassertl (0, "Shifting of longs is currently unsupported");
4966 freeAsmop (left, NULL, ic);
4967 freeAsmop (result, NULL, ic);
4970 /*-----------------------------------------------------------------*/
4971 /* genLeftShift - generates code for left shifting */
4972 /*-----------------------------------------------------------------*/
4974 genLeftShift (iCode * ic)
4978 symbol *tlbl, *tlbl1;
4979 operand *left, *right, *result;
4981 right = IC_RIGHT (ic);
4982 left = IC_LEFT (ic);
4983 result = IC_RESULT (ic);
4985 aopOp (right, ic, FALSE, FALSE);
4987 /* if the shift count is known then do it
4988 as efficiently as possible */
4989 if (AOP_TYPE (right) == AOP_LIT)
4991 genLeftShiftLiteral (left, right, result, ic);
4995 /* shift count is unknown then we have to form a loop get the loop
4996 count in B : Note: we take only the lower order byte since
4997 shifting more that 32 bits make no sense anyway, ( the largest
4998 size of an object can be only 32 bits ) */
4999 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5001 freeAsmop (right, NULL, ic);
5002 aopOp (left, ic, FALSE, FALSE);
5003 aopOp (result, ic, FALSE, FALSE);
5005 /* now move the left to the result if they are not the
5008 if (!sameRegs (AOP (left), AOP (result)))
5011 size = AOP_SIZE (result);
5015 l = aopGet (AOP (left), offset, FALSE);
5016 aopPut (AOP (result), l, offset);
5021 tlbl = newiTempLabel (NULL);
5022 size = AOP_SIZE (result);
5024 tlbl1 = newiTempLabel (NULL);
5026 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5027 emitLabel (tlbl->key + 100);
5028 l = aopGet (AOP (result), offset, FALSE);
5032 l = aopGet (AOP (result), offset, FALSE);
5036 emit2 ("sla %s", l);
5044 emitLabel (tlbl1->key + 100);
5046 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5048 freeAsmop (left, NULL, ic);
5049 freeAsmop (result, NULL, ic);
5052 /*-----------------------------------------------------------------*/
5053 /* genrshOne - left shift two bytes by known amount != 0 */
5054 /*-----------------------------------------------------------------*/
5056 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5059 int size = AOP_SIZE (result);
5062 wassert (size == 1);
5063 wassert (shCount < 8);
5065 l = aopGet (AOP (left), 0, FALSE);
5067 if (AOP (result)->type == AOP_REG)
5069 aopPut (AOP (result), l, 0);
5070 l = aopGet (AOP (result), 0, FALSE);
5073 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5081 emit2 ("%s a", is_signed ? "sra" : "srl");
5083 aopPut (AOP (result), "a", 0);
5087 /*-----------------------------------------------------------------*/
5088 /* AccRsh - right shift accumulator by known count */
5089 /*-----------------------------------------------------------------*/
5091 AccRsh (int shCount)
5093 static const unsigned char SRMask[] =
5095 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5100 /* rotate right accumulator */
5101 AccRol (8 - shCount);
5102 /* and kill the higher order bits */
5103 emit2 ("and a,!immedbyte", SRMask[shCount]);
5107 /*-----------------------------------------------------------------*/
5108 /* shiftR1Left2Result - shift right one byte from left to result */
5109 /*-----------------------------------------------------------------*/
5111 shiftR1Left2Result (operand * left, int offl,
5112 operand * result, int offr,
5113 int shCount, int sign)
5115 _moveA (aopGet (AOP (left), offl, FALSE));
5120 emit2 ("%s a", sign ? "sra" : "srl");
5127 aopPut (AOP (result), "a", offr);
5130 /*-----------------------------------------------------------------*/
5131 /* genrshTwo - right shift two bytes by known amount != 0 */
5132 /*-----------------------------------------------------------------*/
5134 genrshTwo (operand * result, operand * left,
5135 int shCount, int sign)
5137 /* if shCount >= 8 */
5143 shiftR1Left2Result (left, MSB16, result, LSB,
5148 movLeft2Result (left, MSB16, result, LSB, sign);
5152 /* Sign extend the result */
5153 _moveA(aopGet (AOP (result), 0, FALSE));
5157 aopPut (AOP (result), ACC_NAME, MSB16);
5161 aopPut (AOP (result), "!zero", 1);
5164 /* 1 <= shCount <= 7 */
5167 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5171 /*-----------------------------------------------------------------*/
5172 /* genRightShiftLiteral - left shifting by known count */
5173 /*-----------------------------------------------------------------*/
5175 genRightShiftLiteral (operand * left,
5181 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5184 freeAsmop (right, NULL, ic);
5186 aopOp (left, ic, FALSE, FALSE);
5187 aopOp (result, ic, FALSE, FALSE);
5189 size = getSize (operandType (result));
5191 /* I suppose that the left size >= result size */
5197 else if (shCount >= (size * 8))
5199 aopPut (AOP (result), "!zero", size);
5205 genrshOne (result, left, shCount, sign);
5208 genrshTwo (result, left, shCount, sign);
5211 wassertl (0, "Asked to shift right a long which should be a function call");
5214 wassertl (0, "Entered default case in right shift delegate");
5217 freeAsmop (left, NULL, ic);
5218 freeAsmop (result, NULL, ic);
5221 /*-----------------------------------------------------------------*/
5222 /* genRightShift - generate code for right shifting */
5223 /*-----------------------------------------------------------------*/
5225 genRightShift (iCode * ic)
5227 operand *right, *left, *result;
5229 int size, offset, first = 1;
5233 symbol *tlbl, *tlbl1;
5235 /* if signed then we do it the hard way preserve the
5236 sign bit moving it inwards */
5237 retype = getSpec (operandType (IC_RESULT (ic)));
5239 is_signed = !SPEC_USIGN (retype);
5241 /* signed & unsigned types are treated the same : i.e. the
5242 signed is NOT propagated inwards : quoting from the
5243 ANSI - standard : "for E1 >> E2, is equivalent to division
5244 by 2**E2 if unsigned or if it has a non-negative value,
5245 otherwise the result is implementation defined ", MY definition
5246 is that the sign does not get propagated */
5248 right = IC_RIGHT (ic);
5249 left = IC_LEFT (ic);
5250 result = IC_RESULT (ic);
5252 aopOp (right, ic, FALSE, FALSE);
5254 /* if the shift count is known then do it
5255 as efficiently as possible */
5256 if (AOP_TYPE (right) == AOP_LIT)
5258 genRightShiftLiteral (left, right, result, ic, is_signed);
5262 aopOp (left, ic, FALSE, FALSE);
5263 aopOp (result, ic, FALSE, FALSE);
5265 /* now move the left to the result if they are not the
5267 if (!sameRegs (AOP (left), AOP (result)) &&
5268 AOP_SIZE (result) > 1)
5271 size = AOP_SIZE (result);
5275 l = aopGet (AOP (left), offset, FALSE);
5276 aopPut (AOP (result), l, offset);
5281 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5283 freeAsmop (right, NULL, ic);
5285 tlbl = newiTempLabel (NULL);
5286 tlbl1 = newiTempLabel (NULL);
5287 size = AOP_SIZE (result);
5290 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5291 emitLabel (tlbl->key + 100);
5294 l = aopGet (AOP (result), offset--, FALSE);
5297 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5305 emitLabel (tlbl1->key + 100);
5307 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5309 freeAsmop (left, NULL, ic);
5310 freeAsmop (result, NULL, ic);
5313 /*-----------------------------------------------------------------*/
5314 /* genGenPointerGet - get value from generic pointer space */
5315 /*-----------------------------------------------------------------*/
5317 genGenPointerGet (operand * left,
5318 operand * result, iCode * ic)
5321 sym_link *retype = getSpec (operandType (result));
5327 aopOp (left, ic, FALSE, FALSE);
5328 aopOp (result, ic, FALSE, FALSE);
5330 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5333 if (isPtrPair (AOP (left)))
5335 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5336 aopPut (AOP (result), buffer, 0);
5340 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5341 aopPut (AOP (result), "a", 0);
5343 freeAsmop (left, NULL, ic);
5347 /* For now we always load into IY */
5348 /* if this is remateriazable */
5349 fetchPair (pair, AOP (left));
5351 /* so iy now contains the address */
5352 freeAsmop (left, NULL, ic);
5354 /* if bit then unpack */
5355 if (IS_BITVAR (retype))
5361 size = AOP_SIZE (result);
5366 /* PENDING: make this better */
5367 if (!IS_GB && AOP (result)->type == AOP_REG)
5369 aopPut (AOP (result), "!*hl", offset++);
5373 emit2 ("ld a,!*pair", _pairs[pair].name);
5374 aopPut (AOP (result), "a", offset++);
5378 emit2 ("inc %s", _pairs[pair].name);
5379 _G.pairs[pair].offset++;
5385 freeAsmop (result, NULL, ic);
5388 /*-----------------------------------------------------------------*/
5389 /* genPointerGet - generate code for pointer get */
5390 /*-----------------------------------------------------------------*/
5392 genPointerGet (iCode * ic)
5394 operand *left, *result;
5395 sym_link *type, *etype;
5397 left = IC_LEFT (ic);
5398 result = IC_RESULT (ic);
5400 /* depending on the type of pointer we need to
5401 move it to the correct pointer register */
5402 type = operandType (left);
5403 etype = getSpec (type);
5405 genGenPointerGet (left, result, ic);
5409 isRegOrLit (asmop * aop)
5411 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5416 /*-----------------------------------------------------------------*/
5417 /* genGenPointerSet - stores the value into a pointer location */
5418 /*-----------------------------------------------------------------*/
5420 genGenPointerSet (operand * right,
5421 operand * result, iCode * ic)
5424 sym_link *retype = getSpec (operandType (right));
5425 PAIR_ID pairId = PAIR_HL;
5427 aopOp (result, ic, FALSE, FALSE);
5428 aopOp (right, ic, FALSE, FALSE);
5433 /* Handle the exceptions first */
5434 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5437 const char *l = aopGet (AOP (right), 0, FALSE);
5438 const char *pair = getPairName (AOP (result));
5439 if (canAssignToPtr (l) && isPtr (pair))
5441 emit2 ("ld !*pair,%s", pair, l);
5446 emit2 ("ld !*pair,a", pair);
5451 /* if the operand is already in dptr
5452 then we do nothing else we move the value to dptr */
5453 if (AOP_TYPE (result) != AOP_STR)
5455 fetchPair (pairId, AOP (result));
5457 /* so hl know contains the address */
5458 freeAsmop (result, NULL, ic);
5460 /* if bit then unpack */
5461 if (IS_BITVAR (retype))
5467 size = AOP_SIZE (right);
5472 const char *l = aopGet (AOP (right), offset, FALSE);
5473 if (isRegOrLit (AOP (right)) && !IS_GB)
5475 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5480 emit2 ("ld !*pair,a", _pairs[pairId].name);
5484 emit2 ("inc %s", _pairs[pairId].name);
5485 _G.pairs[pairId].offset++;
5491 freeAsmop (right, NULL, ic);
5494 /*-----------------------------------------------------------------*/
5495 /* genPointerSet - stores the value into a pointer location */
5496 /*-----------------------------------------------------------------*/
5498 genPointerSet (iCode * ic)
5500 operand *right, *result;
5501 sym_link *type, *etype;
5503 right = IC_RIGHT (ic);
5504 result = IC_RESULT (ic);
5506 /* depending on the type of pointer we need to
5507 move it to the correct pointer register */
5508 type = operandType (result);
5509 etype = getSpec (type);
5511 genGenPointerSet (right, result, ic);
5514 /*-----------------------------------------------------------------*/
5515 /* genIfx - generate code for Ifx statement */
5516 /*-----------------------------------------------------------------*/
5518 genIfx (iCode * ic, iCode * popIc)
5520 operand *cond = IC_COND (ic);
5523 aopOp (cond, ic, FALSE, TRUE);
5525 /* get the value into acc */
5526 if (AOP_TYPE (cond) != AOP_CRY)
5530 /* the result is now in the accumulator */
5531 freeAsmop (cond, NULL, ic);
5533 /* if there was something to be popped then do it */
5537 /* if the condition is a bit variable */
5538 if (isbit && IS_ITEMP (cond) &&
5540 genIfxJump (ic, SPIL_LOC (cond)->rname);
5541 else if (isbit && !IS_ITEMP (cond))
5542 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5544 genIfxJump (ic, "a");
5549 /*-----------------------------------------------------------------*/
5550 /* genAddrOf - generates code for address of */
5551 /*-----------------------------------------------------------------*/
5553 genAddrOf (iCode * ic)
5555 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5557 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5559 /* if the operand is on the stack then we
5560 need to get the stack offset of this
5567 if (sym->stack <= 0)
5569 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5573 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5580 emit2 ("ld de,!hashedstr", sym->rname);
5582 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5583 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5590 /* if it has an offset then we need to compute it */
5592 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5594 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5595 emit2 ("add hl,sp");
5599 emit2 ("ld hl,#%s", sym->rname);
5601 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5602 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5604 freeAsmop (IC_RESULT (ic), NULL, ic);
5607 /*-----------------------------------------------------------------*/
5608 /* genAssign - generate code for assignment */
5609 /*-----------------------------------------------------------------*/
5611 genAssign (iCode * ic)
5613 operand *result, *right;
5615 unsigned long lit = 0L;
5617 result = IC_RESULT (ic);
5618 right = IC_RIGHT (ic);
5620 /* Dont bother assigning if they are the same */
5621 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5623 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5627 aopOp (right, ic, FALSE, FALSE);
5628 aopOp (result, ic, TRUE, FALSE);
5630 /* if they are the same registers */
5631 if (sameRegs (AOP (right), AOP (result)))
5633 emitDebug ("; (registers are the same)");
5637 /* if the result is a bit */
5638 if (AOP_TYPE (result) == AOP_CRY)
5640 wassertl (0, "Tried to assign to a bit");
5644 size = AOP_SIZE (result);
5647 if (AOP_TYPE (right) == AOP_LIT)
5648 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5649 if (isPair (AOP (result)))
5651 fetchPair (getPairId (AOP (result)), AOP (right));
5653 else if ((size > 1) &&
5654 (AOP_TYPE (result) != AOP_REG) &&
5655 (AOP_TYPE (right) == AOP_LIT) &&
5656 !IS_FLOAT (operandType (right)) &&
5659 bool fXored = FALSE;
5661 /* Work from the top down.
5662 Done this way so that we can use the cached copy of 0
5663 in A for a fast clear */
5666 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5668 if (!fXored && size > 1)
5675 aopPut (AOP (result), "a", offset);
5679 aopPut (AOP (result), "!zero", offset);
5683 aopPut (AOP (result),
5684 aopGet (AOP (right), offset, FALSE),
5689 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5691 /* Special case. Load into a and d, then load out. */
5692 _moveA (aopGet (AOP (right), 0, FALSE));
5693 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5694 aopPut (AOP (result), "a", 0);
5695 aopPut (AOP (result), "e", 1);
5697 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5699 /* Special case - simple memcpy */
5700 aopGet (AOP (right), LSB, FALSE);
5703 aopGet (AOP (result), LSB, FALSE);
5707 emit2 ("ld a,(de)");
5708 /* Peephole will optimise this. */
5709 emit2 ("ld (hl),a");
5717 spillPair (PAIR_HL);
5723 /* PENDING: do this check better */
5724 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5726 _moveA (aopGet (AOP (right), offset, FALSE));
5727 aopPut (AOP (result), "a", offset);
5730 aopPut (AOP (result),
5731 aopGet (AOP (right), offset, FALSE),
5738 freeAsmop (right, NULL, ic);
5739 freeAsmop (result, NULL, ic);
5742 /*-----------------------------------------------------------------*/
5743 /* genJumpTab - genrates code for jump table */
5744 /*-----------------------------------------------------------------*/
5746 genJumpTab (iCode * ic)
5751 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5752 /* get the condition into accumulator */
5753 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5756 emit2 ("ld e,%s", l);
5757 emit2 ("ld d,!zero");
5758 jtab = newiTempLabel (NULL);
5760 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5761 emit2 ("add hl,de");
5762 emit2 ("add hl,de");
5763 emit2 ("add hl,de");
5764 freeAsmop (IC_JTCOND (ic), NULL, ic);
5768 emitLabel (jtab->key + 100);
5769 /* now generate the jump labels */
5770 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5771 jtab = setNextItem (IC_JTLABELS (ic)))
5772 emit2 ("jp !tlabel", jtab->key + 100);
5775 /*-----------------------------------------------------------------*/
5776 /* genCast - gen code for casting */
5777 /*-----------------------------------------------------------------*/
5779 genCast (iCode * ic)
5781 operand *result = IC_RESULT (ic);
5782 sym_link *ctype = operandType (IC_LEFT (ic));
5783 operand *right = IC_RIGHT (ic);
5786 /* if they are equivalent then do nothing */
5787 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5790 aopOp (right, ic, FALSE, FALSE);
5791 aopOp (result, ic, FALSE, FALSE);
5793 /* if the result is a bit */
5794 if (AOP_TYPE (result) == AOP_CRY)
5796 wassertl (0, "Tried to cast to a bit");
5799 /* if they are the same size : or less */
5800 if (AOP_SIZE (result) <= AOP_SIZE (right))
5803 /* if they are in the same place */
5804 if (sameRegs (AOP (right), AOP (result)))
5807 /* if they in different places then copy */
5808 size = AOP_SIZE (result);
5812 aopPut (AOP (result),
5813 aopGet (AOP (right), offset, FALSE),
5820 /* So we now know that the size of destination is greater
5821 than the size of the source */
5822 /* we move to result for the size of source */
5823 size = AOP_SIZE (right);
5827 aopPut (AOP (result),
5828 aopGet (AOP (right), offset, FALSE),
5833 /* now depending on the sign of the destination */
5834 size = AOP_SIZE (result) - AOP_SIZE (right);
5835 /* Unsigned or not an integral type - right fill with zeros */
5836 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5839 aopPut (AOP (result), "!zero", offset++);
5843 /* we need to extend the sign :{ */
5844 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5850 aopPut (AOP (result), "a", offset++);
5854 freeAsmop (right, NULL, ic);
5855 freeAsmop (result, NULL, ic);
5858 /*-----------------------------------------------------------------*/
5859 /* genReceive - generate code for a receive iCode */
5860 /*-----------------------------------------------------------------*/
5862 genReceive (iCode * ic)
5864 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5865 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5866 IS_TRUE_SYMOP (IC_RESULT (ic))))
5876 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5877 size = AOP_SIZE(IC_RESULT(ic));
5879 for (i = 0; i < size; i++) {
5880 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5884 freeAsmop (IC_RESULT (ic), NULL, ic);
5889 /** Maximum number of bytes to emit per line. */
5893 /** Context for the byte output chunker. */
5896 unsigned char buffer[DBEMIT_MAX_RUN];
5901 /** Flushes a byte chunker by writing out all in the buffer and
5905 _dbFlush(DBEMITCTX *self)
5912 sprintf(line, ".db 0x%02X", self->buffer[0]);
5914 for (i = 1; i < self->pos; i++)
5916 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5923 /** Write out another byte, buffering until a decent line is
5927 _dbEmit(DBEMITCTX *self, int c)
5929 if (self->pos == DBEMIT_MAX_RUN)
5933 self->buffer[self->pos++] = c;
5936 /** Context for a simple run length encoder. */
5940 unsigned char buffer[128];
5942 /** runLen may be equivalent to pos. */
5948 RLE_CHANGE_COST = 4,
5952 /** Flush the buffer of a run length encoder by writing out the run or
5953 data that it currently contains.
5956 _rleCommit(RLECTX *self)
5962 memset(&db, 0, sizeof(db));
5964 emit2(".db %u", self->pos);
5966 for (i = 0; i < self->pos; i++)
5968 _dbEmit(&db, self->buffer[i]);
5977 Can get either a run or a block of random stuff.
5978 Only want to change state if a good run comes in or a run ends.
5979 Detecting run end is easy.
5982 Say initial state is in run, len zero, last zero. Then if you get a
5983 few zeros then something else then a short run will be output.
5984 Seems OK. While in run mode, keep counting. While in random mode,
5985 keep a count of the run. If run hits margin, output all up to run,
5986 restart, enter run mode.
5989 /** Add another byte into the run length encoder, flushing as
5990 required. The run length encoder uses the Amiga IFF style, where
5991 a block is prefixed by its run length. A positive length means
5992 the next n bytes pass straight through. A negative length means
5993 that the next byte is repeated -n times. A zero terminates the
5997 _rleAppend(RLECTX *self, int c)
6001 if (c != self->last)
6003 /* The run has stopped. See if it is worthwhile writing it out
6004 as a run. Note that the random data comes in as runs of
6007 if (self->runLen > RLE_CHANGE_COST)
6009 /* Yes, worthwhile. */
6010 /* Commit whatever was in the buffer. */
6012 emit2(".db -%u,0x%02X", self->runLen, self->last);
6016 /* Not worthwhile. Append to the end of the random list. */
6017 for (i = 0; i < self->runLen; i++)
6019 if (self->pos >= RLE_MAX_BLOCK)
6024 self->buffer[self->pos++] = self->last;
6032 if (self->runLen >= RLE_MAX_BLOCK)
6034 /* Commit whatever was in the buffer. */
6037 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6045 _rleFlush(RLECTX *self)
6047 _rleAppend(self, -1);
6054 /** genArrayInit - Special code for initialising an array with constant
6058 genArrayInit (iCode * ic)
6062 int elementSize = 0, eIndex, i;
6063 unsigned val, lastVal;
6067 memset(&rle, 0, sizeof(rle));
6069 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6071 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
6073 /* Emit the support function call and the destination address. */
6074 emit2("call __initrleblock");
6075 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
6079 wassertl (0, "Unexpected operand to genArrayInit.\n");
6082 type = operandType(IC_LEFT(ic));
6084 if (type && type->next)
6086 elementSize = getSize(type->next);
6090 wassertl (0, "Can't determine element size in genArrayInit.");
6093 iLoop = IC_ARRAYILIST(ic);
6094 lastVal = (unsigned)-1;
6096 /* Feed all the bytes into the run length encoder which will handle
6098 This works well for mixed char data, and for random int and long
6107 for (i = 0; i < ix; i++)
6109 for (eIndex = 0; eIndex < elementSize; eIndex++)
6111 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6112 _rleAppend(&rle, val);
6117 iLoop = iLoop->next;
6121 /* Mark the end of the run. */
6124 freeAsmop (IC_LEFT(ic), NULL, ic);
6127 /*-----------------------------------------------------------------*/
6128 /* genZ80Code - generate code for Z80 based controllers */
6129 /*-----------------------------------------------------------------*/
6131 genZ80Code (iCode * lic)
6139 _fReturn = _gbz80_return;
6140 _fTmp = _gbz80_return;
6144 _fReturn = _z80_return;
6145 _fTmp = _z80_return;
6148 _G.lines.head = _G.lines.current = NULL;
6150 for (ic = lic; ic; ic = ic->next)
6153 if (cln != ic->lineno)
6155 emit2 ("; %s %d", ic->filename, ic->lineno);
6158 /* if the result is marked as
6159 spilt and rematerializable or code for
6160 this has already been generated then
6162 if (resultRemat (ic) || ic->generated)
6165 /* depending on the operation */
6169 emitDebug ("; genNot");
6174 emitDebug ("; genCpl");
6179 emitDebug ("; genUminus");
6184 emitDebug ("; genIpush");
6189 /* IPOP happens only when trying to restore a
6190 spilt live range, if there is an ifx statement
6191 following this pop then the if statement might
6192 be using some of the registers being popped which
6193 would destory the contents of the register so
6194 we need to check for this condition and handle it */
6196 ic->next->op == IFX &&
6197 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6199 emitDebug ("; genIfx");
6200 genIfx (ic->next, ic);
6204 emitDebug ("; genIpop");
6210 emitDebug ("; genCall");
6215 emitDebug ("; genPcall");
6220 emitDebug ("; genFunction");
6225 emitDebug ("; genEndFunction");
6226 genEndFunction (ic);
6230 emitDebug ("; genRet");
6235 emitDebug ("; genLabel");
6240 emitDebug ("; genGoto");
6245 emitDebug ("; genPlus");
6250 emitDebug ("; genMinus");
6255 emitDebug ("; genMult");
6260 emitDebug ("; genDiv");
6265 emitDebug ("; genMod");
6270 emitDebug ("; genCmpGt");
6271 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6275 emitDebug ("; genCmpLt");
6276 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6283 /* note these two are xlated by algebraic equivalence
6284 during parsing SDCC.y */
6285 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6286 "got '>=' or '<=' shouldn't have come here");
6290 emitDebug ("; genCmpEq");
6291 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6295 emitDebug ("; genAndOp");
6300 emitDebug ("; genOrOp");
6305 emitDebug ("; genXor");
6306 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6310 emitDebug ("; genOr");
6311 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6315 emitDebug ("; genAnd");
6316 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6320 emitDebug ("; genInline");
6325 emitDebug ("; genRRC");
6330 emitDebug ("; genRLC");
6335 emitDebug ("; genGetHBIT");
6340 emitDebug ("; genLeftShift");
6345 emitDebug ("; genRightShift");
6349 case GET_VALUE_AT_ADDRESS:
6350 emitDebug ("; genPointerGet");
6356 if (POINTER_SET (ic))
6358 emitDebug ("; genAssign (pointer)");
6363 emitDebug ("; genAssign");
6369 emitDebug ("; genIfx");
6374 emitDebug ("; genAddrOf");
6379 emitDebug ("; genJumpTab");
6384 emitDebug ("; genCast");
6389 emitDebug ("; genReceive");
6394 emitDebug ("; addSet");
6395 addSet (&_G.sendSet, ic);
6408 /* now we are ready to call the
6409 peep hole optimizer */
6410 if (!options.nopeep)
6411 peepHole (&_G.lines.head);
6413 /* This is unfortunate */
6414 /* now do the actual printing */
6416 FILE *fp = codeOutFile;
6417 if (isInHome () && codeOutFile == code->oFile)
6418 codeOutFile = home->oFile;
6419 printLine (_G.lines.head, codeOutFile);
6420 if (_G.flushStatics)
6423 _G.flushStatics = 0;
6428 freeTrace(&_G.lines.trace);
6429 freeTrace(&_G.trace.aops);
6435 _isPairUsed (iCode * ic, PAIR_ID pairId)
6441 if (bitVectBitValue (ic->rMask, D_IDX))
6443 if (bitVectBitValue (ic->rMask, E_IDX))
6453 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6456 value *val = aop->aopu.aop_lit;
6458 wassert (aop->type == AOP_LIT);
6459 wassert (!IS_FLOAT (val->type));
6461 v = (unsigned long) floatFromVal (val);
6469 tsprintf (buffer, "!immedword", v);
6470 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));