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 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
91 #include "SDCCglobl.h"
92 #include "SDCCpeeph.h"
97 /* This is the down and dirty file with all kinds of kludgy & hacky
98 stuff. This is what it is all about CODE GENERATION for a specific MCU.
99 Some of the routines may be reusable, will have to see */
101 /* Z80 calling convention description.
102 Parameters are passed right to left. As the stack grows downwards,
103 the parameters are arranged in left to right in memory.
104 Parameters may be passed in the HL and DE registers with one
106 PENDING: What if the parameter is a long?
107 Everything is caller saves. i.e. the caller must save any registers
108 that it wants to preserve over the call.
109 GB: The return value is returned in DEHL. DE is normally used as a
110 working register pair. Caller saves allows it to be used for a
112 va args functions do not use register parameters. All arguments
113 are passed on the stack.
114 IX is used as an index register to the top of the local variable
115 area. ix-0 is the top most local variable.
120 /* Set to enable debugging trace statements in the output assembly code. */
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129 { "c", "b", "e", "d" };
131 static char **_fReturn;
134 extern struct dbuf_s *codeOutBuf;
142 /** Enum covering all the possible register pairs.
161 } _pairs[NUM_PAIRS] = {
162 { "??1", "?2", "?3" },
167 { "iy", "iyl", "iyh" },
168 { "ix", "ixl", "ixh" }
172 #define ACC_NAME _pairs[PAIR_AF].h
182 /** Code generator persistent data.
186 /** Used to optimised setting up of a pair by remebering what it
187 contains and adjusting instead of reloading where possible.
216 const char *lastFunctionName;
217 iCode *current_iCode;
224 /** TRUE if the registers have already been saved. */
243 static const char *aopGet (asmop * aop, int offset, bool bit16);
245 static const char *aopNames[] = {
266 isLastUse (iCode *ic, operand *op)
268 bitVect *uses = bitVectCopy (OP_USES (op));
270 while (!bitVectIsZero (uses))
272 if (bitVectFirstBit (uses) == ic->key)
274 if (bitVectnBitsOn (uses) == 1)
283 bitVectUnSetBit (uses, bitVectFirstBit (uses));
303 _getTempPairName(void)
305 return _pairs[_getTempPairId()].name;
309 isPairInUse (PAIR_ID id, iCode *ic)
313 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
315 else if (id == PAIR_BC)
317 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
321 wassertl (0, "Only implemented for DE and BC");
327 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
331 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
335 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
339 wassertl (0, "Only implemented for DE");
345 getFreePairId (iCode *ic)
347 if (!isPairInUse (PAIR_BC, ic))
351 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
364 /* Clean up the line so that it is 'prettier' */
365 if (strchr (buf, ':'))
367 /* Is a label - cant do anything */
370 /* Change the first (and probably only) ' ' to a tab so
385 _newLineNode (const char *line)
389 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
390 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
396 _vemit2 (const char *szFormat, va_list ap)
401 dbuf_init(&dbuf, INITIAL_INLINEASM);
403 dbuf_tvprintf (&dbuf, szFormat, ap);
405 buffer = dbuf_c_str(&dbuf);
407 _tidyUp ((char *)buffer);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
413 _G.lines.current->isDebug = _G.lines.isDebug;
414 _G.lines.current->ic = _G.current_iCode;
415 _G.lines.current->isComment = (*buffer == ';');
421 emit2 (const char *szFormat,...)
425 va_start (ap, szFormat);
427 _vemit2 (szFormat, ap);
433 emitDebug (const char *szFormat,...)
439 va_start (ap, szFormat);
441 _vemit2 (szFormat, ap);
447 /*-----------------------------------------------------------------*/
448 /* z80_emitDebuggerSymbol - associate the current code location */
449 /* with a debugger symbol */
450 /*-----------------------------------------------------------------*/
452 z80_emitDebuggerSymbol (char * debugSym)
454 _G.lines.isDebug = 1;
455 emit2 ("%s !equ .", debugSym);
456 emit2 ("!global", debugSym);
457 _G.lines.isDebug = 0;
460 /*-----------------------------------------------------------------*/
461 /* emit2 - writes the code into a file : for now it is simple */
462 /*-----------------------------------------------------------------*/
464 _emit2 (const char *inst, const char *fmt,...)
467 char lb[INITIAL_INLINEASM];
474 sprintf (lb, "%s\t", inst);
475 vsprintf (lb + (strlen (lb)), fmt, ap);
478 vsprintf (lb, fmt, ap);
480 while (isspace (*lbp))
485 _G.lines.current = (_G.lines.current ?
486 connectLine (_G.lines.current, _newLineNode (lb)) :
487 (_G.lines.head = _newLineNode (lb)));
489 _G.lines.current->isInline = _G.lines.isInline;
490 _G.lines.current->ic = _G.current_iCode;
495 _emitMove(const char *to, const char *from)
497 if (STRCASECMP(to, from) != 0)
499 emit2("ld %s,%s", to, from);
504 // Could leave this to the peephole, but sometimes the peephole is inhibited.
509 aopDump(const char *plabel, asmop *aop)
515 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
520 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
523 for (i=aop->size-1;i>=0;i--)
524 *rbp++ = *(aop->aopu.aop_reg[i]->name);
526 emitDebug("; reg = %s", regbuf);
529 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
532 /* No information. */
538 _moveA(const char *moveFrom)
540 // Let the peephole optimiser take care of redundent loads
541 _emitMove(ACC_NAME, moveFrom);
551 getPairName (asmop * aop)
553 if (aop->type == AOP_REG)
555 switch (aop->aopu.aop_reg[0]->rIdx)
568 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
571 for (i = 0; i < NUM_PAIRS; i++)
573 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
575 return _pairs[i].name;
579 wassertl (0, "Tried to get the pair name of something that isn't a pair");
584 getPairId (asmop * aop)
588 if (aop->type == AOP_REG)
590 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
594 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
598 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
603 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
606 for (i = 0; i < NUM_PAIRS; i++)
608 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
618 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
622 return (getPairId (aop) != PAIR_INVALID);
625 /** Returns TRUE if the registers used in aop cannot be split into high
628 isUnsplitable (asmop * aop)
630 switch (getPairId (aop))
642 isPtrPair (asmop * aop)
644 PAIR_ID pairId = getPairId (aop);
657 spillPair (PAIR_ID pairId)
659 _G.pairs[pairId].last_type = AOP_INVALID;
660 _G.pairs[pairId].base = NULL;
663 /* Given a register name, spill the pair (if any) the register is part of */
665 spillPairReg (const char *regname)
667 if (strlen(regname)==1)
687 /** Push a register pair onto the stack */
689 genPairPush (asmop * aop)
691 emit2 ("push %s", getPairName (aop));
695 _push (PAIR_ID pairId)
697 emit2 ("push %s", _pairs[pairId].name);
698 _G.stack.pushed += 2;
702 _pop (PAIR_ID pairId)
704 if (pairId != PAIR_INVALID)
706 emit2 ("pop %s", _pairs[pairId].name);
707 _G.stack.pushed -= 2;
713 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
726 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
733 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
734 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
737 wassertl (0, "Tried to move a nonphysical pair");
739 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
740 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
741 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
745 /*-----------------------------------------------------------------*/
746 /* newAsmop - creates a new asmOp */
747 /*-----------------------------------------------------------------*/
749 newAsmop (short type)
753 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
758 /*-----------------------------------------------------------------*/
759 /* aopForSym - for a true symbol */
760 /*-----------------------------------------------------------------*/
762 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
769 wassert (sym->etype);
771 space = SPEC_OCLS (sym->etype);
773 /* if already has one */
779 /* Assign depending on the storage class */
780 if (sym->onStack || sym->iaccess)
782 /* The pointer that is used depends on how big the offset is.
783 Normally everything is AOP_STK, but for offsets of < -128 or
784 > 127 on the Z80 an extended stack pointer is used.
786 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
788 emitDebug ("; AOP_EXSTK for %s", sym->rname);
789 sym->aop = aop = newAsmop (AOP_EXSTK);
793 emitDebug ("; AOP_STK for %s", sym->rname);
794 sym->aop = aop = newAsmop (AOP_STK);
797 aop->size = getSize (sym->type);
798 aop->aopu.aop_stk = sym->stack;
802 /* special case for a function */
803 if (IS_FUNC (sym->type))
805 sym->aop = aop = newAsmop (AOP_IMMD);
806 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
811 if( IN_REGSP( space ))
812 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
815 /* if it is in direct space */
818 sym->aop = aop = newAsmop (AOP_SFR);
819 aop->aopu.aop_dir = sym->rname;
820 aop->size = getSize (sym->type);
821 emitDebug ("; AOP_SFR for %s", sym->rname);
826 { /*.p.t.20030716 adding SFR support to the Z80 port */
827 aop = newAsmop (AOP_SFR);
829 aop->aopu.aop_dir = sym->rname;
830 aop->size = getSize( sym->type );
831 aop->paged = FUNC_REGBANK(sym->type);
832 aop->bcInUse = isPairInUse( PAIR_BC, ic );
833 aop->deInUse = isPairInUse( PAIR_DE, ic );
834 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
840 /* only remaining is far space */
841 /* in which case DPTR gets the address */
844 emitDebug ("; AOP_HL for %s", sym->rname);
845 sym->aop = aop = newAsmop (AOP_HL);
849 sym->aop = aop = newAsmop (AOP_IY);
851 aop->size = getSize (sym->type);
852 aop->aopu.aop_dir = sym->rname;
854 /* if it is in code space */
855 if (IN_CODESPACE (space))
861 /*-----------------------------------------------------------------*/
862 /* aopForRemat - rematerialzes an object */
863 /*-----------------------------------------------------------------*/
865 aopForRemat (symbol * sym)
868 iCode *ic = sym->rematiCode;
869 asmop *aop = newAsmop (AOP_IMMD);
873 /* if plus or minus print the right hand side */
874 if (ic->op == '+' || ic->op == '-')
876 /* PENDING: for re-target */
877 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
880 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
883 /* we reached the end */
884 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
888 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
892 /*-----------------------------------------------------------------*/
893 /* regsInCommon - two operands have some registers in common */
894 /*-----------------------------------------------------------------*/
896 regsInCommon (operand * op1, operand * op2)
901 /* if they have registers in common */
902 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
905 sym1 = OP_SYMBOL (op1);
906 sym2 = OP_SYMBOL (op2);
908 if (sym1->nRegs == 0 || sym2->nRegs == 0)
911 for (i = 0; i < sym1->nRegs; i++)
917 for (j = 0; j < sym2->nRegs; j++)
922 if (sym2->regs[j] == sym1->regs[i])
930 /*-----------------------------------------------------------------*/
931 /* operandsEqu - equivalent */
932 /*-----------------------------------------------------------------*/
934 operandsEqu (operand * op1, operand * op2)
938 /* if they not symbols */
939 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
942 sym1 = OP_SYMBOL (op1);
943 sym2 = OP_SYMBOL (op2);
945 /* if both are itemps & one is spilt
946 and the other is not then false */
947 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
948 sym1->isspilt != sym2->isspilt)
951 /* if they are the same */
955 if (sym1->rname[0] && sym2->rname[0]
956 && strcmp (sym1->rname, sym2->rname) == 0)
959 /* if left is a tmp & right is not */
960 if (IS_ITEMP (op1) &&
963 (sym1->usl.spillLoc == sym2))
966 if (IS_ITEMP (op2) &&
970 (sym2->usl.spillLoc == sym1))
976 /*-----------------------------------------------------------------*/
977 /* sameRegs - two asmops have the same registers */
978 /*-----------------------------------------------------------------*/
980 sameRegs (asmop * aop1, asmop * aop2)
984 if (aop1->type == AOP_SFR ||
985 aop2->type == AOP_SFR)
991 if (aop1->type != AOP_REG ||
992 aop2->type != AOP_REG)
995 if (aop1->size != aop2->size)
998 for (i = 0; i < aop1->size; i++)
999 if (aop1->aopu.aop_reg[i] !=
1000 aop2->aopu.aop_reg[i])
1006 /*-----------------------------------------------------------------*/
1007 /* aopOp - allocates an asmop for an operand : */
1008 /*-----------------------------------------------------------------*/
1010 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1019 /* if this a literal */
1020 if (IS_OP_LITERAL (op))
1022 op->aop = aop = newAsmop (AOP_LIT);
1023 aop->aopu.aop_lit = op->operand.valOperand;
1024 aop->size = getSize (operandType (op));
1028 /* if already has a asmop then continue */
1031 if (op->aop->type == AOP_SFR)
1033 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1034 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1039 /* if the underlying symbol has a aop */
1040 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1042 op->aop = OP_SYMBOL (op)->aop;
1043 if (op->aop->type == AOP_SFR)
1045 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1046 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1051 /* if this is a true symbol */
1052 if (IS_TRUE_SYMOP (op))
1054 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1058 /* this is a temporary : this has
1064 e) can be a return use only */
1066 sym = OP_SYMBOL (op);
1068 /* if the type is a conditional */
1069 if (sym->regType == REG_CND)
1071 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1076 /* if it is spilt then two situations
1078 b) has a spill location */
1079 if (sym->isspilt || sym->nRegs == 0)
1081 /* rematerialize it NOW */
1084 sym->aop = op->aop = aop =
1086 aop->size = getSize (sym->type);
1093 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1094 aop->size = getSize (sym->type);
1095 for (i = 0; i < 4; i++)
1096 aop->aopu.aop_str[i] = _fReturn[i];
1102 if (sym->accuse == ACCUSE_A)
1104 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1105 aop->size = getSize (sym->type);
1106 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1108 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1110 else if (sym->accuse == ACCUSE_SCRATCH)
1112 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1113 aop->size = getSize (sym->type);
1114 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1115 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1116 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1118 else if (sym->accuse == ACCUSE_IY)
1120 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1121 aop->size = getSize (sym->type);
1122 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1123 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1124 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1128 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1133 if (sym->usl.spillLoc)
1135 asmop *oldAsmOp = NULL;
1137 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1139 /* force a new aop if sizes differ */
1140 oldAsmOp = sym->usl.spillLoc->aop;
1141 sym->usl.spillLoc->aop = NULL;
1143 sym->aop = op->aop = aop =
1144 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1145 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1147 /* Don't reuse the new aop, go with the last one */
1148 sym->usl.spillLoc->aop = oldAsmOp;
1150 aop->size = getSize (sym->type);
1154 /* else must be a dummy iTemp */
1155 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1156 aop->size = getSize (sym->type);
1160 /* must be in a register */
1161 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1162 aop->size = sym->nRegs;
1163 for (i = 0; i < sym->nRegs; i++)
1164 aop->aopu.aop_reg[i] = sym->regs[i];
1167 /*-----------------------------------------------------------------*/
1168 /* freeAsmop - free up the asmop given to an operand */
1169 /*----------------------------------------------------------------*/
1171 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1188 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1190 _pop (aop->aopu.aop_pairId);
1193 if (getPairId (aop) == PAIR_HL)
1195 spillPair (PAIR_HL);
1199 /* all other cases just dealloc */
1205 OP_SYMBOL (op)->aop = NULL;
1206 /* if the symbol has a spill */
1208 SPIL_LOC (op)->aop = NULL;
1215 isLitWord (asmop * aop)
1217 /* if (aop->size != 2)
1230 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1232 /* depending on type */
1238 /* PENDING: for re-target */
1241 tsprintf (buffer, sizeof(buffer),
1242 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1244 else if (offset == 0)
1246 tsprintf (buffer, sizeof(buffer),
1247 "%s", aop->aopu.aop_immd);
1251 tsprintf (buffer, sizeof(buffer),
1252 "%s + %d", aop->aopu.aop_immd, offset);
1254 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1258 value *val = aop->aopu.aop_lit;
1259 /* if it is a float then it gets tricky */
1260 /* otherwise it is fairly simple */
1261 if (!IS_FLOAT (val->type))
1263 unsigned long v = ulFromVal (val);
1269 else if (offset == 0)
1275 wassertl(0, "Encountered an invalid offset while fetching a literal");
1279 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1281 tsprintf (buffer, sizeof(buffer), "!constword", v);
1283 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1294 /* it is type float */
1295 fl.f = (float) floatFromVal (val);
1297 #ifdef WORDS_BIGENDIAN
1298 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1300 i = fl.c[offset] | (fl.c[offset+1]<<8);
1303 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1305 tsprintf (buffer, sizeof(buffer), "!constword", i);
1307 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1316 aopGetWord (asmop * aop, int offset)
1318 return aopGetLitWordLong (aop, offset, TRUE);
1322 isPtr (const char *s)
1324 if (!strcmp (s, "hl"))
1326 if (!strcmp (s, "ix"))
1328 if (!strcmp (s, "iy"))
1334 adjustPair (const char *pair, int *pold, int new)
1340 emit2 ("inc %s", pair);
1345 emit2 ("dec %s", pair);
1353 spillPair (PAIR_HL);
1354 spillPair (PAIR_IY);
1358 requiresHL (asmop * aop)
1374 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1376 const char *l, *base;
1377 const char *pair = _pairs[pairId].name;
1378 l = aopGetLitWordLong (left, offset, FALSE);
1379 base = aopGetLitWordLong (left, 0, FALSE);
1380 wassert (l && pair && base);
1384 if (pairId == PAIR_HL || pairId == PAIR_IY)
1386 if (_G.pairs[pairId].last_type == left->type)
1388 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1390 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1392 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1395 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1402 _G.pairs[pairId].last_type = left->type;
1403 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1404 _G.pairs[pairId].offset = offset;
1406 /* Both a lit on the right and a true symbol on the left */
1407 emit2 ("ld %s,!hashedstr", pair, l);
1411 makeFreePairId (iCode *ic, bool *pisUsed)
1417 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1421 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1439 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1441 /* if this is remateriazable */
1442 if (isLitWord (aop)) {
1443 fetchLitPair (pairId, aop, offset);
1447 if (getPairId (aop) == pairId)
1451 /* we need to get it byte by byte */
1452 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1453 aopGet (aop, offset, FALSE);
1454 switch (aop->size - offset) {
1456 emit2 ("ld l,!*hl");
1457 emit2 ("ld h,!immedbyte", 0);
1460 // PENDING: Requires that you are only fetching two bytes.
1463 emit2 ("ld h,!*hl");
1467 wassertl (0, "Attempted to fetch too much data into HL");
1471 else if (IS_Z80 && aop->type == AOP_IY) {
1472 /* Instead of fetching relative to IY, just grab directly
1473 from the address IY refers to */
1474 char *l = aopGetLitWordLong (aop, offset, FALSE);
1476 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1478 if (aop->size < 2) {
1479 emit2("ld %s,!zero", _pairs[pairId].h);
1482 else if (pairId == PAIR_IY)
1486 emit2 ("push %s", _pairs[getPairId(aop)].name);
1492 PAIR_ID id = makeFreePairId (ic, &isUsed);
1495 /* Can't load into parts, so load into HL then exchange. */
1496 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1497 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1498 emit2 ("push %s", _pairs[id].name);
1504 else if (isUnsplitable(aop))
1506 emit2("push %s", _pairs[getPairId(aop)].name);
1507 emit2("pop %s", _pairs[pairId].name);
1511 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1512 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1514 /* PENDING: check? */
1515 if (pairId == PAIR_HL)
1516 spillPair (PAIR_HL);
1521 fetchPair (PAIR_ID pairId, asmop * aop)
1523 fetchPairLong (pairId, aop, NULL, 0);
1527 fetchHL (asmop * aop)
1529 fetchPair (PAIR_HL, aop);
1533 setupPairFromSP (PAIR_ID id, int offset)
1535 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1537 if (_G.preserveCarry)
1543 if (offset < INT8MIN || offset > INT8MAX)
1545 emit2 ("ld hl,!immedword", offset);
1546 emit2 ("add hl,sp");
1550 emit2 ("!ldahlsp", offset);
1553 if (_G.preserveCarry)
1561 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1566 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1567 fetchLitPair (pairId, aop, 0);
1571 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1573 fetchLitPair (pairId, aop, offset);
1574 _G.pairs[pairId].offset = offset;
1578 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1579 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1582 int offset = aop->aopu.aop_stk + _G.stack.offset;
1584 if (_G.pairs[pairId].last_type == aop->type &&
1585 _G.pairs[pairId].offset == offset)
1591 /* PENDING: Do this better. */
1592 if (_G.preserveCarry)
1594 sprintf (buffer, "%d", offset + _G.stack.pushed);
1595 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1596 emit2 ("add %s,sp", _pairs[pairId].name);
1597 _G.pairs[pairId].last_type = aop->type;
1598 _G.pairs[pairId].offset = offset;
1599 if (_G.preserveCarry)
1607 /* Doesnt include _G.stack.pushed */
1608 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1610 if (aop->aopu.aop_stk > 0)
1612 abso += _G.stack.param_offset;
1614 assert (pairId == PAIR_HL);
1615 /* In some cases we can still inc or dec hl */
1616 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1618 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1622 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1624 _G.pairs[pairId].offset = abso;
1629 if (pairId != aop->aopu.aop_pairId)
1630 genMovePairPair(aop->aopu.aop_pairId, pairId);
1631 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1637 _G.pairs[pairId].last_type = aop->type;
1643 emit2 ("!tlabeldef", key);
1644 _G.lines.current->isLabel = 1;
1648 /*-----------------------------------------------------------------*/
1649 /* aopGet - for fetching value of the aop */
1650 /*-----------------------------------------------------------------*/
1652 aopGet (asmop * aop, int offset, bool bit16)
1654 // char *s = buffer;
1656 /* offset is greater than size then zero */
1657 /* PENDING: this seems a bit screwed in some pointer cases. */
1658 if (offset > (aop->size - 1) &&
1659 aop->type != AOP_LIT)
1661 tsprintf (buffer, sizeof(buffer), "!zero");
1662 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1665 /* depending on type */
1669 tsprintf (buffer, sizeof(buffer), "!zero");
1670 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1673 /* PENDING: re-target */
1675 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1680 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1683 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1686 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1689 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1692 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1696 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1697 SNPRINTF (buffer, sizeof(buffer), "a");
1699 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1705 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1706 SNPRINTF (buffer, sizeof(buffer), "a");
1708 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1711 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1714 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1715 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1716 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1718 else if( z80_opts.port_mode == 180 )
1719 { /* z180 in0/out0 mode */
1720 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1724 emit2( "in a,(%s)", aop->aopu.aop_dir );
1727 SNPRINTF (buffer, sizeof(buffer), "a");
1729 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1733 return aop->aopu.aop_reg[offset]->name;
1737 setupPair (PAIR_HL, aop, offset);
1738 tsprintf (buffer, sizeof(buffer), "!*hl");
1740 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1744 setupPair (PAIR_IY, aop, offset);
1745 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1747 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1751 setupPair (PAIR_IY, aop, offset);
1752 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1754 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1759 setupPair (PAIR_HL, aop, offset);
1760 tsprintf (buffer, sizeof(buffer), "!*hl");
1764 if (aop->aopu.aop_stk >= 0)
1765 offset += _G.stack.param_offset;
1766 tsprintf (buffer, sizeof(buffer),
1767 "!*ixx", aop->aopu.aop_stk + offset);
1770 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1773 wassertl (0, "Tried to fetch from a bit variable");
1782 tsprintf(buffer, sizeof(buffer), "!zero");
1783 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1787 wassert (offset < 2);
1788 return aop->aopu.aop_str[offset];
1791 return aopLiteral (aop->aopu.aop_lit, offset);
1795 unsigned long v = aop->aopu.aop_simplelit;
1798 tsprintf (buffer, sizeof(buffer),
1799 "!immedbyte", (unsigned int) v & 0xff);
1801 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1805 return aop->aopu.aop_str[offset];
1808 setupPair (aop->aopu.aop_pairId, aop, offset);
1809 if (aop->aopu.aop_pairId==PAIR_IX)
1810 SNPRINTF (buffer, sizeof(buffer),
1812 else if (aop->aopu.aop_pairId==PAIR_IY)
1813 SNPRINTF (buffer, sizeof(buffer),
1816 SNPRINTF (buffer, sizeof(buffer),
1817 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1819 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1824 wassertl (0, "aopget got unsupported aop->type");
1829 isRegString (const char *s)
1831 if (!strcmp (s, "b") ||
1843 isConstant (const char *s)
1845 /* This is a bit of a hack... */
1846 return (*s == '#' || *s == '$');
1850 canAssignToPtr (const char *s)
1852 if (isRegString (s))
1859 /*-----------------------------------------------------------------*/
1860 /* aopPut - puts a string for a aop */
1861 /*-----------------------------------------------------------------*/
1863 aopPut (asmop * aop, const char *s, int offset)
1867 if (aop->size && offset > (aop->size - 1))
1869 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1870 "aopPut got offset > aop->size");
1875 tsprintf(buffer2, sizeof(buffer2), s);
1878 /* will assign value to value */
1879 /* depending on where it is ofcourse */
1883 _moveA (s); /* in case s is volatile */
1889 if (strcmp (s, "a"))
1890 emit2 ("ld a,%s", s);
1891 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1898 if (strcmp (s, "a"))
1899 emit2 ("ld a,%s", s);
1900 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1903 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1910 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1911 && s[0] != 'h' && s[0] != 'l'))
1913 emit2( "ld a,%s", s );
1917 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1918 emit2( "out (c),%s", s );
1923 spillPair (PAIR_BC);
1925 else if( z80_opts.port_mode == 180 )
1926 { /* z180 in0/out0 mode */
1927 emit2( "ld a,%s", s );
1928 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1932 emit2( "ld a,%s", s );
1933 emit2( "out (%s),a", aop->aopu.aop_dir );
1939 if (!strcmp (s, "!*hl"))
1940 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1943 aop->aopu.aop_reg[offset]->name, s);
1944 spillPairReg(aop->aopu.aop_reg[offset]->name);
1949 if (!canAssignToPtr (s))
1951 emit2 ("ld a,%s", s);
1952 setupPair (PAIR_IY, aop, offset);
1953 emit2 ("ld !*iyx,a", offset);
1957 setupPair (PAIR_IY, aop, offset);
1958 emit2 ("ld !*iyx,%s", offset, s);
1964 /* PENDING: for re-target */
1965 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1967 emit2 ("ld a,!*hl");
1970 setupPair (PAIR_HL, aop, offset);
1972 emit2 ("ld !*hl,%s", s);
1977 if (!canAssignToPtr (s))
1979 emit2 ("ld a,%s", s);
1980 setupPair (PAIR_IY, aop, offset);
1981 emit2 ("ld !*iyx,a", offset);
1985 setupPair (PAIR_IY, aop, offset);
1986 emit2 ("ld !*iyx,%s", offset, s);
1993 /* PENDING: re-target */
1994 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1996 emit2 ("ld a,!*hl");
1999 setupPair (PAIR_HL, aop, offset);
2000 if (!canAssignToPtr (s))
2002 emit2 ("ld a,%s", s);
2003 emit2 ("ld !*hl,a");
2006 emit2 ("ld !*hl,%s", s);
2010 if (aop->aopu.aop_stk >= 0)
2011 offset += _G.stack.param_offset;
2012 if (!canAssignToPtr (s))
2014 emit2 ("ld a,%s", s);
2015 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2019 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2025 /* if bit variable */
2026 if (!aop->aopu.aop_dir)
2028 emit2 ("ld a,!zero");
2033 /* In bit space but not in C - cant happen */
2034 wassertl (0, "Tried to write into a bit variable");
2040 if (strcmp (aop->aopu.aop_str[offset], s))
2042 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2044 spillPairReg(aop->aopu.aop_str[offset]);
2049 if (!offset && (strcmp (s, "acc") == 0))
2053 wassertl (0, "Tried to access past the end of A");
2057 if (strcmp (aop->aopu.aop_str[offset], s))
2059 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2060 spillPairReg(aop->aopu.aop_str[offset]);
2066 wassert (offset < 2);
2067 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2068 spillPairReg(aop->aopu.aop_str[offset]);
2072 setupPair (aop->aopu.aop_pairId, aop, offset);
2073 if (aop->aopu.aop_pairId==PAIR_IX)
2074 emit2 ("ld !*ixx,%s", 0, s);
2075 else if (aop->aopu.aop_pairId==PAIR_IY)
2076 emit2 ("ld !*iyx,%s", 0, s);
2078 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2082 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2083 "aopPut got unsupported aop->type");
2088 #define AOP(op) op->aop
2089 #define AOP_TYPE(op) AOP(op)->type
2090 #define AOP_SIZE(op) AOP(op)->size
2091 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2092 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2095 commitPair (asmop * aop, PAIR_ID id)
2097 /* PENDING: Verify this. */
2098 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2102 aopPut (aop, "a", 0);
2103 aopPut (aop, "d", 1);
2108 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2110 char *l = aopGetLitWordLong (aop, 0, FALSE);
2113 emit2 ("ld (%s),%s", l, _pairs[id].name);
2117 aopPut (aop, _pairs[id].l, 0);
2118 aopPut (aop, _pairs[id].h, 1);
2123 /*-----------------------------------------------------------------*/
2124 /* getDataSize - get the operand data size */
2125 /*-----------------------------------------------------------------*/
2127 getDataSize (operand * op)
2130 size = AOP_SIZE (op);
2134 wassertl (0, "Somehow got a three byte data pointer");
2139 /*-----------------------------------------------------------------*/
2140 /* movLeft2Result - move byte from left to result */
2141 /*-----------------------------------------------------------------*/
2143 movLeft2Result (operand * left, int offl,
2144 operand * result, int offr, int sign)
2148 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2150 l = aopGet (AOP (left), offl, FALSE);
2154 aopPut (AOP (result), l, offr);
2158 if (getDataSize (left) == offl + 1)
2160 emit2 ("ld a,%s", l);
2161 aopPut (AOP (result), "a", offr);
2168 movLeft2ResultLong (operand * left, int offl,
2169 operand * result, int offr, int sign,
2174 movLeft2Result (left, offl, result, offr, sign);
2178 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2179 wassertl (size == 2, "Only implemented for two bytes or one");
2181 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2183 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2184 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2186 spillPair (PAIR_HL);
2188 else if ( getPairId ( AOP (result)) == PAIR_IY)
2190 PAIR_ID id = getPairId (AOP (left));
2191 if (id != PAIR_INVALID)
2193 emit2("push %s", _pairs[id].name);
2204 movLeft2Result (left, offl, result, offr, sign);
2205 movLeft2Result (left, offl+1, result, offr+1, sign);
2210 /** Put Acc into a register set
2213 outAcc (operand * result)
2216 size = getDataSize (result);
2219 aopPut (AOP (result), "a", 0);
2222 /* unsigned or positive */
2225 aopPut (AOP (result), "!zero", offset++);
2230 /** Take the value in carry and put it into a register
2233 outBitC (operand * result)
2235 /* if the result is bit */
2236 if (AOP_TYPE (result) == AOP_CRY)
2238 if (!IS_OP_RUONLY (result))
2239 aopPut (AOP (result), "c", 0);
2243 emit2 ("ld a,!zero");
2249 /*-----------------------------------------------------------------*/
2250 /* toBoolean - emit code for orl a,operator(sizeop) */
2251 /*-----------------------------------------------------------------*/
2253 _toBoolean (operand * oper)
2255 int size = AOP_SIZE (oper);
2259 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2262 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2266 if (AOP (oper)->type != AOP_ACC)
2269 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2275 /*-----------------------------------------------------------------*/
2276 /* genNot - generate code for ! operation */
2277 /*-----------------------------------------------------------------*/
2282 /* assign asmOps to operand & result */
2283 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2284 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2286 /* if in bit space then a special case */
2287 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2289 wassertl (0, "Tried to negate a bit");
2292 _toBoolean (IC_LEFT (ic));
2297 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2298 emit2 ("sub a,!one");
2299 outBitC (IC_RESULT (ic));
2301 /* release the aops */
2302 freeAsmop (IC_LEFT (ic), NULL, ic);
2303 freeAsmop (IC_RESULT (ic), NULL, ic);
2306 /*-----------------------------------------------------------------*/
2307 /* genCpl - generate code for complement */
2308 /*-----------------------------------------------------------------*/
2316 /* assign asmOps to operand & result */
2317 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2318 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2320 /* if both are in bit space then
2322 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2323 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2325 wassertl (0, "Left and the result are in bit space");
2328 size = AOP_SIZE (IC_RESULT (ic));
2331 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2334 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2337 /* release the aops */
2338 freeAsmop (IC_LEFT (ic), NULL, ic);
2339 freeAsmop (IC_RESULT (ic), NULL, ic);
2343 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2350 store de into result
2355 store de into result
2357 const char *first = isAdd ? "add" : "sub";
2358 const char *later = isAdd ? "adc" : "sbc";
2360 wassertl (IS_GB, "Code is only relevent to the gbz80");
2361 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2363 fetchPair (PAIR_DE, left);
2366 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2369 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2372 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2373 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2375 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2376 aopGet (right, MSB24, FALSE);
2380 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2383 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2385 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2386 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2390 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2392 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2395 /*-----------------------------------------------------------------*/
2396 /* genUminusFloat - unary minus for floating points */
2397 /*-----------------------------------------------------------------*/
2399 genUminusFloat (operand * op, operand * result)
2401 int size, offset = 0;
2403 emitDebug("; genUminusFloat");
2405 /* for this we just need to flip the
2406 first bit then copy the rest in place */
2407 size = AOP_SIZE (op) - 1;
2409 _moveA(aopGet (AOP (op), MSB32, FALSE));
2411 emit2("xor a,!immedbyte", 0x80);
2412 aopPut (AOP (result), "a", MSB32);
2416 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2421 /*-----------------------------------------------------------------*/
2422 /* genUminus - unary minus code generation */
2423 /*-----------------------------------------------------------------*/
2425 genUminus (iCode * ic)
2428 sym_link *optype, *rtype;
2431 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2432 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2434 /* if both in bit space then special
2436 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2437 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2439 wassertl (0, "Left and right are in bit space");
2443 optype = operandType (IC_LEFT (ic));
2444 rtype = operandType (IC_RESULT (ic));
2446 /* if float then do float stuff */
2447 if (IS_FLOAT (optype))
2449 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2453 /* otherwise subtract from zero */
2454 size = AOP_SIZE (IC_LEFT (ic));
2456 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2458 /* Create a new asmop with value zero */
2459 asmop *azero = newAsmop (AOP_SIMPLELIT);
2460 azero->aopu.aop_simplelit = 0;
2462 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2470 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2471 emit2 ("ld a,!zero");
2472 emit2 ("sbc a,%s", l);
2473 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2476 /* if any remaining bytes in the result */
2477 /* we just need to propagate the sign */
2478 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2483 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2487 /* release the aops */
2488 freeAsmop (IC_LEFT (ic), NULL, ic);
2489 freeAsmop (IC_RESULT (ic), NULL, ic);
2492 /*-----------------------------------------------------------------*/
2493 /* assignResultValue - */
2494 /*-----------------------------------------------------------------*/
2496 assignResultValue (operand * oper)
2498 int size = AOP_SIZE (oper);
2501 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2502 topInA = requiresHL (AOP (oper));
2504 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2506 /* We do it the hard way here. */
2508 aopPut (AOP (oper), _fReturn[0], 0);
2509 aopPut (AOP (oper), _fReturn[1], 1);
2511 aopPut (AOP (oper), _fReturn[0], 2);
2512 aopPut (AOP (oper), _fReturn[1], 3);
2516 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2517 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2520 _emitMove ("a", _fReturn[size-1]);
2521 _emitMove (_fReturn[size-1], _fReturn[size]);
2522 _emitMove (_fReturn[size], "a");
2523 aopPut (AOP (oper), _fReturn[size], size-1);
2528 aopPut (AOP (oper), _fReturn[size], size);
2533 /** Simple restore that doesn't take into account what is used in the
2537 _restoreRegsAfterCall(void)
2539 if (_G.stack.pushedDE)
2542 _G.stack.pushedDE = FALSE;
2544 if (_G.stack.pushedBC)
2547 _G.stack.pushedBC = FALSE;
2549 _G.saves.saved = FALSE;
2553 _saveRegsForCall(iCode *ic, int sendSetSize)
2556 o Stack parameters are pushed before this function enters
2557 o DE and BC may be used in this function.
2558 o HL and DE may be used to return the result.
2559 o HL and DE may be used to send variables.
2560 o DE and BC may be used to store the result value.
2561 o HL may be used in computing the sent value of DE
2562 o The iPushes for other parameters occur before any addSets
2564 Logic: (to be run inside the first iPush or if none, before sending)
2565 o Compute if DE and/or BC are in use over the call
2566 o Compute if DE is used in the send set
2567 o Compute if DE and/or BC are used to hold the result value
2568 o If (DE is used, or in the send set) and is not used in the result, push.
2569 o If BC is used and is not in the result, push
2571 o If DE is used in the send set, fetch
2572 o If HL is used in the send set, fetch
2576 if (_G.saves.saved == FALSE) {
2577 bool deInUse, bcInUse;
2579 bool bcInRet = FALSE, deInRet = FALSE;
2582 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2583 z80_rUmaskForOp (IC_RESULT(ic)));
2585 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2586 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2588 deSending = (sendSetSize > 1);
2590 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2592 if (bcInUse && bcInRet == FALSE) {
2594 _G.stack.pushedBC = TRUE;
2596 if (deInUse && deInRet == FALSE) {
2598 _G.stack.pushedDE = TRUE;
2601 _G.saves.saved = TRUE;
2604 /* Already saved. */
2608 /*-----------------------------------------------------------------*/
2609 /* genIpush - genrate code for pushing this gets a little complex */
2610 /*-----------------------------------------------------------------*/
2612 genIpush (iCode * ic)
2614 int size, offset = 0;
2617 /* if this is not a parm push : ie. it is spill push
2618 and spill push is always done on the local stack */
2621 wassertl(0, "Encountered an unsupported spill push.");
2625 if (_G.saves.saved == FALSE) {
2626 /* Caller saves, and this is the first iPush. */
2627 /* Scan ahead until we find the function that we are pushing parameters to.
2628 Count the number of addSets on the way to figure out what registers
2629 are used in the send set.
2632 iCode *walk = ic->next;
2635 if (walk->op == SEND) {
2638 else if (walk->op == CALL || walk->op == PCALL) {
2647 _saveRegsForCall(walk, nAddSets);
2650 /* Already saved by another iPush. */
2653 /* then do the push */
2654 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2656 size = AOP_SIZE (IC_LEFT (ic));
2658 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2660 _G.stack.pushed += 2;
2661 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2667 fetchHL (AOP (IC_LEFT (ic)));
2669 spillPair (PAIR_HL);
2670 _G.stack.pushed += 2;
2675 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2677 spillPair (PAIR_HL);
2678 _G.stack.pushed += 2;
2679 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2681 spillPair (PAIR_HL);
2682 _G.stack.pushed += 2;
2688 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2690 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2692 emit2 ("ld a,(%s)", l);
2697 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2698 if (!strcmp(l, "b"))
2700 else if (!strcmp(l, "d"))
2702 else if (!strcmp(l, "h"))
2706 emit2 ("ld a,%s", l);
2715 freeAsmop (IC_LEFT (ic), NULL, ic);
2718 /*-----------------------------------------------------------------*/
2719 /* genIpop - recover the registers: can happen only for spilling */
2720 /*-----------------------------------------------------------------*/
2722 genIpop (iCode * ic)
2727 /* if the temp was not pushed then */
2728 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2731 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2732 size = AOP_SIZE (IC_LEFT (ic));
2733 offset = (size - 1);
2734 if (isPair (AOP (IC_LEFT (ic))))
2736 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2744 spillPair (PAIR_HL);
2745 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2749 freeAsmop (IC_LEFT (ic), NULL, ic);
2752 /* This is quite unfortunate */
2754 setArea (int inHome)
2757 static int lastArea = 0;
2759 if (_G.in_home != inHome) {
2761 const char *sz = port->mem.code_name;
2762 port->mem.code_name = "HOME";
2763 emit2("!area", CODE_NAME);
2764 port->mem.code_name = sz;
2767 emit2("!area", CODE_NAME); */
2768 _G.in_home = inHome;
2779 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2783 symbol *sym = OP_SYMBOL (op);
2785 if (sym->isspilt || sym->nRegs == 0)
2788 aopOp (op, ic, FALSE, FALSE);
2791 if (aop->type == AOP_REG)
2794 for (i = 0; i < aop->size; i++)
2796 if (pairId == PAIR_DE)
2798 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2799 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2801 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2804 else if (pairId == PAIR_BC)
2806 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2807 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2809 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2819 freeAsmop (IC_LEFT (ic), NULL, ic);
2823 /** Emit the code for a call statement
2826 emitCall (iCode * ic, bool ispcall)
2828 bool bInRet, cInRet, dInRet, eInRet;
2829 sym_link *dtype = operandType (IC_LEFT (ic));
2831 /* if caller saves & we have not saved then */
2837 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2839 /* if send set is not empty then assign */
2844 int nSend = elementsInSet(_G.sendSet);
2845 bool swapped = FALSE;
2847 int _z80_sendOrder[] = {
2852 /* Check if the parameters are swapped. If so route through hl instead. */
2853 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2855 sic = setFirstItem(_G.sendSet);
2856 sic = setNextItem(_G.sendSet);
2858 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2859 /* The second send value is loaded from one the one that holds the first
2860 send, i.e. it is overwritten. */
2861 /* Cache the first in HL, and load the second from HL instead. */
2862 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2863 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2869 for (sic = setFirstItem (_G.sendSet); sic;
2870 sic = setNextItem (_G.sendSet))
2873 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2875 size = AOP_SIZE (IC_LEFT (sic));
2876 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2877 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2879 // PENDING: Mild hack
2880 if (swapped == TRUE && send == 1) {
2882 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2885 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2887 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2890 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2894 freeAsmop (IC_LEFT (sic), NULL, sic);
2901 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2903 werror (W_INDIR_BANKED);
2905 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2907 if (isLitWord (AOP (IC_LEFT (ic))))
2909 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2913 symbol *rlbl = newiTempLabel (NULL);
2914 spillPair (PAIR_HL);
2915 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2917 _G.stack.pushed += 2;
2919 fetchHL (AOP (IC_LEFT (ic)));
2921 emit2 ("!tlabeldef", (rlbl->key + 100));
2922 _G.lines.current->isLabel = 1;
2923 _G.stack.pushed -= 2;
2925 freeAsmop (IC_LEFT (ic), NULL, ic);
2929 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2930 OP_SYMBOL (IC_LEFT (ic))->rname :
2931 OP_SYMBOL (IC_LEFT (ic))->name;
2932 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2934 emit2 ("call banked_call");
2935 emit2 ("!dws", name);
2936 emit2 ("!dw !bankimmeds", name);
2941 emit2 ("call %s", name);
2946 /* Mark the registers as restored. */
2947 _G.saves.saved = FALSE;
2949 /* if we need assign a result value */
2950 if ((IS_ITEMP (IC_RESULT (ic)) &&
2951 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2952 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2953 IS_TRUE_SYMOP (IC_RESULT (ic)))
2955 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2957 assignResultValue (IC_RESULT (ic));
2959 freeAsmop (IC_RESULT (ic), NULL, ic);
2962 /* adjust the stack for parameters if required */
2965 int i = ic->parmBytes;
2967 _G.stack.pushed -= i;
2970 emit2 ("!ldaspsp", i);
2977 emit2 ("ld iy,!immedword", i);
2978 emit2 ("add iy,sp");
2999 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3000 bInRet = bitVectBitValue(result, B_IDX);
3001 cInRet = bitVectBitValue(result, C_IDX);
3002 dInRet = bitVectBitValue(result, D_IDX);
3003 eInRet = bitVectBitValue(result, E_IDX);
3013 if (_G.stack.pushedDE)
3015 if (dInRet && eInRet)
3017 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3021 /* Only restore E */
3028 /* Only restore D */
3036 _G.stack.pushedDE = FALSE;
3039 if (_G.stack.pushedBC)
3041 if (bInRet && cInRet)
3043 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3047 /* Only restore C */
3054 /* Only restore B */
3062 _G.stack.pushedBC = FALSE;
3066 /*-----------------------------------------------------------------*/
3067 /* genCall - generates a call statement */
3068 /*-----------------------------------------------------------------*/
3070 genCall (iCode * ic)
3072 emitCall (ic, FALSE);
3075 /*-----------------------------------------------------------------*/
3076 /* genPcall - generates a call by pointer statement */
3077 /*-----------------------------------------------------------------*/
3079 genPcall (iCode * ic)
3081 emitCall (ic, TRUE);
3084 /*-----------------------------------------------------------------*/
3085 /* resultRemat - result is rematerializable */
3086 /*-----------------------------------------------------------------*/
3088 resultRemat (iCode * ic)
3090 if (SKIP_IC (ic) || ic->op == IFX)
3093 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3095 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3096 if (sym->remat && !POINTER_SET (ic))
3103 extern set *publics;
3105 /*-----------------------------------------------------------------*/
3106 /* genFunction - generated code for function entry */
3107 /*-----------------------------------------------------------------*/
3109 genFunction (iCode * ic)
3113 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3116 bool bcInUse = FALSE;
3117 bool deInUse = FALSE;
3119 setArea (IFFUNC_NONBANKED (sym->type));
3121 /* PENDING: Reset the receive offset as it
3122 doesn't seem to get reset anywhere else.
3124 _G.receiveOffset = 0;
3126 /* Record the last function name for debugging. */
3127 _G.lastFunctionName = sym->rname;
3129 /* Create the function header */
3130 emit2 ("!functionheader", sym->name);
3131 if (!IS_STATIC(sym->etype))
3133 sprintf (buffer, "%s_start", sym->rname);
3134 emit2 ("!labeldef", buffer);
3135 _G.lines.current->isLabel = 1;
3137 emit2 ("!functionlabeldef", sym->rname);
3138 _G.lines.current->isLabel = 1;
3140 ftype = operandType (IC_LEFT (ic));
3142 if (IFFUNC_ISNAKED(ftype))
3144 emitDebug("; naked function: no prologue.");
3148 /* if this is an interrupt service routine
3149 then save all potentially used registers. */
3150 if (IFFUNC_ISISR (sym->type))
3152 /* If critical function then turn interrupts off */
3153 /* except when no interrupt number is given then it implies the NMI handler */
3154 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3163 /* This is a non-ISR function.
3164 If critical function then turn interrupts off */
3165 if (IFFUNC_ISCRITICAL (sym->type))
3173 //get interrupt enable flag IFF2 into P/O
3182 if (options.profile)
3184 emit2 ("!profileenter");
3187 /* PENDING: callee-save etc */
3189 _G.stack.param_offset = 0;
3191 if (z80_opts.calleeSavesBC)
3196 /* Detect which registers are used. */
3197 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3200 for (i = 0; i < sym->regsUsed->size; i++)
3202 if (bitVectBitValue (sym->regsUsed, i))
3216 /* Other systems use DE as a temporary. */
3227 _G.stack.param_offset += 2;
3230 _G.calleeSaves.pushedBC = bcInUse;
3235 _G.stack.param_offset += 2;
3238 _G.calleeSaves.pushedDE = deInUse;
3240 /* adjust the stack for the function */
3241 _G.stack.last = sym->stack;
3244 for (sym = setFirstItem (istack->syms); sym;
3245 sym = setNextItem (istack->syms))
3247 if (sym->_isparm && !IS_REGPARM (sym->etype))
3253 sym = OP_SYMBOL (IC_LEFT (ic));
3255 _G.omitFramePtr = options.ommitFramePtr;
3256 if (IS_Z80 && !stackParm && !sym->stack)
3258 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3259 /* the above !sym->stack condition can be removed. -- EEP */
3261 emit2 ("!ldaspsp", -sym->stack);
3262 _G.omitFramePtr = TRUE;
3264 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3265 emit2 ("!enterxl", sym->stack);
3266 else if (sym->stack)
3267 emit2 ("!enterx", sym->stack);
3271 _G.stack.offset = sym->stack;
3274 /*-----------------------------------------------------------------*/
3275 /* genEndFunction - generates epilogue for functions */
3276 /*-----------------------------------------------------------------*/
3278 genEndFunction (iCode * ic)
3280 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3282 if (IFFUNC_ISNAKED(sym->type))
3284 emitDebug("; naked function: no epilogue.");
3288 /* PENDING: calleeSave */
3289 if (IS_Z80 && _G.omitFramePtr)
3291 if (_G.stack.offset)
3292 emit2 ("!ldaspsp", _G.stack.offset);
3294 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3296 emit2 ("!leavexl", _G.stack.offset);
3298 else if (_G.stack.offset)
3300 emit2 ("!leavex", _G.stack.offset);
3307 if (_G.calleeSaves.pushedDE)
3310 _G.calleeSaves.pushedDE = FALSE;
3313 if (_G.calleeSaves.pushedBC)
3316 _G.calleeSaves.pushedBC = FALSE;
3319 if (options.profile)
3321 emit2 ("!profileexit");
3324 /* if this is an interrupt service routine
3325 then save all potentially used registers. */
3326 if (IFFUNC_ISISR (sym->type))
3330 /* If critical function then turn interrupts back on */
3331 /* except when no interrupt number is given then it implies the NMI handler */
3332 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3339 /* This is a non-ISR function.
3340 If critical function then turn interrupts back on */
3341 if (IFFUNC_ISCRITICAL (sym->type))
3349 symbol *tlbl = newiTempLabel (NULL);
3352 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3353 //don't enable interrupts as they were off before
3354 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3356 emit2 ("!tlabeldef", (tlbl->key + 100));
3357 _G.lines.current->isLabel = 1;
3362 if (options.debug && currFunc)
3364 debugFile->writeEndFunction (currFunc, ic, 1);
3367 if (IFFUNC_ISISR (sym->type))
3369 /* "critical interrupt" is used to imply NMI handler */
3370 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3377 /* Both banked and non-banked just ret */
3381 if (!IS_STATIC(sym->etype))
3383 sprintf (buffer, "%s_end", sym->rname);
3384 emit2 ("!labeldef", buffer);
3385 _G.lines.current->isLabel = 1;
3388 _G.flushStatics = 1;
3389 _G.stack.pushed = 0;
3390 _G.stack.offset = 0;
3393 /*-----------------------------------------------------------------*/
3394 /* genRet - generate code for return statement */
3395 /*-----------------------------------------------------------------*/
3400 /* Errk. This is a hack until I can figure out how
3401 to cause dehl to spill on a call */
3402 int size, offset = 0;
3404 /* if we have no return value then
3405 just generate the "ret" */
3409 /* we have something to return then
3410 move the return value into place */
3411 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3412 size = AOP_SIZE (IC_LEFT (ic));
3414 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3417 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3421 emit2 ("ld de,%s", l);
3425 emit2 ("ld hl,%s", l);
3431 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3435 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3437 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3438 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3444 l = aopGet (AOP (IC_LEFT (ic)), offset,
3446 if (strcmp (_fReturn[offset], l))
3447 emit2 ("ld %s,%s", _fReturn[offset], l);
3452 freeAsmop (IC_LEFT (ic), NULL, ic);
3455 /* generate a jump to the return label
3456 if the next is not the return statement */
3457 if (!(ic->next && ic->next->op == LABEL &&
3458 IC_LABEL (ic->next) == returnLabel))
3460 emit2 ("jp !tlabel", returnLabel->key + 100);
3463 /*-----------------------------------------------------------------*/
3464 /* genLabel - generates a label */
3465 /*-----------------------------------------------------------------*/
3467 genLabel (iCode * ic)
3469 /* special case never generate */
3470 if (IC_LABEL (ic) == entryLabel)
3473 emitLabel (IC_LABEL (ic)->key + 100);
3476 /*-----------------------------------------------------------------*/
3477 /* genGoto - generates a ljmp */
3478 /*-----------------------------------------------------------------*/
3480 genGoto (iCode * ic)
3482 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3485 /*-----------------------------------------------------------------*/
3486 /* genPlusIncr :- does addition with increment if possible */
3487 /*-----------------------------------------------------------------*/
3489 genPlusIncr (iCode * ic)
3491 unsigned int icount;
3492 unsigned int size = getDataSize (IC_RESULT (ic));
3493 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3495 /* will try to generate an increment */
3496 /* if the right side is not a literal
3498 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3501 emitDebug ("; genPlusIncr");
3503 icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3505 /* If result is a pair */
3506 if (resultId != PAIR_INVALID)
3508 if (isLitWord (AOP (IC_LEFT (ic))))
3510 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3513 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3515 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3517 PAIR_ID freep = getFreePairId (ic);
3518 if (freep != PAIR_INVALID)
3520 fetchPair (freep, AOP (IC_RIGHT (ic)));
3521 emit2 ("add hl,%s", _pairs[freep].name);
3527 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3528 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3535 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3539 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3543 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3548 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3550 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3551 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3555 /* if the literal value of the right hand side
3556 is greater than 4 then it is not worth it */
3560 /* if increment 16 bits in register */
3561 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3567 symbol *tlbl = NULL;
3568 tlbl = newiTempLabel (NULL);
3571 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3574 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3577 emitLabel (tlbl->key + 100);
3581 /* if the sizes are greater than 1 then we cannot */
3582 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3583 AOP_SIZE (IC_LEFT (ic)) > 1)
3586 /* If the result is in a register then we can load then increment.
3588 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3590 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3593 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3598 /* we can if the aops of the left & result match or
3599 if they are in registers and the registers are the
3601 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3605 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3613 /*-----------------------------------------------------------------*/
3614 /* outBitAcc - output a bit in acc */
3615 /*-----------------------------------------------------------------*/
3617 outBitAcc (operand * result)
3619 symbol *tlbl = newiTempLabel (NULL);
3620 /* if the result is a bit */
3621 if (AOP_TYPE (result) == AOP_CRY)
3623 wassertl (0, "Tried to write A into a bit");
3627 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3628 emit2 ("ld a,!one");
3629 emitLabel (tlbl->key + 100);
3635 couldDestroyCarry (asmop *aop)
3639 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3648 shiftIntoPair (int idx, asmop *aop)
3650 PAIR_ID id = PAIR_INVALID;
3652 wassertl (IS_Z80, "Only implemented for the Z80");
3653 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3655 emitDebug ("; Shift into pair idx %u", idx);
3661 setupPair (PAIR_HL, aop, 0);
3666 setupPair (PAIR_IY, aop, 0);
3668 emit2 ("pop %s", _pairs[id].name);
3672 setupPair (PAIR_IY, aop, 0);
3675 wassertl (0, "Internal error - hit default case");
3678 aop->type = AOP_PAIRPTR;
3679 aop->aopu.aop_pairId = id;
3680 _G.pairs[id].offset = 0;
3681 _G.pairs[id].last_type = aop->type;
3685 setupToPreserveCarry (iCode * ic)
3687 asmop *left = AOP (IC_LEFT (ic));
3688 asmop *right = AOP (IC_RIGHT (ic));
3689 asmop *result = AOP (IC_RESULT (ic));
3691 wassert (left && right);
3695 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3697 shiftIntoPair (0, right);
3698 /* check result again, in case right == result */
3699 if (couldDestroyCarry (result))
3701 if (!isPairInUse (PAIR_DE, ic))
3702 shiftIntoPair (1, result);
3704 shiftIntoPair (2, result);
3707 else if (couldDestroyCarry (right))
3709 if (getPairId (result) == PAIR_HL)
3710 _G.preserveCarry = TRUE;
3712 shiftIntoPair (0, right);
3714 else if (couldDestroyCarry (result))
3716 shiftIntoPair (0, result);
3725 /*-----------------------------------------------------------------*/
3726 /* genPlus - generates code for addition */
3727 /*-----------------------------------------------------------------*/
3729 genPlus (iCode * ic)
3731 int size, offset = 0;
3733 /* special cases :- */
3735 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3736 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3737 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3739 /* Swap the left and right operands if:
3741 if literal, literal on the right or
3742 if left requires ACC or right is already
3745 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3746 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3747 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3749 operand *t = IC_RIGHT (ic);
3750 IC_RIGHT (ic) = IC_LEFT (ic);
3754 /* if both left & right are in bit
3756 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3757 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3760 wassertl (0, "Tried to add two bits");
3763 /* if left in bit space & right literal */
3764 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3765 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3767 /* Can happen I guess */
3768 wassertl (0, "Tried to add a bit to a literal");
3771 /* if I can do an increment instead
3772 of add then GOOD for ME */
3773 if (genPlusIncr (ic) == TRUE)
3776 size = getDataSize (IC_RESULT (ic));
3778 /* Special case when left and right are constant */
3779 if (isPair (AOP (IC_RESULT (ic))))
3782 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3783 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3785 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3791 sprintf (buffer, "#(%s + %s)", left, right);
3792 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3797 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3799 /* Fetch into HL then do the add */
3800 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3801 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3803 spillPair (PAIR_HL);
3805 if (left == PAIR_HL && right != PAIR_INVALID)
3807 emit2 ("add hl,%s", _pairs[right].name);
3810 else if (right == PAIR_HL && left != PAIR_INVALID)
3812 emit2 ("add hl,%s", _pairs[left].name);
3815 else if (right != PAIR_INVALID && right != PAIR_HL)
3817 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3818 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3821 else if (left != PAIR_INVALID && left != PAIR_HL)
3823 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3824 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3833 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3835 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3836 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3838 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3843 ld hl,sp+n trashes C so we can't afford to do it during an
3844 add with stack based variables. Worst case is:
3857 So you can't afford to load up hl if either left, right, or result
3858 is on the stack (*sigh*) The alt is:
3866 Combinations in here are:
3867 * If left or right are in bc then the loss is small - trap later
3868 * If the result is in bc then the loss is also small
3872 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3873 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3874 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3876 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3877 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3878 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3879 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3881 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3883 /* Swap left and right */
3884 operand *t = IC_RIGHT (ic);
3885 IC_RIGHT (ic) = IC_LEFT (ic);
3888 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3890 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3891 emit2 ("add hl,bc");
3895 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3896 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3897 emit2 ("add hl,de");
3899 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3905 /* Be paranoid on the GB with 4 byte variables due to how C
3906 can be trashed by lda hl,n(sp).
3908 _gbz80_emitAddSubLong (ic, TRUE);
3913 setupToPreserveCarry (ic);
3917 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3919 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3922 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3925 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3929 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3932 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3935 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3937 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3941 _G.preserveCarry = FALSE;
3942 freeAsmop (IC_LEFT (ic), NULL, ic);
3943 freeAsmop (IC_RIGHT (ic), NULL, ic);
3944 freeAsmop (IC_RESULT (ic), NULL, ic);
3947 /*-----------------------------------------------------------------*/
3948 /* genMinusDec :- does subtraction with deccrement if possible */
3949 /*-----------------------------------------------------------------*/
3951 genMinusDec (iCode * ic)
3953 unsigned int icount;
3954 unsigned int size = getDataSize (IC_RESULT (ic));
3956 /* will try to generate an increment */
3957 /* if the right side is not a literal we cannot */
3958 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3961 /* if the literal value of the right hand side
3962 is greater than 4 then it is not worth it */
3963 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3966 size = getDataSize (IC_RESULT (ic));
3968 /* if decrement 16 bits in register */
3969 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3970 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3973 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3977 /* If result is a pair */
3978 if (isPair (AOP (IC_RESULT (ic))))
3980 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3982 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3986 /* if increment 16 bits in register */
3987 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3991 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3994 emit2 ("dec %s", _getTempPairName());
3997 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4003 /* if the sizes are greater than 1 then we cannot */
4004 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4005 AOP_SIZE (IC_LEFT (ic)) > 1)
4008 /* we can if the aops of the left & result match or if they are in
4009 registers and the registers are the same */
4010 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4013 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4020 /*-----------------------------------------------------------------*/
4021 /* genMinus - generates code for subtraction */
4022 /*-----------------------------------------------------------------*/
4024 genMinus (iCode * ic)
4026 int size, offset = 0;
4027 unsigned long lit = 0L;
4029 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4030 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4031 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4033 /* special cases :- */
4034 /* if both left & right are in bit space */
4035 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4036 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4038 wassertl (0, "Tried to subtract two bits");
4042 /* if I can do an decrement instead of subtract then GOOD for ME */
4043 if (genMinusDec (ic) == TRUE)
4046 size = getDataSize (IC_RESULT (ic));
4048 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4053 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4057 /* Same logic as genPlus */
4060 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4061 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4062 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4064 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4065 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4066 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4067 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4069 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4070 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4072 if (left == PAIR_INVALID && right == PAIR_INVALID)
4077 else if (right == PAIR_INVALID)
4079 else if (left == PAIR_INVALID)
4082 fetchPair (left, AOP (IC_LEFT (ic)));
4083 /* Order is important. Right may be HL */
4084 fetchPair (right, AOP (IC_RIGHT (ic)));
4086 emit2 ("ld a,%s", _pairs[left].l);
4087 emit2 ("sub a,%s", _pairs[right].l);
4089 emit2 ("ld a,%s", _pairs[left].h);
4090 emit2 ("sbc a,%s", _pairs[right].h);
4092 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4094 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4096 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4102 /* Be paranoid on the GB with 4 byte variables due to how C
4103 can be trashed by lda hl,n(sp).
4105 _gbz80_emitAddSubLong (ic, FALSE);
4110 setupToPreserveCarry (ic);
4112 /* if literal, add a,#-lit, else normal subb */
4115 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4116 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4120 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4123 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4127 /* first add without previous c */
4129 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4131 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4133 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4136 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4137 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4138 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4140 wassertl (0, "Tried to subtract on a long pointer");
4144 _G.preserveCarry = FALSE;
4145 freeAsmop (IC_LEFT (ic), NULL, ic);
4146 freeAsmop (IC_RIGHT (ic), NULL, ic);
4147 freeAsmop (IC_RESULT (ic), NULL, ic);
4150 /*-----------------------------------------------------------------*/
4151 /* genMult - generates code for multiplication */
4152 /*-----------------------------------------------------------------*/
4154 genMult (iCode * ic)
4158 /* If true then the final operation should be a subtract */
4159 bool active = FALSE;
4162 /* Shouldn't occur - all done through function calls */
4163 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4164 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4165 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4167 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4169 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4170 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4171 AOP_SIZE (IC_RESULT (ic)) > 2)
4173 wassertl (0, "Multiplication is handled through support function calls");
4176 /* Swap left and right such that right is a literal */
4177 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4179 operand *t = IC_RIGHT (ic);
4180 IC_RIGHT (ic) = IC_LEFT (ic);
4184 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4186 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4187 // wassertl (val > 0, "Multiply must be positive");
4188 wassertl (val != 1, "Can't multiply by 1");
4190 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4192 _G.stack.pushedDE = TRUE;
4195 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4197 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4208 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4213 /* Fully unroled version of mul.s. Not the most efficient.
4215 for (count = 0; count < 16; count++)
4217 if (count != 0 && active)
4219 emit2 ("add hl,hl");
4223 if (active == FALSE)
4231 emit2 ("add hl,de");
4240 if (IS_Z80 && _G.stack.pushedDE)
4243 _G.stack.pushedDE = FALSE;
4247 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4249 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4251 freeAsmop (IC_LEFT (ic), NULL, ic);
4252 freeAsmop (IC_RIGHT (ic), NULL, ic);
4253 freeAsmop (IC_RESULT (ic), NULL, ic);
4256 /*-----------------------------------------------------------------*/
4257 /* genDiv - generates code for division */
4258 /*-----------------------------------------------------------------*/
4262 /* Shouldn't occur - all done through function calls */
4263 wassertl (0, "Division is handled through support function calls");
4266 /*-----------------------------------------------------------------*/
4267 /* genMod - generates code for division */
4268 /*-----------------------------------------------------------------*/
4272 /* Shouldn't occur - all done through function calls */
4276 /*-----------------------------------------------------------------*/
4277 /* genIfxJump :- will create a jump depending on the ifx */
4278 /*-----------------------------------------------------------------*/
4280 genIfxJump (iCode * ic, char *jval)
4285 /* if true label then we jump if condition
4289 jlbl = IC_TRUE (ic);
4290 if (!strcmp (jval, "a"))
4294 else if (!strcmp (jval, "c"))
4298 else if (!strcmp (jval, "nc"))
4302 else if (!strcmp (jval, "m"))
4306 else if (!strcmp (jval, "p"))
4312 /* The buffer contains the bit on A that we should test */
4318 /* false label is present */
4319 jlbl = IC_FALSE (ic);
4320 if (!strcmp (jval, "a"))
4324 else if (!strcmp (jval, "c"))
4328 else if (!strcmp (jval, "nc"))
4332 else if (!strcmp (jval, "m"))
4336 else if (!strcmp (jval, "p"))
4342 /* The buffer contains the bit on A that we should test */
4346 /* Z80 can do a conditional long jump */
4347 if (!strcmp (jval, "a"))
4351 else if (!strcmp (jval, "c"))
4354 else if (!strcmp (jval, "nc"))
4357 else if (!strcmp (jval, "m"))
4360 else if (!strcmp (jval, "p"))
4365 emit2 ("bit %s,a", jval);
4367 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4369 /* mark the icode as generated */
4375 _getPairIdName (PAIR_ID id)
4377 return _pairs[id].name;
4382 /* if unsigned char cmp with lit, just compare */
4384 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4386 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4389 emit2 ("xor a,!immedbyte", 0x80);
4390 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4393 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4395 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4397 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4398 // Pull left into DE and right into HL
4399 aopGet (AOP(left), LSB, FALSE);
4402 aopGet (AOP(right), LSB, FALSE);
4406 if (size == 0 && sign)
4408 // Highest byte when signed needs the bits flipped
4411 emit2 ("ld a,(de)");
4412 emit2 ("xor !immedbyte", 0x80);
4414 emit2 ("ld a,(hl)");
4415 emit2 ("xor !immedbyte", 0x80);
4419 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4423 emit2 ("ld a,(de)");
4424 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4434 spillPair (PAIR_HL);
4436 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4438 setupPair (PAIR_HL, AOP (left), 0);
4439 aopGet (AOP(right), LSB, FALSE);
4443 if (size == 0 && sign)
4445 // Highest byte when signed needs the bits flipped
4448 emit2 ("ld a,(hl)");
4449 emit2 ("xor !immedbyte", 0x80);
4451 emit2 ("ld a,%d(iy)", offset);
4452 emit2 ("xor !immedbyte", 0x80);
4456 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4460 emit2 ("ld a,(hl)");
4461 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4470 spillPair (PAIR_HL);
4471 spillPair (PAIR_IY);
4475 if (AOP_TYPE (right) == AOP_LIT)
4477 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4478 /* optimize if(x < 0) or if(x >= 0) */
4483 /* No sign so it's always false */
4488 /* Just load in the top most bit */
4489 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4490 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4492 genIfxJump (ifx, "7");
4504 /* First setup h and l contaning the top most bytes XORed */
4505 bool fDidXor = FALSE;
4506 if (AOP_TYPE (left) == AOP_LIT)
4508 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4509 emit2 ("ld %s,!immedbyte", _fTmp[0],
4510 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4514 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4515 emit2 ("xor a,!immedbyte", 0x80);
4516 emit2 ("ld %s,a", _fTmp[0]);
4519 if (AOP_TYPE (right) == AOP_LIT)
4521 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4522 emit2 ("ld %s,!immedbyte", _fTmp[1],
4523 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4527 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4528 emit2 ("xor a,!immedbyte", 0x80);
4529 emit2 ("ld %s,a", _fTmp[1]);
4535 /* Do a long subtract */
4538 _moveA (aopGet (AOP (left), offset, FALSE));
4540 if (sign && size == 0)
4542 emit2 ("ld a,%s", _fTmp[0]);
4543 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4547 /* Subtract through, propagating the carry */
4548 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4556 /** Generic compare for > or <
4559 genCmp (operand * left, operand * right,
4560 operand * result, iCode * ifx, int sign)
4562 int size, offset = 0;
4563 unsigned long lit = 0L;
4565 /* if left & right are bit variables */
4566 if (AOP_TYPE (left) == AOP_CRY &&
4567 AOP_TYPE (right) == AOP_CRY)
4569 /* Cant happen on the Z80 */
4570 wassertl (0, "Tried to compare two bits");
4574 /* Do a long subtract of right from left. */
4575 size = max (AOP_SIZE (left), AOP_SIZE (right));
4577 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4579 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4580 // Pull left into DE and right into HL
4581 aopGet (AOP(left), LSB, FALSE);
4584 aopGet (AOP(right), LSB, FALSE);
4588 emit2 ("ld a,(de)");
4589 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4598 spillPair (PAIR_HL);
4602 if (AOP_TYPE (right) == AOP_LIT)
4604 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4605 /* optimize if(x < 0) or if(x >= 0) */
4610 /* No sign so it's always false */
4615 /* Just load in the top most bit */
4616 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4617 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4619 genIfxJump (ifx, "7");
4630 genIfxJump (ifx, "nc");
4641 _moveA (aopGet (AOP (left), offset, FALSE));
4642 /* Subtract through, propagating the carry */
4643 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4649 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4653 /* Shift the sign bit up into carry */
4660 /* if the result is used in the next
4661 ifx conditional branch then generate
4662 code a little differently */
4670 genIfxJump (ifx, "c");
4674 genIfxJump (ifx, "m");
4679 genIfxJump (ifx, "c");
4686 /* Shift the sign bit up into carry */
4691 /* leave the result in acc */
4695 /*-----------------------------------------------------------------*/
4696 /* genCmpGt :- greater than comparison */
4697 /*-----------------------------------------------------------------*/
4699 genCmpGt (iCode * ic, iCode * ifx)
4701 operand *left, *right, *result;
4702 sym_link *letype, *retype;
4705 left = IC_LEFT (ic);
4706 right = IC_RIGHT (ic);
4707 result = IC_RESULT (ic);
4709 letype = getSpec (operandType (left));
4710 retype = getSpec (operandType (right));
4711 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4712 /* assign the amsops */
4713 aopOp (left, ic, FALSE, FALSE);
4714 aopOp (right, ic, FALSE, FALSE);
4715 aopOp (result, ic, TRUE, FALSE);
4717 genCmp (right, left, result, ifx, sign);
4719 freeAsmop (left, NULL, ic);
4720 freeAsmop (right, NULL, ic);
4721 freeAsmop (result, NULL, ic);
4724 /*-----------------------------------------------------------------*/
4725 /* genCmpLt - less than comparisons */
4726 /*-----------------------------------------------------------------*/
4728 genCmpLt (iCode * ic, iCode * ifx)
4730 operand *left, *right, *result;
4731 sym_link *letype, *retype;
4734 left = IC_LEFT (ic);
4735 right = IC_RIGHT (ic);
4736 result = IC_RESULT (ic);
4738 letype = getSpec (operandType (left));
4739 retype = getSpec (operandType (right));
4740 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4742 /* assign the amsops */
4743 aopOp (left, ic, FALSE, FALSE);
4744 aopOp (right, ic, FALSE, FALSE);
4745 aopOp (result, ic, TRUE, FALSE);
4747 genCmp (left, right, result, ifx, sign);
4749 freeAsmop (left, NULL, ic);
4750 freeAsmop (right, NULL, ic);
4751 freeAsmop (result, NULL, ic);
4754 /*-----------------------------------------------------------------*/
4755 /* gencjneshort - compare and jump if not equal */
4756 /* returns pair that still needs to be popped */
4757 /*-----------------------------------------------------------------*/
4759 gencjneshort (operand * left, operand * right, symbol * lbl)
4761 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4763 unsigned long lit = 0L;
4765 /* Swap the left and right if it makes the computation easier */
4766 if (AOP_TYPE (left) == AOP_LIT)
4773 /* if the right side is a literal then anything goes */
4774 if (AOP_TYPE (right) == AOP_LIT)
4776 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4779 _moveA (aopGet (AOP (left), offset, FALSE));
4784 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4791 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4797 _moveA (aopGet (AOP (left), offset, FALSE));
4798 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4801 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4802 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4807 /* if the right side is in a register or
4808 pointed to by HL, IX or IY */
4809 else if (AOP_TYPE (right) == AOP_REG ||
4810 AOP_TYPE (right) == AOP_HL ||
4811 AOP_TYPE (right) == AOP_IY ||
4812 AOP_TYPE (right) == AOP_STK ||
4813 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4814 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4815 AOP_IS_PAIRPTR (right, PAIR_IY))
4819 _moveA (aopGet (AOP (left), offset, FALSE));
4820 if (AOP_TYPE (right) == AOP_LIT &&
4821 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4824 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4828 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4829 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4834 /* right is in direct space or a pointer reg, need both a & b */
4838 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4840 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4841 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4849 emit2 ("; direct compare");
4850 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4851 _moveA (aopGet (AOP (right), offset, FALSE));
4852 emit2 ("sub %s", _pairs[pair].l);
4853 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4858 return PAIR_INVALID;
4861 /*-----------------------------------------------------------------*/
4862 /* gencjne - compare and jump if not equal */
4863 /*-----------------------------------------------------------------*/
4865 gencjne (operand * left, operand * right, symbol * lbl)
4867 symbol *tlbl = newiTempLabel (NULL);
4869 PAIR_ID pop = gencjneshort (left, right, lbl);
4872 emit2 ("ld a,!one");
4873 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4874 emitLabel (lbl->key + 100);
4876 emitLabel (tlbl->key + 100);
4880 /*-----------------------------------------------------------------*/
4881 /* genCmpEq - generates code for equal to */
4882 /*-----------------------------------------------------------------*/
4884 genCmpEq (iCode * ic, iCode * ifx)
4886 operand *left, *right, *result;
4888 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4889 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4890 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4892 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4894 /* Swap operands if it makes the operation easier. ie if:
4895 1. Left is a literal.
4897 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4899 operand *t = IC_RIGHT (ic);
4900 IC_RIGHT (ic) = IC_LEFT (ic);
4904 if (ifx && !AOP_SIZE (result))
4907 /* if they are both bit variables */
4908 if (AOP_TYPE (left) == AOP_CRY &&
4909 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4911 wassertl (0, "Tried to compare two bits");
4916 tlbl = newiTempLabel (NULL);
4917 pop = gencjneshort (left, right, tlbl);
4921 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4922 emitLabel (tlbl->key + 100);
4927 /* PENDING: do this better */
4928 symbol *lbl = newiTempLabel (NULL);
4930 emit2 ("!shortjp !tlabel", lbl->key + 100);
4931 emitLabel (tlbl->key + 100);
4933 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4934 emitLabel (lbl->key + 100);
4937 /* mark the icode as generated */
4942 /* if they are both bit variables */
4943 if (AOP_TYPE (left) == AOP_CRY &&
4944 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4946 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4952 gencjne (left, right, newiTempLabel (NULL));
4953 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4960 genIfxJump (ifx, "a");
4963 /* if the result is used in an arithmetic operation
4964 then put the result in place */
4965 if (AOP_TYPE (result) != AOP_CRY)
4970 /* leave the result in acc */
4974 freeAsmop (left, NULL, ic);
4975 freeAsmop (right, NULL, ic);
4976 freeAsmop (result, NULL, ic);
4979 /*-----------------------------------------------------------------*/
4980 /* ifxForOp - returns the icode containing the ifx for operand */
4981 /*-----------------------------------------------------------------*/
4983 ifxForOp (operand * op, iCode * ic)
4985 /* if true symbol then needs to be assigned */
4986 if (IS_TRUE_SYMOP (op))
4989 /* if this has register type condition and
4990 the next instruction is ifx with the same operand
4991 and live to of the operand is upto the ifx only then */
4993 ic->next->op == IFX &&
4994 IC_COND (ic->next)->key == op->key &&
4995 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5001 /*-----------------------------------------------------------------*/
5002 /* genAndOp - for && operation */
5003 /*-----------------------------------------------------------------*/
5005 genAndOp (iCode * ic)
5007 operand *left, *right, *result;
5010 /* note here that && operations that are in an if statement are
5011 taken away by backPatchLabels only those used in arthmetic
5012 operations remain */
5013 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5014 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5015 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5017 /* if both are bit variables */
5018 if (AOP_TYPE (left) == AOP_CRY &&
5019 AOP_TYPE (right) == AOP_CRY)
5021 wassertl (0, "Tried to and two bits");
5025 tlbl = newiTempLabel (NULL);
5027 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5029 emitLabel (tlbl->key + 100);
5033 freeAsmop (left, NULL, ic);
5034 freeAsmop (right, NULL, ic);
5035 freeAsmop (result, NULL, ic);
5038 /*-----------------------------------------------------------------*/
5039 /* genOrOp - for || operation */
5040 /*-----------------------------------------------------------------*/
5042 genOrOp (iCode * ic)
5044 operand *left, *right, *result;
5047 /* note here that || operations that are in an
5048 if statement are taken away by backPatchLabels
5049 only those used in arthmetic operations remain */
5050 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5051 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5052 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5054 /* if both are bit variables */
5055 if (AOP_TYPE (left) == AOP_CRY &&
5056 AOP_TYPE (right) == AOP_CRY)
5058 wassertl (0, "Tried to OR two bits");
5062 tlbl = newiTempLabel (NULL);
5064 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5066 emitLabel (tlbl->key + 100);
5070 freeAsmop (left, NULL, ic);
5071 freeAsmop (right, NULL, ic);
5072 freeAsmop (result, NULL, ic);
5075 /*-----------------------------------------------------------------*/
5076 /* isLiteralBit - test if lit == 2^n */
5077 /*-----------------------------------------------------------------*/
5079 isLiteralBit (unsigned long lit)
5081 unsigned long pw[32] =
5082 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5083 0x100L, 0x200L, 0x400L, 0x800L,
5084 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5085 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5086 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5087 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5088 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5091 for (idx = 0; idx < 32; idx++)
5097 /*-----------------------------------------------------------------*/
5098 /* jmpTrueOrFalse - */
5099 /*-----------------------------------------------------------------*/
5101 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5103 // ugly but optimized by peephole
5106 symbol *nlbl = newiTempLabel (NULL);
5107 emit2 ("jp !tlabel", nlbl->key + 100);
5108 emitLabel (tlbl->key + 100);
5109 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5110 emitLabel (nlbl->key + 100);
5114 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5115 emitLabel (tlbl->key + 100);
5120 /*-----------------------------------------------------------------*/
5121 /* genAnd - code for and */
5122 /*-----------------------------------------------------------------*/
5124 genAnd (iCode * ic, iCode * ifx)
5126 operand *left, *right, *result;
5127 int size, offset = 0;
5128 unsigned long lit = 0L;
5131 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5132 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5133 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5135 /* if left is a literal & right is not then exchange them */
5136 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5137 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5139 operand *tmp = right;
5144 /* if result = right then exchange them */
5145 if (sameRegs (AOP (result), AOP (right)))
5147 operand *tmp = right;
5152 /* if right is bit then exchange them */
5153 if (AOP_TYPE (right) == AOP_CRY &&
5154 AOP_TYPE (left) != AOP_CRY)
5156 operand *tmp = right;
5160 if (AOP_TYPE (right) == AOP_LIT)
5161 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5163 size = AOP_SIZE (result);
5165 if (AOP_TYPE (left) == AOP_CRY)
5167 wassertl (0, "Tried to perform an AND with a bit as an operand");
5171 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5172 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5173 if ((AOP_TYPE (right) == AOP_LIT) &&
5174 (AOP_TYPE (result) == AOP_CRY) &&
5175 (AOP_TYPE (left) != AOP_CRY))
5177 symbol *tlbl = newiTempLabel (NULL);
5178 int sizel = AOP_SIZE (left);
5181 /* PENDING: Test case for this. */
5186 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5188 _moveA (aopGet (AOP (left), offset, FALSE));
5189 if (bytelit != 0x0FFL)
5191 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5198 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5202 // bit = left & literal
5206 emit2 ("!tlabeldef", tlbl->key + 100);
5207 _G.lines.current->isLabel = 1;
5209 // if(left & literal)
5214 jmpTrueOrFalse (ifx, tlbl);
5222 /* if left is same as result */
5223 if (sameRegs (AOP (result), AOP (left)))
5225 for (; size--; offset++)
5227 if (AOP_TYPE (right) == AOP_LIT)
5229 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5234 aopPut (AOP (result), "!zero", offset);
5237 _moveA (aopGet (AOP (left), offset, FALSE));
5239 aopGet (AOP (right), offset, FALSE));
5240 aopPut (AOP (left), "a", offset);
5247 if (AOP_TYPE (left) == AOP_ACC)
5249 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5253 _moveA (aopGet (AOP (left), offset, FALSE));
5255 aopGet (AOP (right), offset, FALSE));
5256 aopPut (AOP (left), "a", offset);
5263 // left & result in different registers
5264 if (AOP_TYPE (result) == AOP_CRY)
5266 wassertl (0, "Tried to AND where the result is in carry");
5270 for (; (size--); offset++)
5273 // result = left & right
5274 if (AOP_TYPE (right) == AOP_LIT)
5276 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5278 aopPut (AOP (result),
5279 aopGet (AOP (left), offset, FALSE),
5283 else if (bytelit == 0)
5285 aopPut (AOP (result), "!zero", offset);
5289 // faster than result <- left, anl result,right
5290 // and better if result is SFR
5291 if (AOP_TYPE (left) == AOP_ACC)
5292 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5295 _moveA (aopGet (AOP (left), offset, FALSE));
5297 aopGet (AOP (right), offset, FALSE));
5299 aopPut (AOP (result), "a", offset);
5306 freeAsmop (left, NULL, ic);
5307 freeAsmop (right, NULL, ic);
5308 freeAsmop (result, NULL, ic);
5311 /*-----------------------------------------------------------------*/
5312 /* genOr - code for or */
5313 /*-----------------------------------------------------------------*/
5315 genOr (iCode * ic, iCode * ifx)
5317 operand *left, *right, *result;
5318 int size, offset = 0;
5319 unsigned long lit = 0L;
5322 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5323 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5324 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5326 /* if left is a literal & right is not then exchange them */
5327 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5328 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5330 operand *tmp = right;
5335 /* if result = right then exchange them */
5336 if (sameRegs (AOP (result), AOP (right)))
5338 operand *tmp = right;
5343 /* if right is bit then exchange them */
5344 if (AOP_TYPE (right) == AOP_CRY &&
5345 AOP_TYPE (left) != AOP_CRY)
5347 operand *tmp = right;
5351 if (AOP_TYPE (right) == AOP_LIT)
5352 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5354 size = AOP_SIZE (result);
5356 if (AOP_TYPE (left) == AOP_CRY)
5358 wassertl (0, "Tried to OR where left is a bit");
5362 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5363 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5364 if ((AOP_TYPE (right) == AOP_LIT) &&
5365 (AOP_TYPE (result) == AOP_CRY) &&
5366 (AOP_TYPE (left) != AOP_CRY))
5368 symbol *tlbl = newiTempLabel (NULL);
5369 int sizel = AOP_SIZE (left);
5373 wassertl (0, "Result is assigned to a bit");
5375 /* PENDING: Modeled after the AND code which is inefficient. */
5378 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5380 _moveA (aopGet (AOP (left), offset, FALSE));
5381 /* OR with any literal is the same as OR with itself. */
5383 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5389 jmpTrueOrFalse (ifx, tlbl);
5394 /* if left is same as result */
5395 if (sameRegs (AOP (result), AOP (left)))
5397 for (; size--; offset++)
5399 if (AOP_TYPE (right) == AOP_LIT)
5401 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5405 _moveA (aopGet (AOP (left), offset, FALSE));
5407 aopGet (AOP (right), offset, FALSE));
5408 aopPut (AOP (result), "a", offset);
5413 if (AOP_TYPE (left) == AOP_ACC)
5414 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5417 _moveA (aopGet (AOP (left), offset, FALSE));
5419 aopGet (AOP (right), offset, FALSE));
5420 aopPut (AOP (result), "a", offset);
5427 // left & result in different registers
5428 if (AOP_TYPE (result) == AOP_CRY)
5430 wassertl (0, "Result of OR is in a bit");
5433 for (; (size--); offset++)
5436 // result = left & right
5437 if (AOP_TYPE (right) == AOP_LIT)
5439 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5441 aopPut (AOP (result),
5442 aopGet (AOP (left), offset, FALSE),
5447 // faster than result <- left, anl result,right
5448 // and better if result is SFR
5449 if (AOP_TYPE (left) == AOP_ACC)
5450 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5453 _moveA (aopGet (AOP (left), offset, FALSE));
5455 aopGet (AOP (right), offset, FALSE));
5457 aopPut (AOP (result), "a", offset);
5458 /* PENDING: something weird is going on here. Add exception. */
5459 if (AOP_TYPE (result) == AOP_ACC)
5465 freeAsmop (left, NULL, ic);
5466 freeAsmop (right, NULL, ic);
5467 freeAsmop (result, NULL, ic);
5470 /*-----------------------------------------------------------------*/
5471 /* genXor - code for xclusive or */
5472 /*-----------------------------------------------------------------*/
5474 genXor (iCode * ic, iCode * ifx)
5476 operand *left, *right, *result;
5477 int size, offset = 0;
5478 unsigned long lit = 0L;
5480 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5481 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5482 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5484 /* if left is a literal & right is not then exchange them */
5485 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5486 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5488 operand *tmp = right;
5493 /* if result = right then exchange them */
5494 if (sameRegs (AOP (result), AOP (right)))
5496 operand *tmp = right;
5501 /* if right is bit then exchange them */
5502 if (AOP_TYPE (right) == AOP_CRY &&
5503 AOP_TYPE (left) != AOP_CRY)
5505 operand *tmp = right;
5509 if (AOP_TYPE (right) == AOP_LIT)
5510 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5512 size = AOP_SIZE (result);
5514 if (AOP_TYPE (left) == AOP_CRY)
5516 wassertl (0, "Tried to XOR a bit");
5520 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5521 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5522 if ((AOP_TYPE (right) == AOP_LIT) &&
5523 (AOP_TYPE (result) == AOP_CRY) &&
5524 (AOP_TYPE (left) != AOP_CRY))
5526 symbol *tlbl = newiTempLabel (NULL);
5527 int sizel = AOP_SIZE (left);
5531 /* PENDING: Test case for this. */
5532 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5536 _moveA (aopGet (AOP (left), offset, FALSE));
5537 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5538 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5543 jmpTrueOrFalse (ifx, tlbl);
5547 wassertl (0, "Result of XOR was destined for a bit");
5552 /* if left is same as result */
5553 if (sameRegs (AOP (result), AOP (left)))
5555 for (; size--; offset++)
5557 if (AOP_TYPE (right) == AOP_LIT)
5559 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5563 _moveA (aopGet (AOP (left), offset, FALSE));
5565 aopGet (AOP (right), offset, FALSE));
5566 aopPut (AOP (result), "a", offset);
5571 if (AOP_TYPE (left) == AOP_ACC)
5573 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5577 _moveA (aopGet (AOP (left), offset, FALSE));
5579 aopGet (AOP (right), offset, FALSE));
5580 aopPut (AOP (result), "a", offset);
5587 // left & result in different registers
5588 if (AOP_TYPE (result) == AOP_CRY)
5590 wassertl (0, "Result of XOR is in a bit");
5593 for (; (size--); offset++)
5596 // result = left & right
5597 if (AOP_TYPE (right) == AOP_LIT)
5599 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5601 aopPut (AOP (result),
5602 aopGet (AOP (left), offset, FALSE),
5607 // faster than result <- left, anl result,right
5608 // and better if result is SFR
5609 if (AOP_TYPE (left) == AOP_ACC)
5611 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5615 _moveA (aopGet (AOP (left), offset, FALSE));
5617 aopGet (AOP (right), offset, FALSE));
5619 aopPut (AOP (result), "a", offset);
5624 freeAsmop (left, NULL, ic);
5625 freeAsmop (right, NULL, ic);
5626 freeAsmop (result, NULL, ic);
5629 /*-----------------------------------------------------------------*/
5630 /* genInline - write the inline code out */
5631 /*-----------------------------------------------------------------*/
5633 genInline (iCode * ic)
5635 char *buffer, *bp, *bp1;
5636 bool inComment = FALSE;
5638 _G.lines.isInline += (!options.asmpeep);
5640 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5642 /* emit each line as a code */
5660 /* Add \n for labels, not dirs such as c:\mydir */
5661 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5679 _G.lines.isInline -= (!options.asmpeep);
5683 /*-----------------------------------------------------------------*/
5684 /* genRRC - rotate right with carry */
5685 /*-----------------------------------------------------------------*/
5692 /*-----------------------------------------------------------------*/
5693 /* genRLC - generate code for rotate left with carry */
5694 /*-----------------------------------------------------------------*/
5701 /*-----------------------------------------------------------------*/
5702 /* genGetHbit - generates code get highest order bit */
5703 /*-----------------------------------------------------------------*/
5705 genGetHbit (iCode * ic)
5707 operand *left, *result;
5708 left = IC_LEFT (ic);
5709 result = IC_RESULT (ic);
5711 aopOp (left, ic, FALSE, FALSE);
5712 aopOp (result, ic, FALSE, FALSE);
5714 /* get the highest order byte into a */
5715 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5717 if (AOP_TYPE (result) == AOP_CRY)
5725 emit2 ("and a,!one");
5730 freeAsmop (left, NULL, ic);
5731 freeAsmop (result, NULL, ic);
5735 emitRsh2 (asmop *aop, int size, int is_signed)
5741 const char *l = aopGet (aop, size, FALSE);
5744 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5754 /*-----------------------------------------------------------------*/
5755 /* shiftR2Left2Result - shift right two bytes from left to result */
5756 /*-----------------------------------------------------------------*/
5758 shiftR2Left2Result (operand * left, int offl,
5759 operand * result, int offr,
5760 int shCount, int is_signed)
5765 movLeft2Result (left, offl, result, offr, 0);
5766 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5771 /* if (AOP(result)->type == AOP_REG) { */
5773 tlbl = newiTempLabel (NULL);
5775 /* Left is already in result - so now do the shift */
5776 /* Optimizing for speed by default. */
5777 if (!optimize.codeSize || shCount <= 2)
5781 emitRsh2 (AOP (result), size, is_signed);
5786 emit2 ("ld a,!immedbyte", shCount);
5788 emitLabel (tlbl->key + 100);
5790 emitRsh2 (AOP (result), size, is_signed);
5793 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5797 /*-----------------------------------------------------------------*/
5798 /* shiftL2Left2Result - shift left two bytes from left to result */
5799 /*-----------------------------------------------------------------*/
5801 shiftL2Left2Result (operand * left, int offl,
5802 operand * result, int offr, int shCount)
5804 if (sameRegs (AOP (result), AOP (left)) &&
5805 ((offl + MSB16) == offr))
5811 /* Copy left into result */
5812 movLeft2Result (left, offl, result, offr, 0);
5813 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5819 if (getPairId (AOP (result)) == PAIR_HL)
5823 emit2 ("add hl,hl");
5830 symbol *tlbl, *tlbl1;
5833 tlbl = newiTempLabel (NULL);
5834 tlbl1 = newiTempLabel (NULL);
5836 if (AOP (result)->type == AOP_REG)
5840 for (offset = 0; offset < size; offset++)
5842 l = aopGet (AOP (result), offset, FALSE);
5846 emit2 ("sla %s", l);
5857 /* Left is already in result - so now do the shift */
5860 emit2 ("ld a,!immedbyte+1", shCount);
5861 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5862 emitLabel (tlbl->key + 100);
5867 l = aopGet (AOP (result), offset, FALSE);
5871 emit2 ("sla %s", l);
5882 emitLabel (tlbl1->key + 100);
5884 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5890 /*-----------------------------------------------------------------*/
5891 /* AccRol - rotate left accumulator by known count */
5892 /*-----------------------------------------------------------------*/
5894 AccRol (int shCount)
5896 shCount &= 0x0007; // shCount : 0..7
5973 /*-----------------------------------------------------------------*/
5974 /* AccLsh - left shift accumulator by known count */
5975 /*-----------------------------------------------------------------*/
5977 AccLsh (int shCount)
5979 static const unsigned char SLMask[] =
5981 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5990 else if (shCount == 2)
5997 /* rotate left accumulator */
5999 /* and kill the lower order bits */
6000 emit2 ("and a,!immedbyte", SLMask[shCount]);
6005 /*-----------------------------------------------------------------*/
6006 /* shiftL1Left2Result - shift left one byte from left to result */
6007 /*-----------------------------------------------------------------*/
6009 shiftL1Left2Result (operand * left, int offl,
6010 operand * result, int offr, int shCount)
6014 /* If operand and result are the same we can shift in place.
6015 However shifting in acc using add is cheaper than shifting
6016 in place using sla; when shifting by more than 2 shifting in
6017 acc is worth the additional effort for loading from/to acc. */
6018 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6021 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6025 l = aopGet (AOP (left), offl, FALSE);
6027 /* shift left accumulator */
6029 aopPut (AOP (result), "a", offr);
6033 /*-----------------------------------------------------------------*/
6034 /* genlshTwo - left shift two bytes by known amount */
6035 /*-----------------------------------------------------------------*/
6037 genlshTwo (operand * result, operand * left, int shCount)
6039 int size = AOP_SIZE (result);
6041 wassert (size == 2);
6043 /* if shCount >= 8 */
6051 movLeft2Result (left, LSB, result, MSB16, 0);
6052 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6053 aopPut (AOP (result), "!zero", LSB);
6057 movLeft2Result (left, LSB, result, MSB16, 0);
6058 aopPut (AOP (result), "!zero", 0);
6063 aopPut (AOP (result), "!zero", LSB);
6066 /* 0 <= shCount <= 7 */
6075 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6080 /*-----------------------------------------------------------------*/
6081 /* genlshOne - left shift a one byte quantity by known count */
6082 /*-----------------------------------------------------------------*/
6084 genlshOne (operand * result, operand * left, int shCount)
6086 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6089 /*-----------------------------------------------------------------*/
6090 /* genLeftShiftLiteral - left shifting by known count */
6091 /*-----------------------------------------------------------------*/
6093 genLeftShiftLiteral (operand * left,
6098 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6101 freeAsmop (right, NULL, ic);
6103 aopOp (left, ic, FALSE, FALSE);
6104 aopOp (result, ic, FALSE, FALSE);
6106 size = getSize (operandType (result));
6108 /* I suppose that the left size >= result size */
6110 if (shCount >= (size * 8))
6114 aopPut (AOP (result), "!zero", size);
6122 genlshOne (result, left, shCount);
6125 genlshTwo (result, left, shCount);
6128 wassertl (0, "Shifting of longs is currently unsupported");
6134 freeAsmop (left, NULL, ic);
6135 freeAsmop (result, NULL, ic);
6138 /*-----------------------------------------------------------------*/
6139 /* genLeftShift - generates code for left shifting */
6140 /*-----------------------------------------------------------------*/
6142 genLeftShift (iCode * ic)
6146 symbol *tlbl, *tlbl1;
6147 operand *left, *right, *result;
6149 right = IC_RIGHT (ic);
6150 left = IC_LEFT (ic);
6151 result = IC_RESULT (ic);
6153 aopOp (right, ic, FALSE, FALSE);
6155 /* if the shift count is known then do it
6156 as efficiently as possible */
6157 if (AOP_TYPE (right) == AOP_LIT)
6159 genLeftShiftLiteral (left, right, result, ic);
6163 /* shift count is unknown then we have to form a loop get the loop
6164 count in B : Note: we take only the lower order byte since
6165 shifting more that 32 bits make no sense anyway, ( the largest
6166 size of an object can be only 32 bits ) */
6167 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6169 freeAsmop (right, NULL, ic);
6170 aopOp (left, ic, FALSE, FALSE);
6171 aopOp (result, ic, FALSE, FALSE);
6173 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6176 /* now move the left to the result if they are not the
6179 if (!sameRegs (AOP (left), AOP (result)))
6182 size = AOP_SIZE (result);
6186 l = aopGet (AOP (left), offset, FALSE);
6187 aopPut (AOP (result), l, offset);
6192 tlbl = newiTempLabel (NULL);
6193 size = AOP_SIZE (result);
6195 tlbl1 = newiTempLabel (NULL);
6197 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6200 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6201 emitLabel (tlbl->key + 100);
6202 l = aopGet (AOP (result), offset, FALSE);
6206 l = aopGet (AOP (result), offset, FALSE);
6210 emit2 ("sla %s", l);
6218 emitLabel (tlbl1->key + 100);
6220 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6222 freeAsmop (left, NULL, ic);
6223 freeAsmop (result, NULL, ic);
6226 /*-----------------------------------------------------------------*/
6227 /* genrshOne - left shift two bytes by known amount != 0 */
6228 /*-----------------------------------------------------------------*/
6230 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6233 int size = AOP_SIZE (result);
6236 wassert (size == 1);
6237 wassert (shCount < 8);
6239 l = aopGet (AOP (left), 0, FALSE);
6241 if (AOP (result)->type == AOP_REG)
6243 aopPut (AOP (result), l, 0);
6244 l = aopGet (AOP (result), 0, FALSE);
6247 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6255 emit2 ("%s a", is_signed ? "sra" : "srl");
6257 aopPut (AOP (result), "a", 0);
6261 /*-----------------------------------------------------------------*/
6262 /* AccRsh - right shift accumulator by known count */
6263 /*-----------------------------------------------------------------*/
6265 AccRsh (int shCount)
6267 static const unsigned char SRMask[] =
6269 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6274 /* rotate right accumulator */
6275 AccRol (8 - shCount);
6276 /* and kill the higher order bits */
6277 emit2 ("and a,!immedbyte", SRMask[shCount]);
6281 /*-----------------------------------------------------------------*/
6282 /* shiftR1Left2Result - shift right one byte from left to result */
6283 /*-----------------------------------------------------------------*/
6285 shiftR1Left2Result (operand * left, int offl,
6286 operand * result, int offr,
6287 int shCount, int sign)
6289 _moveA (aopGet (AOP (left), offl, FALSE));
6294 emit2 ("%s a", sign ? "sra" : "srl");
6301 aopPut (AOP (result), "a", offr);
6304 /*-----------------------------------------------------------------*/
6305 /* genrshTwo - right shift two bytes by known amount */
6306 /*-----------------------------------------------------------------*/
6308 genrshTwo (operand * result, operand * left,
6309 int shCount, int sign)
6311 /* if shCount >= 8 */
6317 shiftR1Left2Result (left, MSB16, result, LSB,
6322 movLeft2Result (left, MSB16, result, LSB, sign);
6326 /* Sign extend the result */
6327 _moveA(aopGet (AOP (result), 0, FALSE));
6331 aopPut (AOP (result), ACC_NAME, MSB16);
6335 aopPut (AOP (result), "!zero", 1);
6338 /* 0 <= shCount <= 7 */
6341 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6345 /*-----------------------------------------------------------------*/
6346 /* genRightShiftLiteral - left shifting by known count */
6347 /*-----------------------------------------------------------------*/
6349 genRightShiftLiteral (operand * left,
6355 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6358 freeAsmop (right, NULL, ic);
6360 aopOp (left, ic, FALSE, FALSE);
6361 aopOp (result, ic, FALSE, FALSE);
6363 size = getSize (operandType (result));
6365 /* I suppose that the left size >= result size */
6367 if (shCount >= (size * 8)) {
6369 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6370 _moveA(aopGet (AOP (left), 0, FALSE));
6378 aopPut (AOP (result), s, size);
6385 genrshOne (result, left, shCount, sign);
6388 genrshTwo (result, left, shCount, sign);
6391 wassertl (0, "Asked to shift right a long which should be a function call");
6394 wassertl (0, "Entered default case in right shift delegate");
6397 freeAsmop (left, NULL, ic);
6398 freeAsmop (result, NULL, ic);
6401 /*-----------------------------------------------------------------*/
6402 /* genRightShift - generate code for right shifting */
6403 /*-----------------------------------------------------------------*/
6405 genRightShift (iCode * ic)
6407 operand *right, *left, *result;
6409 int size, offset, first = 1;
6413 symbol *tlbl, *tlbl1;
6415 /* if signed then we do it the hard way preserve the
6416 sign bit moving it inwards */
6417 retype = getSpec (operandType (IC_RESULT (ic)));
6419 is_signed = !SPEC_USIGN (retype);
6421 /* signed & unsigned types are treated the same : i.e. the
6422 signed is NOT propagated inwards : quoting from the
6423 ANSI - standard : "for E1 >> E2, is equivalent to division
6424 by 2**E2 if unsigned or if it has a non-negative value,
6425 otherwise the result is implementation defined ", MY definition
6426 is that the sign does not get propagated */
6428 right = IC_RIGHT (ic);
6429 left = IC_LEFT (ic);
6430 result = IC_RESULT (ic);
6432 aopOp (right, ic, FALSE, FALSE);
6434 /* if the shift count is known then do it
6435 as efficiently as possible */
6436 if (AOP_TYPE (right) == AOP_LIT)
6438 genRightShiftLiteral (left, right, result, ic, is_signed);
6442 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6444 freeAsmop (right, NULL, ic);
6446 aopOp (left, ic, FALSE, FALSE);
6447 aopOp (result, ic, FALSE, FALSE);
6449 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6452 /* now move the left to the result if they are not the
6454 if (!sameRegs (AOP (left), AOP (result)))
6457 size = AOP_SIZE (result);
6461 l = aopGet (AOP (left), offset, FALSE);
6462 aopPut (AOP (result), l, offset);
6467 tlbl = newiTempLabel (NULL);
6468 tlbl1 = newiTempLabel (NULL);
6469 size = AOP_SIZE (result);
6472 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6475 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6476 emitLabel (tlbl->key + 100);
6479 l = aopGet (AOP (result), offset--, FALSE);
6482 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6490 emitLabel (tlbl1->key + 100);
6492 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6494 freeAsmop (left, NULL, ic);
6495 freeAsmop (result, NULL, ic);
6499 /*-----------------------------------------------------------------*/
6500 /* genUnpackBits - generates code for unpacking bits */
6501 /*-----------------------------------------------------------------*/
6503 genUnpackBits (operand * result, int pair)
6505 int offset = 0; /* result byte offset */
6506 int rsize; /* result size */
6507 int rlen = 0; /* remaining bitfield length */
6508 sym_link *etype; /* bitfield type information */
6509 int blen; /* bitfield length */
6510 int bstr; /* bitfield starting bit within byte */
6512 emitDebug ("; genUnpackBits");
6514 etype = getSpec (operandType (result));
6515 rsize = getSize (operandType (result));
6516 blen = SPEC_BLEN (etype);
6517 bstr = SPEC_BSTR (etype);
6519 /* If the bitfield length is less than a byte */
6522 emit2 ("ld a,!*pair", _pairs[pair].name);
6524 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6525 if (!SPEC_USIGN (etype))
6527 /* signed bitfield */
6528 symbol *tlbl = newiTempLabel (NULL);
6530 emit2 ("bit %d,a", blen - 1);
6531 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6532 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6533 emitLabel (tlbl->key + 100);
6535 aopPut (AOP (result), "a", offset++);
6539 /* TODO: what if pair == PAIR_DE ? */
6540 if (getPairId (AOP (result)) == PAIR_HL)
6542 wassertl (rsize == 2, "HL must be of size 2");
6543 emit2 ("ld a,!*hl");
6545 emit2 ("ld h,!*hl");
6548 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6549 if (!SPEC_USIGN (etype))
6551 /* signed bitfield */
6552 symbol *tlbl = newiTempLabel (NULL);
6554 emit2 ("bit %d,a", blen - 1);
6555 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6556 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6557 emitLabel (tlbl->key + 100);
6560 spillPair (PAIR_HL);
6564 /* Bit field did not fit in a byte. Copy all
6565 but the partial byte at the end. */
6566 for (rlen=blen;rlen>=8;rlen-=8)
6568 emit2 ("ld a,!*pair", _pairs[pair].name);
6569 aopPut (AOP (result), "a", offset++);
6572 emit2 ("inc %s", _pairs[pair].name);
6573 _G.pairs[pair].offset++;
6577 /* Handle the partial byte at the end */
6580 emit2 ("ld a,!*pair", _pairs[pair].name);
6581 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6582 if (!SPEC_USIGN (etype))
6584 /* signed bitfield */
6585 symbol *tlbl = newiTempLabel (NULL);
6587 emit2 ("bit %d,a", rlen - 1);
6588 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6589 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6590 emitLabel (tlbl->key + 100);
6592 aopPut (AOP (result), "a", offset++);
6600 if (SPEC_USIGN (etype))
6604 /* signed bitfield: sign extension with 0x00 or 0xff */
6612 aopPut (AOP (result), source, offset++);
6616 /*-----------------------------------------------------------------*/
6617 /* genGenPointerGet - get value from generic pointer space */
6618 /*-----------------------------------------------------------------*/
6620 genGenPointerGet (operand * left,
6621 operand * result, iCode * ic)
6624 sym_link *retype = getSpec (operandType (result));
6630 aopOp (left, ic, FALSE, FALSE);
6631 aopOp (result, ic, FALSE, FALSE);
6633 size = AOP_SIZE (result);
6635 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6638 if (isPtrPair (AOP (left)))
6640 tsprintf (buffer, sizeof(buffer),
6641 "!*pair", getPairName (AOP (left)));
6642 aopPut (AOP (result), buffer, 0);
6646 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6647 aopPut (AOP (result), "a", 0);
6649 freeAsmop (left, NULL, ic);
6653 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6660 tsprintf (at, sizeof(at), "!*iyx", offset);
6661 aopPut (AOP (result), at, offset);
6665 freeAsmop (left, NULL, ic);
6669 /* For now we always load into IY */
6670 /* if this is remateriazable */
6671 fetchPair (pair, AOP (left));
6673 /* if bit then unpack */
6674 if (IS_BITVAR (retype))
6676 genUnpackBits (result, pair);
6677 freeAsmop (left, NULL, ic);
6681 else if (getPairId (AOP (result)) == PAIR_HL)
6683 wassertl (size == 2, "HL must be of size 2");
6684 emit2 ("ld a,!*hl");
6686 emit2 ("ld h,!*hl");
6688 spillPair (PAIR_HL);
6690 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6692 size = AOP_SIZE (result);
6697 /* PENDING: make this better */
6698 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6700 aopPut (AOP (result), "!*hl", offset++);
6704 emit2 ("ld a,!*pair", _pairs[pair].name);
6705 aopPut (AOP (result), "a", offset++);
6709 emit2 ("inc %s", _pairs[pair].name);
6710 _G.pairs[pair].offset++;
6713 /* Fixup HL back down */
6714 for (size = AOP_SIZE (result)-1; size; size--)
6716 emit2 ("dec %s", _pairs[pair].name);
6721 size = AOP_SIZE (result);
6726 /* PENDING: make this better */
6728 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6730 aopPut (AOP (result), "!*hl", offset++);
6734 emit2 ("ld a,!*pair", _pairs[pair].name);
6735 aopPut (AOP (result), "a", offset++);
6739 emit2 ("inc %s", _pairs[pair].name);
6740 _G.pairs[pair].offset++;
6745 freeAsmop (left, NULL, ic);
6748 freeAsmop (result, NULL, ic);
6751 /*-----------------------------------------------------------------*/
6752 /* genPointerGet - generate code for pointer get */
6753 /*-----------------------------------------------------------------*/
6755 genPointerGet (iCode * ic)
6757 operand *left, *result;
6758 sym_link *type, *etype;
6760 left = IC_LEFT (ic);
6761 result = IC_RESULT (ic);
6763 /* depending on the type of pointer we need to
6764 move it to the correct pointer register */
6765 type = operandType (left);
6766 etype = getSpec (type);
6768 genGenPointerGet (left, result, ic);
6772 isRegOrLit (asmop * aop)
6774 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6780 /*-----------------------------------------------------------------*/
6781 /* genPackBits - generates code for packed bit storage */
6782 /*-----------------------------------------------------------------*/
6784 genPackBits (sym_link * etype,
6789 int offset = 0; /* source byte offset */
6790 int rlen = 0; /* remaining bitfield length */
6791 int blen; /* bitfield length */
6792 int bstr; /* bitfield starting bit within byte */
6793 int litval; /* source literal value (if AOP_LIT) */
6794 unsigned char mask; /* bitmask within current byte */
6795 int extraPair; /* a tempory register */
6796 bool needPopExtra=0; /* need to restore original value of temp reg */
6798 emitDebug ("; genPackBits","");
6800 blen = SPEC_BLEN (etype);
6801 bstr = SPEC_BSTR (etype);
6803 /* If the bitfield length is less than a byte */
6806 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6807 (unsigned char) (0xFF >> (8 - bstr)));
6809 if (AOP_TYPE (right) == AOP_LIT)
6811 /* Case with a bitfield length <8 and literal source
6813 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6815 litval &= (~mask) & 0xff;
6816 emit2 ("ld a,!*pair", _pairs[pair].name);
6817 if ((mask|litval)!=0xff)
6818 emit2 ("and a,!immedbyte", mask);
6820 emit2 ("or a,!immedbyte", litval);
6821 emit2 ("ld !*pair,a", _pairs[pair].name);
6826 /* Case with a bitfield length <8 and arbitrary source
6828 _moveA (aopGet (AOP (right), 0, FALSE));
6829 /* shift and mask source value */
6831 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6833 extraPair = getFreePairId(ic);
6834 if (extraPair == PAIR_INVALID)
6836 extraPair = PAIR_BC;
6837 if (getPairId (AOP (right)) != PAIR_BC
6838 || !isLastUse (ic, right))
6844 emit2 ("ld %s,a", _pairs[extraPair].l);
6845 emit2 ("ld a,!*pair", _pairs[pair].name);
6847 emit2 ("and a,!immedbyte", mask);
6848 emit2 ("or a,%s", _pairs[extraPair].l);
6849 emit2 ("ld !*pair,a", _pairs[pair].name);
6856 /* Bit length is greater than 7 bits. In this case, copy */
6857 /* all except the partial byte at the end */
6858 for (rlen=blen;rlen>=8;rlen-=8)
6860 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6861 emit2 ("ld !*pair,a", _pairs[pair].name);
6864 emit2 ("inc %s", _pairs[pair].name);
6865 _G.pairs[pair].offset++;
6869 /* If there was a partial byte at the end */
6872 mask = (((unsigned char) -1 << rlen) & 0xff);
6874 if (AOP_TYPE (right) == AOP_LIT)
6876 /* Case with partial byte and literal source
6878 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6879 litval >>= (blen-rlen);
6880 litval &= (~mask) & 0xff;
6881 emit2 ("ld a,!*pair", _pairs[pair].name);
6882 if ((mask|litval)!=0xff)
6883 emit2 ("and a,!immedbyte", mask);
6885 emit2 ("or a,!immedbyte", litval);
6889 /* Case with partial byte and arbitrary source
6891 _moveA (aopGet (AOP (right), offset++, FALSE));
6892 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6894 extraPair = getFreePairId(ic);
6895 if (extraPair == PAIR_INVALID)
6897 extraPair = getPairId (AOP (right));
6898 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6899 extraPair = PAIR_BC;
6901 if (getPairId (AOP (right)) != PAIR_BC
6902 || !isLastUse (ic, right))
6908 emit2 ("ld %s,a", _pairs[extraPair].l);
6909 emit2 ("ld a,!*pair", _pairs[pair].name);
6911 emit2 ("and a,!immedbyte", mask);
6912 emit2 ("or a,%s", _pairs[extraPair].l);
6917 emit2 ("ld !*pair,a", _pairs[pair].name);
6922 /*-----------------------------------------------------------------*/
6923 /* genGenPointerSet - stores the value into a pointer location */
6924 /*-----------------------------------------------------------------*/
6926 genGenPointerSet (operand * right,
6927 operand * result, iCode * ic)
6930 sym_link *retype = getSpec (operandType (right));
6931 sym_link *letype = getSpec (operandType (result));
6932 PAIR_ID pairId = PAIR_HL;
6935 aopOp (result, ic, FALSE, FALSE);
6936 aopOp (right, ic, FALSE, FALSE);
6941 size = AOP_SIZE (right);
6943 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6944 emitDebug("; isBitvar = %d", isBitvar);
6946 /* Handle the exceptions first */
6947 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6950 const char *l = aopGet (AOP (right), 0, FALSE);
6951 const char *pair = getPairName (AOP (result));
6952 if (canAssignToPtr (l) && isPtr (pair))
6954 emit2 ("ld !*pair,%s", pair, l);
6959 emit2 ("ld !*pair,a", pair);
6964 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6967 const char *l = aopGet (AOP (right), 0, FALSE);
6972 if (canAssignToPtr (l))
6974 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6978 _moveA (aopGet (AOP (right), offset, FALSE));
6979 emit2 ("ld !*iyx,a", offset);
6985 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6992 const char *l = aopGet (AOP (right), offset, FALSE);
6993 if (isRegOrLit (AOP (right)) && !IS_GB)
6995 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7000 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7004 emit2 ("inc %s", _pairs[PAIR_HL].name);
7005 _G.pairs[PAIR_HL].offset++;
7010 /* Fixup HL back down */
7011 for (size = AOP_SIZE (right)-1; size; size--)
7013 emit2 ("dec %s", _pairs[PAIR_HL].name);
7018 /* if the operand is already in dptr
7019 then we do nothing else we move the value to dptr */
7020 if (AOP_TYPE (result) != AOP_STR)
7022 fetchPair (pairId, AOP (result));
7024 /* so hl now contains the address */
7025 freeAsmop (result, NULL, ic);
7027 /* if bit then unpack */
7030 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7040 const char *l = aopGet (AOP (right), offset, FALSE);
7041 if (isRegOrLit (AOP (right)) && !IS_GB)
7043 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7048 emit2 ("ld !*pair,a", _pairs[pairId].name);
7052 emit2 ("inc %s", _pairs[pairId].name);
7053 _G.pairs[pairId].offset++;
7059 freeAsmop (right, NULL, ic);
7062 /*-----------------------------------------------------------------*/
7063 /* genPointerSet - stores the value into a pointer location */
7064 /*-----------------------------------------------------------------*/
7066 genPointerSet (iCode * ic)
7068 operand *right, *result;
7069 sym_link *type, *etype;
7071 right = IC_RIGHT (ic);
7072 result = IC_RESULT (ic);
7074 /* depending on the type of pointer we need to
7075 move it to the correct pointer register */
7076 type = operandType (result);
7077 etype = getSpec (type);
7079 genGenPointerSet (right, result, ic);
7082 /*-----------------------------------------------------------------*/
7083 /* genIfx - generate code for Ifx statement */
7084 /*-----------------------------------------------------------------*/
7086 genIfx (iCode * ic, iCode * popIc)
7088 operand *cond = IC_COND (ic);
7091 aopOp (cond, ic, FALSE, TRUE);
7093 /* get the value into acc */
7094 if (AOP_TYPE (cond) != AOP_CRY)
7098 /* the result is now in the accumulator */
7099 freeAsmop (cond, NULL, ic);
7101 /* if there was something to be popped then do it */
7105 /* if the condition is a bit variable */
7106 if (isbit && IS_ITEMP (cond) &&
7108 genIfxJump (ic, SPIL_LOC (cond)->rname);
7109 else if (isbit && !IS_ITEMP (cond))
7110 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7112 genIfxJump (ic, "a");
7117 /*-----------------------------------------------------------------*/
7118 /* genAddrOf - generates code for address of */
7119 /*-----------------------------------------------------------------*/
7121 genAddrOf (iCode * ic)
7123 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7125 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7127 /* if the operand is on the stack then we
7128 need to get the stack offset of this
7135 if (sym->stack <= 0)
7137 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7141 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7143 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7147 emit2 ("ld de,!hashedstr", sym->rname);
7148 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7156 /* if it has an offset then we need to compute it */
7158 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7160 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7161 emit2 ("add hl,sp");
7165 emit2 ("ld hl,!hashedstr", sym->rname);
7167 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7169 freeAsmop (IC_RESULT (ic), NULL, ic);
7172 /*-----------------------------------------------------------------*/
7173 /* genAssign - generate code for assignment */
7174 /*-----------------------------------------------------------------*/
7176 genAssign (iCode * ic)
7178 operand *result, *right;
7180 unsigned long lit = 0L;
7182 result = IC_RESULT (ic);
7183 right = IC_RIGHT (ic);
7185 /* Dont bother assigning if they are the same */
7186 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7188 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7192 aopOp (right, ic, FALSE, FALSE);
7193 aopOp (result, ic, TRUE, FALSE);
7195 /* if they are the same registers */
7196 if (sameRegs (AOP (right), AOP (result)))
7198 emitDebug ("; (registers are the same)");
7202 /* if the result is a bit */
7203 if (AOP_TYPE (result) == AOP_CRY)
7205 wassertl (0, "Tried to assign to a bit");
7209 size = AOP_SIZE (result);
7212 if (AOP_TYPE (right) == AOP_LIT)
7214 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7217 if (isPair (AOP (result)))
7219 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7221 else if ((size > 1) &&
7222 (AOP_TYPE (result) != AOP_REG) &&
7223 (AOP_TYPE (right) == AOP_LIT) &&
7224 !IS_FLOAT (operandType (right)) &&
7227 bool fXored = FALSE;
7229 /* Work from the top down.
7230 Done this way so that we can use the cached copy of 0
7231 in A for a fast clear */
7234 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7236 if (!fXored && size > 1)
7243 aopPut (AOP (result), "a", offset);
7247 aopPut (AOP (result), "!zero", offset);
7251 aopPut (AOP (result),
7252 aopGet (AOP (right), offset, FALSE),
7257 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7259 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7260 aopPut (AOP (result), "l", LSB);
7261 aopPut (AOP (result), "h", MSB16);
7263 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7265 /* Special case. Load into a and d, then load out. */
7266 _moveA (aopGet (AOP (right), 0, FALSE));
7267 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7268 aopPut (AOP (result), "a", 0);
7269 aopPut (AOP (result), "e", 1);
7271 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7273 /* Special case - simple memcpy */
7274 aopGet (AOP (right), LSB, FALSE);
7277 aopGet (AOP (result), LSB, FALSE);
7281 emit2 ("ld a,(de)");
7282 /* Peephole will optimise this. */
7283 emit2 ("ld (hl),a");
7291 spillPair (PAIR_HL);
7297 /* PENDING: do this check better */
7298 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7300 _moveA (aopGet (AOP (right), offset, FALSE));
7301 aopPut (AOP (result), "a", offset);
7304 aopPut (AOP (result),
7305 aopGet (AOP (right), offset, FALSE),
7312 freeAsmop (right, NULL, ic);
7313 freeAsmop (result, NULL, ic);
7316 /*-----------------------------------------------------------------*/
7317 /* genJumpTab - genrates code for jump table */
7318 /*-----------------------------------------------------------------*/
7320 genJumpTab (iCode * ic)
7325 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7326 /* get the condition into accumulator */
7327 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7330 emit2 ("ld e,%s", l);
7331 emit2 ("ld d,!zero");
7332 jtab = newiTempLabel (NULL);
7334 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7335 emit2 ("add hl,de");
7336 emit2 ("add hl,de");
7337 emit2 ("add hl,de");
7338 freeAsmop (IC_JTCOND (ic), NULL, ic);
7342 emitLabel (jtab->key + 100);
7343 /* now generate the jump labels */
7344 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7345 jtab = setNextItem (IC_JTLABELS (ic)))
7346 emit2 ("jp !tlabel", jtab->key + 100);
7349 /*-----------------------------------------------------------------*/
7350 /* genCast - gen code for casting */
7351 /*-----------------------------------------------------------------*/
7353 genCast (iCode * ic)
7355 operand *result = IC_RESULT (ic);
7356 sym_link *rtype = operandType (IC_RIGHT (ic));
7357 operand *right = IC_RIGHT (ic);
7360 /* if they are equivalent then do nothing */
7361 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7364 aopOp (right, ic, FALSE, FALSE);
7365 aopOp (result, ic, FALSE, FALSE);
7367 /* if the result is a bit */
7368 if (AOP_TYPE (result) == AOP_CRY)
7370 wassertl (0, "Tried to cast to a bit");
7373 /* if they are the same size : or less */
7374 if (AOP_SIZE (result) <= AOP_SIZE (right))
7377 /* if they are in the same place */
7378 if (sameRegs (AOP (right), AOP (result)))
7381 /* if they in different places then copy */
7382 size = AOP_SIZE (result);
7386 aopPut (AOP (result),
7387 aopGet (AOP (right), offset, FALSE),
7394 /* So we now know that the size of destination is greater
7395 than the size of the source */
7396 /* we move to result for the size of source */
7397 size = AOP_SIZE (right);
7401 aopPut (AOP (result),
7402 aopGet (AOP (right), offset, FALSE),
7407 /* now depending on the sign of the destination */
7408 size = AOP_SIZE (result) - AOP_SIZE (right);
7409 /* Unsigned or not an integral type - right fill with zeros */
7410 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7413 aopPut (AOP (result), "!zero", offset++);
7417 /* we need to extend the sign :{ */
7418 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7424 aopPut (AOP (result), "a", offset++);
7428 freeAsmop (right, NULL, ic);
7429 freeAsmop (result, NULL, ic);
7432 /*-----------------------------------------------------------------*/
7433 /* genReceive - generate code for a receive iCode */
7434 /*-----------------------------------------------------------------*/
7436 genReceive (iCode * ic)
7438 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7439 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7440 IS_TRUE_SYMOP (IC_RESULT (ic))))
7450 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7451 size = AOP_SIZE(IC_RESULT(ic));
7453 for (i = 0; i < size; i++) {
7454 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7458 freeAsmop (IC_RESULT (ic), NULL, ic);
7461 /*-----------------------------------------------------------------*/
7462 /* genDummyRead - generate code for dummy read of volatiles */
7463 /*-----------------------------------------------------------------*/
7465 genDummyRead (iCode * ic)
7471 if (op && IS_SYMOP (op))
7473 aopOp (op, ic, FALSE, FALSE);
7476 size = AOP_SIZE (op);
7481 _moveA (aopGet (AOP (op), offset, FALSE));
7485 freeAsmop (op, NULL, ic);
7489 if (op && IS_SYMOP (op))
7491 aopOp (op, ic, FALSE, FALSE);
7494 size = AOP_SIZE (op);
7499 _moveA (aopGet (AOP (op), offset, FALSE));
7503 freeAsmop (op, NULL, ic);
7507 /*-----------------------------------------------------------------*/
7508 /* genCritical - generate code for start of a critical sequence */
7509 /*-----------------------------------------------------------------*/
7511 genCritical (iCode *ic)
7513 symbol *tlbl = newiTempLabel (NULL);
7519 else if (IC_RESULT (ic))
7521 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7522 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7523 //get interrupt enable flag IFF2 into P/O
7527 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7528 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7529 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7530 emit2 ("!tlabeldef", (tlbl->key + 100));
7531 _G.lines.current->isLabel = 1;
7532 freeAsmop (IC_RESULT (ic), NULL, ic);
7536 //get interrupt enable flag IFF2 into P/O
7545 /*-----------------------------------------------------------------*/
7546 /* genEndCritical - generate code for end of a critical sequence */
7547 /*-----------------------------------------------------------------*/
7549 genEndCritical (iCode *ic)
7551 symbol *tlbl = newiTempLabel (NULL);
7557 else if (IC_RIGHT (ic))
7559 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7560 _toBoolean (IC_RIGHT (ic));
7561 //don't enable interrupts if they were off before
7562 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7564 emitLabel (tlbl->key + 100);
7565 freeAsmop (IC_RIGHT (ic), NULL, ic);
7571 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7572 //don't enable interrupts as they were off before
7573 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7575 emit2 ("!tlabeldef", (tlbl->key + 100));
7576 _G.lines.current->isLabel = 1;
7582 /** Maximum number of bytes to emit per line. */
7586 /** Context for the byte output chunker. */
7589 unsigned char buffer[DBEMIT_MAX_RUN];
7594 /** Flushes a byte chunker by writing out all in the buffer and
7598 _dbFlush(DBEMITCTX *self)
7605 sprintf(line, ".db 0x%02X", self->buffer[0]);
7607 for (i = 1; i < self->pos; i++)
7609 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7616 /** Write out another byte, buffering until a decent line is
7620 _dbEmit(DBEMITCTX *self, int c)
7622 if (self->pos == DBEMIT_MAX_RUN)
7626 self->buffer[self->pos++] = c;
7629 /** Context for a simple run length encoder. */
7633 unsigned char buffer[128];
7635 /** runLen may be equivalent to pos. */
7641 RLE_CHANGE_COST = 4,
7645 /** Flush the buffer of a run length encoder by writing out the run or
7646 data that it currently contains.
7649 _rleCommit(RLECTX *self)
7655 memset(&db, 0, sizeof(db));
7657 emit2(".db %u", self->pos);
7659 for (i = 0; i < self->pos; i++)
7661 _dbEmit(&db, self->buffer[i]);
7670 Can get either a run or a block of random stuff.
7671 Only want to change state if a good run comes in or a run ends.
7672 Detecting run end is easy.
7675 Say initial state is in run, len zero, last zero. Then if you get a
7676 few zeros then something else then a short run will be output.
7677 Seems OK. While in run mode, keep counting. While in random mode,
7678 keep a count of the run. If run hits margin, output all up to run,
7679 restart, enter run mode.
7682 /** Add another byte into the run length encoder, flushing as
7683 required. The run length encoder uses the Amiga IFF style, where
7684 a block is prefixed by its run length. A positive length means
7685 the next n bytes pass straight through. A negative length means
7686 that the next byte is repeated -n times. A zero terminates the
7690 _rleAppend(RLECTX *self, unsigned c)
7694 if (c != self->last)
7696 /* The run has stopped. See if it is worthwhile writing it out
7697 as a run. Note that the random data comes in as runs of
7700 if (self->runLen > RLE_CHANGE_COST)
7702 /* Yes, worthwhile. */
7703 /* Commit whatever was in the buffer. */
7705 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7709 /* Not worthwhile. Append to the end of the random list. */
7710 for (i = 0; i < self->runLen; i++)
7712 if (self->pos >= RLE_MAX_BLOCK)
7717 self->buffer[self->pos++] = self->last;
7725 if (self->runLen >= RLE_MAX_BLOCK)
7727 /* Commit whatever was in the buffer. */
7730 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7738 _rleFlush(RLECTX *self)
7740 _rleAppend(self, -1);
7747 /** genArrayInit - Special code for initialising an array with constant
7751 genArrayInit (iCode * ic)
7755 int elementSize = 0, eIndex, i;
7756 unsigned val, lastVal;
7760 memset(&rle, 0, sizeof(rle));
7762 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7764 _saveRegsForCall(ic, 0);
7766 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7767 emit2 ("call __initrleblock");
7769 type = operandType(IC_LEFT(ic));
7771 if (type && type->next)
7773 if (IS_SPEC(type->next) || IS_PTR(type->next))
7775 elementSize = getSize(type->next);
7777 else if (IS_ARRAY(type->next) && type->next->next)
7779 elementSize = getSize(type->next->next);
7783 printTypeChainRaw (type, NULL);
7784 wassertl (0, "Can't determine element size in genArrayInit.");
7789 wassertl (0, "Can't determine element size in genArrayInit.");
7792 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7794 iLoop = IC_ARRAYILIST(ic);
7795 lastVal = (unsigned)-1;
7797 /* Feed all the bytes into the run length encoder which will handle
7799 This works well for mixed char data, and for random int and long
7806 for (i = 0; i < ix; i++)
7808 for (eIndex = 0; eIndex < elementSize; eIndex++)
7810 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7811 _rleAppend(&rle, val);
7815 iLoop = iLoop->next;
7819 /* Mark the end of the run. */
7822 _restoreRegsAfterCall();
7826 freeAsmop (IC_LEFT(ic), NULL, ic);
7830 _swap (PAIR_ID one, PAIR_ID two)
7832 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7838 emit2 ("ld a,%s", _pairs[one].l);
7839 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7840 emit2 ("ld %s,a", _pairs[two].l);
7841 emit2 ("ld a,%s", _pairs[one].h);
7842 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7843 emit2 ("ld %s,a", _pairs[two].h);
7847 /* The problem is that we may have all three pairs used and they may
7848 be needed in a different order.
7853 hl = hl => unity, fine
7857 hl = hl hl = hl, swap de <=> bc
7865 hl = bc de = de, swap bc <=> hl
7873 hl = de bc = bc, swap hl <=> de
7878 * Any pair = pair are done last
7879 * Any pair = iTemp are done last
7880 * Any swaps can be done any time
7888 So how do we detect the cases?
7889 How about a 3x3 matrix?
7893 x x x x (Fourth for iTemp/other)
7895 First determin which mode to use by counting the number of unity and
7898 Two - Assign the pair first, then the rest
7899 One - Swap the two, then the rest
7903 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7905 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7907 PAIR_BC, PAIR_HL, PAIR_DE
7909 int i, j, nunity = 0;
7910 memset (ids, PAIR_INVALID, sizeof (ids));
7913 wassert (nparams == 3);
7915 /* First save everything that needs to be saved. */
7916 _saveRegsForCall (ic, 0);
7918 /* Loading HL first means that DE is always fine. */
7919 for (i = 0; i < nparams; i++)
7921 aopOp (pparams[i], ic, FALSE, FALSE);
7922 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7925 /* Count the number of unity or iTemp assigns. */
7926 for (i = 0; i < 3; i++)
7928 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7936 /* Any order, fall through. */
7938 else if (nunity == 2)
7940 /* One is assigned. Pull it out and assign. */
7941 for (i = 0; i < 3; i++)
7943 for (j = 0; j < NUM_PAIRS; j++)
7945 if (ids[dest[i]][j] == TRUE)
7947 /* Found it. See if it's the right one. */
7948 if (j == PAIR_INVALID || j == dest[i])
7954 fetchPair(dest[i], AOP (pparams[i]));
7961 else if (nunity == 1)
7963 /* Find the pairs to swap. */
7964 for (i = 0; i < 3; i++)
7966 for (j = 0; j < NUM_PAIRS; j++)
7968 if (ids[dest[i]][j] == TRUE)
7970 if (j == PAIR_INVALID || j == dest[i])
7985 int next = getPairId (AOP (pparams[0]));
7986 emit2 ("push %s", _pairs[next].name);
7988 if (next == dest[1])
7990 fetchPair (dest[1], AOP (pparams[1]));
7991 fetchPair (dest[2], AOP (pparams[2]));
7995 fetchPair (dest[2], AOP (pparams[2]));
7996 fetchPair (dest[1], AOP (pparams[1]));
7998 emit2 ("pop %s", _pairs[dest[0]].name);
8001 /* Finally pull out all of the iTemps */
8002 for (i = 0; i < 3; i++)
8004 if (ids[dest[i]][PAIR_INVALID] == 1)
8006 fetchPair (dest[i], AOP (pparams[i]));
8012 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8018 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8022 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8024 setupForBuiltin3 (ic, nParams, pparams);
8026 label = newiTempLabel(NULL);
8028 emitLabel (label->key);
8029 emit2 ("ld a,(hl)");
8032 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8034 freeAsmop (from, NULL, ic->next);
8035 freeAsmop (to, NULL, ic);
8039 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8041 operand *from, *to, *count;
8044 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8049 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8051 setupForBuiltin3 (ic, nParams, pparams);
8055 freeAsmop (count, NULL, ic->next->next);
8056 freeAsmop (from, NULL, ic);
8058 _restoreRegsAfterCall();
8060 /* if we need assign a result value */
8061 if ((IS_ITEMP (IC_RESULT (ic)) &&
8062 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8063 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8064 IS_TRUE_SYMOP (IC_RESULT (ic)))
8066 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8067 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8068 freeAsmop (IC_RESULT (ic), NULL, ic);
8071 freeAsmop (to, NULL, ic->next);
8074 /*-----------------------------------------------------------------*/
8075 /* genBuiltIn - calls the appropriate function to generating code */
8076 /* for a built in function */
8077 /*-----------------------------------------------------------------*/
8078 static void genBuiltIn (iCode *ic)
8080 operand *bi_parms[MAX_BUILTIN_ARGS];
8085 /* get all the arguments for a built in function */
8086 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8088 /* which function is it */
8089 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8091 if (strcmp(bif->name,"__builtin_strcpy")==0)
8093 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8095 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8097 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8101 wassertl (0, "Unknown builtin function encountered");
8105 /*-----------------------------------------------------------------*/
8106 /* genZ80Code - generate code for Z80 based controllers */
8107 /*-----------------------------------------------------------------*/
8109 genZ80Code (iCode * lic)
8117 _fReturn = _gbz80_return;
8118 _fTmp = _gbz80_return;
8122 _fReturn = _z80_return;
8123 _fTmp = _z80_return;
8126 _G.lines.head = _G.lines.current = NULL;
8128 /* if debug information required */
8129 if (options.debug && currFunc)
8131 debugFile->writeFunction (currFunc, lic);
8134 for (ic = lic; ic; ic = ic->next)
8136 _G.current_iCode = ic;
8138 if (ic->lineno && cln != ic->lineno)
8142 debugFile->writeCLine (ic);
8144 if (!options.noCcodeInAsm)
8146 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8147 printCLine(ic->filename, ic->lineno));
8151 if (options.iCodeInAsm)
8153 const char *iLine = printILine(ic);
8154 emit2 (";ic:%d: %s", ic->key, iLine);
8157 /* if the result is marked as
8158 spilt and rematerializable or code for
8159 this has already been generated then
8161 if (resultRemat (ic) || ic->generated)
8164 /* depending on the operation */
8168 emitDebug ("; genNot");
8173 emitDebug ("; genCpl");
8178 emitDebug ("; genUminus");
8183 emitDebug ("; genIpush");
8188 /* IPOP happens only when trying to restore a
8189 spilt live range, if there is an ifx statement
8190 following this pop then the if statement might
8191 be using some of the registers being popped which
8192 would destroy the contents of the register so
8193 we need to check for this condition and handle it */
8195 ic->next->op == IFX &&
8196 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8198 emitDebug ("; genIfx");
8199 genIfx (ic->next, ic);
8203 emitDebug ("; genIpop");
8209 emitDebug ("; genCall");
8214 emitDebug ("; genPcall");
8219 emitDebug ("; genFunction");
8224 emitDebug ("; genEndFunction");
8225 genEndFunction (ic);
8229 emitDebug ("; genRet");
8234 emitDebug ("; genLabel");
8239 emitDebug ("; genGoto");
8244 emitDebug ("; genPlus");
8249 emitDebug ("; genMinus");
8254 emitDebug ("; genMult");
8259 emitDebug ("; genDiv");
8264 emitDebug ("; genMod");
8269 emitDebug ("; genCmpGt");
8270 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8274 emitDebug ("; genCmpLt");
8275 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8282 /* note these two are xlated by algebraic equivalence
8283 during parsing SDCC.y */
8284 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8285 "got '>=' or '<=' shouldn't have come here");
8289 emitDebug ("; genCmpEq");
8290 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8294 emitDebug ("; genAndOp");
8299 emitDebug ("; genOrOp");
8304 emitDebug ("; genXor");
8305 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8309 emitDebug ("; genOr");
8310 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8314 emitDebug ("; genAnd");
8315 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8319 emitDebug ("; genInline");
8324 emitDebug ("; genRRC");
8329 emitDebug ("; genRLC");
8334 emitDebug ("; genGetHBIT");
8339 emitDebug ("; genLeftShift");
8344 emitDebug ("; genRightShift");
8348 case GET_VALUE_AT_ADDRESS:
8349 emitDebug ("; genPointerGet");
8355 if (POINTER_SET (ic))
8357 emitDebug ("; genAssign (pointer)");
8362 emitDebug ("; genAssign");
8368 emitDebug ("; genIfx");
8373 emitDebug ("; genAddrOf");
8378 emitDebug ("; genJumpTab");
8383 emitDebug ("; genCast");
8388 emitDebug ("; genReceive");
8393 if (ic->builtinSEND)
8395 emitDebug ("; genBuiltIn");
8400 emitDebug ("; addSet");
8401 addSet (&_G.sendSet, ic);
8406 emitDebug ("; genArrayInit");
8410 case DUMMY_READ_VOLATILE:
8411 emitDebug ("; genDummyRead");
8416 emitDebug ("; genCritical");
8421 emitDebug ("; genEndCritical");
8422 genEndCritical (ic);
8431 /* now we are ready to call the
8432 peep hole optimizer */
8433 if (!options.nopeep)
8434 peepHole (&_G.lines.head);
8436 /* This is unfortunate */
8437 /* now do the actual printing */
8439 struct dbuf_s *buf = codeOutBuf;
8440 if (isInHome () && codeOutBuf == &code->oBuf)
8441 codeOutBuf = &home->oBuf;
8442 printLine (_G.lines.head, codeOutBuf);
8443 if (_G.flushStatics)
8446 _G.flushStatics = 0;
8451 freeTrace(&_G.lines.trace);
8452 freeTrace(&_G.trace.aops);
8458 _isPairUsed (iCode * ic, PAIR_ID pairId)
8464 if (bitVectBitValue (ic->rMask, D_IDX))
8466 if (bitVectBitValue (ic->rMask, E_IDX))
8476 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8479 value *val = aop->aopu.aop_lit;
8481 wassert (aop->type == AOP_LIT);
8482 wassert (!IS_FLOAT (val->type));
8484 v = ulFromVal (val);
8492 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8493 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));