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;
4234 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4236 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4247 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4252 /* Fully unroled version of mul.s. Not the most efficient.
4254 for (count = 0; count < 16; count++)
4256 if (count != 0 && active)
4258 emit2 ("add hl,hl");
4262 if (active == FALSE)
4270 emit2 ("add hl,de");
4279 if (IS_Z80 && _G.stack.pushedDE)
4282 _G.stack.pushedDE = FALSE;
4286 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4288 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4290 freeAsmop (IC_LEFT (ic), NULL, ic);
4291 freeAsmop (IC_RIGHT (ic), NULL, ic);
4292 freeAsmop (IC_RESULT (ic), NULL, ic);
4295 /*-----------------------------------------------------------------*/
4296 /* genDiv - generates code for division */
4297 /*-----------------------------------------------------------------*/
4301 /* Shouldn't occur - all done through function calls */
4302 wassertl (0, "Division is handled through support function calls");
4305 /*-----------------------------------------------------------------*/
4306 /* genMod - generates code for division */
4307 /*-----------------------------------------------------------------*/
4311 /* Shouldn't occur - all done through function calls */
4315 /*-----------------------------------------------------------------*/
4316 /* genIfxJump :- will create a jump depending on the ifx */
4317 /*-----------------------------------------------------------------*/
4319 genIfxJump (iCode * ic, char *jval)
4324 /* if true label then we jump if condition
4328 jlbl = IC_TRUE (ic);
4329 if (!strcmp (jval, "a"))
4333 else if (!strcmp (jval, "c"))
4337 else if (!strcmp (jval, "nc"))
4341 else if (!strcmp (jval, "m"))
4345 else if (!strcmp (jval, "p"))
4351 /* The buffer contains the bit on A that we should test */
4357 /* false label is present */
4358 jlbl = IC_FALSE (ic);
4359 if (!strcmp (jval, "a"))
4363 else if (!strcmp (jval, "c"))
4367 else if (!strcmp (jval, "nc"))
4371 else if (!strcmp (jval, "m"))
4375 else if (!strcmp (jval, "p"))
4381 /* The buffer contains the bit on A that we should test */
4385 /* Z80 can do a conditional long jump */
4386 if (!strcmp (jval, "a"))
4390 else if (!strcmp (jval, "c"))
4393 else if (!strcmp (jval, "nc"))
4396 else if (!strcmp (jval, "m"))
4399 else if (!strcmp (jval, "p"))
4404 emit2 ("bit %s,a", jval);
4406 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4408 /* mark the icode as generated */
4414 _getPairIdName (PAIR_ID id)
4416 return _pairs[id].name;
4421 /* if unsigned char cmp with lit, just compare */
4423 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4425 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4428 emit2 ("xor a,!immedbyte", 0x80);
4429 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4432 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4434 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4436 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4437 // Pull left into DE and right into HL
4438 aopGet (AOP(left), LSB, FALSE);
4441 aopGet (AOP(right), LSB, FALSE);
4445 if (size == 0 && sign)
4447 // Highest byte when signed needs the bits flipped
4450 emit2 ("ld a,(de)");
4451 emit2 ("xor !immedbyte", 0x80);
4453 emit2 ("ld a,(hl)");
4454 emit2 ("xor !immedbyte", 0x80);
4458 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4462 emit2 ("ld a,(de)");
4463 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4473 spillPair (PAIR_HL);
4475 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4477 setupPair (PAIR_HL, AOP (left), 0);
4478 aopGet (AOP(right), LSB, FALSE);
4482 if (size == 0 && sign)
4484 // Highest byte when signed needs the bits flipped
4487 emit2 ("ld a,(hl)");
4488 emit2 ("xor !immedbyte", 0x80);
4490 emit2 ("ld a,%d(iy)", offset);
4491 emit2 ("xor !immedbyte", 0x80);
4495 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4499 emit2 ("ld a,(hl)");
4500 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4509 spillPair (PAIR_HL);
4510 spillPair (PAIR_IY);
4514 if (AOP_TYPE (right) == AOP_LIT)
4516 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4517 /* optimize if(x < 0) or if(x >= 0) */
4522 /* No sign so it's always false */
4527 /* Just load in the top most bit */
4528 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4529 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4531 genIfxJump (ifx, "7");
4543 /* First setup h and l contaning the top most bytes XORed */
4544 bool fDidXor = FALSE;
4545 if (AOP_TYPE (left) == AOP_LIT)
4547 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4548 emit2 ("ld %s,!immedbyte", _fTmp[0],
4549 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4553 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4554 emit2 ("xor a,!immedbyte", 0x80);
4555 emit2 ("ld %s,a", _fTmp[0]);
4558 if (AOP_TYPE (right) == AOP_LIT)
4560 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4561 emit2 ("ld %s,!immedbyte", _fTmp[1],
4562 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4566 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4567 emit2 ("xor a,!immedbyte", 0x80);
4568 emit2 ("ld %s,a", _fTmp[1]);
4574 /* Do a long subtract */
4577 _moveA (aopGet (AOP (left), offset, FALSE));
4579 if (sign && size == 0)
4581 emit2 ("ld a,%s", _fTmp[0]);
4582 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4586 /* Subtract through, propagating the carry */
4587 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4595 /** Generic compare for > or <
4598 genCmp (operand * left, operand * right,
4599 operand * result, iCode * ifx, int sign)
4601 int size, offset = 0;
4602 unsigned long lit = 0L;
4604 /* if left & right are bit variables */
4605 if (AOP_TYPE (left) == AOP_CRY &&
4606 AOP_TYPE (right) == AOP_CRY)
4608 /* Cant happen on the Z80 */
4609 wassertl (0, "Tried to compare two bits");
4613 /* Do a long subtract of right from left. */
4614 size = max (AOP_SIZE (left), AOP_SIZE (right));
4616 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4618 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4619 // Pull left into DE and right into HL
4620 aopGet (AOP(left), LSB, FALSE);
4623 aopGet (AOP(right), LSB, FALSE);
4627 emit2 ("ld a,(de)");
4628 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4637 spillPair (PAIR_HL);
4641 if (AOP_TYPE (right) == AOP_LIT)
4643 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4644 /* optimize if(x < 0) or if(x >= 0) */
4649 /* No sign so it's always false */
4654 /* Just load in the top most bit */
4655 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4656 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4658 genIfxJump (ifx, "7");
4669 genIfxJump (ifx, "nc");
4680 _moveA (aopGet (AOP (left), offset, FALSE));
4681 /* Subtract through, propagating the carry */
4682 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4688 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4692 /* Shift the sign bit up into carry */
4699 /* if the result is used in the next
4700 ifx conditional branch then generate
4701 code a little differently */
4709 genIfxJump (ifx, "c");
4713 genIfxJump (ifx, "m");
4718 genIfxJump (ifx, "c");
4725 /* Shift the sign bit up into carry */
4730 /* leave the result in acc */
4734 /*-----------------------------------------------------------------*/
4735 /* genCmpGt :- greater than comparison */
4736 /*-----------------------------------------------------------------*/
4738 genCmpGt (iCode * ic, iCode * ifx)
4740 operand *left, *right, *result;
4741 sym_link *letype, *retype;
4744 left = IC_LEFT (ic);
4745 right = IC_RIGHT (ic);
4746 result = IC_RESULT (ic);
4748 letype = getSpec (operandType (left));
4749 retype = getSpec (operandType (right));
4750 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4751 /* assign the amsops */
4752 aopOp (left, ic, FALSE, FALSE);
4753 aopOp (right, ic, FALSE, FALSE);
4754 aopOp (result, ic, TRUE, FALSE);
4756 genCmp (right, left, result, ifx, sign);
4758 freeAsmop (left, NULL, ic);
4759 freeAsmop (right, NULL, ic);
4760 freeAsmop (result, NULL, ic);
4763 /*-----------------------------------------------------------------*/
4764 /* genCmpLt - less than comparisons */
4765 /*-----------------------------------------------------------------*/
4767 genCmpLt (iCode * ic, iCode * ifx)
4769 operand *left, *right, *result;
4770 sym_link *letype, *retype;
4773 left = IC_LEFT (ic);
4774 right = IC_RIGHT (ic);
4775 result = IC_RESULT (ic);
4777 letype = getSpec (operandType (left));
4778 retype = getSpec (operandType (right));
4779 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4781 /* assign the amsops */
4782 aopOp (left, ic, FALSE, FALSE);
4783 aopOp (right, ic, FALSE, FALSE);
4784 aopOp (result, ic, TRUE, FALSE);
4786 genCmp (left, right, result, ifx, sign);
4788 freeAsmop (left, NULL, ic);
4789 freeAsmop (right, NULL, ic);
4790 freeAsmop (result, NULL, ic);
4793 /*-----------------------------------------------------------------*/
4794 /* gencjneshort - compare and jump if not equal */
4795 /* returns pair that still needs to be popped */
4796 /*-----------------------------------------------------------------*/
4798 gencjneshort (operand * left, operand * right, symbol * lbl)
4800 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4802 unsigned long lit = 0L;
4804 /* Swap the left and right if it makes the computation easier */
4805 if (AOP_TYPE (left) == AOP_LIT)
4812 /* if the right side is a literal then anything goes */
4813 if (AOP_TYPE (right) == AOP_LIT)
4815 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4818 _moveA (aopGet (AOP (left), offset, FALSE));
4823 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4830 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4836 _moveA (aopGet (AOP (left), offset, FALSE));
4837 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4840 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4841 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4846 /* if the right side is in a register or
4847 pointed to by HL, IX or IY */
4848 else if (AOP_TYPE (right) == AOP_REG ||
4849 AOP_TYPE (right) == AOP_HL ||
4850 AOP_TYPE (right) == AOP_IY ||
4851 AOP_TYPE (right) == AOP_STK ||
4852 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4853 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4854 AOP_IS_PAIRPTR (right, PAIR_IY))
4858 _moveA (aopGet (AOP (left), offset, FALSE));
4859 if (AOP_TYPE (right) == AOP_LIT &&
4860 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4863 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4867 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4868 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4873 /* right is in direct space or a pointer reg, need both a & b */
4877 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4879 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4880 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4888 emit2 ("; direct compare");
4889 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4890 _moveA (aopGet (AOP (right), offset, FALSE));
4891 emit2 ("sub %s", _pairs[pair].l);
4892 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4897 return PAIR_INVALID;
4900 /*-----------------------------------------------------------------*/
4901 /* gencjne - compare and jump if not equal */
4902 /*-----------------------------------------------------------------*/
4904 gencjne (operand * left, operand * right, symbol * lbl)
4906 symbol *tlbl = newiTempLabel (NULL);
4908 PAIR_ID pop = gencjneshort (left, right, lbl);
4911 emit2 ("ld a,!one");
4912 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4913 emitLabel (lbl->key + 100);
4915 emitLabel (tlbl->key + 100);
4919 /*-----------------------------------------------------------------*/
4920 /* genCmpEq - generates code for equal to */
4921 /*-----------------------------------------------------------------*/
4923 genCmpEq (iCode * ic, iCode * ifx)
4925 operand *left, *right, *result;
4927 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4928 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4929 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4931 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4933 /* Swap operands if it makes the operation easier. ie if:
4934 1. Left is a literal.
4936 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4938 operand *t = IC_RIGHT (ic);
4939 IC_RIGHT (ic) = IC_LEFT (ic);
4943 if (ifx && !AOP_SIZE (result))
4946 /* if they are both bit variables */
4947 if (AOP_TYPE (left) == AOP_CRY &&
4948 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4950 wassertl (0, "Tried to compare two bits");
4955 tlbl = newiTempLabel (NULL);
4956 pop = gencjneshort (left, right, tlbl);
4960 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4961 emitLabel (tlbl->key + 100);
4966 /* PENDING: do this better */
4967 symbol *lbl = newiTempLabel (NULL);
4969 emit2 ("!shortjp !tlabel", lbl->key + 100);
4970 emitLabel (tlbl->key + 100);
4972 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4973 emitLabel (lbl->key + 100);
4976 /* mark the icode as generated */
4981 /* if they are both bit variables */
4982 if (AOP_TYPE (left) == AOP_CRY &&
4983 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4985 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4991 gencjne (left, right, newiTempLabel (NULL));
4992 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4999 genIfxJump (ifx, "a");
5002 /* if the result is used in an arithmetic operation
5003 then put the result in place */
5004 if (AOP_TYPE (result) != AOP_CRY)
5009 /* leave the result in acc */
5013 freeAsmop (left, NULL, ic);
5014 freeAsmop (right, NULL, ic);
5015 freeAsmop (result, NULL, ic);
5018 /*-----------------------------------------------------------------*/
5019 /* ifxForOp - returns the icode containing the ifx for operand */
5020 /*-----------------------------------------------------------------*/
5022 ifxForOp (operand * op, iCode * ic)
5024 /* if true symbol then needs to be assigned */
5025 if (IS_TRUE_SYMOP (op))
5028 /* if this has register type condition and
5029 the next instruction is ifx with the same operand
5030 and live to of the operand is upto the ifx only then */
5032 ic->next->op == IFX &&
5033 IC_COND (ic->next)->key == op->key &&
5034 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5040 /*-----------------------------------------------------------------*/
5041 /* genAndOp - for && operation */
5042 /*-----------------------------------------------------------------*/
5044 genAndOp (iCode * ic)
5046 operand *left, *right, *result;
5049 /* note here that && operations that are in an if statement are
5050 taken away by backPatchLabels only those used in arthmetic
5051 operations remain */
5052 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5053 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5054 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5056 /* if both are bit variables */
5057 if (AOP_TYPE (left) == AOP_CRY &&
5058 AOP_TYPE (right) == AOP_CRY)
5060 wassertl (0, "Tried to and two bits");
5064 tlbl = newiTempLabel (NULL);
5066 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5068 emitLabel (tlbl->key + 100);
5072 freeAsmop (left, NULL, ic);
5073 freeAsmop (right, NULL, ic);
5074 freeAsmop (result, NULL, ic);
5077 /*-----------------------------------------------------------------*/
5078 /* genOrOp - for || operation */
5079 /*-----------------------------------------------------------------*/
5081 genOrOp (iCode * ic)
5083 operand *left, *right, *result;
5086 /* note here that || operations that are in an
5087 if statement are taken away by backPatchLabels
5088 only those used in arthmetic operations remain */
5089 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5090 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5091 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5093 /* if both are bit variables */
5094 if (AOP_TYPE (left) == AOP_CRY &&
5095 AOP_TYPE (right) == AOP_CRY)
5097 wassertl (0, "Tried to OR two bits");
5101 tlbl = newiTempLabel (NULL);
5103 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5105 emitLabel (tlbl->key + 100);
5109 freeAsmop (left, NULL, ic);
5110 freeAsmop (right, NULL, ic);
5111 freeAsmop (result, NULL, ic);
5114 /*-----------------------------------------------------------------*/
5115 /* isLiteralBit - test if lit == 2^n */
5116 /*-----------------------------------------------------------------*/
5118 isLiteralBit (unsigned long lit)
5120 unsigned long pw[32] =
5121 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5122 0x100L, 0x200L, 0x400L, 0x800L,
5123 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5124 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5125 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5126 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5127 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5130 for (idx = 0; idx < 32; idx++)
5136 /*-----------------------------------------------------------------*/
5137 /* jmpTrueOrFalse - */
5138 /*-----------------------------------------------------------------*/
5140 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5142 // ugly but optimized by peephole
5145 symbol *nlbl = newiTempLabel (NULL);
5146 emit2 ("jp !tlabel", nlbl->key + 100);
5147 emitLabel (tlbl->key + 100);
5148 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5149 emitLabel (nlbl->key + 100);
5153 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5154 emitLabel (tlbl->key + 100);
5159 /*-----------------------------------------------------------------*/
5160 /* genAnd - code for and */
5161 /*-----------------------------------------------------------------*/
5163 genAnd (iCode * ic, iCode * ifx)
5165 operand *left, *right, *result;
5166 int size, offset = 0;
5167 unsigned long lit = 0L;
5170 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5171 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5172 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5174 /* if left is a literal & right is not then exchange them */
5175 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5176 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5178 operand *tmp = right;
5183 /* if result = right then exchange them */
5184 if (sameRegs (AOP (result), AOP (right)))
5186 operand *tmp = right;
5191 /* if right is bit then exchange them */
5192 if (AOP_TYPE (right) == AOP_CRY &&
5193 AOP_TYPE (left) != AOP_CRY)
5195 operand *tmp = right;
5199 if (AOP_TYPE (right) == AOP_LIT)
5200 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5202 size = AOP_SIZE (result);
5204 if (AOP_TYPE (left) == AOP_CRY)
5206 wassertl (0, "Tried to perform an AND with a bit as an operand");
5210 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5211 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5212 if ((AOP_TYPE (right) == AOP_LIT) &&
5213 (AOP_TYPE (result) == AOP_CRY) &&
5214 (AOP_TYPE (left) != AOP_CRY))
5216 symbol *tlbl = newiTempLabel (NULL);
5217 int sizel = AOP_SIZE (left);
5220 /* PENDING: Test case for this. */
5225 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5227 _moveA (aopGet (AOP (left), offset, FALSE));
5228 if (bytelit != 0x0FFL)
5230 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5237 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5241 // bit = left & literal
5245 emit2 ("!tlabeldef", tlbl->key + 100);
5246 _G.lines.current->isLabel = 1;
5248 // if(left & literal)
5253 jmpTrueOrFalse (ifx, tlbl);
5261 /* if left is same as result */
5262 if (sameRegs (AOP (result), AOP (left)))
5264 for (; size--; offset++)
5266 if (AOP_TYPE (right) == AOP_LIT)
5268 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5273 aopPut (AOP (result), "!zero", offset);
5276 _moveA (aopGet (AOP (left), offset, FALSE));
5278 aopGet (AOP (right), offset, FALSE));
5279 aopPut (AOP (left), "a", offset);
5286 if (AOP_TYPE (left) == AOP_ACC)
5288 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5292 _moveA (aopGet (AOP (left), offset, FALSE));
5294 aopGet (AOP (right), offset, FALSE));
5295 aopPut (AOP (left), "a", offset);
5302 // left & result in different registers
5303 if (AOP_TYPE (result) == AOP_CRY)
5305 wassertl (0, "Tried to AND where the result is in carry");
5309 for (; (size--); offset++)
5312 // result = left & right
5313 if (AOP_TYPE (right) == AOP_LIT)
5315 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5317 aopPut (AOP (result),
5318 aopGet (AOP (left), offset, FALSE),
5322 else if (bytelit == 0)
5324 aopPut (AOP (result), "!zero", offset);
5328 // faster than result <- left, anl result,right
5329 // and better if result is SFR
5330 if (AOP_TYPE (left) == AOP_ACC)
5331 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5334 _moveA (aopGet (AOP (left), offset, FALSE));
5336 aopGet (AOP (right), offset, FALSE));
5338 aopPut (AOP (result), "a", offset);
5345 freeAsmop (left, NULL, ic);
5346 freeAsmop (right, NULL, ic);
5347 freeAsmop (result, NULL, ic);
5350 /*-----------------------------------------------------------------*/
5351 /* genOr - code for or */
5352 /*-----------------------------------------------------------------*/
5354 genOr (iCode * ic, iCode * ifx)
5356 operand *left, *right, *result;
5357 int size, offset = 0;
5358 unsigned long lit = 0L;
5361 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5362 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5363 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5365 /* if left is a literal & right is not then exchange them */
5366 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5367 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5369 operand *tmp = right;
5374 /* if result = right then exchange them */
5375 if (sameRegs (AOP (result), AOP (right)))
5377 operand *tmp = right;
5382 /* if right is bit then exchange them */
5383 if (AOP_TYPE (right) == AOP_CRY &&
5384 AOP_TYPE (left) != AOP_CRY)
5386 operand *tmp = right;
5390 if (AOP_TYPE (right) == AOP_LIT)
5391 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5393 size = AOP_SIZE (result);
5395 if (AOP_TYPE (left) == AOP_CRY)
5397 wassertl (0, "Tried to OR where left is a bit");
5401 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5402 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5403 if ((AOP_TYPE (right) == AOP_LIT) &&
5404 (AOP_TYPE (result) == AOP_CRY) &&
5405 (AOP_TYPE (left) != AOP_CRY))
5407 symbol *tlbl = newiTempLabel (NULL);
5408 int sizel = AOP_SIZE (left);
5412 wassertl (0, "Result is assigned to a bit");
5414 /* PENDING: Modeled after the AND code which is inefficient. */
5417 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5419 _moveA (aopGet (AOP (left), offset, FALSE));
5420 /* OR with any literal is the same as OR with itself. */
5422 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5428 jmpTrueOrFalse (ifx, tlbl);
5433 /* if left is same as result */
5434 if (sameRegs (AOP (result), AOP (left)))
5436 for (; size--; offset++)
5438 if (AOP_TYPE (right) == AOP_LIT)
5440 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5444 _moveA (aopGet (AOP (left), offset, FALSE));
5446 aopGet (AOP (right), offset, FALSE));
5447 aopPut (AOP (result), "a", offset);
5452 if (AOP_TYPE (left) == AOP_ACC)
5453 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5456 _moveA (aopGet (AOP (left), offset, FALSE));
5458 aopGet (AOP (right), offset, FALSE));
5459 aopPut (AOP (result), "a", offset);
5466 // left & result in different registers
5467 if (AOP_TYPE (result) == AOP_CRY)
5469 wassertl (0, "Result of OR is in a bit");
5472 for (; (size--); offset++)
5475 // result = left & right
5476 if (AOP_TYPE (right) == AOP_LIT)
5478 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5480 aopPut (AOP (result),
5481 aopGet (AOP (left), offset, FALSE),
5486 // faster than result <- left, anl result,right
5487 // and better if result is SFR
5488 if (AOP_TYPE (left) == AOP_ACC)
5489 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5492 _moveA (aopGet (AOP (left), offset, FALSE));
5494 aopGet (AOP (right), offset, FALSE));
5496 aopPut (AOP (result), "a", offset);
5497 /* PENDING: something weird is going on here. Add exception. */
5498 if (AOP_TYPE (result) == AOP_ACC)
5504 freeAsmop (left, NULL, ic);
5505 freeAsmop (right, NULL, ic);
5506 freeAsmop (result, NULL, ic);
5509 /*-----------------------------------------------------------------*/
5510 /* genXor - code for xclusive or */
5511 /*-----------------------------------------------------------------*/
5513 genXor (iCode * ic, iCode * ifx)
5515 operand *left, *right, *result;
5516 int size, offset = 0;
5517 unsigned long lit = 0L;
5519 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5520 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5521 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5523 /* if left is a literal & right is not then exchange them */
5524 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5525 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5527 operand *tmp = right;
5532 /* if result = right then exchange them */
5533 if (sameRegs (AOP (result), AOP (right)))
5535 operand *tmp = right;
5540 /* if right is bit then exchange them */
5541 if (AOP_TYPE (right) == AOP_CRY &&
5542 AOP_TYPE (left) != AOP_CRY)
5544 operand *tmp = right;
5548 if (AOP_TYPE (right) == AOP_LIT)
5549 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5551 size = AOP_SIZE (result);
5553 if (AOP_TYPE (left) == AOP_CRY)
5555 wassertl (0, "Tried to XOR a bit");
5559 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5560 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5561 if ((AOP_TYPE (right) == AOP_LIT) &&
5562 (AOP_TYPE (result) == AOP_CRY) &&
5563 (AOP_TYPE (left) != AOP_CRY))
5565 symbol *tlbl = newiTempLabel (NULL);
5566 int sizel = AOP_SIZE (left);
5570 /* PENDING: Test case for this. */
5571 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5575 _moveA (aopGet (AOP (left), offset, FALSE));
5576 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5577 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5582 jmpTrueOrFalse (ifx, tlbl);
5586 wassertl (0, "Result of XOR was destined for a bit");
5591 /* if left is same as result */
5592 if (sameRegs (AOP (result), AOP (left)))
5594 for (; size--; offset++)
5596 if (AOP_TYPE (right) == AOP_LIT)
5598 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5602 _moveA (aopGet (AOP (left), offset, FALSE));
5604 aopGet (AOP (right), offset, FALSE));
5605 aopPut (AOP (result), "a", offset);
5610 if (AOP_TYPE (left) == AOP_ACC)
5612 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5616 _moveA (aopGet (AOP (left), offset, FALSE));
5618 aopGet (AOP (right), offset, FALSE));
5619 aopPut (AOP (result), "a", offset);
5626 // left & result in different registers
5627 if (AOP_TYPE (result) == AOP_CRY)
5629 wassertl (0, "Result of XOR is in a bit");
5632 for (; (size--); offset++)
5635 // result = left & right
5636 if (AOP_TYPE (right) == AOP_LIT)
5638 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5640 aopPut (AOP (result),
5641 aopGet (AOP (left), offset, FALSE),
5646 // faster than result <- left, anl result,right
5647 // and better if result is SFR
5648 if (AOP_TYPE (left) == AOP_ACC)
5650 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5654 _moveA (aopGet (AOP (left), offset, FALSE));
5656 aopGet (AOP (right), offset, FALSE));
5658 aopPut (AOP (result), "a", offset);
5663 freeAsmop (left, NULL, ic);
5664 freeAsmop (right, NULL, ic);
5665 freeAsmop (result, NULL, ic);
5668 /*-----------------------------------------------------------------*/
5669 /* genInline - write the inline code out */
5670 /*-----------------------------------------------------------------*/
5672 genInline (iCode * ic)
5674 char *buffer, *bp, *bp1;
5675 bool inComment = FALSE;
5677 _G.lines.isInline += (!options.asmpeep);
5679 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5681 /* emit each line as a code */
5699 /* Add \n for labels, not dirs such as c:\mydir */
5700 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5718 _G.lines.isInline -= (!options.asmpeep);
5722 /*-----------------------------------------------------------------*/
5723 /* genRRC - rotate right with carry */
5724 /*-----------------------------------------------------------------*/
5731 /*-----------------------------------------------------------------*/
5732 /* genRLC - generate code for rotate left with carry */
5733 /*-----------------------------------------------------------------*/
5740 /*-----------------------------------------------------------------*/
5741 /* genGetHbit - generates code get highest order bit */
5742 /*-----------------------------------------------------------------*/
5744 genGetHbit (iCode * ic)
5746 operand *left, *result;
5747 left = IC_LEFT (ic);
5748 result = IC_RESULT (ic);
5750 aopOp (left, ic, FALSE, FALSE);
5751 aopOp (result, ic, FALSE, FALSE);
5753 /* get the highest order byte into a */
5754 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5756 if (AOP_TYPE (result) == AOP_CRY)
5764 emit2 ("and a,!one");
5769 freeAsmop (left, NULL, ic);
5770 freeAsmop (result, NULL, ic);
5774 emitRsh2 (asmop *aop, int size, int is_signed)
5780 const char *l = aopGet (aop, size, FALSE);
5783 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5793 /*-----------------------------------------------------------------*/
5794 /* shiftR2Left2Result - shift right two bytes from left to result */
5795 /*-----------------------------------------------------------------*/
5797 shiftR2Left2Result (operand * left, int offl,
5798 operand * result, int offr,
5799 int shCount, int is_signed)
5804 movLeft2Result (left, offl, result, offr, 0);
5805 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5810 /* if (AOP(result)->type == AOP_REG) { */
5812 tlbl = newiTempLabel (NULL);
5814 /* Left is already in result - so now do the shift */
5815 /* Optimizing for speed by default. */
5816 if (!optimize.codeSize || shCount <= 2)
5820 emitRsh2 (AOP (result), size, is_signed);
5825 emit2 ("ld a,!immedbyte", shCount);
5827 emitLabel (tlbl->key + 100);
5829 emitRsh2 (AOP (result), size, is_signed);
5832 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5836 /*-----------------------------------------------------------------*/
5837 /* shiftL2Left2Result - shift left two bytes from left to result */
5838 /*-----------------------------------------------------------------*/
5840 shiftL2Left2Result (operand * left, int offl,
5841 operand * result, int offr, int shCount)
5843 if (sameRegs (AOP (result), AOP (left)) &&
5844 ((offl + MSB16) == offr))
5850 /* Copy left into result */
5851 movLeft2Result (left, offl, result, offr, 0);
5852 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5858 if (getPairId (AOP (result)) == PAIR_HL)
5862 emit2 ("add hl,hl");
5869 symbol *tlbl, *tlbl1;
5872 tlbl = newiTempLabel (NULL);
5873 tlbl1 = newiTempLabel (NULL);
5875 if (AOP (result)->type == AOP_REG)
5879 for (offset = 0; offset < size; offset++)
5881 l = aopGet (AOP (result), offset, FALSE);
5885 emit2 ("sla %s", l);
5896 /* Left is already in result - so now do the shift */
5899 emit2 ("ld a,!immedbyte+1", shCount);
5900 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5901 emitLabel (tlbl->key + 100);
5906 l = aopGet (AOP (result), offset, FALSE);
5910 emit2 ("sla %s", l);
5921 emitLabel (tlbl1->key + 100);
5923 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5929 /*-----------------------------------------------------------------*/
5930 /* AccRol - rotate left accumulator by known count */
5931 /*-----------------------------------------------------------------*/
5933 AccRol (int shCount)
5935 shCount &= 0x0007; // shCount : 0..7
6012 /*-----------------------------------------------------------------*/
6013 /* AccLsh - left shift accumulator by known count */
6014 /*-----------------------------------------------------------------*/
6016 AccLsh (int shCount)
6018 static const unsigned char SLMask[] =
6020 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6029 else if (shCount == 2)
6036 /* rotate left accumulator */
6038 /* and kill the lower order bits */
6039 emit2 ("and a,!immedbyte", SLMask[shCount]);
6044 /*-----------------------------------------------------------------*/
6045 /* shiftL1Left2Result - shift left one byte from left to result */
6046 /*-----------------------------------------------------------------*/
6048 shiftL1Left2Result (operand * left, int offl,
6049 operand * result, int offr, int shCount)
6053 /* If operand and result are the same we can shift in place.
6054 However shifting in acc using add is cheaper than shifting
6055 in place using sla; when shifting by more than 2 shifting in
6056 acc is worth the additional effort for loading from/to acc. */
6057 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6060 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6064 l = aopGet (AOP (left), offl, FALSE);
6066 /* shift left accumulator */
6068 aopPut (AOP (result), "a", offr);
6072 /*-----------------------------------------------------------------*/
6073 /* genlshTwo - left shift two bytes by known amount */
6074 /*-----------------------------------------------------------------*/
6076 genlshTwo (operand * result, operand * left, int shCount)
6078 int size = AOP_SIZE (result);
6080 wassert (size == 2);
6082 /* if shCount >= 8 */
6090 movLeft2Result (left, LSB, result, MSB16, 0);
6091 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6092 aopPut (AOP (result), "!zero", LSB);
6096 movLeft2Result (left, LSB, result, MSB16, 0);
6097 aopPut (AOP (result), "!zero", 0);
6102 aopPut (AOP (result), "!zero", LSB);
6105 /* 0 <= shCount <= 7 */
6114 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6119 /*-----------------------------------------------------------------*/
6120 /* genlshOne - left shift a one byte quantity by known count */
6121 /*-----------------------------------------------------------------*/
6123 genlshOne (operand * result, operand * left, int shCount)
6125 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6128 /*-----------------------------------------------------------------*/
6129 /* genLeftShiftLiteral - left shifting by known count */
6130 /*-----------------------------------------------------------------*/
6132 genLeftShiftLiteral (operand * left,
6137 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6140 freeAsmop (right, NULL, ic);
6142 aopOp (left, ic, FALSE, FALSE);
6143 aopOp (result, ic, FALSE, FALSE);
6145 size = getSize (operandType (result));
6147 /* I suppose that the left size >= result size */
6149 if (shCount >= (size * 8))
6153 aopPut (AOP (result), "!zero", size);
6161 genlshOne (result, left, shCount);
6164 genlshTwo (result, left, shCount);
6167 wassertl (0, "Shifting of longs is currently unsupported");
6173 freeAsmop (left, NULL, ic);
6174 freeAsmop (result, NULL, ic);
6177 /*-----------------------------------------------------------------*/
6178 /* genLeftShift - generates code for left shifting */
6179 /*-----------------------------------------------------------------*/
6181 genLeftShift (iCode * ic)
6185 symbol *tlbl, *tlbl1;
6186 operand *left, *right, *result;
6188 right = IC_RIGHT (ic);
6189 left = IC_LEFT (ic);
6190 result = IC_RESULT (ic);
6192 aopOp (right, ic, FALSE, FALSE);
6194 /* if the shift count is known then do it
6195 as efficiently as possible */
6196 if (AOP_TYPE (right) == AOP_LIT)
6198 genLeftShiftLiteral (left, right, result, ic);
6202 /* shift count is unknown then we have to form a loop get the loop
6203 count in B : Note: we take only the lower order byte since
6204 shifting more that 32 bits make no sense anyway, ( the largest
6205 size of an object can be only 32 bits ) */
6206 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6208 freeAsmop (right, NULL, ic);
6209 aopOp (left, ic, FALSE, FALSE);
6210 aopOp (result, ic, FALSE, FALSE);
6212 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6215 /* now move the left to the result if they are not the
6218 if (!sameRegs (AOP (left), AOP (result)))
6221 size = AOP_SIZE (result);
6225 l = aopGet (AOP (left), offset, FALSE);
6226 aopPut (AOP (result), l, offset);
6231 tlbl = newiTempLabel (NULL);
6232 size = AOP_SIZE (result);
6234 tlbl1 = newiTempLabel (NULL);
6236 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6239 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6240 emitLabel (tlbl->key + 100);
6241 l = aopGet (AOP (result), offset, FALSE);
6245 l = aopGet (AOP (result), offset, FALSE);
6249 emit2 ("sla %s", l);
6257 emitLabel (tlbl1->key + 100);
6259 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6261 freeAsmop (left, NULL, ic);
6262 freeAsmop (result, NULL, ic);
6265 /*-----------------------------------------------------------------*/
6266 /* genrshOne - left shift two bytes by known amount != 0 */
6267 /*-----------------------------------------------------------------*/
6269 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6272 int size = AOP_SIZE (result);
6275 wassert (size == 1);
6276 wassert (shCount < 8);
6278 l = aopGet (AOP (left), 0, FALSE);
6280 if (AOP (result)->type == AOP_REG)
6282 aopPut (AOP (result), l, 0);
6283 l = aopGet (AOP (result), 0, FALSE);
6286 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6294 emit2 ("%s a", is_signed ? "sra" : "srl");
6296 aopPut (AOP (result), "a", 0);
6300 /*-----------------------------------------------------------------*/
6301 /* AccRsh - right shift accumulator by known count */
6302 /*-----------------------------------------------------------------*/
6304 AccRsh (int shCount)
6306 static const unsigned char SRMask[] =
6308 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6313 /* rotate right accumulator */
6314 AccRol (8 - shCount);
6315 /* and kill the higher order bits */
6316 emit2 ("and a,!immedbyte", SRMask[shCount]);
6320 /*-----------------------------------------------------------------*/
6321 /* shiftR1Left2Result - shift right one byte from left to result */
6322 /*-----------------------------------------------------------------*/
6324 shiftR1Left2Result (operand * left, int offl,
6325 operand * result, int offr,
6326 int shCount, int sign)
6328 _moveA (aopGet (AOP (left), offl, FALSE));
6333 emit2 ("%s a", sign ? "sra" : "srl");
6340 aopPut (AOP (result), "a", offr);
6343 /*-----------------------------------------------------------------*/
6344 /* genrshTwo - right shift two bytes by known amount */
6345 /*-----------------------------------------------------------------*/
6347 genrshTwo (operand * result, operand * left,
6348 int shCount, int sign)
6350 /* if shCount >= 8 */
6356 shiftR1Left2Result (left, MSB16, result, LSB,
6361 movLeft2Result (left, MSB16, result, LSB, sign);
6365 /* Sign extend the result */
6366 _moveA(aopGet (AOP (result), 0, FALSE));
6370 aopPut (AOP (result), ACC_NAME, MSB16);
6374 aopPut (AOP (result), "!zero", 1);
6377 /* 0 <= shCount <= 7 */
6380 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6384 /*-----------------------------------------------------------------*/
6385 /* genRightShiftLiteral - left shifting by known count */
6386 /*-----------------------------------------------------------------*/
6388 genRightShiftLiteral (operand * left,
6394 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6397 freeAsmop (right, NULL, ic);
6399 aopOp (left, ic, FALSE, FALSE);
6400 aopOp (result, ic, FALSE, FALSE);
6402 size = getSize (operandType (result));
6404 /* I suppose that the left size >= result size */
6406 if (shCount >= (size * 8)) {
6408 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6409 _moveA(aopGet (AOP (left), 0, FALSE));
6417 aopPut (AOP (result), s, size);
6424 genrshOne (result, left, shCount, sign);
6427 genrshTwo (result, left, shCount, sign);
6430 wassertl (0, "Asked to shift right a long which should be a function call");
6433 wassertl (0, "Entered default case in right shift delegate");
6436 freeAsmop (left, NULL, ic);
6437 freeAsmop (result, NULL, ic);
6440 /*-----------------------------------------------------------------*/
6441 /* genRightShift - generate code for right shifting */
6442 /*-----------------------------------------------------------------*/
6444 genRightShift (iCode * ic)
6446 operand *right, *left, *result;
6448 int size, offset, first = 1;
6452 symbol *tlbl, *tlbl1;
6454 /* if signed then we do it the hard way preserve the
6455 sign bit moving it inwards */
6456 retype = getSpec (operandType (IC_RESULT (ic)));
6458 is_signed = !SPEC_USIGN (retype);
6460 /* signed & unsigned types are treated the same : i.e. the
6461 signed is NOT propagated inwards : quoting from the
6462 ANSI - standard : "for E1 >> E2, is equivalent to division
6463 by 2**E2 if unsigned or if it has a non-negative value,
6464 otherwise the result is implementation defined ", MY definition
6465 is that the sign does not get propagated */
6467 right = IC_RIGHT (ic);
6468 left = IC_LEFT (ic);
6469 result = IC_RESULT (ic);
6471 aopOp (right, ic, FALSE, FALSE);
6473 /* if the shift count is known then do it
6474 as efficiently as possible */
6475 if (AOP_TYPE (right) == AOP_LIT)
6477 genRightShiftLiteral (left, right, result, ic, is_signed);
6481 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6483 freeAsmop (right, NULL, ic);
6485 aopOp (left, ic, FALSE, FALSE);
6486 aopOp (result, ic, FALSE, FALSE);
6488 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6491 /* now move the left to the result if they are not the
6493 if (!sameRegs (AOP (left), AOP (result)))
6496 size = AOP_SIZE (result);
6500 l = aopGet (AOP (left), offset, FALSE);
6501 aopPut (AOP (result), l, offset);
6506 tlbl = newiTempLabel (NULL);
6507 tlbl1 = newiTempLabel (NULL);
6508 size = AOP_SIZE (result);
6511 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6514 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6515 emitLabel (tlbl->key + 100);
6518 l = aopGet (AOP (result), offset--, FALSE);
6521 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6529 emitLabel (tlbl1->key + 100);
6531 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6533 freeAsmop (left, NULL, ic);
6534 freeAsmop (result, NULL, ic);
6538 /*-----------------------------------------------------------------*/
6539 /* genUnpackBits - generates code for unpacking bits */
6540 /*-----------------------------------------------------------------*/
6542 genUnpackBits (operand * result, int pair)
6544 int offset = 0; /* result byte offset */
6545 int rsize; /* result size */
6546 int rlen = 0; /* remaining bitfield length */
6547 sym_link *etype; /* bitfield type information */
6548 int blen; /* bitfield length */
6549 int bstr; /* bitfield starting bit within byte */
6551 emitDebug ("; genUnpackBits");
6553 etype = getSpec (operandType (result));
6554 rsize = getSize (operandType (result));
6555 blen = SPEC_BLEN (etype);
6556 bstr = SPEC_BSTR (etype);
6558 /* If the bitfield length is less than a byte */
6561 emit2 ("ld a,!*pair", _pairs[pair].name);
6563 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6564 if (!SPEC_USIGN (etype))
6566 /* signed bitfield */
6567 symbol *tlbl = newiTempLabel (NULL);
6569 emit2 ("bit %d,a", blen - 1);
6570 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6571 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6572 emitLabel (tlbl->key + 100);
6574 aopPut (AOP (result), "a", offset++);
6578 /* TODO: what if pair == PAIR_DE ? */
6579 if (getPairId (AOP (result)) == PAIR_HL)
6581 wassertl (rsize == 2, "HL must be of size 2");
6582 emit2 ("ld a,!*hl");
6584 emit2 ("ld h,!*hl");
6587 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6588 if (!SPEC_USIGN (etype))
6590 /* signed bitfield */
6591 symbol *tlbl = newiTempLabel (NULL);
6593 emit2 ("bit %d,a", blen - 1);
6594 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6595 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6596 emitLabel (tlbl->key + 100);
6599 spillPair (PAIR_HL);
6603 /* Bit field did not fit in a byte. Copy all
6604 but the partial byte at the end. */
6605 for (rlen=blen;rlen>=8;rlen-=8)
6607 emit2 ("ld a,!*pair", _pairs[pair].name);
6608 aopPut (AOP (result), "a", offset++);
6611 emit2 ("inc %s", _pairs[pair].name);
6612 _G.pairs[pair].offset++;
6616 /* Handle the partial byte at the end */
6619 emit2 ("ld a,!*pair", _pairs[pair].name);
6620 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6621 if (!SPEC_USIGN (etype))
6623 /* signed bitfield */
6624 symbol *tlbl = newiTempLabel (NULL);
6626 emit2 ("bit %d,a", rlen - 1);
6627 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6628 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6629 emitLabel (tlbl->key + 100);
6631 aopPut (AOP (result), "a", offset++);
6639 if (SPEC_USIGN (etype))
6643 /* signed bitfield: sign extension with 0x00 or 0xff */
6651 aopPut (AOP (result), source, offset++);
6655 /*-----------------------------------------------------------------*/
6656 /* genGenPointerGet - get value from generic pointer space */
6657 /*-----------------------------------------------------------------*/
6659 genGenPointerGet (operand * left,
6660 operand * result, iCode * ic)
6663 sym_link *retype = getSpec (operandType (result));
6669 aopOp (left, ic, FALSE, FALSE);
6670 aopOp (result, ic, FALSE, FALSE);
6672 size = AOP_SIZE (result);
6674 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6677 if (isPtrPair (AOP (left)))
6679 tsprintf (buffer, sizeof(buffer),
6680 "!*pair", getPairName (AOP (left)));
6681 aopPut (AOP (result), buffer, 0);
6685 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6686 aopPut (AOP (result), "a", 0);
6688 freeAsmop (left, NULL, ic);
6692 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6699 tsprintf (at, sizeof(at), "!*iyx", offset);
6700 aopPut (AOP (result), at, offset);
6704 freeAsmop (left, NULL, ic);
6708 /* For now we always load into IY */
6709 /* if this is remateriazable */
6710 fetchPair (pair, AOP (left));
6712 /* if bit then unpack */
6713 if (IS_BITVAR (retype))
6715 genUnpackBits (result, pair);
6716 freeAsmop (left, NULL, ic);
6720 else if (getPairId (AOP (result)) == PAIR_HL)
6722 wassertl (size == 2, "HL must be of size 2");
6723 emit2 ("ld a,!*hl");
6725 emit2 ("ld h,!*hl");
6727 spillPair (PAIR_HL);
6729 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6731 size = AOP_SIZE (result);
6736 /* PENDING: make this better */
6737 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6739 aopPut (AOP (result), "!*hl", offset++);
6743 emit2 ("ld a,!*pair", _pairs[pair].name);
6744 aopPut (AOP (result), "a", offset++);
6748 emit2 ("inc %s", _pairs[pair].name);
6749 _G.pairs[pair].offset++;
6752 /* Fixup HL back down */
6753 for (size = AOP_SIZE (result)-1; size; size--)
6755 emit2 ("dec %s", _pairs[pair].name);
6760 size = AOP_SIZE (result);
6765 /* PENDING: make this better */
6767 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6769 aopPut (AOP (result), "!*hl", offset++);
6773 emit2 ("ld a,!*pair", _pairs[pair].name);
6774 aopPut (AOP (result), "a", offset++);
6778 emit2 ("inc %s", _pairs[pair].name);
6779 _G.pairs[pair].offset++;
6784 freeAsmop (left, NULL, ic);
6787 freeAsmop (result, NULL, ic);
6790 /*-----------------------------------------------------------------*/
6791 /* genPointerGet - generate code for pointer get */
6792 /*-----------------------------------------------------------------*/
6794 genPointerGet (iCode * ic)
6796 operand *left, *result;
6797 sym_link *type, *etype;
6799 left = IC_LEFT (ic);
6800 result = IC_RESULT (ic);
6802 /* depending on the type of pointer we need to
6803 move it to the correct pointer register */
6804 type = operandType (left);
6805 etype = getSpec (type);
6807 genGenPointerGet (left, result, ic);
6811 isRegOrLit (asmop * aop)
6813 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6819 /*-----------------------------------------------------------------*/
6820 /* genPackBits - generates code for packed bit storage */
6821 /*-----------------------------------------------------------------*/
6823 genPackBits (sym_link * etype,
6828 int offset = 0; /* source byte offset */
6829 int rlen = 0; /* remaining bitfield length */
6830 int blen; /* bitfield length */
6831 int bstr; /* bitfield starting bit within byte */
6832 int litval; /* source literal value (if AOP_LIT) */
6833 unsigned char mask; /* bitmask within current byte */
6834 int extraPair; /* a tempory register */
6835 bool needPopExtra=0; /* need to restore original value of temp reg */
6837 emitDebug ("; genPackBits","");
6839 blen = SPEC_BLEN (etype);
6840 bstr = SPEC_BSTR (etype);
6842 /* If the bitfield length is less than a byte */
6845 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6846 (unsigned char) (0xFF >> (8 - bstr)));
6848 if (AOP_TYPE (right) == AOP_LIT)
6850 /* Case with a bitfield length <8 and literal source
6852 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6854 litval &= (~mask) & 0xff;
6855 emit2 ("ld a,!*pair", _pairs[pair].name);
6856 if ((mask|litval)!=0xff)
6857 emit2 ("and a,!immedbyte", mask);
6859 emit2 ("or a,!immedbyte", litval);
6860 emit2 ("ld !*pair,a", _pairs[pair].name);
6865 /* Case with a bitfield length <8 and arbitrary source
6867 _moveA (aopGet (AOP (right), 0, FALSE));
6868 /* shift and mask source value */
6870 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6872 extraPair = getFreePairId(ic);
6873 if (extraPair == PAIR_INVALID)
6875 extraPair = PAIR_BC;
6876 if (getPairId (AOP (right)) != PAIR_BC
6877 || !isLastUse (ic, right))
6883 emit2 ("ld %s,a", _pairs[extraPair].l);
6884 emit2 ("ld a,!*pair", _pairs[pair].name);
6886 emit2 ("and a,!immedbyte", mask);
6887 emit2 ("or a,%s", _pairs[extraPair].l);
6888 emit2 ("ld !*pair,a", _pairs[pair].name);
6895 /* Bit length is greater than 7 bits. In this case, copy */
6896 /* all except the partial byte at the end */
6897 for (rlen=blen;rlen>=8;rlen-=8)
6899 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6900 emit2 ("ld !*pair,a", _pairs[pair].name);
6903 emit2 ("inc %s", _pairs[pair].name);
6904 _G.pairs[pair].offset++;
6908 /* If there was a partial byte at the end */
6911 mask = (((unsigned char) -1 << rlen) & 0xff);
6913 if (AOP_TYPE (right) == AOP_LIT)
6915 /* Case with partial byte and literal source
6917 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6918 litval >>= (blen-rlen);
6919 litval &= (~mask) & 0xff;
6920 emit2 ("ld a,!*pair", _pairs[pair].name);
6921 if ((mask|litval)!=0xff)
6922 emit2 ("and a,!immedbyte", mask);
6924 emit2 ("or a,!immedbyte", litval);
6928 /* Case with partial byte and arbitrary source
6930 _moveA (aopGet (AOP (right), offset++, FALSE));
6931 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6933 extraPair = getFreePairId(ic);
6934 if (extraPair == PAIR_INVALID)
6936 extraPair = getPairId (AOP (right));
6937 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6938 extraPair = PAIR_BC;
6940 if (getPairId (AOP (right)) != PAIR_BC
6941 || !isLastUse (ic, right))
6947 emit2 ("ld %s,a", _pairs[extraPair].l);
6948 emit2 ("ld a,!*pair", _pairs[pair].name);
6950 emit2 ("and a,!immedbyte", mask);
6951 emit2 ("or a,%s", _pairs[extraPair].l);
6956 emit2 ("ld !*pair,a", _pairs[pair].name);
6961 /*-----------------------------------------------------------------*/
6962 /* genGenPointerSet - stores the value into a pointer location */
6963 /*-----------------------------------------------------------------*/
6965 genGenPointerSet (operand * right,
6966 operand * result, iCode * ic)
6969 sym_link *retype = getSpec (operandType (right));
6970 sym_link *letype = getSpec (operandType (result));
6971 PAIR_ID pairId = PAIR_HL;
6974 aopOp (result, ic, FALSE, FALSE);
6975 aopOp (right, ic, FALSE, FALSE);
6980 size = AOP_SIZE (right);
6982 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6983 emitDebug("; isBitvar = %d", isBitvar);
6985 /* Handle the exceptions first */
6986 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6989 const char *l = aopGet (AOP (right), 0, FALSE);
6990 const char *pair = getPairName (AOP (result));
6991 if (canAssignToPtr (l) && isPtr (pair))
6993 emit2 ("ld !*pair,%s", pair, l);
6998 emit2 ("ld !*pair,a", pair);
7003 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7006 const char *l = aopGet (AOP (right), 0, FALSE);
7011 if (canAssignToPtr (l))
7013 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7017 _moveA (aopGet (AOP (right), offset, FALSE));
7018 emit2 ("ld !*iyx,a", offset);
7024 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7031 const char *l = aopGet (AOP (right), offset, FALSE);
7032 if (isRegOrLit (AOP (right)) && !IS_GB)
7034 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7039 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7043 emit2 ("inc %s", _pairs[PAIR_HL].name);
7044 _G.pairs[PAIR_HL].offset++;
7049 /* Fixup HL back down */
7050 for (size = AOP_SIZE (right)-1; size; size--)
7052 emit2 ("dec %s", _pairs[PAIR_HL].name);
7057 /* if the operand is already in dptr
7058 then we do nothing else we move the value to dptr */
7059 if (AOP_TYPE (result) != AOP_STR)
7061 fetchPair (pairId, AOP (result));
7063 /* so hl now contains the address */
7064 freeAsmop (result, NULL, ic);
7066 /* if bit then unpack */
7069 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7079 const char *l = aopGet (AOP (right), offset, FALSE);
7080 if (isRegOrLit (AOP (right)) && !IS_GB)
7082 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7087 emit2 ("ld !*pair,a", _pairs[pairId].name);
7091 emit2 ("inc %s", _pairs[pairId].name);
7092 _G.pairs[pairId].offset++;
7098 freeAsmop (right, NULL, ic);
7101 /*-----------------------------------------------------------------*/
7102 /* genPointerSet - stores the value into a pointer location */
7103 /*-----------------------------------------------------------------*/
7105 genPointerSet (iCode * ic)
7107 operand *right, *result;
7108 sym_link *type, *etype;
7110 right = IC_RIGHT (ic);
7111 result = IC_RESULT (ic);
7113 /* depending on the type of pointer we need to
7114 move it to the correct pointer register */
7115 type = operandType (result);
7116 etype = getSpec (type);
7118 genGenPointerSet (right, result, ic);
7121 /*-----------------------------------------------------------------*/
7122 /* genIfx - generate code for Ifx statement */
7123 /*-----------------------------------------------------------------*/
7125 genIfx (iCode * ic, iCode * popIc)
7127 operand *cond = IC_COND (ic);
7130 aopOp (cond, ic, FALSE, TRUE);
7132 /* get the value into acc */
7133 if (AOP_TYPE (cond) != AOP_CRY)
7137 /* the result is now in the accumulator */
7138 freeAsmop (cond, NULL, ic);
7140 /* if there was something to be popped then do it */
7144 /* if the condition is a bit variable */
7145 if (isbit && IS_ITEMP (cond) &&
7147 genIfxJump (ic, SPIL_LOC (cond)->rname);
7148 else if (isbit && !IS_ITEMP (cond))
7149 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7151 genIfxJump (ic, "a");
7156 /*-----------------------------------------------------------------*/
7157 /* genAddrOf - generates code for address of */
7158 /*-----------------------------------------------------------------*/
7160 genAddrOf (iCode * ic)
7162 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7164 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7166 /* if the operand is on the stack then we
7167 need to get the stack offset of this
7174 if (sym->stack <= 0)
7176 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7180 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7182 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7186 emit2 ("ld de,!hashedstr", sym->rname);
7187 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7195 /* if it has an offset then we need to compute it */
7197 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7199 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7200 emit2 ("add hl,sp");
7204 emit2 ("ld hl,!hashedstr", sym->rname);
7206 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7208 freeAsmop (IC_RESULT (ic), NULL, ic);
7211 /*-----------------------------------------------------------------*/
7212 /* genAssign - generate code for assignment */
7213 /*-----------------------------------------------------------------*/
7215 genAssign (iCode * ic)
7217 operand *result, *right;
7219 unsigned long lit = 0L;
7221 result = IC_RESULT (ic);
7222 right = IC_RIGHT (ic);
7224 /* Dont bother assigning if they are the same */
7225 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7227 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7231 aopOp (right, ic, FALSE, FALSE);
7232 aopOp (result, ic, TRUE, FALSE);
7234 /* if they are the same registers */
7235 if (sameRegs (AOP (right), AOP (result)))
7237 emitDebug ("; (registers are the same)");
7241 /* if the result is a bit */
7242 if (AOP_TYPE (result) == AOP_CRY)
7244 wassertl (0, "Tried to assign to a bit");
7248 size = AOP_SIZE (result);
7251 if (AOP_TYPE (right) == AOP_LIT)
7253 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7256 if (isPair (AOP (result)))
7258 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7260 else if ((size > 1) &&
7261 (AOP_TYPE (result) != AOP_REG) &&
7262 (AOP_TYPE (right) == AOP_LIT) &&
7263 !IS_FLOAT (operandType (right)) &&
7266 bool fXored = FALSE;
7268 /* Work from the top down.
7269 Done this way so that we can use the cached copy of 0
7270 in A for a fast clear */
7273 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7275 if (!fXored && size > 1)
7282 aopPut (AOP (result), "a", offset);
7286 aopPut (AOP (result), "!zero", offset);
7290 aopPut (AOP (result),
7291 aopGet (AOP (right), offset, FALSE),
7296 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7298 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7299 aopPut (AOP (result), "l", LSB);
7300 aopPut (AOP (result), "h", MSB16);
7302 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7304 /* Special case. Load into a and d, then load out. */
7305 _moveA (aopGet (AOP (right), 0, FALSE));
7306 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7307 aopPut (AOP (result), "a", 0);
7308 aopPut (AOP (result), "e", 1);
7310 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7312 /* Special case - simple memcpy */
7313 aopGet (AOP (right), LSB, FALSE);
7316 aopGet (AOP (result), LSB, FALSE);
7320 emit2 ("ld a,(de)");
7321 /* Peephole will optimise this. */
7322 emit2 ("ld (hl),a");
7330 spillPair (PAIR_HL);
7336 /* PENDING: do this check better */
7337 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7339 _moveA (aopGet (AOP (right), offset, FALSE));
7340 aopPut (AOP (result), "a", offset);
7343 aopPut (AOP (result),
7344 aopGet (AOP (right), offset, FALSE),
7351 freeAsmop (right, NULL, ic);
7352 freeAsmop (result, NULL, ic);
7355 /*-----------------------------------------------------------------*/
7356 /* genJumpTab - genrates code for jump table */
7357 /*-----------------------------------------------------------------*/
7359 genJumpTab (iCode * ic)
7364 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7365 /* get the condition into accumulator */
7366 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7369 emit2 ("ld e,%s", l);
7370 emit2 ("ld d,!zero");
7371 jtab = newiTempLabel (NULL);
7373 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7374 emit2 ("add hl,de");
7375 emit2 ("add hl,de");
7376 emit2 ("add hl,de");
7377 freeAsmop (IC_JTCOND (ic), NULL, ic);
7381 emitLabel (jtab->key + 100);
7382 /* now generate the jump labels */
7383 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7384 jtab = setNextItem (IC_JTLABELS (ic)))
7385 emit2 ("jp !tlabel", jtab->key + 100);
7388 /*-----------------------------------------------------------------*/
7389 /* genCast - gen code for casting */
7390 /*-----------------------------------------------------------------*/
7392 genCast (iCode * ic)
7394 operand *result = IC_RESULT (ic);
7395 sym_link *rtype = operandType (IC_RIGHT (ic));
7396 operand *right = IC_RIGHT (ic);
7399 /* if they are equivalent then do nothing */
7400 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7403 aopOp (right, ic, FALSE, FALSE);
7404 aopOp (result, ic, FALSE, FALSE);
7406 /* if the result is a bit */
7407 if (AOP_TYPE (result) == AOP_CRY)
7409 wassertl (0, "Tried to cast to a bit");
7412 /* if they are the same size : or less */
7413 if (AOP_SIZE (result) <= AOP_SIZE (right))
7416 /* if they are in the same place */
7417 if (sameRegs (AOP (right), AOP (result)))
7420 /* if they in different places then copy */
7421 size = AOP_SIZE (result);
7425 aopPut (AOP (result),
7426 aopGet (AOP (right), offset, FALSE),
7433 /* So we now know that the size of destination is greater
7434 than the size of the source */
7435 /* we move to result for the size of source */
7436 size = AOP_SIZE (right);
7440 aopPut (AOP (result),
7441 aopGet (AOP (right), offset, FALSE),
7446 /* now depending on the sign of the destination */
7447 size = AOP_SIZE (result) - AOP_SIZE (right);
7448 /* Unsigned or not an integral type - right fill with zeros */
7449 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7452 aopPut (AOP (result), "!zero", offset++);
7456 /* we need to extend the sign :{ */
7457 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7463 aopPut (AOP (result), "a", offset++);
7467 freeAsmop (right, NULL, ic);
7468 freeAsmop (result, NULL, ic);
7471 /*-----------------------------------------------------------------*/
7472 /* genReceive - generate code for a receive iCode */
7473 /*-----------------------------------------------------------------*/
7475 genReceive (iCode * ic)
7477 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7478 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7479 IS_TRUE_SYMOP (IC_RESULT (ic))))
7489 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7490 size = AOP_SIZE(IC_RESULT(ic));
7492 for (i = 0; i < size; i++) {
7493 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7497 freeAsmop (IC_RESULT (ic), NULL, ic);
7500 /*-----------------------------------------------------------------*/
7501 /* genDummyRead - generate code for dummy read of volatiles */
7502 /*-----------------------------------------------------------------*/
7504 genDummyRead (iCode * ic)
7510 if (op && IS_SYMOP (op))
7512 aopOp (op, ic, FALSE, FALSE);
7515 size = AOP_SIZE (op);
7520 _moveA (aopGet (AOP (op), offset, FALSE));
7524 freeAsmop (op, NULL, ic);
7528 if (op && IS_SYMOP (op))
7530 aopOp (op, ic, FALSE, FALSE);
7533 size = AOP_SIZE (op);
7538 _moveA (aopGet (AOP (op), offset, FALSE));
7542 freeAsmop (op, NULL, ic);
7546 /*-----------------------------------------------------------------*/
7547 /* genCritical - generate code for start of a critical sequence */
7548 /*-----------------------------------------------------------------*/
7550 genCritical (iCode *ic)
7552 symbol *tlbl = newiTempLabel (NULL);
7558 else if (IC_RESULT (ic))
7560 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7561 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7562 //get interrupt enable flag IFF2 into P/O
7566 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7567 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7568 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7569 emit2 ("!tlabeldef", (tlbl->key + 100));
7570 _G.lines.current->isLabel = 1;
7571 freeAsmop (IC_RESULT (ic), NULL, ic);
7575 //get interrupt enable flag IFF2 into P/O
7584 /*-----------------------------------------------------------------*/
7585 /* genEndCritical - generate code for end of a critical sequence */
7586 /*-----------------------------------------------------------------*/
7588 genEndCritical (iCode *ic)
7590 symbol *tlbl = newiTempLabel (NULL);
7596 else if (IC_RIGHT (ic))
7598 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7599 _toBoolean (IC_RIGHT (ic));
7600 //don't enable interrupts if they were off before
7601 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7603 emitLabel (tlbl->key + 100);
7604 freeAsmop (IC_RIGHT (ic), NULL, ic);
7610 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7611 //don't enable interrupts as they were off before
7612 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7614 emit2 ("!tlabeldef", (tlbl->key + 100));
7615 _G.lines.current->isLabel = 1;
7621 /** Maximum number of bytes to emit per line. */
7625 /** Context for the byte output chunker. */
7628 unsigned char buffer[DBEMIT_MAX_RUN];
7633 /** Flushes a byte chunker by writing out all in the buffer and
7637 _dbFlush(DBEMITCTX *self)
7644 sprintf(line, ".db 0x%02X", self->buffer[0]);
7646 for (i = 1; i < self->pos; i++)
7648 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7655 /** Write out another byte, buffering until a decent line is
7659 _dbEmit(DBEMITCTX *self, int c)
7661 if (self->pos == DBEMIT_MAX_RUN)
7665 self->buffer[self->pos++] = c;
7668 /** Context for a simple run length encoder. */
7672 unsigned char buffer[128];
7674 /** runLen may be equivalent to pos. */
7680 RLE_CHANGE_COST = 4,
7684 /** Flush the buffer of a run length encoder by writing out the run or
7685 data that it currently contains.
7688 _rleCommit(RLECTX *self)
7694 memset(&db, 0, sizeof(db));
7696 emit2(".db %u", self->pos);
7698 for (i = 0; i < self->pos; i++)
7700 _dbEmit(&db, self->buffer[i]);
7709 Can get either a run or a block of random stuff.
7710 Only want to change state if a good run comes in or a run ends.
7711 Detecting run end is easy.
7714 Say initial state is in run, len zero, last zero. Then if you get a
7715 few zeros then something else then a short run will be output.
7716 Seems OK. While in run mode, keep counting. While in random mode,
7717 keep a count of the run. If run hits margin, output all up to run,
7718 restart, enter run mode.
7721 /** Add another byte into the run length encoder, flushing as
7722 required. The run length encoder uses the Amiga IFF style, where
7723 a block is prefixed by its run length. A positive length means
7724 the next n bytes pass straight through. A negative length means
7725 that the next byte is repeated -n times. A zero terminates the
7729 _rleAppend(RLECTX *self, unsigned c)
7733 if (c != self->last)
7735 /* The run has stopped. See if it is worthwhile writing it out
7736 as a run. Note that the random data comes in as runs of
7739 if (self->runLen > RLE_CHANGE_COST)
7741 /* Yes, worthwhile. */
7742 /* Commit whatever was in the buffer. */
7744 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7748 /* Not worthwhile. Append to the end of the random list. */
7749 for (i = 0; i < self->runLen; i++)
7751 if (self->pos >= RLE_MAX_BLOCK)
7756 self->buffer[self->pos++] = self->last;
7764 if (self->runLen >= RLE_MAX_BLOCK)
7766 /* Commit whatever was in the buffer. */
7769 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7777 _rleFlush(RLECTX *self)
7779 _rleAppend(self, -1);
7786 /** genArrayInit - Special code for initialising an array with constant
7790 genArrayInit (iCode * ic)
7794 int elementSize = 0, eIndex, i;
7795 unsigned val, lastVal;
7799 memset(&rle, 0, sizeof(rle));
7801 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7803 _saveRegsForCall(ic, 0);
7805 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7806 emit2 ("call __initrleblock");
7808 type = operandType(IC_LEFT(ic));
7810 if (type && type->next)
7812 if (IS_SPEC(type->next) || IS_PTR(type->next))
7814 elementSize = getSize(type->next);
7816 else if (IS_ARRAY(type->next) && type->next->next)
7818 elementSize = getSize(type->next->next);
7822 printTypeChainRaw (type, NULL);
7823 wassertl (0, "Can't determine element size in genArrayInit.");
7828 wassertl (0, "Can't determine element size in genArrayInit.");
7831 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7833 iLoop = IC_ARRAYILIST(ic);
7834 lastVal = (unsigned)-1;
7836 /* Feed all the bytes into the run length encoder which will handle
7838 This works well for mixed char data, and for random int and long
7845 for (i = 0; i < ix; i++)
7847 for (eIndex = 0; eIndex < elementSize; eIndex++)
7849 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7850 _rleAppend(&rle, val);
7854 iLoop = iLoop->next;
7858 /* Mark the end of the run. */
7861 _restoreRegsAfterCall();
7865 freeAsmop (IC_LEFT(ic), NULL, ic);
7869 _swap (PAIR_ID one, PAIR_ID two)
7871 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7877 emit2 ("ld a,%s", _pairs[one].l);
7878 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7879 emit2 ("ld %s,a", _pairs[two].l);
7880 emit2 ("ld a,%s", _pairs[one].h);
7881 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7882 emit2 ("ld %s,a", _pairs[two].h);
7886 /* The problem is that we may have all three pairs used and they may
7887 be needed in a different order.
7892 hl = hl => unity, fine
7896 hl = hl hl = hl, swap de <=> bc
7904 hl = bc de = de, swap bc <=> hl
7912 hl = de bc = bc, swap hl <=> de
7917 * Any pair = pair are done last
7918 * Any pair = iTemp are done last
7919 * Any swaps can be done any time
7927 So how do we detect the cases?
7928 How about a 3x3 matrix?
7932 x x x x (Fourth for iTemp/other)
7934 First determin which mode to use by counting the number of unity and
7937 Two - Assign the pair first, then the rest
7938 One - Swap the two, then the rest
7942 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7944 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7946 PAIR_BC, PAIR_HL, PAIR_DE
7948 int i, j, nunity = 0;
7949 memset (ids, PAIR_INVALID, sizeof (ids));
7952 wassert (nparams == 3);
7954 /* First save everything that needs to be saved. */
7955 _saveRegsForCall (ic, 0);
7957 /* Loading HL first means that DE is always fine. */
7958 for (i = 0; i < nparams; i++)
7960 aopOp (pparams[i], ic, FALSE, FALSE);
7961 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7964 /* Count the number of unity or iTemp assigns. */
7965 for (i = 0; i < 3; i++)
7967 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7975 /* Any order, fall through. */
7977 else if (nunity == 2)
7979 /* One is assigned. Pull it out and assign. */
7980 for (i = 0; i < 3; i++)
7982 for (j = 0; j < NUM_PAIRS; j++)
7984 if (ids[dest[i]][j] == TRUE)
7986 /* Found it. See if it's the right one. */
7987 if (j == PAIR_INVALID || j == dest[i])
7993 fetchPair(dest[i], AOP (pparams[i]));
8000 else if (nunity == 1)
8002 /* Find the pairs to swap. */
8003 for (i = 0; i < 3; i++)
8005 for (j = 0; j < NUM_PAIRS; j++)
8007 if (ids[dest[i]][j] == TRUE)
8009 if (j == PAIR_INVALID || j == dest[i])
8024 int next = getPairId (AOP (pparams[0]));
8025 emit2 ("push %s", _pairs[next].name);
8027 if (next == dest[1])
8029 fetchPair (dest[1], AOP (pparams[1]));
8030 fetchPair (dest[2], AOP (pparams[2]));
8034 fetchPair (dest[2], AOP (pparams[2]));
8035 fetchPair (dest[1], AOP (pparams[1]));
8037 emit2 ("pop %s", _pairs[dest[0]].name);
8040 /* Finally pull out all of the iTemps */
8041 for (i = 0; i < 3; i++)
8043 if (ids[dest[i]][PAIR_INVALID] == 1)
8045 fetchPair (dest[i], AOP (pparams[i]));
8051 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8057 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8061 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8063 setupForBuiltin3 (ic, nParams, pparams);
8065 label = newiTempLabel(NULL);
8067 emitLabel (label->key);
8068 emit2 ("ld a,(hl)");
8071 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8073 freeAsmop (from, NULL, ic->next);
8074 freeAsmop (to, NULL, ic);
8078 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8080 operand *from, *to, *count;
8083 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8088 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8090 setupForBuiltin3 (ic, nParams, pparams);
8094 freeAsmop (count, NULL, ic->next->next);
8095 freeAsmop (from, NULL, ic);
8097 _restoreRegsAfterCall();
8099 /* if we need assign a result value */
8100 if ((IS_ITEMP (IC_RESULT (ic)) &&
8101 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8102 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8103 IS_TRUE_SYMOP (IC_RESULT (ic)))
8105 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8106 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8107 freeAsmop (IC_RESULT (ic), NULL, ic);
8110 freeAsmop (to, NULL, ic->next);
8113 /*-----------------------------------------------------------------*/
8114 /* genBuiltIn - calls the appropriate function to generating code */
8115 /* for a built in function */
8116 /*-----------------------------------------------------------------*/
8117 static void genBuiltIn (iCode *ic)
8119 operand *bi_parms[MAX_BUILTIN_ARGS];
8124 /* get all the arguments for a built in function */
8125 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8127 /* which function is it */
8128 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8130 if (strcmp(bif->name,"__builtin_strcpy")==0)
8132 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8134 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8136 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8140 wassertl (0, "Unknown builtin function encountered");
8144 /*-----------------------------------------------------------------*/
8145 /* genZ80Code - generate code for Z80 based controllers */
8146 /*-----------------------------------------------------------------*/
8148 genZ80Code (iCode * lic)
8156 _fReturn = _gbz80_return;
8157 _fTmp = _gbz80_return;
8161 _fReturn = _z80_return;
8162 _fTmp = _z80_return;
8165 _G.lines.head = _G.lines.current = NULL;
8167 /* if debug information required */
8168 if (options.debug && currFunc)
8170 debugFile->writeFunction (currFunc, lic);
8173 for (ic = lic; ic; ic = ic->next)
8175 _G.current_iCode = ic;
8177 if (ic->lineno && cln != ic->lineno)
8181 debugFile->writeCLine (ic);
8183 if (!options.noCcodeInAsm)
8185 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8186 printCLine(ic->filename, ic->lineno));
8190 if (options.iCodeInAsm)
8192 const char *iLine = printILine(ic);
8193 emit2 (";ic:%d: %s", ic->key, iLine);
8196 /* if the result is marked as
8197 spilt and rematerializable or code for
8198 this has already been generated then
8200 if (resultRemat (ic) || ic->generated)
8203 /* depending on the operation */
8207 emitDebug ("; genNot");
8212 emitDebug ("; genCpl");
8217 emitDebug ("; genUminus");
8222 emitDebug ("; genIpush");
8227 /* IPOP happens only when trying to restore a
8228 spilt live range, if there is an ifx statement
8229 following this pop then the if statement might
8230 be using some of the registers being popped which
8231 would destroy the contents of the register so
8232 we need to check for this condition and handle it */
8234 ic->next->op == IFX &&
8235 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8237 emitDebug ("; genIfx");
8238 genIfx (ic->next, ic);
8242 emitDebug ("; genIpop");
8248 emitDebug ("; genCall");
8253 emitDebug ("; genPcall");
8258 emitDebug ("; genFunction");
8263 emitDebug ("; genEndFunction");
8264 genEndFunction (ic);
8268 emitDebug ("; genRet");
8273 emitDebug ("; genLabel");
8278 emitDebug ("; genGoto");
8283 emitDebug ("; genPlus");
8288 emitDebug ("; genMinus");
8293 emitDebug ("; genMult");
8298 emitDebug ("; genDiv");
8303 emitDebug ("; genMod");
8308 emitDebug ("; genCmpGt");
8309 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8313 emitDebug ("; genCmpLt");
8314 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8321 /* note these two are xlated by algebraic equivalence
8322 during parsing SDCC.y */
8323 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8324 "got '>=' or '<=' shouldn't have come here");
8328 emitDebug ("; genCmpEq");
8329 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8333 emitDebug ("; genAndOp");
8338 emitDebug ("; genOrOp");
8343 emitDebug ("; genXor");
8344 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8348 emitDebug ("; genOr");
8349 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8353 emitDebug ("; genAnd");
8354 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8358 emitDebug ("; genInline");
8363 emitDebug ("; genRRC");
8368 emitDebug ("; genRLC");
8373 emitDebug ("; genGetHBIT");
8378 emitDebug ("; genLeftShift");
8383 emitDebug ("; genRightShift");
8387 case GET_VALUE_AT_ADDRESS:
8388 emitDebug ("; genPointerGet");
8394 if (POINTER_SET (ic))
8396 emitDebug ("; genAssign (pointer)");
8401 emitDebug ("; genAssign");
8407 emitDebug ("; genIfx");
8412 emitDebug ("; genAddrOf");
8417 emitDebug ("; genJumpTab");
8422 emitDebug ("; genCast");
8427 emitDebug ("; genReceive");
8432 if (ic->builtinSEND)
8434 emitDebug ("; genBuiltIn");
8439 emitDebug ("; addSet");
8440 addSet (&_G.sendSet, ic);
8445 emitDebug ("; genArrayInit");
8449 case DUMMY_READ_VOLATILE:
8450 emitDebug ("; genDummyRead");
8455 emitDebug ("; genCritical");
8460 emitDebug ("; genEndCritical");
8461 genEndCritical (ic);
8470 /* now we are ready to call the
8471 peep hole optimizer */
8472 if (!options.nopeep)
8473 peepHole (&_G.lines.head);
8475 /* This is unfortunate */
8476 /* now do the actual printing */
8478 struct dbuf_s *buf = codeOutBuf;
8479 if (isInHome () && codeOutBuf == &code->oBuf)
8480 codeOutBuf = &home->oBuf;
8481 printLine (_G.lines.head, codeOutBuf);
8482 if (_G.flushStatics)
8485 _G.flushStatics = 0;
8490 freeTrace(&_G.lines.trace);
8491 freeTrace(&_G.trace.aops);
8497 _isPairUsed (iCode * ic, PAIR_ID pairId)
8503 if (bitVectBitValue (ic->rMask, D_IDX))
8505 if (bitVectBitValue (ic->rMask, E_IDX))
8515 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8518 value *val = aop->aopu.aop_lit;
8520 wassert (aop->type == AOP_LIT);
8521 wassert (!IS_FLOAT (val->type));
8523 v = ulFromVal (val);
8531 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8532 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));