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)
6013 l = aopGet (AOP (left), offl, FALSE);
6015 /* shift left accumulator */
6017 aopPut (AOP (result), "a", offr);
6021 /*-----------------------------------------------------------------*/
6022 /* genlshTwo - left shift two bytes by known amount */
6023 /*-----------------------------------------------------------------*/
6025 genlshTwo (operand * result, operand * left, int shCount)
6027 int size = AOP_SIZE (result);
6029 wassert (size == 2);
6031 /* if shCount >= 8 */
6039 movLeft2Result (left, LSB, result, MSB16, 0);
6040 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6041 aopPut (AOP (result), "!zero", LSB);
6045 movLeft2Result (left, LSB, result, MSB16, 0);
6046 aopPut (AOP (result), "!zero", 0);
6051 aopPut (AOP (result), "!zero", LSB);
6054 /* 0 <= shCount <= 7 */
6063 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6068 /*-----------------------------------------------------------------*/
6069 /* genlshOne - left shift a one byte quantity by known count */
6070 /*-----------------------------------------------------------------*/
6072 genlshOne (operand * result, operand * left, int shCount)
6074 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6077 /*-----------------------------------------------------------------*/
6078 /* genLeftShiftLiteral - left shifting by known count */
6079 /*-----------------------------------------------------------------*/
6081 genLeftShiftLiteral (operand * left,
6086 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6089 freeAsmop (right, NULL, ic);
6091 aopOp (left, ic, FALSE, FALSE);
6092 aopOp (result, ic, FALSE, FALSE);
6094 size = getSize (operandType (result));
6096 /* I suppose that the left size >= result size */
6098 if (shCount >= (size * 8))
6102 aopPut (AOP (result), "!zero", size);
6110 genlshOne (result, left, shCount);
6113 genlshTwo (result, left, shCount);
6116 wassertl (0, "Shifting of longs is currently unsupported");
6122 freeAsmop (left, NULL, ic);
6123 freeAsmop (result, NULL, ic);
6126 /*-----------------------------------------------------------------*/
6127 /* genLeftShift - generates code for left shifting */
6128 /*-----------------------------------------------------------------*/
6130 genLeftShift (iCode * ic)
6134 symbol *tlbl, *tlbl1;
6135 operand *left, *right, *result;
6137 right = IC_RIGHT (ic);
6138 left = IC_LEFT (ic);
6139 result = IC_RESULT (ic);
6141 aopOp (right, ic, FALSE, FALSE);
6143 /* if the shift count is known then do it
6144 as efficiently as possible */
6145 if (AOP_TYPE (right) == AOP_LIT)
6147 genLeftShiftLiteral (left, right, result, ic);
6151 /* shift count is unknown then we have to form a loop get the loop
6152 count in B : Note: we take only the lower order byte since
6153 shifting more that 32 bits make no sense anyway, ( the largest
6154 size of an object can be only 32 bits ) */
6155 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6157 freeAsmop (right, NULL, ic);
6158 aopOp (left, ic, FALSE, FALSE);
6159 aopOp (result, ic, FALSE, FALSE);
6161 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6164 /* now move the left to the result if they are not the
6167 if (!sameRegs (AOP (left), AOP (result)))
6170 size = AOP_SIZE (result);
6174 l = aopGet (AOP (left), offset, FALSE);
6175 aopPut (AOP (result), l, offset);
6180 tlbl = newiTempLabel (NULL);
6181 size = AOP_SIZE (result);
6183 tlbl1 = newiTempLabel (NULL);
6185 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6188 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6189 emitLabel (tlbl->key + 100);
6190 l = aopGet (AOP (result), offset, FALSE);
6194 l = aopGet (AOP (result), offset, FALSE);
6198 emit2 ("sla %s", l);
6206 emitLabel (tlbl1->key + 100);
6208 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6210 freeAsmop (left, NULL, ic);
6211 freeAsmop (result, NULL, ic);
6214 /*-----------------------------------------------------------------*/
6215 /* genrshOne - left shift two bytes by known amount != 0 */
6216 /*-----------------------------------------------------------------*/
6218 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6221 int size = AOP_SIZE (result);
6224 wassert (size == 1);
6225 wassert (shCount < 8);
6227 l = aopGet (AOP (left), 0, FALSE);
6229 if (AOP (result)->type == AOP_REG)
6231 aopPut (AOP (result), l, 0);
6232 l = aopGet (AOP (result), 0, FALSE);
6235 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6243 emit2 ("%s a", is_signed ? "sra" : "srl");
6245 aopPut (AOP (result), "a", 0);
6249 /*-----------------------------------------------------------------*/
6250 /* AccRsh - right shift accumulator by known count */
6251 /*-----------------------------------------------------------------*/
6253 AccRsh (int shCount)
6255 static const unsigned char SRMask[] =
6257 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6262 /* rotate right accumulator */
6263 AccRol (8 - shCount);
6264 /* and kill the higher order bits */
6265 emit2 ("and a,!immedbyte", SRMask[shCount]);
6269 /*-----------------------------------------------------------------*/
6270 /* shiftR1Left2Result - shift right one byte from left to result */
6271 /*-----------------------------------------------------------------*/
6273 shiftR1Left2Result (operand * left, int offl,
6274 operand * result, int offr,
6275 int shCount, int sign)
6277 _moveA (aopGet (AOP (left), offl, FALSE));
6282 emit2 ("%s a", sign ? "sra" : "srl");
6289 aopPut (AOP (result), "a", offr);
6292 /*-----------------------------------------------------------------*/
6293 /* genrshTwo - right shift two bytes by known amount */
6294 /*-----------------------------------------------------------------*/
6296 genrshTwo (operand * result, operand * left,
6297 int shCount, int sign)
6299 /* if shCount >= 8 */
6305 shiftR1Left2Result (left, MSB16, result, LSB,
6310 movLeft2Result (left, MSB16, result, LSB, sign);
6314 /* Sign extend the result */
6315 _moveA(aopGet (AOP (result), 0, FALSE));
6319 aopPut (AOP (result), ACC_NAME, MSB16);
6323 aopPut (AOP (result), "!zero", 1);
6326 /* 0 <= shCount <= 7 */
6329 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6333 /*-----------------------------------------------------------------*/
6334 /* genRightShiftLiteral - left shifting by known count */
6335 /*-----------------------------------------------------------------*/
6337 genRightShiftLiteral (operand * left,
6343 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6346 freeAsmop (right, NULL, ic);
6348 aopOp (left, ic, FALSE, FALSE);
6349 aopOp (result, ic, FALSE, FALSE);
6351 size = getSize (operandType (result));
6353 /* I suppose that the left size >= result size */
6355 if (shCount >= (size * 8)) {
6357 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6358 _moveA(aopGet (AOP (left), 0, FALSE));
6366 aopPut (AOP (result), s, size);
6373 genrshOne (result, left, shCount, sign);
6376 genrshTwo (result, left, shCount, sign);
6379 wassertl (0, "Asked to shift right a long which should be a function call");
6382 wassertl (0, "Entered default case in right shift delegate");
6385 freeAsmop (left, NULL, ic);
6386 freeAsmop (result, NULL, ic);
6389 /*-----------------------------------------------------------------*/
6390 /* genRightShift - generate code for right shifting */
6391 /*-----------------------------------------------------------------*/
6393 genRightShift (iCode * ic)
6395 operand *right, *left, *result;
6397 int size, offset, first = 1;
6401 symbol *tlbl, *tlbl1;
6403 /* if signed then we do it the hard way preserve the
6404 sign bit moving it inwards */
6405 retype = getSpec (operandType (IC_RESULT (ic)));
6407 is_signed = !SPEC_USIGN (retype);
6409 /* signed & unsigned types are treated the same : i.e. the
6410 signed is NOT propagated inwards : quoting from the
6411 ANSI - standard : "for E1 >> E2, is equivalent to division
6412 by 2**E2 if unsigned or if it has a non-negative value,
6413 otherwise the result is implementation defined ", MY definition
6414 is that the sign does not get propagated */
6416 right = IC_RIGHT (ic);
6417 left = IC_LEFT (ic);
6418 result = IC_RESULT (ic);
6420 aopOp (right, ic, FALSE, FALSE);
6422 /* if the shift count is known then do it
6423 as efficiently as possible */
6424 if (AOP_TYPE (right) == AOP_LIT)
6426 genRightShiftLiteral (left, right, result, ic, is_signed);
6430 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6432 freeAsmop (right, NULL, ic);
6434 aopOp (left, ic, FALSE, FALSE);
6435 aopOp (result, ic, FALSE, FALSE);
6437 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6440 /* now move the left to the result if they are not the
6442 if (!sameRegs (AOP (left), AOP (result)))
6445 size = AOP_SIZE (result);
6449 l = aopGet (AOP (left), offset, FALSE);
6450 aopPut (AOP (result), l, offset);
6455 tlbl = newiTempLabel (NULL);
6456 tlbl1 = newiTempLabel (NULL);
6457 size = AOP_SIZE (result);
6460 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6463 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6464 emitLabel (tlbl->key + 100);
6467 l = aopGet (AOP (result), offset--, FALSE);
6470 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6478 emitLabel (tlbl1->key + 100);
6480 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6482 freeAsmop (left, NULL, ic);
6483 freeAsmop (result, NULL, ic);
6487 /*-----------------------------------------------------------------*/
6488 /* genUnpackBits - generates code for unpacking bits */
6489 /*-----------------------------------------------------------------*/
6491 genUnpackBits (operand * result, int pair)
6493 int offset = 0; /* result byte offset */
6494 int rsize; /* result size */
6495 int rlen = 0; /* remaining bitfield length */
6496 sym_link *etype; /* bitfield type information */
6497 int blen; /* bitfield length */
6498 int bstr; /* bitfield starting bit within byte */
6500 emitDebug ("; genUnpackBits");
6502 etype = getSpec (operandType (result));
6503 rsize = getSize (operandType (result));
6504 blen = SPEC_BLEN (etype);
6505 bstr = SPEC_BSTR (etype);
6507 /* If the bitfield length is less than a byte */
6510 emit2 ("ld a,!*pair", _pairs[pair].name);
6512 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6513 if (!SPEC_USIGN (etype))
6515 /* signed bitfield */
6516 symbol *tlbl = newiTempLabel (NULL);
6518 emit2 ("bit %d,a", blen - 1);
6519 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6520 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6521 emitLabel (tlbl->key + 100);
6523 aopPut (AOP (result), "a", offset++);
6527 /* TODO: what if pair == PAIR_DE ? */
6528 if (getPairId (AOP (result)) == PAIR_HL)
6530 wassertl (rsize == 2, "HL must be of size 2");
6531 emit2 ("ld a,!*hl");
6533 emit2 ("ld h,!*hl");
6536 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6537 if (!SPEC_USIGN (etype))
6539 /* signed bitfield */
6540 symbol *tlbl = newiTempLabel (NULL);
6542 emit2 ("bit %d,a", blen - 1);
6543 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6544 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6545 emitLabel (tlbl->key + 100);
6548 spillPair (PAIR_HL);
6552 /* Bit field did not fit in a byte. Copy all
6553 but the partial byte at the end. */
6554 for (rlen=blen;rlen>=8;rlen-=8)
6556 emit2 ("ld a,!*pair", _pairs[pair].name);
6557 aopPut (AOP (result), "a", offset++);
6560 emit2 ("inc %s", _pairs[pair].name);
6561 _G.pairs[pair].offset++;
6565 /* Handle the partial byte at the end */
6568 emit2 ("ld a,!*pair", _pairs[pair].name);
6569 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6570 if (!SPEC_USIGN (etype))
6572 /* signed bitfield */
6573 symbol *tlbl = newiTempLabel (NULL);
6575 emit2 ("bit %d,a", rlen - 1);
6576 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6577 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6578 emitLabel (tlbl->key + 100);
6580 aopPut (AOP (result), "a", offset++);
6588 if (SPEC_USIGN (etype))
6592 /* signed bitfield: sign extension with 0x00 or 0xff */
6600 aopPut (AOP (result), source, offset++);
6604 /*-----------------------------------------------------------------*/
6605 /* genGenPointerGet - get value from generic pointer space */
6606 /*-----------------------------------------------------------------*/
6608 genGenPointerGet (operand * left,
6609 operand * result, iCode * ic)
6612 sym_link *retype = getSpec (operandType (result));
6618 aopOp (left, ic, FALSE, FALSE);
6619 aopOp (result, ic, FALSE, FALSE);
6621 size = AOP_SIZE (result);
6623 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6626 if (isPtrPair (AOP (left)))
6628 tsprintf (buffer, sizeof(buffer),
6629 "!*pair", getPairName (AOP (left)));
6630 aopPut (AOP (result), buffer, 0);
6634 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6635 aopPut (AOP (result), "a", 0);
6637 freeAsmop (left, NULL, ic);
6641 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6648 tsprintf (at, sizeof(at), "!*iyx", offset);
6649 aopPut (AOP (result), at, offset);
6653 freeAsmop (left, NULL, ic);
6657 /* For now we always load into IY */
6658 /* if this is remateriazable */
6659 fetchPair (pair, AOP (left));
6661 /* if bit then unpack */
6662 if (IS_BITVAR (retype))
6664 genUnpackBits (result, pair);
6665 freeAsmop (left, NULL, ic);
6669 else if (getPairId (AOP (result)) == PAIR_HL)
6671 wassertl (size == 2, "HL must be of size 2");
6672 emit2 ("ld a,!*hl");
6674 emit2 ("ld h,!*hl");
6676 spillPair (PAIR_HL);
6678 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6680 size = AOP_SIZE (result);
6685 /* PENDING: make this better */
6686 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6688 aopPut (AOP (result), "!*hl", offset++);
6692 emit2 ("ld a,!*pair", _pairs[pair].name);
6693 aopPut (AOP (result), "a", offset++);
6697 emit2 ("inc %s", _pairs[pair].name);
6698 _G.pairs[pair].offset++;
6701 /* Fixup HL back down */
6702 for (size = AOP_SIZE (result)-1; size; size--)
6704 emit2 ("dec %s", _pairs[pair].name);
6709 size = AOP_SIZE (result);
6714 /* PENDING: make this better */
6716 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6718 aopPut (AOP (result), "!*hl", offset++);
6722 emit2 ("ld a,!*pair", _pairs[pair].name);
6723 aopPut (AOP (result), "a", offset++);
6727 emit2 ("inc %s", _pairs[pair].name);
6728 _G.pairs[pair].offset++;
6733 freeAsmop (left, NULL, ic);
6736 freeAsmop (result, NULL, ic);
6739 /*-----------------------------------------------------------------*/
6740 /* genPointerGet - generate code for pointer get */
6741 /*-----------------------------------------------------------------*/
6743 genPointerGet (iCode * ic)
6745 operand *left, *result;
6746 sym_link *type, *etype;
6748 left = IC_LEFT (ic);
6749 result = IC_RESULT (ic);
6751 /* depending on the type of pointer we need to
6752 move it to the correct pointer register */
6753 type = operandType (left);
6754 etype = getSpec (type);
6756 genGenPointerGet (left, result, ic);
6760 isRegOrLit (asmop * aop)
6762 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6768 /*-----------------------------------------------------------------*/
6769 /* genPackBits - generates code for packed bit storage */
6770 /*-----------------------------------------------------------------*/
6772 genPackBits (sym_link * etype,
6777 int offset = 0; /* source byte offset */
6778 int rlen = 0; /* remaining bitfield length */
6779 int blen; /* bitfield length */
6780 int bstr; /* bitfield starting bit within byte */
6781 int litval; /* source literal value (if AOP_LIT) */
6782 unsigned char mask; /* bitmask within current byte */
6783 int extraPair; /* a tempory register */
6784 bool needPopExtra=0; /* need to restore original value of temp reg */
6786 emitDebug ("; genPackBits","");
6788 blen = SPEC_BLEN (etype);
6789 bstr = SPEC_BSTR (etype);
6791 /* If the bitfield length is less than a byte */
6794 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6795 (unsigned char) (0xFF >> (8 - bstr)));
6797 if (AOP_TYPE (right) == AOP_LIT)
6799 /* Case with a bitfield length <8 and literal source
6801 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6803 litval &= (~mask) & 0xff;
6804 emit2 ("ld a,!*pair", _pairs[pair].name);
6805 if ((mask|litval)!=0xff)
6806 emit2 ("and a,!immedbyte", mask);
6808 emit2 ("or a,!immedbyte", litval);
6809 emit2 ("ld !*pair,a", _pairs[pair].name);
6814 /* Case with a bitfield length <8 and arbitrary source
6816 _moveA (aopGet (AOP (right), 0, FALSE));
6817 /* shift and mask source value */
6819 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6821 extraPair = getFreePairId(ic);
6822 if (extraPair == PAIR_INVALID)
6824 extraPair = PAIR_BC;
6825 if (getPairId (AOP (right)) != PAIR_BC
6826 || !isLastUse (ic, right))
6832 emit2 ("ld %s,a", _pairs[extraPair].l);
6833 emit2 ("ld a,!*pair", _pairs[pair].name);
6835 emit2 ("and a,!immedbyte", mask);
6836 emit2 ("or a,%s", _pairs[extraPair].l);
6837 emit2 ("ld !*pair,a", _pairs[pair].name);
6844 /* Bit length is greater than 7 bits. In this case, copy */
6845 /* all except the partial byte at the end */
6846 for (rlen=blen;rlen>=8;rlen-=8)
6848 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6849 emit2 ("ld !*pair,a", _pairs[pair].name);
6852 emit2 ("inc %s", _pairs[pair].name);
6853 _G.pairs[pair].offset++;
6857 /* If there was a partial byte at the end */
6860 mask = (((unsigned char) -1 << rlen) & 0xff);
6862 if (AOP_TYPE (right) == AOP_LIT)
6864 /* Case with partial byte and literal source
6866 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6867 litval >>= (blen-rlen);
6868 litval &= (~mask) & 0xff;
6869 emit2 ("ld a,!*pair", _pairs[pair].name);
6870 if ((mask|litval)!=0xff)
6871 emit2 ("and a,!immedbyte", mask);
6873 emit2 ("or a,!immedbyte", litval);
6877 /* Case with partial byte and arbitrary source
6879 _moveA (aopGet (AOP (right), offset++, FALSE));
6880 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6882 extraPair = getFreePairId(ic);
6883 if (extraPair == PAIR_INVALID)
6885 extraPair = getPairId (AOP (right));
6886 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6887 extraPair = PAIR_BC;
6889 if (getPairId (AOP (right)) != PAIR_BC
6890 || !isLastUse (ic, right))
6896 emit2 ("ld %s,a", _pairs[extraPair].l);
6897 emit2 ("ld a,!*pair", _pairs[pair].name);
6899 emit2 ("and a,!immedbyte", mask);
6900 emit2 ("or a,%s", _pairs[extraPair].l);
6905 emit2 ("ld !*pair,a", _pairs[pair].name);
6910 /*-----------------------------------------------------------------*/
6911 /* genGenPointerSet - stores the value into a pointer location */
6912 /*-----------------------------------------------------------------*/
6914 genGenPointerSet (operand * right,
6915 operand * result, iCode * ic)
6918 sym_link *retype = getSpec (operandType (right));
6919 sym_link *letype = getSpec (operandType (result));
6920 PAIR_ID pairId = PAIR_HL;
6923 aopOp (result, ic, FALSE, FALSE);
6924 aopOp (right, ic, FALSE, FALSE);
6929 size = AOP_SIZE (right);
6931 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6932 emitDebug("; isBitvar = %d", isBitvar);
6934 /* Handle the exceptions first */
6935 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6938 const char *l = aopGet (AOP (right), 0, FALSE);
6939 const char *pair = getPairName (AOP (result));
6940 if (canAssignToPtr (l) && isPtr (pair))
6942 emit2 ("ld !*pair,%s", pair, l);
6947 emit2 ("ld !*pair,a", pair);
6952 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6955 const char *l = aopGet (AOP (right), 0, FALSE);
6960 if (canAssignToPtr (l))
6962 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6966 _moveA (aopGet (AOP (right), offset, FALSE));
6967 emit2 ("ld !*iyx,a", offset);
6973 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6980 const char *l = aopGet (AOP (right), offset, FALSE);
6981 if (isRegOrLit (AOP (right)) && !IS_GB)
6983 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6988 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6992 emit2 ("inc %s", _pairs[PAIR_HL].name);
6993 _G.pairs[PAIR_HL].offset++;
6998 /* Fixup HL back down */
6999 for (size = AOP_SIZE (right)-1; size; size--)
7001 emit2 ("dec %s", _pairs[PAIR_HL].name);
7006 /* if the operand is already in dptr
7007 then we do nothing else we move the value to dptr */
7008 if (AOP_TYPE (result) != AOP_STR)
7010 fetchPair (pairId, AOP (result));
7012 /* so hl now contains the address */
7013 freeAsmop (result, NULL, ic);
7015 /* if bit then unpack */
7018 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7028 const char *l = aopGet (AOP (right), offset, FALSE);
7029 if (isRegOrLit (AOP (right)) && !IS_GB)
7031 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7036 emit2 ("ld !*pair,a", _pairs[pairId].name);
7040 emit2 ("inc %s", _pairs[pairId].name);
7041 _G.pairs[pairId].offset++;
7047 freeAsmop (right, NULL, ic);
7050 /*-----------------------------------------------------------------*/
7051 /* genPointerSet - stores the value into a pointer location */
7052 /*-----------------------------------------------------------------*/
7054 genPointerSet (iCode * ic)
7056 operand *right, *result;
7057 sym_link *type, *etype;
7059 right = IC_RIGHT (ic);
7060 result = IC_RESULT (ic);
7062 /* depending on the type of pointer we need to
7063 move it to the correct pointer register */
7064 type = operandType (result);
7065 etype = getSpec (type);
7067 genGenPointerSet (right, result, ic);
7070 /*-----------------------------------------------------------------*/
7071 /* genIfx - generate code for Ifx statement */
7072 /*-----------------------------------------------------------------*/
7074 genIfx (iCode * ic, iCode * popIc)
7076 operand *cond = IC_COND (ic);
7079 aopOp (cond, ic, FALSE, TRUE);
7081 /* get the value into acc */
7082 if (AOP_TYPE (cond) != AOP_CRY)
7086 /* the result is now in the accumulator */
7087 freeAsmop (cond, NULL, ic);
7089 /* if there was something to be popped then do it */
7093 /* if the condition is a bit variable */
7094 if (isbit && IS_ITEMP (cond) &&
7096 genIfxJump (ic, SPIL_LOC (cond)->rname);
7097 else if (isbit && !IS_ITEMP (cond))
7098 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7100 genIfxJump (ic, "a");
7105 /*-----------------------------------------------------------------*/
7106 /* genAddrOf - generates code for address of */
7107 /*-----------------------------------------------------------------*/
7109 genAddrOf (iCode * ic)
7111 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7113 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7115 /* if the operand is on the stack then we
7116 need to get the stack offset of this
7123 if (sym->stack <= 0)
7125 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7129 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7131 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7135 emit2 ("ld de,!hashedstr", sym->rname);
7136 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7144 /* if it has an offset then we need to compute it */
7146 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7148 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7149 emit2 ("add hl,sp");
7153 emit2 ("ld hl,!hashedstr", sym->rname);
7155 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7157 freeAsmop (IC_RESULT (ic), NULL, ic);
7160 /*-----------------------------------------------------------------*/
7161 /* genAssign - generate code for assignment */
7162 /*-----------------------------------------------------------------*/
7164 genAssign (iCode * ic)
7166 operand *result, *right;
7168 unsigned long lit = 0L;
7170 result = IC_RESULT (ic);
7171 right = IC_RIGHT (ic);
7173 /* Dont bother assigning if they are the same */
7174 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7176 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7180 aopOp (right, ic, FALSE, FALSE);
7181 aopOp (result, ic, TRUE, FALSE);
7183 /* if they are the same registers */
7184 if (sameRegs (AOP (right), AOP (result)))
7186 emitDebug ("; (registers are the same)");
7190 /* if the result is a bit */
7191 if (AOP_TYPE (result) == AOP_CRY)
7193 wassertl (0, "Tried to assign to a bit");
7197 size = AOP_SIZE (result);
7200 if (AOP_TYPE (right) == AOP_LIT)
7202 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7205 if (isPair (AOP (result)))
7207 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7209 else if ((size > 1) &&
7210 (AOP_TYPE (result) != AOP_REG) &&
7211 (AOP_TYPE (right) == AOP_LIT) &&
7212 !IS_FLOAT (operandType (right)) &&
7215 bool fXored = FALSE;
7217 /* Work from the top down.
7218 Done this way so that we can use the cached copy of 0
7219 in A for a fast clear */
7222 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7224 if (!fXored && size > 1)
7231 aopPut (AOP (result), "a", offset);
7235 aopPut (AOP (result), "!zero", offset);
7239 aopPut (AOP (result),
7240 aopGet (AOP (right), offset, FALSE),
7245 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7247 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7248 aopPut (AOP (result), "l", LSB);
7249 aopPut (AOP (result), "h", MSB16);
7251 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7253 /* Special case. Load into a and d, then load out. */
7254 _moveA (aopGet (AOP (right), 0, FALSE));
7255 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7256 aopPut (AOP (result), "a", 0);
7257 aopPut (AOP (result), "e", 1);
7259 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7261 /* Special case - simple memcpy */
7262 aopGet (AOP (right), LSB, FALSE);
7265 aopGet (AOP (result), LSB, FALSE);
7269 emit2 ("ld a,(de)");
7270 /* Peephole will optimise this. */
7271 emit2 ("ld (hl),a");
7279 spillPair (PAIR_HL);
7285 /* PENDING: do this check better */
7286 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7288 _moveA (aopGet (AOP (right), offset, FALSE));
7289 aopPut (AOP (result), "a", offset);
7292 aopPut (AOP (result),
7293 aopGet (AOP (right), offset, FALSE),
7300 freeAsmop (right, NULL, ic);
7301 freeAsmop (result, NULL, ic);
7304 /*-----------------------------------------------------------------*/
7305 /* genJumpTab - genrates code for jump table */
7306 /*-----------------------------------------------------------------*/
7308 genJumpTab (iCode * ic)
7313 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7314 /* get the condition into accumulator */
7315 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7318 emit2 ("ld e,%s", l);
7319 emit2 ("ld d,!zero");
7320 jtab = newiTempLabel (NULL);
7322 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7323 emit2 ("add hl,de");
7324 emit2 ("add hl,de");
7325 emit2 ("add hl,de");
7326 freeAsmop (IC_JTCOND (ic), NULL, ic);
7330 emitLabel (jtab->key + 100);
7331 /* now generate the jump labels */
7332 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7333 jtab = setNextItem (IC_JTLABELS (ic)))
7334 emit2 ("jp !tlabel", jtab->key + 100);
7337 /*-----------------------------------------------------------------*/
7338 /* genCast - gen code for casting */
7339 /*-----------------------------------------------------------------*/
7341 genCast (iCode * ic)
7343 operand *result = IC_RESULT (ic);
7344 sym_link *rtype = operandType (IC_RIGHT (ic));
7345 operand *right = IC_RIGHT (ic);
7348 /* if they are equivalent then do nothing */
7349 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7352 aopOp (right, ic, FALSE, FALSE);
7353 aopOp (result, ic, FALSE, FALSE);
7355 /* if the result is a bit */
7356 if (AOP_TYPE (result) == AOP_CRY)
7358 wassertl (0, "Tried to cast to a bit");
7361 /* if they are the same size : or less */
7362 if (AOP_SIZE (result) <= AOP_SIZE (right))
7365 /* if they are in the same place */
7366 if (sameRegs (AOP (right), AOP (result)))
7369 /* if they in different places then copy */
7370 size = AOP_SIZE (result);
7374 aopPut (AOP (result),
7375 aopGet (AOP (right), offset, FALSE),
7382 /* So we now know that the size of destination is greater
7383 than the size of the source */
7384 /* we move to result for the size of source */
7385 size = AOP_SIZE (right);
7389 aopPut (AOP (result),
7390 aopGet (AOP (right), offset, FALSE),
7395 /* now depending on the sign of the destination */
7396 size = AOP_SIZE (result) - AOP_SIZE (right);
7397 /* Unsigned or not an integral type - right fill with zeros */
7398 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7401 aopPut (AOP (result), "!zero", offset++);
7405 /* we need to extend the sign :{ */
7406 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7412 aopPut (AOP (result), "a", offset++);
7416 freeAsmop (right, NULL, ic);
7417 freeAsmop (result, NULL, ic);
7420 /*-----------------------------------------------------------------*/
7421 /* genReceive - generate code for a receive iCode */
7422 /*-----------------------------------------------------------------*/
7424 genReceive (iCode * ic)
7426 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7427 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7428 IS_TRUE_SYMOP (IC_RESULT (ic))))
7438 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7439 size = AOP_SIZE(IC_RESULT(ic));
7441 for (i = 0; i < size; i++) {
7442 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7446 freeAsmop (IC_RESULT (ic), NULL, ic);
7449 /*-----------------------------------------------------------------*/
7450 /* genDummyRead - generate code for dummy read of volatiles */
7451 /*-----------------------------------------------------------------*/
7453 genDummyRead (iCode * ic)
7459 if (op && IS_SYMOP (op))
7461 aopOp (op, ic, FALSE, FALSE);
7464 size = AOP_SIZE (op);
7469 _moveA (aopGet (AOP (op), offset, FALSE));
7473 freeAsmop (op, NULL, ic);
7477 if (op && IS_SYMOP (op))
7479 aopOp (op, ic, FALSE, FALSE);
7482 size = AOP_SIZE (op);
7487 _moveA (aopGet (AOP (op), offset, FALSE));
7491 freeAsmop (op, NULL, ic);
7495 /*-----------------------------------------------------------------*/
7496 /* genCritical - generate code for start of a critical sequence */
7497 /*-----------------------------------------------------------------*/
7499 genCritical (iCode *ic)
7501 symbol *tlbl = newiTempLabel (NULL);
7507 else if (IC_RESULT (ic))
7509 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7510 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7511 //get interrupt enable flag IFF2 into P/O
7515 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7516 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7517 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7518 emit2 ("!tlabeldef", (tlbl->key + 100));
7519 _G.lines.current->isLabel = 1;
7520 freeAsmop (IC_RESULT (ic), NULL, ic);
7524 //get interrupt enable flag IFF2 into P/O
7533 /*-----------------------------------------------------------------*/
7534 /* genEndCritical - generate code for end of a critical sequence */
7535 /*-----------------------------------------------------------------*/
7537 genEndCritical (iCode *ic)
7539 symbol *tlbl = newiTempLabel (NULL);
7545 else if (IC_RIGHT (ic))
7547 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7548 _toBoolean (IC_RIGHT (ic));
7549 //don't enable interrupts if they were off before
7550 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7552 emitLabel (tlbl->key + 100);
7553 freeAsmop (IC_RIGHT (ic), NULL, ic);
7559 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7560 //don't enable interrupts as they were off before
7561 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7563 emit2 ("!tlabeldef", (tlbl->key + 100));
7564 _G.lines.current->isLabel = 1;
7570 /** Maximum number of bytes to emit per line. */
7574 /** Context for the byte output chunker. */
7577 unsigned char buffer[DBEMIT_MAX_RUN];
7582 /** Flushes a byte chunker by writing out all in the buffer and
7586 _dbFlush(DBEMITCTX *self)
7593 sprintf(line, ".db 0x%02X", self->buffer[0]);
7595 for (i = 1; i < self->pos; i++)
7597 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7604 /** Write out another byte, buffering until a decent line is
7608 _dbEmit(DBEMITCTX *self, int c)
7610 if (self->pos == DBEMIT_MAX_RUN)
7614 self->buffer[self->pos++] = c;
7617 /** Context for a simple run length encoder. */
7621 unsigned char buffer[128];
7623 /** runLen may be equivalent to pos. */
7629 RLE_CHANGE_COST = 4,
7633 /** Flush the buffer of a run length encoder by writing out the run or
7634 data that it currently contains.
7637 _rleCommit(RLECTX *self)
7643 memset(&db, 0, sizeof(db));
7645 emit2(".db %u", self->pos);
7647 for (i = 0; i < self->pos; i++)
7649 _dbEmit(&db, self->buffer[i]);
7658 Can get either a run or a block of random stuff.
7659 Only want to change state if a good run comes in or a run ends.
7660 Detecting run end is easy.
7663 Say initial state is in run, len zero, last zero. Then if you get a
7664 few zeros then something else then a short run will be output.
7665 Seems OK. While in run mode, keep counting. While in random mode,
7666 keep a count of the run. If run hits margin, output all up to run,
7667 restart, enter run mode.
7670 /** Add another byte into the run length encoder, flushing as
7671 required. The run length encoder uses the Amiga IFF style, where
7672 a block is prefixed by its run length. A positive length means
7673 the next n bytes pass straight through. A negative length means
7674 that the next byte is repeated -n times. A zero terminates the
7678 _rleAppend(RLECTX *self, unsigned c)
7682 if (c != self->last)
7684 /* The run has stopped. See if it is worthwhile writing it out
7685 as a run. Note that the random data comes in as runs of
7688 if (self->runLen > RLE_CHANGE_COST)
7690 /* Yes, worthwhile. */
7691 /* Commit whatever was in the buffer. */
7693 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7697 /* Not worthwhile. Append to the end of the random list. */
7698 for (i = 0; i < self->runLen; i++)
7700 if (self->pos >= RLE_MAX_BLOCK)
7705 self->buffer[self->pos++] = self->last;
7713 if (self->runLen >= RLE_MAX_BLOCK)
7715 /* Commit whatever was in the buffer. */
7718 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7726 _rleFlush(RLECTX *self)
7728 _rleAppend(self, -1);
7735 /** genArrayInit - Special code for initialising an array with constant
7739 genArrayInit (iCode * ic)
7743 int elementSize = 0, eIndex, i;
7744 unsigned val, lastVal;
7748 memset(&rle, 0, sizeof(rle));
7750 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7752 _saveRegsForCall(ic, 0);
7754 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7755 emit2 ("call __initrleblock");
7757 type = operandType(IC_LEFT(ic));
7759 if (type && type->next)
7761 if (IS_SPEC(type->next) || IS_PTR(type->next))
7763 elementSize = getSize(type->next);
7765 else if (IS_ARRAY(type->next) && type->next->next)
7767 elementSize = getSize(type->next->next);
7771 printTypeChainRaw (type, NULL);
7772 wassertl (0, "Can't determine element size in genArrayInit.");
7777 wassertl (0, "Can't determine element size in genArrayInit.");
7780 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7782 iLoop = IC_ARRAYILIST(ic);
7783 lastVal = (unsigned)-1;
7785 /* Feed all the bytes into the run length encoder which will handle
7787 This works well for mixed char data, and for random int and long
7794 for (i = 0; i < ix; i++)
7796 for (eIndex = 0; eIndex < elementSize; eIndex++)
7798 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7799 _rleAppend(&rle, val);
7803 iLoop = iLoop->next;
7807 /* Mark the end of the run. */
7810 _restoreRegsAfterCall();
7814 freeAsmop (IC_LEFT(ic), NULL, ic);
7818 _swap (PAIR_ID one, PAIR_ID two)
7820 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7826 emit2 ("ld a,%s", _pairs[one].l);
7827 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7828 emit2 ("ld %s,a", _pairs[two].l);
7829 emit2 ("ld a,%s", _pairs[one].h);
7830 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7831 emit2 ("ld %s,a", _pairs[two].h);
7835 /* The problem is that we may have all three pairs used and they may
7836 be needed in a different order.
7841 hl = hl => unity, fine
7845 hl = hl hl = hl, swap de <=> bc
7853 hl = bc de = de, swap bc <=> hl
7861 hl = de bc = bc, swap hl <=> de
7866 * Any pair = pair are done last
7867 * Any pair = iTemp are done last
7868 * Any swaps can be done any time
7876 So how do we detect the cases?
7877 How about a 3x3 matrix?
7881 x x x x (Fourth for iTemp/other)
7883 First determin which mode to use by counting the number of unity and
7886 Two - Assign the pair first, then the rest
7887 One - Swap the two, then the rest
7891 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7893 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7895 PAIR_BC, PAIR_HL, PAIR_DE
7897 int i, j, nunity = 0;
7898 memset (ids, PAIR_INVALID, sizeof (ids));
7901 wassert (nparams == 3);
7903 /* First save everything that needs to be saved. */
7904 _saveRegsForCall (ic, 0);
7906 /* Loading HL first means that DE is always fine. */
7907 for (i = 0; i < nparams; i++)
7909 aopOp (pparams[i], ic, FALSE, FALSE);
7910 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7913 /* Count the number of unity or iTemp assigns. */
7914 for (i = 0; i < 3; i++)
7916 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7924 /* Any order, fall through. */
7926 else if (nunity == 2)
7928 /* One is assigned. Pull it out and assign. */
7929 for (i = 0; i < 3; i++)
7931 for (j = 0; j < NUM_PAIRS; j++)
7933 if (ids[dest[i]][j] == TRUE)
7935 /* Found it. See if it's the right one. */
7936 if (j == PAIR_INVALID || j == dest[i])
7942 fetchPair(dest[i], AOP (pparams[i]));
7949 else if (nunity == 1)
7951 /* Find the pairs to swap. */
7952 for (i = 0; i < 3; i++)
7954 for (j = 0; j < NUM_PAIRS; j++)
7956 if (ids[dest[i]][j] == TRUE)
7958 if (j == PAIR_INVALID || j == dest[i])
7973 int next = getPairId (AOP (pparams[0]));
7974 emit2 ("push %s", _pairs[next].name);
7976 if (next == dest[1])
7978 fetchPair (dest[1], AOP (pparams[1]));
7979 fetchPair (dest[2], AOP (pparams[2]));
7983 fetchPair (dest[2], AOP (pparams[2]));
7984 fetchPair (dest[1], AOP (pparams[1]));
7986 emit2 ("pop %s", _pairs[dest[0]].name);
7989 /* Finally pull out all of the iTemps */
7990 for (i = 0; i < 3; i++)
7992 if (ids[dest[i]][PAIR_INVALID] == 1)
7994 fetchPair (dest[i], AOP (pparams[i]));
8000 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8006 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8010 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8012 setupForBuiltin3 (ic, nParams, pparams);
8014 label = newiTempLabel(NULL);
8016 emitLabel (label->key);
8017 emit2 ("ld a,(hl)");
8020 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8022 freeAsmop (from, NULL, ic->next);
8023 freeAsmop (to, NULL, ic);
8027 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8029 operand *from, *to, *count;
8032 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8037 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8039 setupForBuiltin3 (ic, nParams, pparams);
8043 freeAsmop (count, NULL, ic->next->next);
8044 freeAsmop (from, NULL, ic);
8046 _restoreRegsAfterCall();
8048 /* if we need assign a result value */
8049 if ((IS_ITEMP (IC_RESULT (ic)) &&
8050 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8051 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8052 IS_TRUE_SYMOP (IC_RESULT (ic)))
8054 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8055 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8056 freeAsmop (IC_RESULT (ic), NULL, ic);
8059 freeAsmop (to, NULL, ic->next);
8062 /*-----------------------------------------------------------------*/
8063 /* genBuiltIn - calls the appropriate function to generating code */
8064 /* for a built in function */
8065 /*-----------------------------------------------------------------*/
8066 static void genBuiltIn (iCode *ic)
8068 operand *bi_parms[MAX_BUILTIN_ARGS];
8073 /* get all the arguments for a built in function */
8074 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8076 /* which function is it */
8077 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8079 if (strcmp(bif->name,"__builtin_strcpy")==0)
8081 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8083 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8085 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8089 wassertl (0, "Unknown builtin function encountered");
8093 /*-----------------------------------------------------------------*/
8094 /* genZ80Code - generate code for Z80 based controllers */
8095 /*-----------------------------------------------------------------*/
8097 genZ80Code (iCode * lic)
8105 _fReturn = _gbz80_return;
8106 _fTmp = _gbz80_return;
8110 _fReturn = _z80_return;
8111 _fTmp = _z80_return;
8114 _G.lines.head = _G.lines.current = NULL;
8116 /* if debug information required */
8117 if (options.debug && currFunc)
8119 debugFile->writeFunction (currFunc, lic);
8122 for (ic = lic; ic; ic = ic->next)
8124 _G.current_iCode = ic;
8126 if (ic->lineno && cln != ic->lineno)
8130 debugFile->writeCLine (ic);
8132 if (!options.noCcodeInAsm)
8134 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8135 printCLine(ic->filename, ic->lineno));
8139 if (options.iCodeInAsm)
8141 char *iLine = printILine(ic);
8142 emit2 (";ic:%d: %s", ic->key, iLine);
8145 /* if the result is marked as
8146 spilt and rematerializable or code for
8147 this has already been generated then
8149 if (resultRemat (ic) || ic->generated)
8152 /* depending on the operation */
8156 emitDebug ("; genNot");
8161 emitDebug ("; genCpl");
8166 emitDebug ("; genUminus");
8171 emitDebug ("; genIpush");
8176 /* IPOP happens only when trying to restore a
8177 spilt live range, if there is an ifx statement
8178 following this pop then the if statement might
8179 be using some of the registers being popped which
8180 would destroy the contents of the register so
8181 we need to check for this condition and handle it */
8183 ic->next->op == IFX &&
8184 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8186 emitDebug ("; genIfx");
8187 genIfx (ic->next, ic);
8191 emitDebug ("; genIpop");
8197 emitDebug ("; genCall");
8202 emitDebug ("; genPcall");
8207 emitDebug ("; genFunction");
8212 emitDebug ("; genEndFunction");
8213 genEndFunction (ic);
8217 emitDebug ("; genRet");
8222 emitDebug ("; genLabel");
8227 emitDebug ("; genGoto");
8232 emitDebug ("; genPlus");
8237 emitDebug ("; genMinus");
8242 emitDebug ("; genMult");
8247 emitDebug ("; genDiv");
8252 emitDebug ("; genMod");
8257 emitDebug ("; genCmpGt");
8258 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8262 emitDebug ("; genCmpLt");
8263 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8270 /* note these two are xlated by algebraic equivalence
8271 during parsing SDCC.y */
8272 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8273 "got '>=' or '<=' shouldn't have come here");
8277 emitDebug ("; genCmpEq");
8278 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8282 emitDebug ("; genAndOp");
8287 emitDebug ("; genOrOp");
8292 emitDebug ("; genXor");
8293 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8297 emitDebug ("; genOr");
8298 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8302 emitDebug ("; genAnd");
8303 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8307 emitDebug ("; genInline");
8312 emitDebug ("; genRRC");
8317 emitDebug ("; genRLC");
8322 emitDebug ("; genGetHBIT");
8327 emitDebug ("; genLeftShift");
8332 emitDebug ("; genRightShift");
8336 case GET_VALUE_AT_ADDRESS:
8337 emitDebug ("; genPointerGet");
8343 if (POINTER_SET (ic))
8345 emitDebug ("; genAssign (pointer)");
8350 emitDebug ("; genAssign");
8356 emitDebug ("; genIfx");
8361 emitDebug ("; genAddrOf");
8366 emitDebug ("; genJumpTab");
8371 emitDebug ("; genCast");
8376 emitDebug ("; genReceive");
8381 if (ic->builtinSEND)
8383 emitDebug ("; genBuiltIn");
8388 emitDebug ("; addSet");
8389 addSet (&_G.sendSet, ic);
8394 emitDebug ("; genArrayInit");
8398 case DUMMY_READ_VOLATILE:
8399 emitDebug ("; genDummyRead");
8404 emitDebug ("; genCritical");
8409 emitDebug ("; genEndCritical");
8410 genEndCritical (ic);
8419 /* now we are ready to call the
8420 peep hole optimizer */
8421 if (!options.nopeep)
8422 peepHole (&_G.lines.head);
8424 /* This is unfortunate */
8425 /* now do the actual printing */
8427 struct dbuf_s *buf = codeOutBuf;
8428 if (isInHome () && codeOutBuf == &code->oBuf)
8429 codeOutBuf = &home->oBuf;
8430 printLine (_G.lines.head, codeOutBuf);
8431 if (_G.flushStatics)
8434 _G.flushStatics = 0;
8439 freeTrace(&_G.lines.trace);
8440 freeTrace(&_G.trace.aops);
8446 _isPairUsed (iCode * ic, PAIR_ID pairId)
8452 if (bitVectBitValue (ic->rMask, D_IDX))
8454 if (bitVectBitValue (ic->rMask, E_IDX))
8464 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8467 value *val = aop->aopu.aop_lit;
8469 wassert (aop->type == AOP_LIT);
8470 wassert (!IS_FLOAT (val->type));
8472 v = ulFromVal (val);
8480 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8481 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));