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 /* Swapping register contents within register pair */
1512 if(!strcmp(aopGet (aop, offset, FALSE), _pairs[pairId].h))
1514 emit2 ("ld a,%s",aopGet (aop, offset + 1, FALSE));
1515 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1516 emit2 ("ld %s,a", _pairs[pairId].h);
1520 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1521 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1524 /* PENDING: check? */
1525 if (pairId == PAIR_HL)
1526 spillPair (PAIR_HL);
1531 fetchPair (PAIR_ID pairId, asmop * aop)
1533 fetchPairLong (pairId, aop, NULL, 0);
1537 fetchHL (asmop * aop)
1539 fetchPair (PAIR_HL, aop);
1543 setupPairFromSP (PAIR_ID id, int offset)
1545 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1547 if (_G.preserveCarry)
1553 if (offset < INT8MIN || offset > INT8MAX)
1555 emit2 ("ld hl,!immedword", offset);
1556 emit2 ("add hl,sp");
1560 emit2 ("!ldahlsp", offset);
1563 if (_G.preserveCarry)
1571 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1576 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1577 fetchLitPair (pairId, aop, 0);
1581 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1583 fetchLitPair (pairId, aop, offset);
1584 _G.pairs[pairId].offset = offset;
1588 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1589 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1592 int offset = aop->aopu.aop_stk + _G.stack.offset;
1594 if (_G.pairs[pairId].last_type == aop->type &&
1595 _G.pairs[pairId].offset == offset)
1601 /* PENDING: Do this better. */
1602 if (_G.preserveCarry)
1604 sprintf (buffer, "%d", offset + _G.stack.pushed);
1605 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1606 emit2 ("add %s,sp", _pairs[pairId].name);
1607 _G.pairs[pairId].last_type = aop->type;
1608 _G.pairs[pairId].offset = offset;
1609 if (_G.preserveCarry)
1617 /* Doesnt include _G.stack.pushed */
1618 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1620 if (aop->aopu.aop_stk > 0)
1622 abso += _G.stack.param_offset;
1624 assert (pairId == PAIR_HL);
1625 /* In some cases we can still inc or dec hl */
1626 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1628 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1632 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1634 _G.pairs[pairId].offset = abso;
1639 if (pairId != aop->aopu.aop_pairId)
1640 genMovePairPair(aop->aopu.aop_pairId, pairId);
1641 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1647 _G.pairs[pairId].last_type = aop->type;
1653 emit2 ("!tlabeldef", key);
1654 _G.lines.current->isLabel = 1;
1658 /*-----------------------------------------------------------------*/
1659 /* aopGet - for fetching value of the aop */
1660 /*-----------------------------------------------------------------*/
1662 aopGet (asmop * aop, int offset, bool bit16)
1664 // char *s = buffer;
1666 /* offset is greater than size then zero */
1667 /* PENDING: this seems a bit screwed in some pointer cases. */
1668 if (offset > (aop->size - 1) &&
1669 aop->type != AOP_LIT)
1671 tsprintf (buffer, sizeof(buffer), "!zero");
1672 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1675 /* depending on type */
1679 tsprintf (buffer, sizeof(buffer), "!zero");
1680 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1683 /* PENDING: re-target */
1685 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1690 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1693 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1696 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1699 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1702 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1706 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1707 SNPRINTF (buffer, sizeof(buffer), "a");
1709 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1715 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1716 SNPRINTF (buffer, sizeof(buffer), "a");
1718 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1721 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1724 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1725 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1726 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1728 else if( z80_opts.port_mode == 180 )
1729 { /* z180 in0/out0 mode */
1730 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1734 emit2( "in a,(%s)", aop->aopu.aop_dir );
1737 SNPRINTF (buffer, sizeof(buffer), "a");
1739 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1743 return aop->aopu.aop_reg[offset]->name;
1747 setupPair (PAIR_HL, aop, offset);
1748 tsprintf (buffer, sizeof(buffer), "!*hl");
1750 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1754 setupPair (PAIR_IY, aop, offset);
1755 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1757 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1761 setupPair (PAIR_IY, aop, offset);
1762 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1764 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1769 setupPair (PAIR_HL, aop, offset);
1770 tsprintf (buffer, sizeof(buffer), "!*hl");
1774 if (aop->aopu.aop_stk >= 0)
1775 offset += _G.stack.param_offset;
1776 tsprintf (buffer, sizeof(buffer),
1777 "!*ixx", aop->aopu.aop_stk + offset);
1780 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1783 wassertl (0, "Tried to fetch from a bit variable");
1792 tsprintf(buffer, sizeof(buffer), "!zero");
1793 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1797 wassert (offset < 2);
1798 return aop->aopu.aop_str[offset];
1801 return aopLiteral (aop->aopu.aop_lit, offset);
1805 unsigned long v = aop->aopu.aop_simplelit;
1808 tsprintf (buffer, sizeof(buffer),
1809 "!immedbyte", (unsigned int) v & 0xff);
1811 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1815 return aop->aopu.aop_str[offset];
1818 setupPair (aop->aopu.aop_pairId, aop, offset);
1819 if (aop->aopu.aop_pairId==PAIR_IX)
1820 SNPRINTF (buffer, sizeof(buffer),
1822 else if (aop->aopu.aop_pairId==PAIR_IY)
1823 SNPRINTF (buffer, sizeof(buffer),
1826 SNPRINTF (buffer, sizeof(buffer),
1827 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1829 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1834 wassertl (0, "aopget got unsupported aop->type");
1839 isRegString (const char *s)
1841 if (!strcmp (s, "b") ||
1853 isConstant (const char *s)
1855 /* This is a bit of a hack... */
1856 return (*s == '#' || *s == '$');
1860 canAssignToPtr (const char *s)
1862 if (isRegString (s))
1869 /*-----------------------------------------------------------------*/
1870 /* aopPut - puts a string for a aop */
1871 /*-----------------------------------------------------------------*/
1873 aopPut (asmop * aop, const char *s, int offset)
1877 if (aop->size && offset > (aop->size - 1))
1879 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1880 "aopPut got offset > aop->size");
1885 tsprintf(buffer2, sizeof(buffer2), s);
1888 /* will assign value to value */
1889 /* depending on where it is ofcourse */
1893 _moveA (s); /* in case s is volatile */
1899 if (strcmp (s, "a"))
1900 emit2 ("ld a,%s", s);
1901 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1908 if (strcmp (s, "a"))
1909 emit2 ("ld a,%s", s);
1910 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1913 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1920 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1921 && s[0] != 'h' && s[0] != 'l'))
1923 emit2( "ld a,%s", s );
1927 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1928 emit2( "out (c),%s", s );
1933 spillPair (PAIR_BC);
1935 else if( z80_opts.port_mode == 180 )
1936 { /* z180 in0/out0 mode */
1937 emit2( "ld a,%s", s );
1938 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1942 emit2( "ld a,%s", s );
1943 emit2( "out (%s),a", aop->aopu.aop_dir );
1949 if (!strcmp (s, "!*hl"))
1950 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1953 aop->aopu.aop_reg[offset]->name, s);
1954 spillPairReg(aop->aopu.aop_reg[offset]->name);
1959 if (!canAssignToPtr (s))
1961 emit2 ("ld a,%s", s);
1962 setupPair (PAIR_IY, aop, offset);
1963 emit2 ("ld !*iyx,a", offset);
1967 setupPair (PAIR_IY, aop, offset);
1968 emit2 ("ld !*iyx,%s", offset, s);
1974 /* PENDING: for re-target */
1975 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1977 emit2 ("ld a,!*hl");
1980 setupPair (PAIR_HL, aop, offset);
1982 emit2 ("ld !*hl,%s", s);
1987 if (!canAssignToPtr (s))
1989 emit2 ("ld a,%s", s);
1990 setupPair (PAIR_IY, aop, offset);
1991 emit2 ("ld !*iyx,a", offset);
1995 setupPair (PAIR_IY, aop, offset);
1996 emit2 ("ld !*iyx,%s", offset, s);
2003 /* PENDING: re-target */
2004 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2006 emit2 ("ld a,!*hl");
2009 setupPair (PAIR_HL, aop, offset);
2010 if (!canAssignToPtr (s))
2012 emit2 ("ld a,%s", s);
2013 emit2 ("ld !*hl,a");
2016 emit2 ("ld !*hl,%s", s);
2020 if (aop->aopu.aop_stk >= 0)
2021 offset += _G.stack.param_offset;
2022 if (!canAssignToPtr (s))
2024 emit2 ("ld a,%s", s);
2025 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2029 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2035 /* if bit variable */
2036 if (!aop->aopu.aop_dir)
2038 emit2 ("ld a,!zero");
2043 /* In bit space but not in C - cant happen */
2044 wassertl (0, "Tried to write into a bit variable");
2050 if (strcmp (aop->aopu.aop_str[offset], s))
2052 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2054 spillPairReg(aop->aopu.aop_str[offset]);
2059 if (!offset && (strcmp (s, "acc") == 0))
2063 wassertl (0, "Tried to access past the end of A");
2067 if (strcmp (aop->aopu.aop_str[offset], s))
2069 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2070 spillPairReg(aop->aopu.aop_str[offset]);
2076 wassert (offset < 2);
2077 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2078 spillPairReg(aop->aopu.aop_str[offset]);
2082 setupPair (aop->aopu.aop_pairId, aop, offset);
2083 if (aop->aopu.aop_pairId==PAIR_IX)
2084 emit2 ("ld !*ixx,%s", 0, s);
2085 else if (aop->aopu.aop_pairId==PAIR_IY)
2086 emit2 ("ld !*iyx,%s", 0, s);
2088 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2092 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2093 "aopPut got unsupported aop->type");
2098 #define AOP(op) op->aop
2099 #define AOP_TYPE(op) AOP(op)->type
2100 #define AOP_SIZE(op) AOP(op)->size
2101 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2102 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2105 commitPair (asmop * aop, PAIR_ID id)
2107 /* PENDING: Verify this. */
2108 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2112 aopPut (aop, "a", 0);
2113 aopPut (aop, "d", 1);
2118 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2120 char *l = aopGetLitWordLong (aop, 0, FALSE);
2123 emit2 ("ld (%s),%s", l, _pairs[id].name);
2127 aopPut (aop, _pairs[id].l, 0);
2128 aopPut (aop, _pairs[id].h, 1);
2133 /*-----------------------------------------------------------------*/
2134 /* getDataSize - get the operand data size */
2135 /*-----------------------------------------------------------------*/
2137 getDataSize (operand * op)
2140 size = AOP_SIZE (op);
2144 wassertl (0, "Somehow got a three byte data pointer");
2149 /*-----------------------------------------------------------------*/
2150 /* movLeft2Result - move byte from left to result */
2151 /*-----------------------------------------------------------------*/
2153 movLeft2Result (operand * left, int offl,
2154 operand * result, int offr, int sign)
2158 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2160 l = aopGet (AOP (left), offl, FALSE);
2164 aopPut (AOP (result), l, offr);
2168 if (getDataSize (left) == offl + 1)
2170 emit2 ("ld a,%s", l);
2171 aopPut (AOP (result), "a", offr);
2178 movLeft2ResultLong (operand * left, int offl,
2179 operand * result, int offr, int sign,
2184 movLeft2Result (left, offl, result, offr, sign);
2188 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2189 wassertl (size == 2, "Only implemented for two bytes or one");
2191 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2193 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2194 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2196 spillPair (PAIR_HL);
2198 else if ( getPairId ( AOP (result)) == PAIR_IY)
2200 PAIR_ID id = getPairId (AOP (left));
2201 if (id != PAIR_INVALID)
2203 emit2("push %s", _pairs[id].name);
2214 movLeft2Result (left, offl, result, offr, sign);
2215 movLeft2Result (left, offl+1, result, offr+1, sign);
2220 /** Put Acc into a register set
2223 outAcc (operand * result)
2226 size = getDataSize (result);
2229 aopPut (AOP (result), "a", 0);
2232 /* unsigned or positive */
2235 aopPut (AOP (result), "!zero", offset++);
2240 /** Take the value in carry and put it into a register
2243 outBitC (operand * result)
2245 /* if the result is bit */
2246 if (AOP_TYPE (result) == AOP_CRY)
2248 if (!IS_OP_RUONLY (result))
2249 aopPut (AOP (result), "c", 0);
2253 emit2 ("ld a,!zero");
2259 /*-----------------------------------------------------------------*/
2260 /* toBoolean - emit code for orl a,operator(sizeop) */
2261 /*-----------------------------------------------------------------*/
2263 _toBoolean (operand * oper)
2265 int size = AOP_SIZE (oper);
2269 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2272 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2276 if (AOP (oper)->type != AOP_ACC)
2279 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2285 /*-----------------------------------------------------------------*/
2286 /* genNot - generate code for ! operation */
2287 /*-----------------------------------------------------------------*/
2292 /* assign asmOps to operand & result */
2293 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2294 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2296 /* if in bit space then a special case */
2297 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2299 wassertl (0, "Tried to negate a bit");
2302 _toBoolean (IC_LEFT (ic));
2307 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2308 emit2 ("sub a,!one");
2309 outBitC (IC_RESULT (ic));
2311 /* release the aops */
2312 freeAsmop (IC_LEFT (ic), NULL, ic);
2313 freeAsmop (IC_RESULT (ic), NULL, ic);
2316 /*-----------------------------------------------------------------*/
2317 /* genCpl - generate code for complement */
2318 /*-----------------------------------------------------------------*/
2326 /* assign asmOps to operand & result */
2327 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2328 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2330 /* if both are in bit space then
2332 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2333 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2335 wassertl (0, "Left and the result are in bit space");
2338 size = AOP_SIZE (IC_RESULT (ic));
2341 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2344 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2347 /* release the aops */
2348 freeAsmop (IC_LEFT (ic), NULL, ic);
2349 freeAsmop (IC_RESULT (ic), NULL, ic);
2353 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2360 store de into result
2365 store de into result
2367 const char *first = isAdd ? "add" : "sub";
2368 const char *later = isAdd ? "adc" : "sbc";
2370 wassertl (IS_GB, "Code is only relevent to the gbz80");
2371 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2373 fetchPair (PAIR_DE, left);
2376 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2379 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2382 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2383 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2385 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2386 aopGet (right, MSB24, FALSE);
2390 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2393 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2395 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2396 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2400 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2402 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2405 /*-----------------------------------------------------------------*/
2406 /* genUminusFloat - unary minus for floating points */
2407 /*-----------------------------------------------------------------*/
2409 genUminusFloat (operand * op, operand * result)
2411 int size, offset = 0;
2413 emitDebug("; genUminusFloat");
2415 /* for this we just need to flip the
2416 first bit then copy the rest in place */
2417 size = AOP_SIZE (op) - 1;
2419 _moveA(aopGet (AOP (op), MSB32, FALSE));
2421 emit2("xor a,!immedbyte", 0x80);
2422 aopPut (AOP (result), "a", MSB32);
2426 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2431 /*-----------------------------------------------------------------*/
2432 /* genUminus - unary minus code generation */
2433 /*-----------------------------------------------------------------*/
2435 genUminus (iCode * ic)
2438 sym_link *optype, *rtype;
2441 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2442 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2444 /* if both in bit space then special
2446 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2447 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2449 wassertl (0, "Left and right are in bit space");
2453 optype = operandType (IC_LEFT (ic));
2454 rtype = operandType (IC_RESULT (ic));
2456 /* if float then do float stuff */
2457 if (IS_FLOAT (optype))
2459 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2463 /* otherwise subtract from zero */
2464 size = AOP_SIZE (IC_LEFT (ic));
2466 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2468 /* Create a new asmop with value zero */
2469 asmop *azero = newAsmop (AOP_SIMPLELIT);
2470 azero->aopu.aop_simplelit = 0;
2472 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2480 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2481 emit2 ("ld a,!zero");
2482 emit2 ("sbc a,%s", l);
2483 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2486 /* if any remaining bytes in the result */
2487 /* we just need to propagate the sign */
2488 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2493 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2497 /* release the aops */
2498 freeAsmop (IC_LEFT (ic), NULL, ic);
2499 freeAsmop (IC_RESULT (ic), NULL, ic);
2502 /*-----------------------------------------------------------------*/
2503 /* assignResultValue - */
2504 /*-----------------------------------------------------------------*/
2506 assignResultValue (operand * oper)
2508 int size = AOP_SIZE (oper);
2511 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2512 topInA = requiresHL (AOP (oper));
2514 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2516 /* We do it the hard way here. */
2518 aopPut (AOP (oper), _fReturn[0], 0);
2519 aopPut (AOP (oper), _fReturn[1], 1);
2521 aopPut (AOP (oper), _fReturn[0], 2);
2522 aopPut (AOP (oper), _fReturn[1], 3);
2526 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2527 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2530 _emitMove ("a", _fReturn[size-1]);
2531 _emitMove (_fReturn[size-1], _fReturn[size]);
2532 _emitMove (_fReturn[size], "a");
2533 aopPut (AOP (oper), _fReturn[size], size-1);
2538 aopPut (AOP (oper), _fReturn[size], size);
2543 /** Simple restore that doesn't take into account what is used in the
2547 _restoreRegsAfterCall(void)
2549 if (_G.stack.pushedDE)
2552 _G.stack.pushedDE = FALSE;
2554 if (_G.stack.pushedBC)
2557 _G.stack.pushedBC = FALSE;
2559 _G.saves.saved = FALSE;
2563 _saveRegsForCall(iCode *ic, int sendSetSize)
2566 o Stack parameters are pushed before this function enters
2567 o DE and BC may be used in this function.
2568 o HL and DE may be used to return the result.
2569 o HL and DE may be used to send variables.
2570 o DE and BC may be used to store the result value.
2571 o HL may be used in computing the sent value of DE
2572 o The iPushes for other parameters occur before any addSets
2574 Logic: (to be run inside the first iPush or if none, before sending)
2575 o Compute if DE and/or BC are in use over the call
2576 o Compute if DE is used in the send set
2577 o Compute if DE and/or BC are used to hold the result value
2578 o If (DE is used, or in the send set) and is not used in the result, push.
2579 o If BC is used and is not in the result, push
2581 o If DE is used in the send set, fetch
2582 o If HL is used in the send set, fetch
2586 if (_G.saves.saved == FALSE) {
2587 bool deInUse, bcInUse;
2589 bool bcInRet = FALSE, deInRet = FALSE;
2592 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2593 z80_rUmaskForOp (IC_RESULT(ic)));
2595 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2596 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2598 deSending = (sendSetSize > 1);
2600 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2602 if (bcInUse && bcInRet == FALSE) {
2604 _G.stack.pushedBC = TRUE;
2606 if (deInUse && deInRet == FALSE) {
2608 _G.stack.pushedDE = TRUE;
2611 _G.saves.saved = TRUE;
2614 /* Already saved. */
2618 /*-----------------------------------------------------------------*/
2619 /* genIpush - genrate code for pushing this gets a little complex */
2620 /*-----------------------------------------------------------------*/
2622 genIpush (iCode * ic)
2624 int size, offset = 0;
2627 /* if this is not a parm push : ie. it is spill push
2628 and spill push is always done on the local stack */
2631 wassertl(0, "Encountered an unsupported spill push.");
2635 if (_G.saves.saved == FALSE) {
2636 /* Caller saves, and this is the first iPush. */
2637 /* Scan ahead until we find the function that we are pushing parameters to.
2638 Count the number of addSets on the way to figure out what registers
2639 are used in the send set.
2642 iCode *walk = ic->next;
2645 if (walk->op == SEND) {
2648 else if (walk->op == CALL || walk->op == PCALL) {
2657 _saveRegsForCall(walk, nAddSets);
2660 /* Already saved by another iPush. */
2663 /* then do the push */
2664 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2666 size = AOP_SIZE (IC_LEFT (ic));
2668 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2670 _G.stack.pushed += 2;
2671 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2677 fetchHL (AOP (IC_LEFT (ic)));
2679 spillPair (PAIR_HL);
2680 _G.stack.pushed += 2;
2685 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2687 spillPair (PAIR_HL);
2688 _G.stack.pushed += 2;
2689 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2691 spillPair (PAIR_HL);
2692 _G.stack.pushed += 2;
2698 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2700 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2702 emit2 ("ld a,(%s)", l);
2707 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2708 if (!strcmp(l, "b"))
2710 else if (!strcmp(l, "d"))
2712 else if (!strcmp(l, "h"))
2716 emit2 ("ld a,%s", l);
2725 freeAsmop (IC_LEFT (ic), NULL, ic);
2728 /*-----------------------------------------------------------------*/
2729 /* genIpop - recover the registers: can happen only for spilling */
2730 /*-----------------------------------------------------------------*/
2732 genIpop (iCode * ic)
2737 /* if the temp was not pushed then */
2738 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2741 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2742 size = AOP_SIZE (IC_LEFT (ic));
2743 offset = (size - 1);
2744 if (isPair (AOP (IC_LEFT (ic))))
2746 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2754 spillPair (PAIR_HL);
2755 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2759 freeAsmop (IC_LEFT (ic), NULL, ic);
2762 /* This is quite unfortunate */
2764 setArea (int inHome)
2767 static int lastArea = 0;
2769 if (_G.in_home != inHome) {
2771 const char *sz = port->mem.code_name;
2772 port->mem.code_name = "HOME";
2773 emit2("!area", CODE_NAME);
2774 port->mem.code_name = sz;
2777 emit2("!area", CODE_NAME); */
2778 _G.in_home = inHome;
2789 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2793 symbol *sym = OP_SYMBOL (op);
2795 if (sym->isspilt || sym->nRegs == 0)
2798 aopOp (op, ic, FALSE, FALSE);
2801 if (aop->type == AOP_REG)
2804 for (i = 0; i < aop->size; i++)
2806 if (pairId == PAIR_DE)
2808 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2809 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2811 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2814 else if (pairId == PAIR_BC)
2816 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2817 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2819 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2829 freeAsmop (IC_LEFT (ic), NULL, ic);
2833 /** Emit the code for a call statement
2836 emitCall (iCode * ic, bool ispcall)
2838 bool bInRet, cInRet, dInRet, eInRet;
2839 sym_link *dtype = operandType (IC_LEFT (ic));
2841 /* if caller saves & we have not saved then */
2847 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2849 /* if send set is not empty then assign */
2854 int nSend = elementsInSet(_G.sendSet);
2855 bool swapped = FALSE;
2857 int _z80_sendOrder[] = {
2862 /* Check if the parameters are swapped. If so route through hl instead. */
2863 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2865 sic = setFirstItem(_G.sendSet);
2866 sic = setNextItem(_G.sendSet);
2868 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2869 /* The second send value is loaded from one the one that holds the first
2870 send, i.e. it is overwritten. */
2871 /* Cache the first in HL, and load the second from HL instead. */
2872 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2873 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2879 for (sic = setFirstItem (_G.sendSet); sic;
2880 sic = setNextItem (_G.sendSet))
2883 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2885 size = AOP_SIZE (IC_LEFT (sic));
2886 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2887 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2889 // PENDING: Mild hack
2890 if (swapped == TRUE && send == 1) {
2892 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2895 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2897 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2900 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2904 freeAsmop (IC_LEFT (sic), NULL, sic);
2911 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2913 werror (W_INDIR_BANKED);
2915 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2917 if (isLitWord (AOP (IC_LEFT (ic))))
2919 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2923 symbol *rlbl = newiTempLabel (NULL);
2924 spillPair (PAIR_HL);
2925 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2927 _G.stack.pushed += 2;
2929 fetchHL (AOP (IC_LEFT (ic)));
2931 emit2 ("!tlabeldef", (rlbl->key + 100));
2932 _G.lines.current->isLabel = 1;
2933 _G.stack.pushed -= 2;
2935 freeAsmop (IC_LEFT (ic), NULL, ic);
2939 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2940 OP_SYMBOL (IC_LEFT (ic))->rname :
2941 OP_SYMBOL (IC_LEFT (ic))->name;
2942 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2944 emit2 ("call banked_call");
2945 emit2 ("!dws", name);
2946 emit2 ("!dw !bankimmeds", name);
2951 emit2 ("call %s", name);
2956 /* Mark the registers as restored. */
2957 _G.saves.saved = FALSE;
2959 /* if we need assign a result value */
2960 if ((IS_ITEMP (IC_RESULT (ic)) &&
2961 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2962 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2963 IS_TRUE_SYMOP (IC_RESULT (ic)))
2965 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2967 assignResultValue (IC_RESULT (ic));
2969 freeAsmop (IC_RESULT (ic), NULL, ic);
2972 /* adjust the stack for parameters if required */
2975 int i = ic->parmBytes;
2977 _G.stack.pushed -= i;
2980 emit2 ("!ldaspsp", i);
2987 emit2 ("ld iy,!immedword", i);
2988 emit2 ("add iy,sp");
3009 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3010 bInRet = bitVectBitValue(result, B_IDX);
3011 cInRet = bitVectBitValue(result, C_IDX);
3012 dInRet = bitVectBitValue(result, D_IDX);
3013 eInRet = bitVectBitValue(result, E_IDX);
3023 if (_G.stack.pushedDE)
3025 if (dInRet && eInRet)
3027 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3031 /* Only restore E */
3038 /* Only restore D */
3046 _G.stack.pushedDE = FALSE;
3049 if (_G.stack.pushedBC)
3051 if (bInRet && cInRet)
3053 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3057 /* Only restore C */
3064 /* Only restore B */
3072 _G.stack.pushedBC = FALSE;
3076 /*-----------------------------------------------------------------*/
3077 /* genCall - generates a call statement */
3078 /*-----------------------------------------------------------------*/
3080 genCall (iCode * ic)
3082 emitCall (ic, FALSE);
3085 /*-----------------------------------------------------------------*/
3086 /* genPcall - generates a call by pointer statement */
3087 /*-----------------------------------------------------------------*/
3089 genPcall (iCode * ic)
3091 emitCall (ic, TRUE);
3094 /*-----------------------------------------------------------------*/
3095 /* resultRemat - result is rematerializable */
3096 /*-----------------------------------------------------------------*/
3098 resultRemat (iCode * ic)
3100 if (SKIP_IC (ic) || ic->op == IFX)
3103 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3105 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3106 if (sym->remat && !POINTER_SET (ic))
3113 extern set *publics;
3115 /*-----------------------------------------------------------------*/
3116 /* genFunction - generated code for function entry */
3117 /*-----------------------------------------------------------------*/
3119 genFunction (iCode * ic)
3123 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3126 bool bcInUse = FALSE;
3127 bool deInUse = FALSE;
3129 setArea (IFFUNC_NONBANKED (sym->type));
3131 /* PENDING: Reset the receive offset as it
3132 doesn't seem to get reset anywhere else.
3134 _G.receiveOffset = 0;
3136 /* Record the last function name for debugging. */
3137 _G.lastFunctionName = sym->rname;
3139 /* Create the function header */
3140 emit2 ("!functionheader", sym->name);
3141 if (!IS_STATIC(sym->etype))
3143 sprintf (buffer, "%s_start", sym->rname);
3144 emit2 ("!labeldef", buffer);
3145 _G.lines.current->isLabel = 1;
3147 emit2 ("!functionlabeldef", sym->rname);
3148 _G.lines.current->isLabel = 1;
3150 ftype = operandType (IC_LEFT (ic));
3152 if (IFFUNC_ISNAKED(ftype))
3154 emitDebug("; naked function: no prologue.");
3158 /* if this is an interrupt service routine
3159 then save all potentially used registers. */
3160 if (IFFUNC_ISISR (sym->type))
3162 /* If critical function then turn interrupts off */
3163 /* except when no interrupt number is given then it implies the NMI handler */
3164 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3173 /* This is a non-ISR function.
3174 If critical function then turn interrupts off */
3175 if (IFFUNC_ISCRITICAL (sym->type))
3183 //get interrupt enable flag IFF2 into P/O
3192 if (options.profile)
3194 emit2 ("!profileenter");
3197 /* PENDING: callee-save etc */
3199 _G.stack.param_offset = 0;
3201 if (z80_opts.calleeSavesBC)
3206 /* Detect which registers are used. */
3207 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3210 for (i = 0; i < sym->regsUsed->size; i++)
3212 if (bitVectBitValue (sym->regsUsed, i))
3226 /* Other systems use DE as a temporary. */
3237 _G.stack.param_offset += 2;
3240 _G.calleeSaves.pushedBC = bcInUse;
3245 _G.stack.param_offset += 2;
3248 _G.calleeSaves.pushedDE = deInUse;
3250 /* adjust the stack for the function */
3251 _G.stack.last = sym->stack;
3254 for (sym = setFirstItem (istack->syms); sym;
3255 sym = setNextItem (istack->syms))
3257 if (sym->_isparm && !IS_REGPARM (sym->etype))
3263 sym = OP_SYMBOL (IC_LEFT (ic));
3265 _G.omitFramePtr = options.ommitFramePtr;
3266 if (IS_Z80 && !stackParm && !sym->stack)
3268 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3269 /* the above !sym->stack condition can be removed. -- EEP */
3271 emit2 ("!ldaspsp", -sym->stack);
3272 _G.omitFramePtr = TRUE;
3274 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3275 emit2 ("!enterxl", sym->stack);
3276 else if (sym->stack)
3277 emit2 ("!enterx", sym->stack);
3281 _G.stack.offset = sym->stack;
3284 /*-----------------------------------------------------------------*/
3285 /* genEndFunction - generates epilogue for functions */
3286 /*-----------------------------------------------------------------*/
3288 genEndFunction (iCode * ic)
3290 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3292 if (IFFUNC_ISNAKED(sym->type))
3294 emitDebug("; naked function: no epilogue.");
3298 /* PENDING: calleeSave */
3299 if (IS_Z80 && _G.omitFramePtr)
3301 if (_G.stack.offset)
3302 emit2 ("!ldaspsp", _G.stack.offset);
3304 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3306 emit2 ("!leavexl", _G.stack.offset);
3308 else if (_G.stack.offset)
3310 emit2 ("!leavex", _G.stack.offset);
3317 if (_G.calleeSaves.pushedDE)
3320 _G.calleeSaves.pushedDE = FALSE;
3323 if (_G.calleeSaves.pushedBC)
3326 _G.calleeSaves.pushedBC = FALSE;
3329 if (options.profile)
3331 emit2 ("!profileexit");
3334 /* if this is an interrupt service routine
3335 then save all potentially used registers. */
3336 if (IFFUNC_ISISR (sym->type))
3340 /* If critical function then turn interrupts back on */
3341 /* except when no interrupt number is given then it implies the NMI handler */
3342 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3349 /* This is a non-ISR function.
3350 If critical function then turn interrupts back on */
3351 if (IFFUNC_ISCRITICAL (sym->type))
3359 symbol *tlbl = newiTempLabel (NULL);
3362 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3363 //don't enable interrupts as they were off before
3364 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3366 emit2 ("!tlabeldef", (tlbl->key + 100));
3367 _G.lines.current->isLabel = 1;
3372 if (options.debug && currFunc)
3374 debugFile->writeEndFunction (currFunc, ic, 1);
3377 if (IFFUNC_ISISR (sym->type))
3379 /* "critical interrupt" is used to imply NMI handler */
3380 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3387 /* Both banked and non-banked just ret */
3391 if (!IS_STATIC(sym->etype))
3393 sprintf (buffer, "%s_end", sym->rname);
3394 emit2 ("!labeldef", buffer);
3395 _G.lines.current->isLabel = 1;
3398 _G.flushStatics = 1;
3399 _G.stack.pushed = 0;
3400 _G.stack.offset = 0;
3403 /*-----------------------------------------------------------------*/
3404 /* genRet - generate code for return statement */
3405 /*-----------------------------------------------------------------*/
3410 /* Errk. This is a hack until I can figure out how
3411 to cause dehl to spill on a call */
3412 int size, offset = 0;
3414 /* if we have no return value then
3415 just generate the "ret" */
3419 /* we have something to return then
3420 move the return value into place */
3421 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3422 size = AOP_SIZE (IC_LEFT (ic));
3424 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3427 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3431 emit2 ("ld de,%s", l);
3435 emit2 ("ld hl,%s", l);
3441 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3445 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3447 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3448 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3454 l = aopGet (AOP (IC_LEFT (ic)), offset,
3456 if (strcmp (_fReturn[offset], l))
3457 emit2 ("ld %s,%s", _fReturn[offset], l);
3462 freeAsmop (IC_LEFT (ic), NULL, ic);
3465 /* generate a jump to the return label
3466 if the next is not the return statement */
3467 if (!(ic->next && ic->next->op == LABEL &&
3468 IC_LABEL (ic->next) == returnLabel))
3470 emit2 ("jp !tlabel", returnLabel->key + 100);
3473 /*-----------------------------------------------------------------*/
3474 /* genLabel - generates a label */
3475 /*-----------------------------------------------------------------*/
3477 genLabel (iCode * ic)
3479 /* special case never generate */
3480 if (IC_LABEL (ic) == entryLabel)
3483 emitLabel (IC_LABEL (ic)->key + 100);
3486 /*-----------------------------------------------------------------*/
3487 /* genGoto - generates a ljmp */
3488 /*-----------------------------------------------------------------*/
3490 genGoto (iCode * ic)
3492 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3495 /*-----------------------------------------------------------------*/
3496 /* genPlusIncr :- does addition with increment if possible */
3497 /*-----------------------------------------------------------------*/
3499 genPlusIncr (iCode * ic)
3501 unsigned int icount;
3502 unsigned int size = getDataSize (IC_RESULT (ic));
3503 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3505 /* will try to generate an increment */
3506 /* if the right side is not a literal
3508 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3511 emitDebug ("; genPlusIncr");
3513 icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3515 /* If result is a pair */
3516 if (resultId != PAIR_INVALID)
3518 if (isLitWord (AOP (IC_LEFT (ic))))
3520 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3523 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3525 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3527 PAIR_ID freep = getFreePairId (ic);
3528 if (freep != PAIR_INVALID)
3530 fetchPair (freep, AOP (IC_RIGHT (ic)));
3531 emit2 ("add hl,%s", _pairs[freep].name);
3537 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3538 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3545 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3549 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3553 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3558 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3560 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3561 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3565 /* if the literal value of the right hand side
3566 is greater than 4 then it is not worth it */
3570 /* if increment 16 bits in register */
3571 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3577 symbol *tlbl = NULL;
3578 tlbl = newiTempLabel (NULL);
3581 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3584 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3587 emitLabel (tlbl->key + 100);
3591 /* if the sizes are greater than 1 then we cannot */
3592 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3593 AOP_SIZE (IC_LEFT (ic)) > 1)
3596 /* If the result is in a register then we can load then increment.
3598 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3600 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3603 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3608 /* we can if the aops of the left & result match or
3609 if they are in registers and the registers are the
3611 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3615 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3623 /*-----------------------------------------------------------------*/
3624 /* outBitAcc - output a bit in acc */
3625 /*-----------------------------------------------------------------*/
3627 outBitAcc (operand * result)
3629 symbol *tlbl = newiTempLabel (NULL);
3630 /* if the result is a bit */
3631 if (AOP_TYPE (result) == AOP_CRY)
3633 wassertl (0, "Tried to write A into a bit");
3637 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3638 emit2 ("ld a,!one");
3639 emitLabel (tlbl->key + 100);
3645 couldDestroyCarry (asmop *aop)
3649 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3658 shiftIntoPair (int idx, asmop *aop)
3660 PAIR_ID id = PAIR_INVALID;
3662 wassertl (IS_Z80, "Only implemented for the Z80");
3663 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3665 emitDebug ("; Shift into pair idx %u", idx);
3671 setupPair (PAIR_HL, aop, 0);
3676 setupPair (PAIR_IY, aop, 0);
3678 emit2 ("pop %s", _pairs[id].name);
3682 setupPair (PAIR_IY, aop, 0);
3685 wassertl (0, "Internal error - hit default case");
3688 aop->type = AOP_PAIRPTR;
3689 aop->aopu.aop_pairId = id;
3690 _G.pairs[id].offset = 0;
3691 _G.pairs[id].last_type = aop->type;
3695 setupToPreserveCarry (iCode * ic)
3697 asmop *left = AOP (IC_LEFT (ic));
3698 asmop *right = AOP (IC_RIGHT (ic));
3699 asmop *result = AOP (IC_RESULT (ic));
3701 wassert (left && right);
3705 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3707 shiftIntoPair (0, right);
3708 /* check result again, in case right == result */
3709 if (couldDestroyCarry (result))
3711 if (!isPairInUse (PAIR_DE, ic))
3712 shiftIntoPair (1, result);
3714 shiftIntoPair (2, result);
3717 else if (couldDestroyCarry (right))
3719 if (getPairId (result) == PAIR_HL)
3720 _G.preserveCarry = TRUE;
3722 shiftIntoPair (0, right);
3724 else if (couldDestroyCarry (result))
3726 shiftIntoPair (0, result);
3735 /*-----------------------------------------------------------------*/
3736 /* genPlus - generates code for addition */
3737 /*-----------------------------------------------------------------*/
3739 genPlus (iCode * ic)
3741 int size, offset = 0;
3743 /* special cases :- */
3745 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3746 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3747 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3749 /* Swap the left and right operands if:
3751 if literal, literal on the right or
3752 if left requires ACC or right is already
3755 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3756 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3757 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3759 operand *t = IC_RIGHT (ic);
3760 IC_RIGHT (ic) = IC_LEFT (ic);
3764 /* if both left & right are in bit
3766 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3767 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3770 wassertl (0, "Tried to add two bits");
3773 /* if left in bit space & right literal */
3774 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3775 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3777 /* Can happen I guess */
3778 wassertl (0, "Tried to add a bit to a literal");
3781 /* if I can do an increment instead
3782 of add then GOOD for ME */
3783 if (genPlusIncr (ic) == TRUE)
3786 size = getDataSize (IC_RESULT (ic));
3788 /* Special case when left and right are constant */
3789 if (isPair (AOP (IC_RESULT (ic))))
3792 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3793 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3795 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3801 sprintf (buffer, "#(%s + %s)", left, right);
3802 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3807 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3809 /* Fetch into HL then do the add */
3810 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3811 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3813 spillPair (PAIR_HL);
3815 if (left == PAIR_HL && right != PAIR_INVALID)
3817 emit2 ("add hl,%s", _pairs[right].name);
3820 else if (right == PAIR_HL && left != PAIR_INVALID)
3822 emit2 ("add hl,%s", _pairs[left].name);
3825 else if (right != PAIR_INVALID && right != PAIR_HL)
3827 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3828 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3831 else if (left != PAIR_INVALID && left != PAIR_HL)
3833 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3834 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3843 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3845 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3846 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3848 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3853 ld hl,sp+n trashes C so we can't afford to do it during an
3854 add with stack based variables. Worst case is:
3867 So you can't afford to load up hl if either left, right, or result
3868 is on the stack (*sigh*) The alt is:
3876 Combinations in here are:
3877 * If left or right are in bc then the loss is small - trap later
3878 * If the result is in bc then the loss is also small
3882 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3883 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3884 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3886 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3887 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3888 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3889 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3891 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3893 /* Swap left and right */
3894 operand *t = IC_RIGHT (ic);
3895 IC_RIGHT (ic) = IC_LEFT (ic);
3898 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3900 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3901 emit2 ("add hl,bc");
3905 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3906 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3907 emit2 ("add hl,de");
3909 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3915 /* Be paranoid on the GB with 4 byte variables due to how C
3916 can be trashed by lda hl,n(sp).
3918 _gbz80_emitAddSubLong (ic, TRUE);
3923 setupToPreserveCarry (ic);
3925 /* This is ugly, but it fixes the worst code generation bug on Z80. */
3926 /* Probably something similar has to be done for addition of larger numbers, too. */
3929 _moveA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3930 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), 0, FALSE));
3931 if(strcmp (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), aopGet (AOP (IC_LEFT (ic)), 1, FALSE)))
3933 aopPut (AOP (IC_RESULT (ic)), "a", 0);
3934 _moveA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3938 emitDebug ("; Addition result is in same register as operand of next addition.");
3939 if(strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'c') ||
3940 strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'b') )
3944 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3947 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3955 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3958 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3964 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), 1, FALSE));
3965 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3971 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3973 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3975 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3976 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3980 _G.preserveCarry = FALSE;
3981 freeAsmop (IC_LEFT (ic), NULL, ic);
3982 freeAsmop (IC_RIGHT (ic), NULL, ic);
3983 freeAsmop (IC_RESULT (ic), NULL, ic);
3986 /*-----------------------------------------------------------------*/
3987 /* genMinusDec :- does subtraction with deccrement if possible */
3988 /*-----------------------------------------------------------------*/
3990 genMinusDec (iCode * ic)
3992 unsigned int icount;
3993 unsigned int size = getDataSize (IC_RESULT (ic));
3995 /* will try to generate an increment */
3996 /* if the right side is not a literal we cannot */
3997 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4000 /* if the literal value of the right hand side
4001 is greater than 4 then it is not worth it */
4002 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
4005 size = getDataSize (IC_RESULT (ic));
4007 /* if decrement 16 bits in register */
4008 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4009 (size > 1) && isPair (AOP (IC_RESULT (ic))))
4012 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4016 /* If result is a pair */
4017 if (isPair (AOP (IC_RESULT (ic))))
4019 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
4021 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4025 /* if increment 16 bits in register */
4026 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4030 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4033 emit2 ("dec %s", _getTempPairName());
4036 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4042 /* if the sizes are greater than 1 then we cannot */
4043 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4044 AOP_SIZE (IC_LEFT (ic)) > 1)
4047 /* we can if the aops of the left & result match or if they are in
4048 registers and the registers are the same */
4049 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4052 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4059 /*-----------------------------------------------------------------*/
4060 /* genMinus - generates code for subtraction */
4061 /*-----------------------------------------------------------------*/
4063 genMinus (iCode * ic)
4065 int size, offset = 0;
4066 unsigned long lit = 0L;
4068 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4069 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4070 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4072 /* special cases :- */
4073 /* if both left & right are in bit space */
4074 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4075 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4077 wassertl (0, "Tried to subtract two bits");
4081 /* if I can do an decrement instead of subtract then GOOD for ME */
4082 if (genMinusDec (ic) == TRUE)
4085 size = getDataSize (IC_RESULT (ic));
4087 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4092 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4096 /* Same logic as genPlus */
4099 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4100 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4101 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4103 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4104 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4105 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4106 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4108 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4109 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4111 if (left == PAIR_INVALID && right == PAIR_INVALID)
4116 else if (right == PAIR_INVALID)
4118 else if (left == PAIR_INVALID)
4121 fetchPair (left, AOP (IC_LEFT (ic)));
4122 /* Order is important. Right may be HL */
4123 fetchPair (right, AOP (IC_RIGHT (ic)));
4125 emit2 ("ld a,%s", _pairs[left].l);
4126 emit2 ("sub a,%s", _pairs[right].l);
4128 emit2 ("ld a,%s", _pairs[left].h);
4129 emit2 ("sbc a,%s", _pairs[right].h);
4131 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4133 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4135 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4141 /* Be paranoid on the GB with 4 byte variables due to how C
4142 can be trashed by lda hl,n(sp).
4144 _gbz80_emitAddSubLong (ic, FALSE);
4149 setupToPreserveCarry (ic);
4151 /* if literal, add a,#-lit, else normal subb */
4154 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4155 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4159 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4162 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4166 /* first add without previous c */
4168 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4170 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4172 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4175 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4176 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4177 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4179 wassertl (0, "Tried to subtract on a long pointer");
4183 _G.preserveCarry = FALSE;
4184 freeAsmop (IC_LEFT (ic), NULL, ic);
4185 freeAsmop (IC_RIGHT (ic), NULL, ic);
4186 freeAsmop (IC_RESULT (ic), NULL, ic);
4189 /*-----------------------------------------------------------------*/
4190 /* genMult - generates code for multiplication */
4191 /*-----------------------------------------------------------------*/
4193 genMult (iCode * ic)
4197 /* If true then the final operation should be a subtract */
4198 bool active = FALSE;
4201 /* Shouldn't occur - all done through function calls */
4202 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4203 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4204 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4206 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4208 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4209 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4210 AOP_SIZE (IC_RESULT (ic)) > 2)
4212 wassertl (0, "Multiplication is handled through support function calls");
4215 /* Swap left and right such that right is a literal */
4216 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4218 operand *t = IC_RIGHT (ic);
4219 IC_RIGHT (ic) = IC_LEFT (ic);
4223 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4225 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4226 // wassertl (val > 0, "Multiply must be positive");
4227 wassertl (val != 1, "Can't multiply by 1");
4229 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4231 _G.stack.pushedDE = TRUE;
4235 emit2 ("ld a,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4236 else if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4238 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4249 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4254 for (count = 0; count < 16; count++)
4256 if (count != 0 && active)
4261 emit2 ("add hl,hl");
4265 if (active == FALSE)
4280 emit2 ("add hl,de");
4289 if (IS_Z80 && _G.stack.pushedDE)
4292 _G.stack.pushedDE = FALSE;
4296 aopPut (AOP (IC_RESULT (ic)), "a", 0);
4298 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4300 freeAsmop (IC_LEFT (ic), NULL, ic);
4301 freeAsmop (IC_RIGHT (ic), NULL, ic);
4302 freeAsmop (IC_RESULT (ic), NULL, ic);
4305 /*-----------------------------------------------------------------*/
4306 /* genDiv - generates code for division */
4307 /*-----------------------------------------------------------------*/
4311 /* Shouldn't occur - all done through function calls */
4312 wassertl (0, "Division is handled through support function calls");
4315 /*-----------------------------------------------------------------*/
4316 /* genMod - generates code for division */
4317 /*-----------------------------------------------------------------*/
4321 /* Shouldn't occur - all done through function calls */
4325 /*-----------------------------------------------------------------*/
4326 /* genIfxJump :- will create a jump depending on the ifx */
4327 /*-----------------------------------------------------------------*/
4329 genIfxJump (iCode * ic, char *jval)
4334 /* if true label then we jump if condition
4338 jlbl = IC_TRUE (ic);
4339 if (!strcmp (jval, "a"))
4343 else if (!strcmp (jval, "c"))
4347 else if (!strcmp (jval, "nc"))
4351 else if (!strcmp (jval, "m"))
4355 else if (!strcmp (jval, "p"))
4361 /* The buffer contains the bit on A that we should test */
4367 /* false label is present */
4368 jlbl = IC_FALSE (ic);
4369 if (!strcmp (jval, "a"))
4373 else if (!strcmp (jval, "c"))
4377 else if (!strcmp (jval, "nc"))
4381 else if (!strcmp (jval, "m"))
4385 else if (!strcmp (jval, "p"))
4391 /* The buffer contains the bit on A that we should test */
4395 /* Z80 can do a conditional long jump */
4396 if (!strcmp (jval, "a"))
4400 else if (!strcmp (jval, "c"))
4403 else if (!strcmp (jval, "nc"))
4406 else if (!strcmp (jval, "m"))
4409 else if (!strcmp (jval, "p"))
4414 emit2 ("bit %s,a", jval);
4416 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4418 /* mark the icode as generated */
4424 _getPairIdName (PAIR_ID id)
4426 return _pairs[id].name;
4431 /* if unsigned char cmp with lit, just compare */
4433 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4435 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4438 emit2 ("xor a,!immedbyte", 0x80);
4439 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4442 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4444 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4446 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4447 // Pull left into DE and right into HL
4448 aopGet (AOP(left), LSB, FALSE);
4451 aopGet (AOP(right), LSB, FALSE);
4455 if (size == 0 && sign)
4457 // Highest byte when signed needs the bits flipped
4460 emit2 ("ld a,(de)");
4461 emit2 ("xor !immedbyte", 0x80);
4463 emit2 ("ld a,(hl)");
4464 emit2 ("xor !immedbyte", 0x80);
4468 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4472 emit2 ("ld a,(de)");
4473 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4483 spillPair (PAIR_HL);
4485 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4487 setupPair (PAIR_HL, AOP (left), 0);
4488 aopGet (AOP(right), LSB, FALSE);
4492 if (size == 0 && sign)
4494 // Highest byte when signed needs the bits flipped
4497 emit2 ("ld a,(hl)");
4498 emit2 ("xor !immedbyte", 0x80);
4500 emit2 ("ld a,%d(iy)", offset);
4501 emit2 ("xor !immedbyte", 0x80);
4505 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4509 emit2 ("ld a,(hl)");
4510 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4519 spillPair (PAIR_HL);
4520 spillPair (PAIR_IY);
4524 if (AOP_TYPE (right) == AOP_LIT)
4526 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4527 /* optimize if(x < 0) or if(x >= 0) */
4532 /* No sign so it's always false */
4537 /* Just load in the top most bit */
4538 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4539 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4541 genIfxJump (ifx, "7");
4553 /* First setup h and l contaning the top most bytes XORed */
4554 bool fDidXor = FALSE;
4555 if (AOP_TYPE (left) == AOP_LIT)
4557 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4558 emit2 ("ld %s,!immedbyte", _fTmp[0],
4559 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4563 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4564 emit2 ("xor a,!immedbyte", 0x80);
4565 emit2 ("ld %s,a", _fTmp[0]);
4568 if (AOP_TYPE (right) == AOP_LIT)
4570 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4571 emit2 ("ld %s,!immedbyte", _fTmp[1],
4572 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4576 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4577 emit2 ("xor a,!immedbyte", 0x80);
4578 emit2 ("ld %s,a", _fTmp[1]);
4584 /* Do a long subtract */
4587 _moveA (aopGet (AOP (left), offset, FALSE));
4589 if (sign && size == 0)
4591 emit2 ("ld a,%s", _fTmp[0]);
4592 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4596 /* Subtract through, propagating the carry */
4597 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4605 /** Generic compare for > or <
4608 genCmp (operand * left, operand * right,
4609 operand * result, iCode * ifx, int sign)
4611 int size, offset = 0;
4612 unsigned long lit = 0L;
4614 /* if left & right are bit variables */
4615 if (AOP_TYPE (left) == AOP_CRY &&
4616 AOP_TYPE (right) == AOP_CRY)
4618 /* Cant happen on the Z80 */
4619 wassertl (0, "Tried to compare two bits");
4623 /* Do a long subtract of right from left. */
4624 size = max (AOP_SIZE (left), AOP_SIZE (right));
4626 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4628 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4629 // Pull left into DE and right into HL
4630 aopGet (AOP(left), LSB, FALSE);
4633 aopGet (AOP(right), LSB, FALSE);
4637 emit2 ("ld a,(de)");
4638 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4647 spillPair (PAIR_HL);
4651 if (AOP_TYPE (right) == AOP_LIT)
4653 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4654 /* optimize if(x < 0) or if(x >= 0) */
4659 /* No sign so it's always false */
4664 /* Just load in the top most bit */
4665 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4666 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4668 genIfxJump (ifx, "7");
4679 genIfxJump (ifx, "nc");
4690 _moveA (aopGet (AOP (left), offset, FALSE));
4691 /* Subtract through, propagating the carry */
4692 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4698 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4702 /* Shift the sign bit up into carry */
4709 /* if the result is used in the next
4710 ifx conditional branch then generate
4711 code a little differently */
4719 genIfxJump (ifx, "c");
4723 genIfxJump (ifx, "m");
4728 genIfxJump (ifx, "c");
4735 /* Shift the sign bit up into carry */
4740 /* leave the result in acc */
4744 /*-----------------------------------------------------------------*/
4745 /* genCmpGt :- greater than comparison */
4746 /*-----------------------------------------------------------------*/
4748 genCmpGt (iCode * ic, iCode * ifx)
4750 operand *left, *right, *result;
4751 sym_link *letype, *retype;
4754 left = IC_LEFT (ic);
4755 right = IC_RIGHT (ic);
4756 result = IC_RESULT (ic);
4758 letype = getSpec (operandType (left));
4759 retype = getSpec (operandType (right));
4760 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4761 /* assign the amsops */
4762 aopOp (left, ic, FALSE, FALSE);
4763 aopOp (right, ic, FALSE, FALSE);
4764 aopOp (result, ic, TRUE, FALSE);
4766 genCmp (right, left, result, ifx, sign);
4768 freeAsmop (left, NULL, ic);
4769 freeAsmop (right, NULL, ic);
4770 freeAsmop (result, NULL, ic);
4773 /*-----------------------------------------------------------------*/
4774 /* genCmpLt - less than comparisons */
4775 /*-----------------------------------------------------------------*/
4777 genCmpLt (iCode * ic, iCode * ifx)
4779 operand *left, *right, *result;
4780 sym_link *letype, *retype;
4783 left = IC_LEFT (ic);
4784 right = IC_RIGHT (ic);
4785 result = IC_RESULT (ic);
4787 letype = getSpec (operandType (left));
4788 retype = getSpec (operandType (right));
4789 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4791 /* assign the amsops */
4792 aopOp (left, ic, FALSE, FALSE);
4793 aopOp (right, ic, FALSE, FALSE);
4794 aopOp (result, ic, TRUE, FALSE);
4796 genCmp (left, right, result, ifx, sign);
4798 freeAsmop (left, NULL, ic);
4799 freeAsmop (right, NULL, ic);
4800 freeAsmop (result, NULL, ic);
4803 /*-----------------------------------------------------------------*/
4804 /* gencjneshort - compare and jump if not equal */
4805 /* returns pair that still needs to be popped */
4806 /*-----------------------------------------------------------------*/
4808 gencjneshort (operand * left, operand * right, symbol * lbl)
4810 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4812 unsigned long lit = 0L;
4814 /* Swap the left and right if it makes the computation easier */
4815 if (AOP_TYPE (left) == AOP_LIT)
4822 /* if the right side is a literal then anything goes */
4823 if (AOP_TYPE (right) == AOP_LIT)
4825 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4828 _moveA (aopGet (AOP (left), offset, FALSE));
4833 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4840 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4846 _moveA (aopGet (AOP (left), offset, FALSE));
4847 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4850 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4851 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4856 /* if the right side is in a register or
4857 pointed to by HL, IX or IY */
4858 else if (AOP_TYPE (right) == AOP_REG ||
4859 AOP_TYPE (right) == AOP_HL ||
4860 AOP_TYPE (right) == AOP_IY ||
4861 AOP_TYPE (right) == AOP_STK ||
4862 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4863 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4864 AOP_IS_PAIRPTR (right, PAIR_IY))
4868 _moveA (aopGet (AOP (left), offset, FALSE));
4869 if (AOP_TYPE (right) == AOP_LIT &&
4870 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4873 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4877 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4878 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4883 /* right is in direct space or a pointer reg, need both a & b */
4887 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4889 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4890 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4898 emit2 ("; direct compare");
4899 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4900 _moveA (aopGet (AOP (right), offset, FALSE));
4901 emit2 ("sub %s", _pairs[pair].l);
4902 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4907 return PAIR_INVALID;
4910 /*-----------------------------------------------------------------*/
4911 /* gencjne - compare and jump if not equal */
4912 /*-----------------------------------------------------------------*/
4914 gencjne (operand * left, operand * right, symbol * lbl)
4916 symbol *tlbl = newiTempLabel (NULL);
4918 PAIR_ID pop = gencjneshort (left, right, lbl);
4921 emit2 ("ld a,!one");
4922 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4923 emitLabel (lbl->key + 100);
4925 emitLabel (tlbl->key + 100);
4929 /*-----------------------------------------------------------------*/
4930 /* genCmpEq - generates code for equal to */
4931 /*-----------------------------------------------------------------*/
4933 genCmpEq (iCode * ic, iCode * ifx)
4935 operand *left, *right, *result;
4937 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4938 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4939 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4941 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4943 /* Swap operands if it makes the operation easier. ie if:
4944 1. Left is a literal.
4946 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4948 operand *t = IC_RIGHT (ic);
4949 IC_RIGHT (ic) = IC_LEFT (ic);
4953 if (ifx && !AOP_SIZE (result))
4956 /* if they are both bit variables */
4957 if (AOP_TYPE (left) == AOP_CRY &&
4958 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4960 wassertl (0, "Tried to compare two bits");
4965 tlbl = newiTempLabel (NULL);
4966 pop = gencjneshort (left, right, tlbl);
4970 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4971 emitLabel (tlbl->key + 100);
4976 /* PENDING: do this better */
4977 symbol *lbl = newiTempLabel (NULL);
4979 emit2 ("!shortjp !tlabel", lbl->key + 100);
4980 emitLabel (tlbl->key + 100);
4982 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4983 emitLabel (lbl->key + 100);
4986 /* mark the icode as generated */
4991 /* if they are both bit variables */
4992 if (AOP_TYPE (left) == AOP_CRY &&
4993 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4995 wassertl (0, "Tried to compare a bit to either a literal or another bit");
5001 gencjne (left, right, newiTempLabel (NULL));
5002 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5009 genIfxJump (ifx, "a");
5012 /* if the result is used in an arithmetic operation
5013 then put the result in place */
5014 if (AOP_TYPE (result) != AOP_CRY)
5019 /* leave the result in acc */
5023 freeAsmop (left, NULL, ic);
5024 freeAsmop (right, NULL, ic);
5025 freeAsmop (result, NULL, ic);
5028 /*-----------------------------------------------------------------*/
5029 /* ifxForOp - returns the icode containing the ifx for operand */
5030 /*-----------------------------------------------------------------*/
5032 ifxForOp (operand * op, iCode * ic)
5034 /* if true symbol then needs to be assigned */
5035 if (IS_TRUE_SYMOP (op))
5038 /* if this has register type condition and
5039 the next instruction is ifx with the same operand
5040 and live to of the operand is upto the ifx only then */
5042 ic->next->op == IFX &&
5043 IC_COND (ic->next)->key == op->key &&
5044 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5050 /*-----------------------------------------------------------------*/
5051 /* genAndOp - for && operation */
5052 /*-----------------------------------------------------------------*/
5054 genAndOp (iCode * ic)
5056 operand *left, *right, *result;
5059 /* note here that && operations that are in an if statement are
5060 taken away by backPatchLabels only those used in arthmetic
5061 operations remain */
5062 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5063 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5064 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5066 /* if both are bit variables */
5067 if (AOP_TYPE (left) == AOP_CRY &&
5068 AOP_TYPE (right) == AOP_CRY)
5070 wassertl (0, "Tried to and two bits");
5074 tlbl = newiTempLabel (NULL);
5076 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5078 emitLabel (tlbl->key + 100);
5082 freeAsmop (left, NULL, ic);
5083 freeAsmop (right, NULL, ic);
5084 freeAsmop (result, NULL, ic);
5087 /*-----------------------------------------------------------------*/
5088 /* genOrOp - for || operation */
5089 /*-----------------------------------------------------------------*/
5091 genOrOp (iCode * ic)
5093 operand *left, *right, *result;
5096 /* note here that || operations that are in an
5097 if statement are taken away by backPatchLabels
5098 only those used in arthmetic operations remain */
5099 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5100 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5101 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5103 /* if both are bit variables */
5104 if (AOP_TYPE (left) == AOP_CRY &&
5105 AOP_TYPE (right) == AOP_CRY)
5107 wassertl (0, "Tried to OR two bits");
5111 tlbl = newiTempLabel (NULL);
5113 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5115 emitLabel (tlbl->key + 100);
5119 freeAsmop (left, NULL, ic);
5120 freeAsmop (right, NULL, ic);
5121 freeAsmop (result, NULL, ic);
5124 /*-----------------------------------------------------------------*/
5125 /* isLiteralBit - test if lit == 2^n */
5126 /*-----------------------------------------------------------------*/
5128 isLiteralBit (unsigned long lit)
5130 unsigned long pw[32] =
5131 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5132 0x100L, 0x200L, 0x400L, 0x800L,
5133 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5134 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5135 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5136 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5137 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5140 for (idx = 0; idx < 32; idx++)
5146 /*-----------------------------------------------------------------*/
5147 /* jmpTrueOrFalse - */
5148 /*-----------------------------------------------------------------*/
5150 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5152 // ugly but optimized by peephole
5155 symbol *nlbl = newiTempLabel (NULL);
5156 emit2 ("jp !tlabel", nlbl->key + 100);
5157 emitLabel (tlbl->key + 100);
5158 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5159 emitLabel (nlbl->key + 100);
5163 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5164 emitLabel (tlbl->key + 100);
5169 /*-----------------------------------------------------------------*/
5170 /* genAnd - code for and */
5171 /*-----------------------------------------------------------------*/
5173 genAnd (iCode * ic, iCode * ifx)
5175 operand *left, *right, *result;
5176 int size, offset = 0;
5177 unsigned long lit = 0L;
5180 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5181 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5182 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5184 /* if left is a literal & right is not then exchange them */
5185 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5186 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5188 operand *tmp = right;
5193 /* if result = right then exchange them */
5194 if (sameRegs (AOP (result), AOP (right)))
5196 operand *tmp = right;
5201 /* if right is bit then exchange them */
5202 if (AOP_TYPE (right) == AOP_CRY &&
5203 AOP_TYPE (left) != AOP_CRY)
5205 operand *tmp = right;
5209 if (AOP_TYPE (right) == AOP_LIT)
5210 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5212 size = AOP_SIZE (result);
5214 if (AOP_TYPE (left) == AOP_CRY)
5216 wassertl (0, "Tried to perform an AND with a bit as an operand");
5220 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5221 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5222 if ((AOP_TYPE (right) == AOP_LIT) &&
5223 (AOP_TYPE (result) == AOP_CRY) &&
5224 (AOP_TYPE (left) != AOP_CRY))
5226 symbol *tlbl = newiTempLabel (NULL);
5227 int sizel = AOP_SIZE (left);
5230 /* PENDING: Test case for this. */
5235 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5237 _moveA (aopGet (AOP (left), offset, FALSE));
5238 if (bytelit != 0x0FFL)
5240 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5247 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5251 // bit = left & literal
5255 emit2 ("!tlabeldef", tlbl->key + 100);
5256 _G.lines.current->isLabel = 1;
5258 // if(left & literal)
5263 jmpTrueOrFalse (ifx, tlbl);
5271 /* if left is same as result */
5272 if (sameRegs (AOP (result), AOP (left)))
5274 for (; size--; offset++)
5276 if (AOP_TYPE (right) == AOP_LIT)
5278 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5283 aopPut (AOP (result), "!zero", offset);
5286 _moveA (aopGet (AOP (left), offset, FALSE));
5288 aopGet (AOP (right), offset, FALSE));
5289 aopPut (AOP (left), "a", offset);
5296 if (AOP_TYPE (left) == AOP_ACC)
5298 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5302 _moveA (aopGet (AOP (left), offset, FALSE));
5304 aopGet (AOP (right), offset, FALSE));
5305 aopPut (AOP (left), "a", offset);
5312 // left & result in different registers
5313 if (AOP_TYPE (result) == AOP_CRY)
5315 wassertl (0, "Tried to AND where the result is in carry");
5319 for (; (size--); offset++)
5322 // result = left & right
5323 if (AOP_TYPE (right) == AOP_LIT)
5325 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5327 aopPut (AOP (result),
5328 aopGet (AOP (left), offset, FALSE),
5332 else if (bytelit == 0)
5334 aopPut (AOP (result), "!zero", offset);
5338 // faster than result <- left, anl result,right
5339 // and better if result is SFR
5340 if (AOP_TYPE (left) == AOP_ACC)
5341 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5344 _moveA (aopGet (AOP (left), offset, FALSE));
5346 aopGet (AOP (right), offset, FALSE));
5348 aopPut (AOP (result), "a", offset);
5355 freeAsmop (left, NULL, ic);
5356 freeAsmop (right, NULL, ic);
5357 freeAsmop (result, NULL, ic);
5360 /*-----------------------------------------------------------------*/
5361 /* genOr - code for or */
5362 /*-----------------------------------------------------------------*/
5364 genOr (iCode * ic, iCode * ifx)
5366 operand *left, *right, *result;
5367 int size, offset = 0;
5368 unsigned long lit = 0L;
5371 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5372 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5373 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5375 /* if left is a literal & right is not then exchange them */
5376 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5377 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5379 operand *tmp = right;
5384 /* if result = right then exchange them */
5385 if (sameRegs (AOP (result), AOP (right)))
5387 operand *tmp = right;
5392 /* if right is bit then exchange them */
5393 if (AOP_TYPE (right) == AOP_CRY &&
5394 AOP_TYPE (left) != AOP_CRY)
5396 operand *tmp = right;
5400 if (AOP_TYPE (right) == AOP_LIT)
5401 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5403 size = AOP_SIZE (result);
5405 if (AOP_TYPE (left) == AOP_CRY)
5407 wassertl (0, "Tried to OR where left is a bit");
5411 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5412 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5413 if ((AOP_TYPE (right) == AOP_LIT) &&
5414 (AOP_TYPE (result) == AOP_CRY) &&
5415 (AOP_TYPE (left) != AOP_CRY))
5417 symbol *tlbl = newiTempLabel (NULL);
5418 int sizel = AOP_SIZE (left);
5422 wassertl (0, "Result is assigned to a bit");
5424 /* PENDING: Modeled after the AND code which is inefficient. */
5427 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5429 _moveA (aopGet (AOP (left), offset, FALSE));
5430 /* OR with any literal is the same as OR with itself. */
5432 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5438 jmpTrueOrFalse (ifx, tlbl);
5443 /* if left is same as result */
5444 if (sameRegs (AOP (result), AOP (left)))
5446 for (; size--; offset++)
5448 if (AOP_TYPE (right) == AOP_LIT)
5450 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5454 _moveA (aopGet (AOP (left), offset, FALSE));
5456 aopGet (AOP (right), offset, FALSE));
5457 aopPut (AOP (result), "a", offset);
5462 if (AOP_TYPE (left) == AOP_ACC)
5463 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5466 _moveA (aopGet (AOP (left), offset, FALSE));
5468 aopGet (AOP (right), offset, FALSE));
5469 aopPut (AOP (result), "a", offset);
5476 // left & result in different registers
5477 if (AOP_TYPE (result) == AOP_CRY)
5479 wassertl (0, "Result of OR is in a bit");
5482 for (; (size--); offset++)
5485 // result = left & right
5486 if (AOP_TYPE (right) == AOP_LIT)
5488 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5490 aopPut (AOP (result),
5491 aopGet (AOP (left), offset, FALSE),
5496 // faster than result <- left, anl result,right
5497 // and better if result is SFR
5498 if (AOP_TYPE (left) == AOP_ACC)
5499 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5502 _moveA (aopGet (AOP (left), offset, FALSE));
5504 aopGet (AOP (right), offset, FALSE));
5506 aopPut (AOP (result), "a", offset);
5507 /* PENDING: something weird is going on here. Add exception. */
5508 if (AOP_TYPE (result) == AOP_ACC)
5514 freeAsmop (left, NULL, ic);
5515 freeAsmop (right, NULL, ic);
5516 freeAsmop (result, NULL, ic);
5519 /*-----------------------------------------------------------------*/
5520 /* genXor - code for xclusive or */
5521 /*-----------------------------------------------------------------*/
5523 genXor (iCode * ic, iCode * ifx)
5525 operand *left, *right, *result;
5526 int size, offset = 0;
5527 unsigned long lit = 0L;
5529 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5530 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5531 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5533 /* if left is a literal & right is not then exchange them */
5534 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5535 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5537 operand *tmp = right;
5542 /* if result = right then exchange them */
5543 if (sameRegs (AOP (result), AOP (right)))
5545 operand *tmp = right;
5550 /* if right is bit then exchange them */
5551 if (AOP_TYPE (right) == AOP_CRY &&
5552 AOP_TYPE (left) != AOP_CRY)
5554 operand *tmp = right;
5558 if (AOP_TYPE (right) == AOP_LIT)
5559 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5561 size = AOP_SIZE (result);
5563 if (AOP_TYPE (left) == AOP_CRY)
5565 wassertl (0, "Tried to XOR a bit");
5569 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5570 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5571 if ((AOP_TYPE (right) == AOP_LIT) &&
5572 (AOP_TYPE (result) == AOP_CRY) &&
5573 (AOP_TYPE (left) != AOP_CRY))
5575 symbol *tlbl = newiTempLabel (NULL);
5576 int sizel = AOP_SIZE (left);
5580 /* PENDING: Test case for this. */
5581 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5585 _moveA (aopGet (AOP (left), offset, FALSE));
5586 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5587 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5592 jmpTrueOrFalse (ifx, tlbl);
5596 wassertl (0, "Result of XOR was destined for a bit");
5601 /* if left is same as result */
5602 if (sameRegs (AOP (result), AOP (left)))
5604 for (; size--; offset++)
5606 if (AOP_TYPE (right) == AOP_LIT)
5608 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5612 _moveA (aopGet (AOP (left), offset, FALSE));
5614 aopGet (AOP (right), offset, FALSE));
5615 aopPut (AOP (result), "a", offset);
5620 if (AOP_TYPE (left) == AOP_ACC)
5622 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5626 _moveA (aopGet (AOP (left), offset, FALSE));
5628 aopGet (AOP (right), offset, FALSE));
5629 aopPut (AOP (result), "a", offset);
5636 // left & result in different registers
5637 if (AOP_TYPE (result) == AOP_CRY)
5639 wassertl (0, "Result of XOR is in a bit");
5642 for (; (size--); offset++)
5645 // result = left & right
5646 if (AOP_TYPE (right) == AOP_LIT)
5648 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5650 aopPut (AOP (result),
5651 aopGet (AOP (left), offset, FALSE),
5656 // faster than result <- left, anl result,right
5657 // and better if result is SFR
5658 if (AOP_TYPE (left) == AOP_ACC)
5660 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5664 _moveA (aopGet (AOP (left), offset, FALSE));
5666 aopGet (AOP (right), offset, FALSE));
5668 aopPut (AOP (result), "a", offset);
5673 freeAsmop (left, NULL, ic);
5674 freeAsmop (right, NULL, ic);
5675 freeAsmop (result, NULL, ic);
5678 /*-----------------------------------------------------------------*/
5679 /* genInline - write the inline code out */
5680 /*-----------------------------------------------------------------*/
5682 genInline (iCode * ic)
5684 char *buffer, *bp, *bp1;
5685 bool inComment = FALSE;
5687 _G.lines.isInline += (!options.asmpeep);
5689 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5691 /* emit each line as a code */
5709 /* Add \n for labels, not dirs such as c:\mydir */
5710 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5728 _G.lines.isInline -= (!options.asmpeep);
5732 /*-----------------------------------------------------------------*/
5733 /* genRRC - rotate right with carry */
5734 /*-----------------------------------------------------------------*/
5741 /*-----------------------------------------------------------------*/
5742 /* genRLC - generate code for rotate left with carry */
5743 /*-----------------------------------------------------------------*/
5750 /*-----------------------------------------------------------------*/
5751 /* genGetHbit - generates code get highest order bit */
5752 /*-----------------------------------------------------------------*/
5754 genGetHbit (iCode * ic)
5756 operand *left, *result;
5757 left = IC_LEFT (ic);
5758 result = IC_RESULT (ic);
5760 aopOp (left, ic, FALSE, FALSE);
5761 aopOp (result, ic, FALSE, FALSE);
5763 /* get the highest order byte into a */
5764 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5766 if (AOP_TYPE (result) == AOP_CRY)
5774 emit2 ("and a,!one");
5779 freeAsmop (left, NULL, ic);
5780 freeAsmop (result, NULL, ic);
5784 emitRsh2 (asmop *aop, int size, int is_signed)
5790 const char *l = aopGet (aop, size, FALSE);
5793 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5803 /*-----------------------------------------------------------------*/
5804 /* shiftR2Left2Result - shift right two bytes from left to result */
5805 /*-----------------------------------------------------------------*/
5807 shiftR2Left2Result (operand * left, int offl,
5808 operand * result, int offr,
5809 int shCount, int is_signed)
5814 movLeft2Result (left, offl, result, offr, 0);
5815 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5820 /* if (AOP(result)->type == AOP_REG) { */
5822 tlbl = newiTempLabel (NULL);
5824 /* Left is already in result - so now do the shift */
5825 /* Optimizing for speed by default. */
5826 if (!optimize.codeSize || shCount <= 2)
5830 emitRsh2 (AOP (result), size, is_signed);
5835 emit2 ("ld a,!immedbyte", shCount);
5837 emitLabel (tlbl->key + 100);
5839 emitRsh2 (AOP (result), size, is_signed);
5842 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5846 /*-----------------------------------------------------------------*/
5847 /* shiftL2Left2Result - shift left two bytes from left to result */
5848 /*-----------------------------------------------------------------*/
5850 shiftL2Left2Result (operand * left, int offl,
5851 operand * result, int offr, int shCount)
5853 if (sameRegs (AOP (result), AOP (left)) &&
5854 ((offl + MSB16) == offr))
5860 /* Copy left into result */
5861 movLeft2Result (left, offl, result, offr, 0);
5862 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5868 if (getPairId (AOP (result)) == PAIR_HL)
5872 emit2 ("add hl,hl");
5879 symbol *tlbl, *tlbl1;
5882 tlbl = newiTempLabel (NULL);
5883 tlbl1 = newiTempLabel (NULL);
5885 if (AOP (result)->type == AOP_REG)
5889 for (offset = 0; offset < size; offset++)
5891 l = aopGet (AOP (result), offset, FALSE);
5895 emit2 ("sla %s", l);
5906 /* Left is already in result - so now do the shift */
5909 emit2 ("ld a,!immedbyte+1", shCount);
5910 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5911 emitLabel (tlbl->key + 100);
5916 l = aopGet (AOP (result), offset, FALSE);
5920 emit2 ("sla %s", l);
5931 emitLabel (tlbl1->key + 100);
5933 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5939 /*-----------------------------------------------------------------*/
5940 /* AccRol - rotate left accumulator by known count */
5941 /*-----------------------------------------------------------------*/
5943 AccRol (int shCount)
5945 shCount &= 0x0007; // shCount : 0..7
6022 /*-----------------------------------------------------------------*/
6023 /* AccLsh - left shift accumulator by known count */
6024 /*-----------------------------------------------------------------*/
6026 AccLsh (int shCount)
6028 static const unsigned char SLMask[] =
6030 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6039 else if (shCount == 2)
6046 /* rotate left accumulator */
6048 /* and kill the lower order bits */
6049 emit2 ("and a,!immedbyte", SLMask[shCount]);
6054 /*-----------------------------------------------------------------*/
6055 /* shiftL1Left2Result - shift left one byte from left to result */
6056 /*-----------------------------------------------------------------*/
6058 shiftL1Left2Result (operand * left, int offl,
6059 operand * result, int offr, int shCount)
6063 /* If operand and result are the same we can shift in place.
6064 However shifting in acc using add is cheaper than shifting
6065 in place using sla; when shifting by more than 2 shifting in
6066 acc is worth the additional effort for loading from/to acc. */
6067 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6070 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6074 l = aopGet (AOP (left), offl, FALSE);
6076 /* shift left accumulator */
6078 aopPut (AOP (result), "a", offr);
6082 /*-----------------------------------------------------------------*/
6083 /* genlshTwo - left shift two bytes by known amount */
6084 /*-----------------------------------------------------------------*/
6086 genlshTwo (operand * result, operand * left, int shCount)
6088 int size = AOP_SIZE (result);
6090 wassert (size == 2);
6092 /* if shCount >= 8 */
6100 movLeft2Result (left, LSB, result, MSB16, 0);
6101 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6102 aopPut (AOP (result), "!zero", LSB);
6106 movLeft2Result (left, LSB, result, MSB16, 0);
6107 aopPut (AOP (result), "!zero", 0);
6112 aopPut (AOP (result), "!zero", LSB);
6115 /* 0 <= shCount <= 7 */
6124 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6129 /*-----------------------------------------------------------------*/
6130 /* genlshOne - left shift a one byte quantity by known count */
6131 /*-----------------------------------------------------------------*/
6133 genlshOne (operand * result, operand * left, int shCount)
6135 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6138 /*-----------------------------------------------------------------*/
6139 /* genLeftShiftLiteral - left shifting by known count */
6140 /*-----------------------------------------------------------------*/
6142 genLeftShiftLiteral (operand * left,
6147 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6150 freeAsmop (right, NULL, ic);
6152 aopOp (left, ic, FALSE, FALSE);
6153 aopOp (result, ic, FALSE, FALSE);
6155 size = getSize (operandType (result));
6157 /* I suppose that the left size >= result size */
6159 if (shCount >= (size * 8))
6163 aopPut (AOP (result), "!zero", size);
6171 genlshOne (result, left, shCount);
6174 genlshTwo (result, left, shCount);
6177 wassertl (0, "Shifting of longs is currently unsupported");
6183 freeAsmop (left, NULL, ic);
6184 freeAsmop (result, NULL, ic);
6187 /*-----------------------------------------------------------------*/
6188 /* genLeftShift - generates code for left shifting */
6189 /*-----------------------------------------------------------------*/
6191 genLeftShift (iCode * ic)
6195 symbol *tlbl, *tlbl1;
6196 operand *left, *right, *result;
6198 right = IC_RIGHT (ic);
6199 left = IC_LEFT (ic);
6200 result = IC_RESULT (ic);
6202 aopOp (right, ic, FALSE, FALSE);
6204 /* if the shift count is known then do it
6205 as efficiently as possible */
6206 if (AOP_TYPE (right) == AOP_LIT)
6208 genLeftShiftLiteral (left, right, result, ic);
6212 /* shift count is unknown then we have to form a loop get the loop
6213 count in B : Note: we take only the lower order byte since
6214 shifting more that 32 bits make no sense anyway, ( the largest
6215 size of an object can be only 32 bits ) */
6216 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6218 freeAsmop (right, NULL, ic);
6219 aopOp (left, ic, FALSE, FALSE);
6220 aopOp (result, ic, FALSE, FALSE);
6222 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6225 /* now move the left to the result if they are not the
6228 if (!sameRegs (AOP (left), AOP (result)))
6231 size = AOP_SIZE (result);
6235 l = aopGet (AOP (left), offset, FALSE);
6236 aopPut (AOP (result), l, offset);
6241 tlbl = newiTempLabel (NULL);
6242 size = AOP_SIZE (result);
6244 tlbl1 = newiTempLabel (NULL);
6246 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6249 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6250 emitLabel (tlbl->key + 100);
6251 l = aopGet (AOP (result), offset, FALSE);
6255 l = aopGet (AOP (result), offset, FALSE);
6259 emit2 ("sla %s", l);
6267 emitLabel (tlbl1->key + 100);
6269 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6271 freeAsmop (left, NULL, ic);
6272 freeAsmop (result, NULL, ic);
6275 /*-----------------------------------------------------------------*/
6276 /* genrshOne - left shift two bytes by known amount != 0 */
6277 /*-----------------------------------------------------------------*/
6279 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6282 int size = AOP_SIZE (result);
6285 wassert (size == 1);
6286 wassert (shCount < 8);
6288 l = aopGet (AOP (left), 0, FALSE);
6290 if (AOP (result)->type == AOP_REG)
6292 aopPut (AOP (result), l, 0);
6293 l = aopGet (AOP (result), 0, FALSE);
6296 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6304 emit2 ("%s a", is_signed ? "sra" : "srl");
6306 aopPut (AOP (result), "a", 0);
6310 /*-----------------------------------------------------------------*/
6311 /* AccRsh - right shift accumulator by known count */
6312 /*-----------------------------------------------------------------*/
6314 AccRsh (int shCount)
6316 static const unsigned char SRMask[] =
6318 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6323 /* rotate right accumulator */
6324 AccRol (8 - shCount);
6325 /* and kill the higher order bits */
6326 emit2 ("and a,!immedbyte", SRMask[shCount]);
6330 /*-----------------------------------------------------------------*/
6331 /* shiftR1Left2Result - shift right one byte from left to result */
6332 /*-----------------------------------------------------------------*/
6334 shiftR1Left2Result (operand * left, int offl,
6335 operand * result, int offr,
6336 int shCount, int sign)
6338 _moveA (aopGet (AOP (left), offl, FALSE));
6343 emit2 ("%s a", sign ? "sra" : "srl");
6350 aopPut (AOP (result), "a", offr);
6353 /*-----------------------------------------------------------------*/
6354 /* genrshTwo - right shift two bytes by known amount */
6355 /*-----------------------------------------------------------------*/
6357 genrshTwo (operand * result, operand * left,
6358 int shCount, int sign)
6360 /* if shCount >= 8 */
6366 shiftR1Left2Result (left, MSB16, result, LSB,
6371 movLeft2Result (left, MSB16, result, LSB, sign);
6375 /* Sign extend the result */
6376 _moveA(aopGet (AOP (result), 0, FALSE));
6380 aopPut (AOP (result), ACC_NAME, MSB16);
6384 aopPut (AOP (result), "!zero", 1);
6387 /* 0 <= shCount <= 7 */
6390 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6394 /*-----------------------------------------------------------------*/
6395 /* genRightShiftLiteral - left shifting by known count */
6396 /*-----------------------------------------------------------------*/
6398 genRightShiftLiteral (operand * left,
6404 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6407 freeAsmop (right, NULL, ic);
6409 aopOp (left, ic, FALSE, FALSE);
6410 aopOp (result, ic, FALSE, FALSE);
6412 size = getSize (operandType (result));
6414 /* I suppose that the left size >= result size */
6416 if (shCount >= (size * 8)) {
6418 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6419 _moveA(aopGet (AOP (left), 0, FALSE));
6427 aopPut (AOP (result), s, size);
6434 genrshOne (result, left, shCount, sign);
6437 genrshTwo (result, left, shCount, sign);
6440 wassertl (0, "Asked to shift right a long which should be a function call");
6443 wassertl (0, "Entered default case in right shift delegate");
6446 freeAsmop (left, NULL, ic);
6447 freeAsmop (result, NULL, ic);
6450 /*-----------------------------------------------------------------*/
6451 /* genRightShift - generate code for right shifting */
6452 /*-----------------------------------------------------------------*/
6454 genRightShift (iCode * ic)
6456 operand *right, *left, *result;
6458 int size, offset, first = 1;
6462 symbol *tlbl, *tlbl1;
6464 /* if signed then we do it the hard way preserve the
6465 sign bit moving it inwards */
6466 retype = getSpec (operandType (IC_RESULT (ic)));
6468 is_signed = !SPEC_USIGN (retype);
6470 /* signed & unsigned types are treated the same : i.e. the
6471 signed is NOT propagated inwards : quoting from the
6472 ANSI - standard : "for E1 >> E2, is equivalent to division
6473 by 2**E2 if unsigned or if it has a non-negative value,
6474 otherwise the result is implementation defined ", MY definition
6475 is that the sign does not get propagated */
6477 right = IC_RIGHT (ic);
6478 left = IC_LEFT (ic);
6479 result = IC_RESULT (ic);
6481 aopOp (right, ic, FALSE, FALSE);
6483 /* if the shift count is known then do it
6484 as efficiently as possible */
6485 if (AOP_TYPE (right) == AOP_LIT)
6487 genRightShiftLiteral (left, right, result, ic, is_signed);
6491 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6493 freeAsmop (right, NULL, ic);
6495 aopOp (left, ic, FALSE, FALSE);
6496 aopOp (result, ic, FALSE, FALSE);
6498 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6501 /* now move the left to the result if they are not the
6503 if (!sameRegs (AOP (left), AOP (result)))
6506 size = AOP_SIZE (result);
6510 l = aopGet (AOP (left), offset, FALSE);
6511 aopPut (AOP (result), l, offset);
6516 tlbl = newiTempLabel (NULL);
6517 tlbl1 = newiTempLabel (NULL);
6518 size = AOP_SIZE (result);
6521 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6524 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6525 emitLabel (tlbl->key + 100);
6528 l = aopGet (AOP (result), offset--, FALSE);
6531 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6539 emitLabel (tlbl1->key + 100);
6541 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6543 freeAsmop (left, NULL, ic);
6544 freeAsmop (result, NULL, ic);
6548 /*-----------------------------------------------------------------*/
6549 /* genUnpackBits - generates code for unpacking bits */
6550 /*-----------------------------------------------------------------*/
6552 genUnpackBits (operand * result, int pair)
6554 int offset = 0; /* result byte offset */
6555 int rsize; /* result size */
6556 int rlen = 0; /* remaining bitfield length */
6557 sym_link *etype; /* bitfield type information */
6558 int blen; /* bitfield length */
6559 int bstr; /* bitfield starting bit within byte */
6561 emitDebug ("; genUnpackBits");
6563 etype = getSpec (operandType (result));
6564 rsize = getSize (operandType (result));
6565 blen = SPEC_BLEN (etype);
6566 bstr = SPEC_BSTR (etype);
6568 /* If the bitfield length is less than a byte */
6571 emit2 ("ld a,!*pair", _pairs[pair].name);
6573 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6574 if (!SPEC_USIGN (etype))
6576 /* signed bitfield */
6577 symbol *tlbl = newiTempLabel (NULL);
6579 emit2 ("bit %d,a", blen - 1);
6580 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6581 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6582 emitLabel (tlbl->key + 100);
6584 aopPut (AOP (result), "a", offset++);
6588 /* TODO: what if pair == PAIR_DE ? */
6589 if (getPairId (AOP (result)) == PAIR_HL)
6591 wassertl (rsize == 2, "HL must be of size 2");
6592 emit2 ("ld a,!*hl");
6594 emit2 ("ld h,!*hl");
6597 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6598 if (!SPEC_USIGN (etype))
6600 /* signed bitfield */
6601 symbol *tlbl = newiTempLabel (NULL);
6603 emit2 ("bit %d,a", blen - 1);
6604 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6605 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6606 emitLabel (tlbl->key + 100);
6609 spillPair (PAIR_HL);
6613 /* Bit field did not fit in a byte. Copy all
6614 but the partial byte at the end. */
6615 for (rlen=blen;rlen>=8;rlen-=8)
6617 emit2 ("ld a,!*pair", _pairs[pair].name);
6618 aopPut (AOP (result), "a", offset++);
6621 emit2 ("inc %s", _pairs[pair].name);
6622 _G.pairs[pair].offset++;
6626 /* Handle the partial byte at the end */
6629 emit2 ("ld a,!*pair", _pairs[pair].name);
6630 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6631 if (!SPEC_USIGN (etype))
6633 /* signed bitfield */
6634 symbol *tlbl = newiTempLabel (NULL);
6636 emit2 ("bit %d,a", rlen - 1);
6637 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6638 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6639 emitLabel (tlbl->key + 100);
6641 aopPut (AOP (result), "a", offset++);
6649 if (SPEC_USIGN (etype))
6653 /* signed bitfield: sign extension with 0x00 or 0xff */
6661 aopPut (AOP (result), source, offset++);
6665 /*-----------------------------------------------------------------*/
6666 /* genGenPointerGet - get value from generic pointer space */
6667 /*-----------------------------------------------------------------*/
6669 genGenPointerGet (operand * left,
6670 operand * result, iCode * ic)
6673 sym_link *retype = getSpec (operandType (result));
6679 aopOp (left, ic, FALSE, FALSE);
6680 aopOp (result, ic, FALSE, FALSE);
6682 size = AOP_SIZE (result);
6684 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6687 if (isPtrPair (AOP (left)))
6689 tsprintf (buffer, sizeof(buffer),
6690 "!*pair", getPairName (AOP (left)));
6691 aopPut (AOP (result), buffer, 0);
6695 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6696 aopPut (AOP (result), "a", 0);
6698 freeAsmop (left, NULL, ic);
6702 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6709 tsprintf (at, sizeof(at), "!*iyx", offset);
6710 aopPut (AOP (result), at, offset);
6714 freeAsmop (left, NULL, ic);
6718 /* For now we always load into IY */
6719 /* if this is remateriazable */
6720 fetchPair (pair, AOP (left));
6722 /* if bit then unpack */
6723 if (IS_BITVAR (retype))
6725 genUnpackBits (result, pair);
6726 freeAsmop (left, NULL, ic);
6730 else if (getPairId (AOP (result)) == PAIR_HL)
6732 wassertl (size == 2, "HL must be of size 2");
6733 emit2 ("ld a,!*hl");
6735 emit2 ("ld h,!*hl");
6737 spillPair (PAIR_HL);
6739 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6741 size = AOP_SIZE (result);
6746 /* PENDING: make this better */
6747 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6749 aopPut (AOP (result), "!*hl", offset++);
6753 emit2 ("ld a,!*pair", _pairs[pair].name);
6754 aopPut (AOP (result), "a", offset++);
6758 emit2 ("inc %s", _pairs[pair].name);
6759 _G.pairs[pair].offset++;
6762 /* Fixup HL back down */
6763 for (size = AOP_SIZE (result)-1; size; size--)
6765 emit2 ("dec %s", _pairs[pair].name);
6770 size = AOP_SIZE (result);
6775 /* PENDING: make this better */
6777 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6779 aopPut (AOP (result), "!*hl", offset++);
6783 emit2 ("ld a,!*pair", _pairs[pair].name);
6784 aopPut (AOP (result), "a", offset++);
6788 emit2 ("inc %s", _pairs[pair].name);
6789 _G.pairs[pair].offset++;
6794 freeAsmop (left, NULL, ic);
6797 freeAsmop (result, NULL, ic);
6800 /*-----------------------------------------------------------------*/
6801 /* genPointerGet - generate code for pointer get */
6802 /*-----------------------------------------------------------------*/
6804 genPointerGet (iCode * ic)
6806 operand *left, *result;
6807 sym_link *type, *etype;
6809 left = IC_LEFT (ic);
6810 result = IC_RESULT (ic);
6812 /* depending on the type of pointer we need to
6813 move it to the correct pointer register */
6814 type = operandType (left);
6815 etype = getSpec (type);
6817 genGenPointerGet (left, result, ic);
6821 isRegOrLit (asmop * aop)
6823 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6829 /*-----------------------------------------------------------------*/
6830 /* genPackBits - generates code for packed bit storage */
6831 /*-----------------------------------------------------------------*/
6833 genPackBits (sym_link * etype,
6838 int offset = 0; /* source byte offset */
6839 int rlen = 0; /* remaining bitfield length */
6840 int blen; /* bitfield length */
6841 int bstr; /* bitfield starting bit within byte */
6842 int litval; /* source literal value (if AOP_LIT) */
6843 unsigned char mask; /* bitmask within current byte */
6844 int extraPair; /* a tempory register */
6845 bool needPopExtra=0; /* need to restore original value of temp reg */
6847 emitDebug ("; genPackBits","");
6849 blen = SPEC_BLEN (etype);
6850 bstr = SPEC_BSTR (etype);
6852 /* If the bitfield length is less than a byte */
6855 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6856 (unsigned char) (0xFF >> (8 - bstr)));
6858 if (AOP_TYPE (right) == AOP_LIT)
6860 /* Case with a bitfield length <8 and literal source
6862 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6864 litval &= (~mask) & 0xff;
6865 emit2 ("ld a,!*pair", _pairs[pair].name);
6866 if ((mask|litval)!=0xff)
6867 emit2 ("and a,!immedbyte", mask);
6869 emit2 ("or a,!immedbyte", litval);
6870 emit2 ("ld !*pair,a", _pairs[pair].name);
6875 /* Case with a bitfield length <8 and arbitrary source
6877 _moveA (aopGet (AOP (right), 0, FALSE));
6878 /* shift and mask source value */
6880 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6882 extraPair = getFreePairId(ic);
6883 if (extraPair == PAIR_INVALID)
6885 extraPair = PAIR_BC;
6886 if (getPairId (AOP (right)) != PAIR_BC
6887 || !isLastUse (ic, right))
6893 emit2 ("ld %s,a", _pairs[extraPair].l);
6894 emit2 ("ld a,!*pair", _pairs[pair].name);
6896 emit2 ("and a,!immedbyte", mask);
6897 emit2 ("or a,%s", _pairs[extraPair].l);
6898 emit2 ("ld !*pair,a", _pairs[pair].name);
6905 /* Bit length is greater than 7 bits. In this case, copy */
6906 /* all except the partial byte at the end */
6907 for (rlen=blen;rlen>=8;rlen-=8)
6909 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6910 emit2 ("ld !*pair,a", _pairs[pair].name);
6913 emit2 ("inc %s", _pairs[pair].name);
6914 _G.pairs[pair].offset++;
6918 /* If there was a partial byte at the end */
6921 mask = (((unsigned char) -1 << rlen) & 0xff);
6923 if (AOP_TYPE (right) == AOP_LIT)
6925 /* Case with partial byte and literal source
6927 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6928 litval >>= (blen-rlen);
6929 litval &= (~mask) & 0xff;
6930 emit2 ("ld a,!*pair", _pairs[pair].name);
6931 if ((mask|litval)!=0xff)
6932 emit2 ("and a,!immedbyte", mask);
6934 emit2 ("or a,!immedbyte", litval);
6938 /* Case with partial byte and arbitrary source
6940 _moveA (aopGet (AOP (right), offset++, FALSE));
6941 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6943 extraPair = getFreePairId(ic);
6944 if (extraPair == PAIR_INVALID)
6946 extraPair = getPairId (AOP (right));
6947 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6948 extraPair = PAIR_BC;
6950 if (getPairId (AOP (right)) != PAIR_BC
6951 || !isLastUse (ic, right))
6957 emit2 ("ld %s,a", _pairs[extraPair].l);
6958 emit2 ("ld a,!*pair", _pairs[pair].name);
6960 emit2 ("and a,!immedbyte", mask);
6961 emit2 ("or a,%s", _pairs[extraPair].l);
6966 emit2 ("ld !*pair,a", _pairs[pair].name);
6971 /*-----------------------------------------------------------------*/
6972 /* genGenPointerSet - stores the value into a pointer location */
6973 /*-----------------------------------------------------------------*/
6975 genGenPointerSet (operand * right,
6976 operand * result, iCode * ic)
6979 sym_link *retype = getSpec (operandType (right));
6980 sym_link *letype = getSpec (operandType (result));
6981 PAIR_ID pairId = PAIR_HL;
6984 aopOp (result, ic, FALSE, FALSE);
6985 aopOp (right, ic, FALSE, FALSE);
6990 size = AOP_SIZE (right);
6992 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6993 emitDebug("; isBitvar = %d", isBitvar);
6995 /* Handle the exceptions first */
6996 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6999 const char *l = aopGet (AOP (right), 0, FALSE);
7000 const char *pair = getPairName (AOP (result));
7001 if (canAssignToPtr (l) && isPtr (pair))
7003 emit2 ("ld !*pair,%s", pair, l);
7008 emit2 ("ld !*pair,a", pair);
7013 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7016 const char *l = aopGet (AOP (right), 0, FALSE);
7021 if (canAssignToPtr (l))
7023 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7027 _moveA (aopGet (AOP (right), offset, FALSE));
7028 emit2 ("ld !*iyx,a", offset);
7034 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7041 const char *l = aopGet (AOP (right), offset, FALSE);
7042 if (isRegOrLit (AOP (right)) && !IS_GB)
7044 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7049 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7053 emit2 ("inc %s", _pairs[PAIR_HL].name);
7054 _G.pairs[PAIR_HL].offset++;
7059 /* Fixup HL back down */
7060 for (size = AOP_SIZE (right)-1; size; size--)
7062 emit2 ("dec %s", _pairs[PAIR_HL].name);
7067 /* if the operand is already in dptr
7068 then we do nothing else we move the value to dptr */
7069 if (AOP_TYPE (result) != AOP_STR)
7071 fetchPair (pairId, AOP (result));
7073 /* so hl now contains the address */
7074 freeAsmop (result, NULL, ic);
7076 /* if bit then unpack */
7079 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7089 const char *l = aopGet (AOP (right), offset, FALSE);
7090 if (isRegOrLit (AOP (right)) && !IS_GB)
7092 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7097 emit2 ("ld !*pair,a", _pairs[pairId].name);
7101 emit2 ("inc %s", _pairs[pairId].name);
7102 _G.pairs[pairId].offset++;
7108 freeAsmop (right, NULL, ic);
7111 /*-----------------------------------------------------------------*/
7112 /* genPointerSet - stores the value into a pointer location */
7113 /*-----------------------------------------------------------------*/
7115 genPointerSet (iCode * ic)
7117 operand *right, *result;
7118 sym_link *type, *etype;
7120 right = IC_RIGHT (ic);
7121 result = IC_RESULT (ic);
7123 /* depending on the type of pointer we need to
7124 move it to the correct pointer register */
7125 type = operandType (result);
7126 etype = getSpec (type);
7128 genGenPointerSet (right, result, ic);
7131 /*-----------------------------------------------------------------*/
7132 /* genIfx - generate code for Ifx statement */
7133 /*-----------------------------------------------------------------*/
7135 genIfx (iCode * ic, iCode * popIc)
7137 operand *cond = IC_COND (ic);
7140 aopOp (cond, ic, FALSE, TRUE);
7142 /* get the value into acc */
7143 if (AOP_TYPE (cond) != AOP_CRY)
7147 /* the result is now in the accumulator */
7148 freeAsmop (cond, NULL, ic);
7150 /* if there was something to be popped then do it */
7154 /* if the condition is a bit variable */
7155 if (isbit && IS_ITEMP (cond) &&
7157 genIfxJump (ic, SPIL_LOC (cond)->rname);
7158 else if (isbit && !IS_ITEMP (cond))
7159 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7161 genIfxJump (ic, "a");
7166 /*-----------------------------------------------------------------*/
7167 /* genAddrOf - generates code for address of */
7168 /*-----------------------------------------------------------------*/
7170 genAddrOf (iCode * ic)
7172 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7174 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7176 /* if the operand is on the stack then we
7177 need to get the stack offset of this
7184 if (sym->stack <= 0)
7186 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7190 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7192 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7196 emit2 ("ld de,!hashedstr", sym->rname);
7197 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7205 /* if it has an offset then we need to compute it */
7207 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7209 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7210 emit2 ("add hl,sp");
7214 emit2 ("ld hl,!hashedstr", sym->rname);
7216 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7218 freeAsmop (IC_RESULT (ic), NULL, ic);
7221 /*-----------------------------------------------------------------*/
7222 /* genAssign - generate code for assignment */
7223 /*-----------------------------------------------------------------*/
7225 genAssign (iCode * ic)
7227 operand *result, *right;
7229 unsigned long lit = 0L;
7231 result = IC_RESULT (ic);
7232 right = IC_RIGHT (ic);
7234 /* Dont bother assigning if they are the same */
7235 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7237 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7241 aopOp (right, ic, FALSE, FALSE);
7242 aopOp (result, ic, TRUE, FALSE);
7244 /* if they are the same registers */
7245 if (sameRegs (AOP (right), AOP (result)))
7247 emitDebug ("; (registers are the same)");
7251 /* if the result is a bit */
7252 if (AOP_TYPE (result) == AOP_CRY)
7254 wassertl (0, "Tried to assign to a bit");
7258 size = AOP_SIZE (result);
7261 if (AOP_TYPE (right) == AOP_LIT)
7263 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7266 if (isPair (AOP (result)))
7268 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7270 else if ((size > 1) &&
7271 (AOP_TYPE (result) != AOP_REG) &&
7272 (AOP_TYPE (right) == AOP_LIT) &&
7273 !IS_FLOAT (operandType (right)) &&
7276 bool fXored = FALSE;
7278 /* Work from the top down.
7279 Done this way so that we can use the cached copy of 0
7280 in A for a fast clear */
7283 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7285 if (!fXored && size > 1)
7292 aopPut (AOP (result), "a", offset);
7296 aopPut (AOP (result), "!zero", offset);
7300 aopPut (AOP (result),
7301 aopGet (AOP (right), offset, FALSE),
7306 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7308 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7309 aopPut (AOP (result), "l", LSB);
7310 aopPut (AOP (result), "h", MSB16);
7312 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7314 /* Special case. Load into a and d, then load out. */
7315 _moveA (aopGet (AOP (right), 0, FALSE));
7316 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7317 aopPut (AOP (result), "a", 0);
7318 aopPut (AOP (result), "e", 1);
7320 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7322 /* Special case - simple memcpy */
7323 aopGet (AOP (right), LSB, FALSE);
7326 aopGet (AOP (result), LSB, FALSE);
7330 emit2 ("ld a,(de)");
7331 /* Peephole will optimise this. */
7332 emit2 ("ld (hl),a");
7340 spillPair (PAIR_HL);
7346 /* PENDING: do this check better */
7347 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7349 _moveA (aopGet (AOP (right), offset, FALSE));
7350 aopPut (AOP (result), "a", offset);
7353 aopPut (AOP (result),
7354 aopGet (AOP (right), offset, FALSE),
7361 freeAsmop (right, NULL, ic);
7362 freeAsmop (result, NULL, ic);
7365 /*-----------------------------------------------------------------*/
7366 /* genJumpTab - genrates code for jump table */
7367 /*-----------------------------------------------------------------*/
7369 genJumpTab (iCode * ic)
7374 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7375 /* get the condition into accumulator */
7376 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7379 emit2 ("ld e,%s", l);
7380 emit2 ("ld d,!zero");
7381 jtab = newiTempLabel (NULL);
7383 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7384 emit2 ("add hl,de");
7385 emit2 ("add hl,de");
7386 emit2 ("add hl,de");
7387 freeAsmop (IC_JTCOND (ic), NULL, ic);
7391 emitLabel (jtab->key + 100);
7392 /* now generate the jump labels */
7393 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7394 jtab = setNextItem (IC_JTLABELS (ic)))
7395 emit2 ("jp !tlabel", jtab->key + 100);
7398 /*-----------------------------------------------------------------*/
7399 /* genCast - gen code for casting */
7400 /*-----------------------------------------------------------------*/
7402 genCast (iCode * ic)
7404 operand *result = IC_RESULT (ic);
7405 sym_link *rtype = operandType (IC_RIGHT (ic));
7406 operand *right = IC_RIGHT (ic);
7409 /* if they are equivalent then do nothing */
7410 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7413 aopOp (right, ic, FALSE, FALSE);
7414 aopOp (result, ic, FALSE, FALSE);
7416 /* if the result is a bit */
7417 if (AOP_TYPE (result) == AOP_CRY)
7419 wassertl (0, "Tried to cast to a bit");
7422 /* if they are the same size : or less */
7423 if (AOP_SIZE (result) <= AOP_SIZE (right))
7426 /* if they are in the same place */
7427 if (sameRegs (AOP (right), AOP (result)))
7430 /* if they in different places then copy */
7431 size = AOP_SIZE (result);
7435 aopPut (AOP (result),
7436 aopGet (AOP (right), offset, FALSE),
7443 /* So we now know that the size of destination is greater
7444 than the size of the source */
7445 /* we move to result for the size of source */
7446 size = AOP_SIZE (right);
7450 aopPut (AOP (result),
7451 aopGet (AOP (right), offset, FALSE),
7456 /* now depending on the sign of the destination */
7457 size = AOP_SIZE (result) - AOP_SIZE (right);
7458 /* Unsigned or not an integral type - right fill with zeros */
7459 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7462 aopPut (AOP (result), "!zero", offset++);
7466 /* we need to extend the sign :{ */
7467 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7473 aopPut (AOP (result), "a", offset++);
7477 freeAsmop (right, NULL, ic);
7478 freeAsmop (result, NULL, ic);
7481 /*-----------------------------------------------------------------*/
7482 /* genReceive - generate code for a receive iCode */
7483 /*-----------------------------------------------------------------*/
7485 genReceive (iCode * ic)
7487 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7488 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7489 IS_TRUE_SYMOP (IC_RESULT (ic))))
7499 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7500 size = AOP_SIZE(IC_RESULT(ic));
7502 for (i = 0; i < size; i++) {
7503 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7507 freeAsmop (IC_RESULT (ic), NULL, ic);
7510 /*-----------------------------------------------------------------*/
7511 /* genDummyRead - generate code for dummy read of volatiles */
7512 /*-----------------------------------------------------------------*/
7514 genDummyRead (iCode * ic)
7520 if (op && IS_SYMOP (op))
7522 aopOp (op, ic, FALSE, FALSE);
7525 size = AOP_SIZE (op);
7530 _moveA (aopGet (AOP (op), offset, FALSE));
7534 freeAsmop (op, NULL, ic);
7538 if (op && IS_SYMOP (op))
7540 aopOp (op, ic, FALSE, FALSE);
7543 size = AOP_SIZE (op);
7548 _moveA (aopGet (AOP (op), offset, FALSE));
7552 freeAsmop (op, NULL, ic);
7556 /*-----------------------------------------------------------------*/
7557 /* genCritical - generate code for start of a critical sequence */
7558 /*-----------------------------------------------------------------*/
7560 genCritical (iCode *ic)
7562 symbol *tlbl = newiTempLabel (NULL);
7568 else if (IC_RESULT (ic))
7570 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7571 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7572 //get interrupt enable flag IFF2 into P/O
7576 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7577 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7578 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7579 emit2 ("!tlabeldef", (tlbl->key + 100));
7580 _G.lines.current->isLabel = 1;
7581 freeAsmop (IC_RESULT (ic), NULL, ic);
7585 //get interrupt enable flag IFF2 into P/O
7594 /*-----------------------------------------------------------------*/
7595 /* genEndCritical - generate code for end of a critical sequence */
7596 /*-----------------------------------------------------------------*/
7598 genEndCritical (iCode *ic)
7600 symbol *tlbl = newiTempLabel (NULL);
7606 else if (IC_RIGHT (ic))
7608 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7609 _toBoolean (IC_RIGHT (ic));
7610 //don't enable interrupts if they were off before
7611 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7613 emitLabel (tlbl->key + 100);
7614 freeAsmop (IC_RIGHT (ic), NULL, ic);
7620 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7621 //don't enable interrupts as they were off before
7622 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7624 emit2 ("!tlabeldef", (tlbl->key + 100));
7625 _G.lines.current->isLabel = 1;
7631 /** Maximum number of bytes to emit per line. */
7635 /** Context for the byte output chunker. */
7638 unsigned char buffer[DBEMIT_MAX_RUN];
7643 /** Flushes a byte chunker by writing out all in the buffer and
7647 _dbFlush(DBEMITCTX *self)
7654 sprintf(line, ".db 0x%02X", self->buffer[0]);
7656 for (i = 1; i < self->pos; i++)
7658 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7665 /** Write out another byte, buffering until a decent line is
7669 _dbEmit(DBEMITCTX *self, int c)
7671 if (self->pos == DBEMIT_MAX_RUN)
7675 self->buffer[self->pos++] = c;
7678 /** Context for a simple run length encoder. */
7682 unsigned char buffer[128];
7684 /** runLen may be equivalent to pos. */
7690 RLE_CHANGE_COST = 4,
7694 /** Flush the buffer of a run length encoder by writing out the run or
7695 data that it currently contains.
7698 _rleCommit(RLECTX *self)
7704 memset(&db, 0, sizeof(db));
7706 emit2(".db %u", self->pos);
7708 for (i = 0; i < self->pos; i++)
7710 _dbEmit(&db, self->buffer[i]);
7719 Can get either a run or a block of random stuff.
7720 Only want to change state if a good run comes in or a run ends.
7721 Detecting run end is easy.
7724 Say initial state is in run, len zero, last zero. Then if you get a
7725 few zeros then something else then a short run will be output.
7726 Seems OK. While in run mode, keep counting. While in random mode,
7727 keep a count of the run. If run hits margin, output all up to run,
7728 restart, enter run mode.
7731 /** Add another byte into the run length encoder, flushing as
7732 required. The run length encoder uses the Amiga IFF style, where
7733 a block is prefixed by its run length. A positive length means
7734 the next n bytes pass straight through. A negative length means
7735 that the next byte is repeated -n times. A zero terminates the
7739 _rleAppend(RLECTX *self, unsigned c)
7743 if (c != self->last)
7745 /* The run has stopped. See if it is worthwhile writing it out
7746 as a run. Note that the random data comes in as runs of
7749 if (self->runLen > RLE_CHANGE_COST)
7751 /* Yes, worthwhile. */
7752 /* Commit whatever was in the buffer. */
7754 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7758 /* Not worthwhile. Append to the end of the random list. */
7759 for (i = 0; i < self->runLen; i++)
7761 if (self->pos >= RLE_MAX_BLOCK)
7766 self->buffer[self->pos++] = self->last;
7774 if (self->runLen >= RLE_MAX_BLOCK)
7776 /* Commit whatever was in the buffer. */
7779 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7787 _rleFlush(RLECTX *self)
7789 _rleAppend(self, -1);
7796 /** genArrayInit - Special code for initialising an array with constant
7800 genArrayInit (iCode * ic)
7804 int elementSize = 0, eIndex, i;
7805 unsigned val, lastVal;
7809 memset(&rle, 0, sizeof(rle));
7811 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7813 _saveRegsForCall(ic, 0);
7815 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7816 emit2 ("call __initrleblock");
7818 type = operandType(IC_LEFT(ic));
7820 if (type && type->next)
7822 if (IS_SPEC(type->next) || IS_PTR(type->next))
7824 elementSize = getSize(type->next);
7826 else if (IS_ARRAY(type->next) && type->next->next)
7828 elementSize = getSize(type->next->next);
7832 printTypeChainRaw (type, NULL);
7833 wassertl (0, "Can't determine element size in genArrayInit.");
7838 wassertl (0, "Can't determine element size in genArrayInit.");
7841 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7843 iLoop = IC_ARRAYILIST(ic);
7844 lastVal = (unsigned)-1;
7846 /* Feed all the bytes into the run length encoder which will handle
7848 This works well for mixed char data, and for random int and long
7855 for (i = 0; i < ix; i++)
7857 for (eIndex = 0; eIndex < elementSize; eIndex++)
7859 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7860 _rleAppend(&rle, val);
7864 iLoop = iLoop->next;
7868 /* Mark the end of the run. */
7871 _restoreRegsAfterCall();
7875 freeAsmop (IC_LEFT(ic), NULL, ic);
7879 _swap (PAIR_ID one, PAIR_ID two)
7881 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7887 emit2 ("ld a,%s", _pairs[one].l);
7888 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7889 emit2 ("ld %s,a", _pairs[two].l);
7890 emit2 ("ld a,%s", _pairs[one].h);
7891 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7892 emit2 ("ld %s,a", _pairs[two].h);
7896 /* The problem is that we may have all three pairs used and they may
7897 be needed in a different order.
7902 hl = hl => unity, fine
7906 hl = hl hl = hl, swap de <=> bc
7914 hl = bc de = de, swap bc <=> hl
7922 hl = de bc = bc, swap hl <=> de
7927 * Any pair = pair are done last
7928 * Any pair = iTemp are done last
7929 * Any swaps can be done any time
7937 So how do we detect the cases?
7938 How about a 3x3 matrix?
7942 x x x x (Fourth for iTemp/other)
7944 First determin which mode to use by counting the number of unity and
7947 Two - Assign the pair first, then the rest
7948 One - Swap the two, then the rest
7952 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7954 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7956 PAIR_BC, PAIR_HL, PAIR_DE
7958 int i, j, nunity = 0;
7959 memset (ids, PAIR_INVALID, sizeof (ids));
7962 wassert (nparams == 3);
7964 /* First save everything that needs to be saved. */
7965 _saveRegsForCall (ic, 0);
7967 /* Loading HL first means that DE is always fine. */
7968 for (i = 0; i < nparams; i++)
7970 aopOp (pparams[i], ic, FALSE, FALSE);
7971 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7974 /* Count the number of unity or iTemp assigns. */
7975 for (i = 0; i < 3; i++)
7977 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7985 /* Any order, fall through. */
7987 else if (nunity == 2)
7989 /* One is assigned. Pull it out and assign. */
7990 for (i = 0; i < 3; i++)
7992 for (j = 0; j < NUM_PAIRS; j++)
7994 if (ids[dest[i]][j] == TRUE)
7996 /* Found it. See if it's the right one. */
7997 if (j == PAIR_INVALID || j == dest[i])
8003 fetchPair(dest[i], AOP (pparams[i]));
8010 else if (nunity == 1)
8012 /* Find the pairs to swap. */
8013 for (i = 0; i < 3; i++)
8015 for (j = 0; j < NUM_PAIRS; j++)
8017 if (ids[dest[i]][j] == TRUE)
8019 if (j == PAIR_INVALID || j == dest[i])
8034 int next = getPairId (AOP (pparams[0]));
8035 emit2 ("push %s", _pairs[next].name);
8037 if (next == dest[1])
8039 fetchPair (dest[1], AOP (pparams[1]));
8040 fetchPair (dest[2], AOP (pparams[2]));
8044 fetchPair (dest[2], AOP (pparams[2]));
8045 fetchPair (dest[1], AOP (pparams[1]));
8047 emit2 ("pop %s", _pairs[dest[0]].name);
8050 /* Finally pull out all of the iTemps */
8051 for (i = 0; i < 3; i++)
8053 if (ids[dest[i]][PAIR_INVALID] == 1)
8055 fetchPair (dest[i], AOP (pparams[i]));
8061 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8067 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8071 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8073 setupForBuiltin3 (ic, nParams, pparams);
8075 label = newiTempLabel(NULL);
8077 emitLabel (label->key);
8078 emit2 ("ld a,(hl)");
8081 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8083 freeAsmop (from, NULL, ic->next);
8084 freeAsmop (to, NULL, ic);
8088 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8090 operand *from, *to, *count;
8093 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8098 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8100 setupForBuiltin3 (ic, nParams, pparams);
8104 freeAsmop (count, NULL, ic->next->next);
8105 freeAsmop (from, NULL, ic);
8107 _restoreRegsAfterCall();
8109 /* if we need assign a result value */
8110 if ((IS_ITEMP (IC_RESULT (ic)) &&
8111 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8112 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8113 IS_TRUE_SYMOP (IC_RESULT (ic)))
8115 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8116 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8117 freeAsmop (IC_RESULT (ic), NULL, ic);
8120 freeAsmop (to, NULL, ic->next);
8123 /*-----------------------------------------------------------------*/
8124 /* genBuiltIn - calls the appropriate function to generating code */
8125 /* for a built in function */
8126 /*-----------------------------------------------------------------*/
8127 static void genBuiltIn (iCode *ic)
8129 operand *bi_parms[MAX_BUILTIN_ARGS];
8134 /* get all the arguments for a built in function */
8135 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8137 /* which function is it */
8138 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8140 if (strcmp(bif->name,"__builtin_strcpy")==0)
8142 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8144 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8146 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8150 wassertl (0, "Unknown builtin function encountered");
8154 /*-----------------------------------------------------------------*/
8155 /* genZ80Code - generate code for Z80 based controllers */
8156 /*-----------------------------------------------------------------*/
8158 genZ80Code (iCode * lic)
8166 _fReturn = _gbz80_return;
8167 _fTmp = _gbz80_return;
8171 _fReturn = _z80_return;
8172 _fTmp = _z80_return;
8175 _G.lines.head = _G.lines.current = NULL;
8177 /* if debug information required */
8178 if (options.debug && currFunc)
8180 debugFile->writeFunction (currFunc, lic);
8183 for (ic = lic; ic; ic = ic->next)
8185 _G.current_iCode = ic;
8187 if (ic->lineno && cln != ic->lineno)
8191 debugFile->writeCLine (ic);
8193 if (!options.noCcodeInAsm)
8195 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8196 printCLine(ic->filename, ic->lineno));
8200 if (options.iCodeInAsm)
8202 const char *iLine = printILine(ic);
8203 emit2 (";ic:%d: %s", ic->key, iLine);
8206 /* if the result is marked as
8207 spilt and rematerializable or code for
8208 this has already been generated then
8210 if (resultRemat (ic) || ic->generated)
8213 /* depending on the operation */
8217 emitDebug ("; genNot");
8222 emitDebug ("; genCpl");
8227 emitDebug ("; genUminus");
8232 emitDebug ("; genIpush");
8237 /* IPOP happens only when trying to restore a
8238 spilt live range, if there is an ifx statement
8239 following this pop then the if statement might
8240 be using some of the registers being popped which
8241 would destroy the contents of the register so
8242 we need to check for this condition and handle it */
8244 ic->next->op == IFX &&
8245 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8247 emitDebug ("; genIfx");
8248 genIfx (ic->next, ic);
8252 emitDebug ("; genIpop");
8258 emitDebug ("; genCall");
8263 emitDebug ("; genPcall");
8268 emitDebug ("; genFunction");
8273 emitDebug ("; genEndFunction");
8274 genEndFunction (ic);
8278 emitDebug ("; genRet");
8283 emitDebug ("; genLabel");
8288 emitDebug ("; genGoto");
8293 emitDebug ("; genPlus");
8298 emitDebug ("; genMinus");
8303 emitDebug ("; genMult");
8308 emitDebug ("; genDiv");
8313 emitDebug ("; genMod");
8318 emitDebug ("; genCmpGt");
8319 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8323 emitDebug ("; genCmpLt");
8324 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8331 /* note these two are xlated by algebraic equivalence
8332 during parsing SDCC.y */
8333 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8334 "got '>=' or '<=' shouldn't have come here");
8338 emitDebug ("; genCmpEq");
8339 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8343 emitDebug ("; genAndOp");
8348 emitDebug ("; genOrOp");
8353 emitDebug ("; genXor");
8354 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8358 emitDebug ("; genOr");
8359 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8363 emitDebug ("; genAnd");
8364 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8368 emitDebug ("; genInline");
8373 emitDebug ("; genRRC");
8378 emitDebug ("; genRLC");
8383 emitDebug ("; genGetHBIT");
8388 emitDebug ("; genLeftShift");
8393 emitDebug ("; genRightShift");
8397 case GET_VALUE_AT_ADDRESS:
8398 emitDebug ("; genPointerGet");
8404 if (POINTER_SET (ic))
8406 emitDebug ("; genAssign (pointer)");
8411 emitDebug ("; genAssign");
8417 emitDebug ("; genIfx");
8422 emitDebug ("; genAddrOf");
8427 emitDebug ("; genJumpTab");
8432 emitDebug ("; genCast");
8437 emitDebug ("; genReceive");
8442 if (ic->builtinSEND)
8444 emitDebug ("; genBuiltIn");
8449 emitDebug ("; addSet");
8450 addSet (&_G.sendSet, ic);
8455 emitDebug ("; genArrayInit");
8459 case DUMMY_READ_VOLATILE:
8460 emitDebug ("; genDummyRead");
8465 emitDebug ("; genCritical");
8470 emitDebug ("; genEndCritical");
8471 genEndCritical (ic);
8480 /* now we are ready to call the
8481 peep hole optimizer */
8482 if (!options.nopeep)
8483 peepHole (&_G.lines.head);
8485 /* This is unfortunate */
8486 /* now do the actual printing */
8488 struct dbuf_s *buf = codeOutBuf;
8489 if (isInHome () && codeOutBuf == &code->oBuf)
8490 codeOutBuf = &home->oBuf;
8491 printLine (_G.lines.head, codeOutBuf);
8492 if (_G.flushStatics)
8495 _G.flushStatics = 0;
8500 freeTrace(&_G.lines.trace);
8501 freeTrace(&_G.trace.aops);
8507 _isPairUsed (iCode * ic, PAIR_ID pairId)
8513 if (bitVectBitValue (ic->rMask, D_IDX))
8515 if (bitVectBitValue (ic->rMask, E_IDX))
8525 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8528 value *val = aop->aopu.aop_lit;
8530 wassert (aop->type == AOP_LIT);
8531 wassert (!IS_FLOAT (val->type));
8533 v = ulFromVal (val);
8541 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8542 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));