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 = (unsigned long) floatFromVal (val);
1269 else if (offset == 0)
1275 wassertl(0, "Encountered an invalid offset while fetching a literal");
1279 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1281 tsprintf (buffer, sizeof(buffer), "!constword", v);
1283 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1294 /* it is type float */
1295 fl.f = (float) floatFromVal (val);
1297 #ifdef WORDS_BIGENDIAN
1298 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1300 i = fl.c[offset] | (fl.c[offset+1]<<8);
1303 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1305 tsprintf (buffer, sizeof(buffer), "!constword", i);
1307 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1316 aopGetWord (asmop * aop, int offset)
1318 return aopGetLitWordLong (aop, offset, TRUE);
1322 isPtr (const char *s)
1324 if (!strcmp (s, "hl"))
1326 if (!strcmp (s, "ix"))
1328 if (!strcmp (s, "iy"))
1334 adjustPair (const char *pair, int *pold, int new)
1340 emit2 ("inc %s", pair);
1345 emit2 ("dec %s", pair);
1353 spillPair (PAIR_HL);
1354 spillPair (PAIR_IY);
1358 requiresHL (asmop * aop)
1374 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1376 const char *l, *base;
1377 const char *pair = _pairs[pairId].name;
1378 l = aopGetLitWordLong (left, offset, FALSE);
1379 base = aopGetLitWordLong (left, 0, FALSE);
1380 wassert (l && pair && base);
1384 if (pairId == PAIR_HL || pairId == PAIR_IY)
1386 if (_G.pairs[pairId].last_type == left->type)
1388 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1390 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1392 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1395 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1402 _G.pairs[pairId].last_type = left->type;
1403 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1404 _G.pairs[pairId].offset = offset;
1406 /* Both a lit on the right and a true symbol on the left */
1407 emit2 ("ld %s,!hashedstr", pair, l);
1411 makeFreePairId (iCode *ic, bool *pisUsed)
1417 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1421 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1439 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1441 /* if this is remateriazable */
1442 if (isLitWord (aop)) {
1443 fetchLitPair (pairId, aop, offset);
1447 if (getPairId (aop) == pairId)
1451 /* we need to get it byte by byte */
1452 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1453 aopGet (aop, offset, FALSE);
1454 switch (aop->size - offset) {
1456 emit2 ("ld l,!*hl");
1457 emit2 ("ld h,!immedbyte", 0);
1460 // PENDING: Requires that you are only fetching two bytes.
1463 emit2 ("ld h,!*hl");
1467 wassertl (0, "Attempted to fetch too much data into HL");
1471 else if (IS_Z80 && aop->type == AOP_IY) {
1472 /* Instead of fetching relative to IY, just grab directly
1473 from the address IY refers to */
1474 char *l = aopGetLitWordLong (aop, offset, FALSE);
1476 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1478 if (aop->size < 2) {
1479 emit2("ld %s,!zero", _pairs[pairId].h);
1482 else if (pairId == PAIR_IY)
1486 emit2 ("push %s", _pairs[getPairId(aop)].name);
1492 PAIR_ID id = makeFreePairId (ic, &isUsed);
1495 /* Can't load into parts, so load into HL then exchange. */
1496 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1497 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1498 emit2 ("push %s", _pairs[id].name);
1504 else if (isUnsplitable(aop))
1506 emit2("push %s", _pairs[getPairId(aop)].name);
1507 emit2("pop %s", _pairs[pairId].name);
1511 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1512 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1514 /* PENDING: check? */
1515 if (pairId == PAIR_HL)
1516 spillPair (PAIR_HL);
1521 fetchPair (PAIR_ID pairId, asmop * aop)
1523 fetchPairLong (pairId, aop, NULL, 0);
1527 fetchHL (asmop * aop)
1529 fetchPair (PAIR_HL, aop);
1533 setupPairFromSP (PAIR_ID id, int offset)
1535 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1537 if (_G.preserveCarry)
1543 if (offset < INT8MIN || offset > INT8MAX)
1545 emit2 ("ld hl,!immedword", offset);
1546 emit2 ("add hl,sp");
1550 emit2 ("!ldahlsp", offset);
1553 if (_G.preserveCarry)
1561 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1566 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1567 fetchLitPair (pairId, aop, 0);
1571 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1573 fetchLitPair (pairId, aop, offset);
1574 _G.pairs[pairId].offset = offset;
1578 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1579 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1582 int offset = aop->aopu.aop_stk + _G.stack.offset;
1584 if (_G.pairs[pairId].last_type == aop->type &&
1585 _G.pairs[pairId].offset == offset)
1591 /* PENDING: Do this better. */
1592 if (_G.preserveCarry)
1594 sprintf (buffer, "%d", offset + _G.stack.pushed);
1595 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1596 emit2 ("add %s,sp", _pairs[pairId].name);
1597 _G.pairs[pairId].last_type = aop->type;
1598 _G.pairs[pairId].offset = offset;
1599 if (_G.preserveCarry)
1607 /* Doesnt include _G.stack.pushed */
1608 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1610 if (aop->aopu.aop_stk > 0)
1612 abso += _G.stack.param_offset;
1614 assert (pairId == PAIR_HL);
1615 /* In some cases we can still inc or dec hl */
1616 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1618 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1622 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1624 _G.pairs[pairId].offset = abso;
1629 if (pairId != aop->aopu.aop_pairId)
1630 genMovePairPair(aop->aopu.aop_pairId, pairId);
1631 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1637 _G.pairs[pairId].last_type = aop->type;
1643 emit2 ("!tlabeldef", key);
1644 _G.lines.current->isLabel = 1;
1648 /*-----------------------------------------------------------------*/
1649 /* aopGet - for fetching value of the aop */
1650 /*-----------------------------------------------------------------*/
1652 aopGet (asmop * aop, int offset, bool bit16)
1654 // char *s = buffer;
1656 /* offset is greater than size then zero */
1657 /* PENDING: this seems a bit screwed in some pointer cases. */
1658 if (offset > (aop->size - 1) &&
1659 aop->type != AOP_LIT)
1661 tsprintf (buffer, sizeof(buffer), "!zero");
1662 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1665 /* depending on type */
1669 tsprintf (buffer, sizeof(buffer), "!zero");
1670 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1673 /* PENDING: re-target */
1675 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1680 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1683 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1686 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1689 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1692 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1696 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1697 SNPRINTF (buffer, sizeof(buffer), "a");
1699 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1705 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1706 SNPRINTF (buffer, sizeof(buffer), "a");
1708 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1711 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1714 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1715 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1716 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1718 else if( z80_opts.port_mode == 180 )
1719 { /* z180 in0/out0 mode */
1720 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1724 emit2( "in a,(%s)", aop->aopu.aop_dir );
1727 SNPRINTF (buffer, sizeof(buffer), "a");
1729 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1733 return aop->aopu.aop_reg[offset]->name;
1737 setupPair (PAIR_HL, aop, offset);
1738 tsprintf (buffer, sizeof(buffer), "!*hl");
1740 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1744 setupPair (PAIR_IY, aop, offset);
1745 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1747 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1751 setupPair (PAIR_IY, aop, offset);
1752 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1754 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1759 setupPair (PAIR_HL, aop, offset);
1760 tsprintf (buffer, sizeof(buffer), "!*hl");
1764 if (aop->aopu.aop_stk >= 0)
1765 offset += _G.stack.param_offset;
1766 tsprintf (buffer, sizeof(buffer),
1767 "!*ixx", aop->aopu.aop_stk + offset);
1770 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1773 wassertl (0, "Tried to fetch from a bit variable");
1782 tsprintf(buffer, sizeof(buffer), "!zero");
1783 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1787 wassert (offset < 2);
1788 return aop->aopu.aop_str[offset];
1791 return aopLiteral (aop->aopu.aop_lit, offset);
1795 unsigned long v = aop->aopu.aop_simplelit;
1798 tsprintf (buffer, sizeof(buffer),
1799 "!immedbyte", (unsigned int) v & 0xff);
1801 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1805 return aop->aopu.aop_str[offset];
1808 setupPair (aop->aopu.aop_pairId, aop, offset);
1809 if (aop->aopu.aop_pairId==PAIR_IX)
1810 SNPRINTF (buffer, sizeof(buffer),
1812 else if (aop->aopu.aop_pairId==PAIR_IY)
1813 SNPRINTF (buffer, sizeof(buffer),
1816 SNPRINTF (buffer, sizeof(buffer),
1817 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1819 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1824 wassertl (0, "aopget got unsupported aop->type");
1829 isRegString (const char *s)
1831 if (!strcmp (s, "b") ||
1843 isConstant (const char *s)
1845 /* This is a bit of a hack... */
1846 return (*s == '#' || *s == '$');
1850 canAssignToPtr (const char *s)
1852 if (isRegString (s))
1859 /*-----------------------------------------------------------------*/
1860 /* aopPut - puts a string for a aop */
1861 /*-----------------------------------------------------------------*/
1863 aopPut (asmop * aop, const char *s, int offset)
1867 if (aop->size && offset > (aop->size - 1))
1869 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1870 "aopPut got offset > aop->size");
1875 tsprintf(buffer2, sizeof(buffer2), s);
1878 /* will assign value to value */
1879 /* depending on where it is ofcourse */
1883 _moveA (s); /* in case s is volatile */
1889 if (strcmp (s, "a"))
1890 emit2 ("ld a,%s", s);
1891 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1898 if (strcmp (s, "a"))
1899 emit2 ("ld a,%s", s);
1900 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1903 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1910 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1911 && s[0] != 'h' && s[0] != 'l'))
1913 emit2( "ld a,%s", s );
1917 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1918 emit2( "out (c),%s", s );
1923 spillPair (PAIR_BC);
1925 else if( z80_opts.port_mode == 180 )
1926 { /* z180 in0/out0 mode */
1927 emit2( "ld a,%s", s );
1928 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1932 emit2( "ld a,%s", s );
1933 emit2( "out (%s),a", aop->aopu.aop_dir );
1939 if (!strcmp (s, "!*hl"))
1940 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1943 aop->aopu.aop_reg[offset]->name, s);
1944 spillPairReg(aop->aopu.aop_reg[offset]->name);
1949 if (!canAssignToPtr (s))
1951 emit2 ("ld a,%s", s);
1952 setupPair (PAIR_IY, aop, offset);
1953 emit2 ("ld !*iyx,a", offset);
1957 setupPair (PAIR_IY, aop, offset);
1958 emit2 ("ld !*iyx,%s", offset, s);
1964 /* PENDING: for re-target */
1965 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1967 emit2 ("ld a,!*hl");
1970 setupPair (PAIR_HL, aop, offset);
1972 emit2 ("ld !*hl,%s", s);
1977 if (!canAssignToPtr (s))
1979 emit2 ("ld a,%s", s);
1980 setupPair (PAIR_IY, aop, offset);
1981 emit2 ("ld !*iyx,a", offset);
1985 setupPair (PAIR_IY, aop, offset);
1986 emit2 ("ld !*iyx,%s", offset, s);
1993 /* PENDING: re-target */
1994 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1996 emit2 ("ld a,!*hl");
1999 setupPair (PAIR_HL, aop, offset);
2000 if (!canAssignToPtr (s))
2002 emit2 ("ld a,%s", s);
2003 emit2 ("ld !*hl,a");
2006 emit2 ("ld !*hl,%s", s);
2010 if (aop->aopu.aop_stk >= 0)
2011 offset += _G.stack.param_offset;
2012 if (!canAssignToPtr (s))
2014 emit2 ("ld a,%s", s);
2015 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2019 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2025 /* if bit variable */
2026 if (!aop->aopu.aop_dir)
2028 emit2 ("ld a,!zero");
2033 /* In bit space but not in C - cant happen */
2034 wassertl (0, "Tried to write into a bit variable");
2040 if (strcmp (aop->aopu.aop_str[offset], s))
2042 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2044 spillPairReg(aop->aopu.aop_str[offset]);
2049 if (!offset && (strcmp (s, "acc") == 0))
2053 wassertl (0, "Tried to access past the end of A");
2057 if (strcmp (aop->aopu.aop_str[offset], s))
2059 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2060 spillPairReg(aop->aopu.aop_str[offset]);
2066 wassert (offset < 2);
2067 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2068 spillPairReg(aop->aopu.aop_str[offset]);
2072 setupPair (aop->aopu.aop_pairId, aop, offset);
2073 if (aop->aopu.aop_pairId==PAIR_IX)
2074 emit2 ("ld !*ixx,%s", 0, s);
2075 else if (aop->aopu.aop_pairId==PAIR_IY)
2076 emit2 ("ld !*iyx,%s", 0, s);
2078 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2082 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2083 "aopPut got unsupported aop->type");
2088 #define AOP(op) op->aop
2089 #define AOP_TYPE(op) AOP(op)->type
2090 #define AOP_SIZE(op) AOP(op)->size
2091 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2092 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2095 commitPair (asmop * aop, PAIR_ID id)
2097 /* PENDING: Verify this. */
2098 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2102 aopPut (aop, "a", 0);
2103 aopPut (aop, "d", 1);
2108 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2110 char *l = aopGetLitWordLong (aop, 0, FALSE);
2113 emit2 ("ld (%s),%s", l, _pairs[id].name);
2117 aopPut (aop, _pairs[id].l, 0);
2118 aopPut (aop, _pairs[id].h, 1);
2123 /*-----------------------------------------------------------------*/
2124 /* getDataSize - get the operand data size */
2125 /*-----------------------------------------------------------------*/
2127 getDataSize (operand * op)
2130 size = AOP_SIZE (op);
2134 wassertl (0, "Somehow got a three byte data pointer");
2139 /*-----------------------------------------------------------------*/
2140 /* movLeft2Result - move byte from left to result */
2141 /*-----------------------------------------------------------------*/
2143 movLeft2Result (operand * left, int offl,
2144 operand * result, int offr, int sign)
2148 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2150 l = aopGet (AOP (left), offl, FALSE);
2154 aopPut (AOP (result), l, offr);
2158 if (getDataSize (left) == offl + 1)
2160 emit2 ("ld a,%s", l);
2161 aopPut (AOP (result), "a", offr);
2168 movLeft2ResultLong (operand * left, int offl,
2169 operand * result, int offr, int sign,
2174 movLeft2Result (left, offl, result, offr, sign);
2178 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2179 wassertl (size == 2, "Only implemented for two bytes or one");
2181 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2183 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2184 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2186 spillPair (PAIR_HL);
2188 else if ( getPairId ( AOP (result)) == PAIR_IY)
2190 PAIR_ID id = getPairId (AOP (left));
2191 if (id != PAIR_INVALID)
2193 emit2("push %s", _pairs[id].name);
2204 movLeft2Result (left, offl, result, offr, sign);
2205 movLeft2Result (left, offl+1, result, offr+1, sign);
2210 /** Put Acc into a register set
2213 outAcc (operand * result)
2216 size = getDataSize (result);
2219 aopPut (AOP (result), "a", 0);
2222 /* unsigned or positive */
2225 aopPut (AOP (result), "!zero", offset++);
2230 /** Take the value in carry and put it into a register
2233 outBitC (operand * result)
2235 /* if the result is bit */
2236 if (AOP_TYPE (result) == AOP_CRY)
2238 if (!IS_OP_RUONLY (result))
2239 aopPut (AOP (result), "c", 0);
2243 emit2 ("ld a,!zero");
2249 /*-----------------------------------------------------------------*/
2250 /* toBoolean - emit code for orl a,operator(sizeop) */
2251 /*-----------------------------------------------------------------*/
2253 _toBoolean (operand * oper)
2255 int size = AOP_SIZE (oper);
2259 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2262 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2266 if (AOP (oper)->type != AOP_ACC)
2269 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2275 /*-----------------------------------------------------------------*/
2276 /* genNot - generate code for ! operation */
2277 /*-----------------------------------------------------------------*/
2282 /* assign asmOps to operand & result */
2283 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2284 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2286 /* if in bit space then a special case */
2287 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2289 wassertl (0, "Tried to negate a bit");
2292 _toBoolean (IC_LEFT (ic));
2297 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2298 emit2 ("sub a,!one");
2299 outBitC (IC_RESULT (ic));
2301 /* release the aops */
2302 freeAsmop (IC_LEFT (ic), NULL, ic);
2303 freeAsmop (IC_RESULT (ic), NULL, ic);
2306 /*-----------------------------------------------------------------*/
2307 /* genCpl - generate code for complement */
2308 /*-----------------------------------------------------------------*/
2316 /* assign asmOps to operand & result */
2317 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2318 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2320 /* if both are in bit space then
2322 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2323 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2325 wassertl (0, "Left and the result are in bit space");
2328 size = AOP_SIZE (IC_RESULT (ic));
2331 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2334 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2337 /* release the aops */
2338 freeAsmop (IC_LEFT (ic), NULL, ic);
2339 freeAsmop (IC_RESULT (ic), NULL, ic);
2343 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2350 store de into result
2355 store de into result
2357 const char *first = isAdd ? "add" : "sub";
2358 const char *later = isAdd ? "adc" : "sbc";
2360 wassertl (IS_GB, "Code is only relevent to the gbz80");
2361 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2363 fetchPair (PAIR_DE, left);
2366 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2369 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2372 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2373 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2375 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2376 aopGet (right, MSB24, FALSE);
2380 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2383 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2385 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2386 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2390 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2392 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2395 /*-----------------------------------------------------------------*/
2396 /* genUminusFloat - unary minus for floating points */
2397 /*-----------------------------------------------------------------*/
2399 genUminusFloat (operand * op, operand * result)
2401 int size, offset = 0;
2403 emitDebug("; genUminusFloat");
2405 /* for this we just need to flip the
2406 first bit then copy the rest in place */
2407 size = AOP_SIZE (op) - 1;
2409 _moveA(aopGet (AOP (op), MSB32, FALSE));
2411 emit2("xor a,!immedbyte", 0x80);
2412 aopPut (AOP (result), "a", MSB32);
2416 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2421 /*-----------------------------------------------------------------*/
2422 /* genUminus - unary minus code generation */
2423 /*-----------------------------------------------------------------*/
2425 genUminus (iCode * ic)
2428 sym_link *optype, *rtype;
2431 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2432 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2434 /* if both in bit space then special
2436 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2437 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2439 wassertl (0, "Left and right are in bit space");
2443 optype = operandType (IC_LEFT (ic));
2444 rtype = operandType (IC_RESULT (ic));
2446 /* if float then do float stuff */
2447 if (IS_FLOAT (optype))
2449 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2453 /* otherwise subtract from zero */
2454 size = AOP_SIZE (IC_LEFT (ic));
2456 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2458 /* Create a new asmop with value zero */
2459 asmop *azero = newAsmop (AOP_SIMPLELIT);
2460 azero->aopu.aop_simplelit = 0;
2462 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2470 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2471 emit2 ("ld a,!zero");
2472 emit2 ("sbc a,%s", l);
2473 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2476 /* if any remaining bytes in the result */
2477 /* we just need to propagate the sign */
2478 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2483 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2487 /* release the aops */
2488 freeAsmop (IC_LEFT (ic), NULL, ic);
2489 freeAsmop (IC_RESULT (ic), NULL, ic);
2492 /*-----------------------------------------------------------------*/
2493 /* assignResultValue - */
2494 /*-----------------------------------------------------------------*/
2496 assignResultValue (operand * oper)
2498 int size = AOP_SIZE (oper);
2501 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2502 topInA = requiresHL (AOP (oper));
2504 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2506 /* We do it the hard way here. */
2508 aopPut (AOP (oper), _fReturn[0], 0);
2509 aopPut (AOP (oper), _fReturn[1], 1);
2511 aopPut (AOP (oper), _fReturn[0], 2);
2512 aopPut (AOP (oper), _fReturn[1], 3);
2516 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2517 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2520 _emitMove ("a", _fReturn[size-1]);
2521 _emitMove (_fReturn[size-1], _fReturn[size]);
2522 _emitMove (_fReturn[size], "a");
2523 aopPut (AOP (oper), _fReturn[size], size-1);
2528 aopPut (AOP (oper), _fReturn[size], size);
2533 /** Simple restore that doesn't take into account what is used in the
2537 _restoreRegsAfterCall(void)
2539 if (_G.stack.pushedDE)
2542 _G.stack.pushedDE = FALSE;
2544 if (_G.stack.pushedBC)
2547 _G.stack.pushedBC = FALSE;
2549 _G.saves.saved = FALSE;
2553 _saveRegsForCall(iCode *ic, int sendSetSize)
2556 o Stack parameters are pushed before this function enters
2557 o DE and BC may be used in this function.
2558 o HL and DE may be used to return the result.
2559 o HL and DE may be used to send variables.
2560 o DE and BC may be used to store the result value.
2561 o HL may be used in computing the sent value of DE
2562 o The iPushes for other parameters occur before any addSets
2564 Logic: (to be run inside the first iPush or if none, before sending)
2565 o Compute if DE and/or BC are in use over the call
2566 o Compute if DE is used in the send set
2567 o Compute if DE and/or BC are used to hold the result value
2568 o If (DE is used, or in the send set) and is not used in the result, push.
2569 o If BC is used and is not in the result, push
2571 o If DE is used in the send set, fetch
2572 o If HL is used in the send set, fetch
2576 if (_G.saves.saved == FALSE) {
2577 bool deInUse, bcInUse;
2579 bool bcInRet = FALSE, deInRet = FALSE;
2582 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2583 z80_rUmaskForOp (IC_RESULT(ic)));
2585 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2586 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2588 deSending = (sendSetSize > 1);
2590 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2592 if (bcInUse && bcInRet == FALSE) {
2594 _G.stack.pushedBC = TRUE;
2596 if (deInUse && deInRet == FALSE) {
2598 _G.stack.pushedDE = TRUE;
2601 _G.saves.saved = TRUE;
2604 /* Already saved. */
2608 /*-----------------------------------------------------------------*/
2609 /* genIpush - genrate code for pushing this gets a little complex */
2610 /*-----------------------------------------------------------------*/
2612 genIpush (iCode * ic)
2614 int size, offset = 0;
2617 /* if this is not a parm push : ie. it is spill push
2618 and spill push is always done on the local stack */
2621 wassertl(0, "Encountered an unsupported spill push.");
2625 if (_G.saves.saved == FALSE) {
2626 /* Caller saves, and this is the first iPush. */
2627 /* Scan ahead until we find the function that we are pushing parameters to.
2628 Count the number of addSets on the way to figure out what registers
2629 are used in the send set.
2632 iCode *walk = ic->next;
2635 if (walk->op == SEND) {
2638 else if (walk->op == CALL || walk->op == PCALL) {
2647 _saveRegsForCall(walk, nAddSets);
2650 /* Already saved by another iPush. */
2653 /* then do the push */
2654 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2656 size = AOP_SIZE (IC_LEFT (ic));
2658 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2660 _G.stack.pushed += 2;
2661 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2667 fetchHL (AOP (IC_LEFT (ic)));
2669 spillPair (PAIR_HL);
2670 _G.stack.pushed += 2;
2675 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2677 spillPair (PAIR_HL);
2678 _G.stack.pushed += 2;
2679 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2681 spillPair (PAIR_HL);
2682 _G.stack.pushed += 2;
2688 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2690 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2692 emit2 ("ld a,(%s)", l);
2697 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2698 if (!strcmp(l, "b"))
2700 else if (!strcmp(l, "d"))
2702 else if (!strcmp(l, "h"))
2706 emit2 ("ld a,%s", l);
2715 freeAsmop (IC_LEFT (ic), NULL, ic);
2718 /*-----------------------------------------------------------------*/
2719 /* genIpop - recover the registers: can happen only for spilling */
2720 /*-----------------------------------------------------------------*/
2722 genIpop (iCode * ic)
2727 /* if the temp was not pushed then */
2728 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2731 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2732 size = AOP_SIZE (IC_LEFT (ic));
2733 offset = (size - 1);
2734 if (isPair (AOP (IC_LEFT (ic))))
2736 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2744 spillPair (PAIR_HL);
2745 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2749 freeAsmop (IC_LEFT (ic), NULL, ic);
2752 /* This is quite unfortunate */
2754 setArea (int inHome)
2757 static int lastArea = 0;
2759 if (_G.in_home != inHome) {
2761 const char *sz = port->mem.code_name;
2762 port->mem.code_name = "HOME";
2763 emit2("!area", CODE_NAME);
2764 port->mem.code_name = sz;
2767 emit2("!area", CODE_NAME); */
2768 _G.in_home = inHome;
2779 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2783 symbol *sym = OP_SYMBOL (op);
2785 if (sym->isspilt || sym->nRegs == 0)
2788 aopOp (op, ic, FALSE, FALSE);
2791 if (aop->type == AOP_REG)
2794 for (i = 0; i < aop->size; i++)
2796 if (pairId == PAIR_DE)
2798 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2799 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2801 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2804 else if (pairId == PAIR_BC)
2806 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2807 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2809 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2819 freeAsmop (IC_LEFT (ic), NULL, ic);
2823 /** Emit the code for a call statement
2826 emitCall (iCode * ic, bool ispcall)
2828 bool bInRet, cInRet, dInRet, eInRet;
2829 sym_link *dtype = operandType (IC_LEFT (ic));
2831 /* if caller saves & we have not saved then */
2837 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2839 /* if send set is not empty then assign */
2844 int nSend = elementsInSet(_G.sendSet);
2845 bool swapped = FALSE;
2847 int _z80_sendOrder[] = {
2852 /* Check if the parameters are swapped. If so route through hl instead. */
2853 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2855 sic = setFirstItem(_G.sendSet);
2856 sic = setNextItem(_G.sendSet);
2858 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2859 /* The second send value is loaded from one the one that holds the first
2860 send, i.e. it is overwritten. */
2861 /* Cache the first in HL, and load the second from HL instead. */
2862 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2863 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2869 for (sic = setFirstItem (_G.sendSet); sic;
2870 sic = setNextItem (_G.sendSet))
2873 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2875 size = AOP_SIZE (IC_LEFT (sic));
2876 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2877 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2879 // PENDING: Mild hack
2880 if (swapped == TRUE && send == 1) {
2882 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2885 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2887 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2890 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2894 freeAsmop (IC_LEFT (sic), NULL, sic);
2901 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2903 werror (W_INDIR_BANKED);
2905 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2907 if (isLitWord (AOP (IC_LEFT (ic))))
2909 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2913 symbol *rlbl = newiTempLabel (NULL);
2914 spillPair (PAIR_HL);
2915 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2917 _G.stack.pushed += 2;
2919 fetchHL (AOP (IC_LEFT (ic)));
2921 emit2 ("!tlabeldef", (rlbl->key + 100));
2922 _G.lines.current->isLabel = 1;
2923 _G.stack.pushed -= 2;
2925 freeAsmop (IC_LEFT (ic), NULL, ic);
2929 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2930 OP_SYMBOL (IC_LEFT (ic))->rname :
2931 OP_SYMBOL (IC_LEFT (ic))->name;
2932 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2934 emit2 ("call banked_call");
2935 emit2 ("!dws", name);
2936 emit2 ("!dw !bankimmeds", name);
2941 emit2 ("call %s", name);
2946 /* Mark the registers as restored. */
2947 _G.saves.saved = FALSE;
2949 /* if we need assign a result value */
2950 if ((IS_ITEMP (IC_RESULT (ic)) &&
2951 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2952 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2953 IS_TRUE_SYMOP (IC_RESULT (ic)))
2955 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2957 assignResultValue (IC_RESULT (ic));
2959 freeAsmop (IC_RESULT (ic), NULL, ic);
2962 /* adjust the stack for parameters if required */
2965 int i = ic->parmBytes;
2967 _G.stack.pushed -= i;
2970 emit2 ("!ldaspsp", i);
2977 emit2 ("ld iy,!immedword", i);
2978 emit2 ("add iy,sp");
2999 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3000 bInRet = bitVectBitValue(result, B_IDX);
3001 cInRet = bitVectBitValue(result, C_IDX);
3002 dInRet = bitVectBitValue(result, D_IDX);
3003 eInRet = bitVectBitValue(result, E_IDX);
3013 if (_G.stack.pushedDE)
3015 if (dInRet && eInRet)
3017 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3021 /* Only restore E */
3028 /* Only restore D */
3036 _G.stack.pushedDE = FALSE;
3039 if (_G.stack.pushedBC)
3041 if (bInRet && cInRet)
3043 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3047 /* Only restore C */
3054 /* Only restore B */
3062 _G.stack.pushedBC = FALSE;
3066 /*-----------------------------------------------------------------*/
3067 /* genCall - generates a call statement */
3068 /*-----------------------------------------------------------------*/
3070 genCall (iCode * ic)
3072 emitCall (ic, FALSE);
3075 /*-----------------------------------------------------------------*/
3076 /* genPcall - generates a call by pointer statement */
3077 /*-----------------------------------------------------------------*/
3079 genPcall (iCode * ic)
3081 emitCall (ic, TRUE);
3084 /*-----------------------------------------------------------------*/
3085 /* resultRemat - result is rematerializable */
3086 /*-----------------------------------------------------------------*/
3088 resultRemat (iCode * ic)
3090 if (SKIP_IC (ic) || ic->op == IFX)
3093 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3095 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3096 if (sym->remat && !POINTER_SET (ic))
3103 extern set *publics;
3105 /*-----------------------------------------------------------------*/
3106 /* genFunction - generated code for function entry */
3107 /*-----------------------------------------------------------------*/
3109 genFunction (iCode * ic)
3113 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3116 bool bcInUse = FALSE;
3117 bool deInUse = FALSE;
3119 setArea (IFFUNC_NONBANKED (sym->type));
3121 /* PENDING: Reset the receive offset as it
3122 doesn't seem to get reset anywhere else.
3124 _G.receiveOffset = 0;
3126 /* Record the last function name for debugging. */
3127 _G.lastFunctionName = sym->rname;
3129 /* Create the function header */
3130 emit2 ("!functionheader", sym->name);
3131 if (!IS_STATIC(sym->etype))
3133 sprintf (buffer, "%s_start", sym->rname);
3134 emit2 ("!labeldef", buffer);
3135 _G.lines.current->isLabel = 1;
3137 emit2 ("!functionlabeldef", sym->rname);
3138 _G.lines.current->isLabel = 1;
3140 ftype = operandType (IC_LEFT (ic));
3142 if (IFFUNC_ISNAKED(ftype))
3144 emitDebug("; naked function: no prologue.");
3148 /* if this is an interrupt service routine
3149 then save all potentially used registers. */
3150 if (IFFUNC_ISISR (sym->type))
3152 /* If critical function then turn interrupts off */
3153 /* except when no interrupt number is given then it implies the NMI handler */
3154 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3163 /* This is a non-ISR function.
3164 If critical function then turn interrupts off */
3165 if (IFFUNC_ISCRITICAL (sym->type))
3173 //get interrupt enable flag IFF2 into P/O
3182 if (options.profile)
3184 emit2 ("!profileenter");
3187 /* PENDING: callee-save etc */
3189 _G.stack.param_offset = 0;
3191 if (z80_opts.calleeSavesBC)
3196 /* Detect which registers are used. */
3197 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3200 for (i = 0; i < sym->regsUsed->size; i++)
3202 if (bitVectBitValue (sym->regsUsed, i))
3216 /* Other systems use DE as a temporary. */
3227 _G.stack.param_offset += 2;
3230 _G.calleeSaves.pushedBC = bcInUse;
3235 _G.stack.param_offset += 2;
3238 _G.calleeSaves.pushedDE = deInUse;
3240 /* adjust the stack for the function */
3241 _G.stack.last = sym->stack;
3244 for (sym = setFirstItem (istack->syms); sym;
3245 sym = setNextItem (istack->syms))
3247 if (sym->_isparm && !IS_REGPARM (sym->etype))
3253 sym = OP_SYMBOL (IC_LEFT (ic));
3255 _G.omitFramePtr = options.ommitFramePtr;
3256 if (IS_Z80 && !stackParm && !sym->stack)
3258 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3259 /* the above !sym->stack condition can be removed. -- EEP */
3261 emit2 ("!ldaspsp", -sym->stack);
3262 _G.omitFramePtr = TRUE;
3264 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3265 emit2 ("!enterxl", sym->stack);
3266 else if (sym->stack)
3267 emit2 ("!enterx", sym->stack);
3271 _G.stack.offset = sym->stack;
3274 /*-----------------------------------------------------------------*/
3275 /* genEndFunction - generates epilogue for functions */
3276 /*-----------------------------------------------------------------*/
3278 genEndFunction (iCode * ic)
3280 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3282 if (IFFUNC_ISNAKED(sym->type))
3284 emitDebug("; naked function: no epilogue.");
3288 /* PENDING: calleeSave */
3289 if (IS_Z80 && _G.omitFramePtr)
3291 if (_G.stack.offset)
3292 emit2 ("!ldaspsp", _G.stack.offset);
3294 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3296 emit2 ("!leavexl", _G.stack.offset);
3298 else if (_G.stack.offset)
3300 emit2 ("!leavex", _G.stack.offset);
3307 if (_G.calleeSaves.pushedDE)
3310 _G.calleeSaves.pushedDE = FALSE;
3313 if (_G.calleeSaves.pushedBC)
3316 _G.calleeSaves.pushedBC = FALSE;
3319 if (options.profile)
3321 emit2 ("!profileexit");
3324 /* if this is an interrupt service routine
3325 then save all potentially used registers. */
3326 if (IFFUNC_ISISR (sym->type))
3330 /* If critical function then turn interrupts back on */
3331 /* except when no interrupt number is given then it implies the NMI handler */
3332 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3339 /* This is a non-ISR function.
3340 If critical function then turn interrupts back on */
3341 if (IFFUNC_ISCRITICAL (sym->type))
3349 symbol *tlbl = newiTempLabel (NULL);
3352 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3353 //don't enable interrupts as they were off before
3354 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3356 emit2 ("!tlabeldef", (tlbl->key + 100));
3357 _G.lines.current->isLabel = 1;
3362 if (options.debug && currFunc)
3364 debugFile->writeEndFunction (currFunc, ic, 1);
3367 if (IFFUNC_ISISR (sym->type))
3369 /* "critical interrupt" is used to imply NMI handler */
3370 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3377 /* Both banked and non-banked just ret */
3381 if (!IS_STATIC(sym->etype))
3383 sprintf (buffer, "%s_end", sym->rname);
3384 emit2 ("!labeldef", buffer);
3385 _G.lines.current->isLabel = 1;
3388 _G.flushStatics = 1;
3389 _G.stack.pushed = 0;
3390 _G.stack.offset = 0;
3393 /*-----------------------------------------------------------------*/
3394 /* genRet - generate code for return statement */
3395 /*-----------------------------------------------------------------*/
3400 /* Errk. This is a hack until I can figure out how
3401 to cause dehl to spill on a call */
3402 int size, offset = 0;
3404 /* if we have no return value then
3405 just generate the "ret" */
3409 /* we have something to return then
3410 move the return value into place */
3411 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3412 size = AOP_SIZE (IC_LEFT (ic));
3414 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3417 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3421 emit2 ("ld de,%s", l);
3425 emit2 ("ld hl,%s", l);
3431 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3435 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3437 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3438 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3444 l = aopGet (AOP (IC_LEFT (ic)), offset,
3446 if (strcmp (_fReturn[offset], l))
3447 emit2 ("ld %s,%s", _fReturn[offset], l);
3452 freeAsmop (IC_LEFT (ic), NULL, ic);
3455 /* generate a jump to the return label
3456 if the next is not the return statement */
3457 if (!(ic->next && ic->next->op == LABEL &&
3458 IC_LABEL (ic->next) == returnLabel))
3460 emit2 ("jp !tlabel", returnLabel->key + 100);
3463 /*-----------------------------------------------------------------*/
3464 /* genLabel - generates a label */
3465 /*-----------------------------------------------------------------*/
3467 genLabel (iCode * ic)
3469 /* special case never generate */
3470 if (IC_LABEL (ic) == entryLabel)
3473 emitLabel (IC_LABEL (ic)->key + 100);
3476 /*-----------------------------------------------------------------*/
3477 /* genGoto - generates a ljmp */
3478 /*-----------------------------------------------------------------*/
3480 genGoto (iCode * ic)
3482 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3485 /*-----------------------------------------------------------------*/
3486 /* genPlusIncr :- does addition with increment if possible */
3487 /*-----------------------------------------------------------------*/
3489 genPlusIncr (iCode * ic)
3491 unsigned int icount;
3492 unsigned int size = getDataSize (IC_RESULT (ic));
3493 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3495 /* will try to generate an increment */
3496 /* if the right side is not a literal
3498 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3501 emitDebug ("; genPlusIncr");
3503 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3505 /* If result is a pair */
3506 if (resultId != PAIR_INVALID)
3508 if (isLitWord (AOP (IC_LEFT (ic))))
3510 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3513 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3515 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3517 PAIR_ID freep = getFreePairId (ic);
3518 if (freep != PAIR_INVALID)
3520 fetchPair (freep, AOP (IC_RIGHT (ic)));
3521 emit2 ("add hl,%s", _pairs[freep].name);
3527 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3528 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3535 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3539 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3543 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3548 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3550 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3551 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3555 /* if the literal value of the right hand side
3556 is greater than 4 then it is not worth it */
3560 /* if increment 16 bits in register */
3561 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3567 symbol *tlbl = NULL;
3568 tlbl = newiTempLabel (NULL);
3571 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3574 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3577 emitLabel (tlbl->key + 100);
3581 /* if the sizes are greater than 1 then we cannot */
3582 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3583 AOP_SIZE (IC_LEFT (ic)) > 1)
3586 /* If the result is in a register then we can load then increment.
3588 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3590 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3593 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3598 /* we can if the aops of the left & result match or
3599 if they are in registers and the registers are the
3601 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3605 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3613 /*-----------------------------------------------------------------*/
3614 /* outBitAcc - output a bit in acc */
3615 /*-----------------------------------------------------------------*/
3617 outBitAcc (operand * result)
3619 symbol *tlbl = newiTempLabel (NULL);
3620 /* if the result is a bit */
3621 if (AOP_TYPE (result) == AOP_CRY)
3623 wassertl (0, "Tried to write A into a bit");
3627 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3628 emit2 ("ld a,!one");
3629 emitLabel (tlbl->key + 100);
3635 couldDestroyCarry (asmop *aop)
3639 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3648 shiftIntoPair (int idx, asmop *aop)
3650 PAIR_ID id = PAIR_INVALID;
3652 wassertl (IS_Z80, "Only implemented for the Z80");
3653 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3655 emitDebug ("; Shift into pair idx %u", idx);
3661 setupPair (PAIR_HL, aop, 0);
3666 setupPair (PAIR_IY, aop, 0);
3668 emit2 ("pop %s", _pairs[id].name);
3672 setupPair (PAIR_IY, aop, 0);
3675 wassertl (0, "Internal error - hit default case");
3678 aop->type = AOP_PAIRPTR;
3679 aop->aopu.aop_pairId = id;
3680 _G.pairs[id].offset = 0;
3681 _G.pairs[id].last_type = aop->type;
3685 setupToPreserveCarry (iCode * ic)
3687 asmop *left = AOP (IC_LEFT (ic));
3688 asmop *right = AOP (IC_RIGHT (ic));
3689 asmop *result = AOP (IC_RESULT (ic));
3691 wassert (left && right);
3695 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3697 shiftIntoPair (0, right);
3698 /* check result again, in case right == result */
3699 if (couldDestroyCarry (result))
3701 if (!isPairInUse (PAIR_DE, ic))
3702 shiftIntoPair (1, result);
3704 shiftIntoPair (2, result);
3707 else if (couldDestroyCarry (right))
3709 if (getPairId (result) == PAIR_HL)
3710 _G.preserveCarry = TRUE;
3712 shiftIntoPair (0, right);
3714 else if (couldDestroyCarry (result))
3716 shiftIntoPair (0, result);
3725 /*-----------------------------------------------------------------*/
3726 /* genPlus - generates code for addition */
3727 /*-----------------------------------------------------------------*/
3729 genPlus (iCode * ic)
3731 int size, offset = 0;
3733 /* special cases :- */
3735 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3736 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3737 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3739 /* Swap the left and right operands if:
3741 if literal, literal on the right or
3742 if left requires ACC or right is already
3745 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3746 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3747 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3749 operand *t = IC_RIGHT (ic);
3750 IC_RIGHT (ic) = IC_LEFT (ic);
3754 /* if both left & right are in bit
3756 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3757 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3760 wassertl (0, "Tried to add two bits");
3763 /* if left in bit space & right literal */
3764 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3765 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3767 /* Can happen I guess */
3768 wassertl (0, "Tried to add a bit to a literal");
3771 /* if I can do an increment instead
3772 of add then GOOD for ME */
3773 if (genPlusIncr (ic) == TRUE)
3776 size = getDataSize (IC_RESULT (ic));
3778 /* Special case when left and right are constant */
3779 if (isPair (AOP (IC_RESULT (ic))))
3782 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3783 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3785 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3791 sprintf (buffer, "#(%s + %s)", left, right);
3792 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3797 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3799 /* Fetch into HL then do the add */
3800 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3801 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3803 spillPair (PAIR_HL);
3805 if (left == PAIR_HL && right != PAIR_INVALID)
3807 emit2 ("add hl,%s", _pairs[right].name);
3810 else if (right == PAIR_HL && left != PAIR_INVALID)
3812 emit2 ("add hl,%s", _pairs[left].name);
3815 else if (right != PAIR_INVALID && right != PAIR_HL)
3817 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3818 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3821 else if (left != PAIR_INVALID && left != PAIR_HL)
3823 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3824 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3833 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3835 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3836 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3838 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3843 ld hl,sp+n trashes C so we can't afford to do it during an
3844 add with stack based variables. Worst case is:
3857 So you can't afford to load up hl if either left, right, or result
3858 is on the stack (*sigh*) The alt is:
3866 Combinations in here are:
3867 * If left or right are in bc then the loss is small - trap later
3868 * If the result is in bc then the loss is also small
3872 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3873 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3874 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3876 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3877 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3878 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3879 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3881 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3883 /* Swap left and right */
3884 operand *t = IC_RIGHT (ic);
3885 IC_RIGHT (ic) = IC_LEFT (ic);
3888 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3890 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3891 emit2 ("add hl,bc");
3895 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3896 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3897 emit2 ("add hl,de");
3899 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3905 /* Be paranoid on the GB with 4 byte variables due to how C
3906 can be trashed by lda hl,n(sp).
3908 _gbz80_emitAddSubLong (ic, TRUE);
3913 setupToPreserveCarry (ic);
3917 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3919 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3922 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3925 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3929 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3932 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3935 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3937 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3941 _G.preserveCarry = FALSE;
3942 freeAsmop (IC_LEFT (ic), NULL, ic);
3943 freeAsmop (IC_RIGHT (ic), NULL, ic);
3944 freeAsmop (IC_RESULT (ic), NULL, ic);
3947 /*-----------------------------------------------------------------*/
3948 /* genMinusDec :- does subtraction with deccrement if possible */
3949 /*-----------------------------------------------------------------*/
3951 genMinusDec (iCode * ic)
3953 unsigned int icount;
3954 unsigned int size = getDataSize (IC_RESULT (ic));
3956 /* will try to generate an increment */
3957 /* if the right side is not a literal we cannot */
3958 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3961 /* if the literal value of the right hand side
3962 is greater than 4 then it is not worth it */
3963 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3966 size = getDataSize (IC_RESULT (ic));
3968 /* if decrement 16 bits in register */
3969 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3970 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3973 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3977 /* If result is a pair */
3978 if (isPair (AOP (IC_RESULT (ic))))
3980 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3982 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3986 /* if increment 16 bits in register */
3987 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3991 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3994 emit2 ("dec %s", _getTempPairName());
3997 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4003 /* if the sizes are greater than 1 then we cannot */
4004 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4005 AOP_SIZE (IC_LEFT (ic)) > 1)
4008 /* we can if the aops of the left & result match or if they are in
4009 registers and the registers are the same */
4010 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4013 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4020 /*-----------------------------------------------------------------*/
4021 /* genMinus - generates code for subtraction */
4022 /*-----------------------------------------------------------------*/
4024 genMinus (iCode * ic)
4026 int size, offset = 0;
4027 unsigned long lit = 0L;
4029 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4030 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4031 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4033 /* special cases :- */
4034 /* if both left & right are in bit space */
4035 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4036 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4038 wassertl (0, "Tried to subtract two bits");
4042 /* if I can do an decrement instead of subtract then GOOD for ME */
4043 if (genMinusDec (ic) == TRUE)
4046 size = getDataSize (IC_RESULT (ic));
4048 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4053 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4057 /* Same logic as genPlus */
4060 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4061 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4062 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4064 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4065 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4066 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4067 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4069 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4070 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4072 if (left == PAIR_INVALID && right == PAIR_INVALID)
4077 else if (right == PAIR_INVALID)
4079 else if (left == PAIR_INVALID)
4082 fetchPair (left, AOP (IC_LEFT (ic)));
4083 /* Order is important. Right may be HL */
4084 fetchPair (right, AOP (IC_RIGHT (ic)));
4086 emit2 ("ld a,%s", _pairs[left].l);
4087 emit2 ("sub a,%s", _pairs[right].l);
4089 emit2 ("ld a,%s", _pairs[left].h);
4090 emit2 ("sbc a,%s", _pairs[right].h);
4092 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4094 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4096 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4102 /* Be paranoid on the GB with 4 byte variables due to how C
4103 can be trashed by lda hl,n(sp).
4105 _gbz80_emitAddSubLong (ic, FALSE);
4110 setupToPreserveCarry (ic);
4112 /* if literal, add a,#-lit, else normal subb */
4115 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4116 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4120 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4123 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4127 /* first add without previous c */
4129 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4131 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4133 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4136 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4137 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4138 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4140 wassertl (0, "Tried to subtract on a long pointer");
4144 _G.preserveCarry = FALSE;
4145 freeAsmop (IC_LEFT (ic), NULL, ic);
4146 freeAsmop (IC_RIGHT (ic), NULL, ic);
4147 freeAsmop (IC_RESULT (ic), NULL, ic);
4150 /*-----------------------------------------------------------------*/
4151 /* genMult - generates code for multiplication */
4152 /*-----------------------------------------------------------------*/
4154 genMult (iCode * ic)
4158 /* If true then the final operation should be a subtract */
4159 bool active = FALSE;
4162 /* Shouldn't occur - all done through function calls */
4163 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4164 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4165 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4167 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4169 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4170 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4171 AOP_SIZE (IC_RESULT (ic)) > 2)
4173 wassertl (0, "Multiplication is handled through support function calls");
4176 /* Swap left and right such that right is a literal */
4177 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4179 operand *t = IC_RIGHT (ic);
4180 IC_RIGHT (ic) = IC_LEFT (ic);
4184 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4186 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4187 // wassertl (val > 0, "Multiply must be positive");
4188 wassertl (val != 1, "Can't multiply by 1");
4190 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4192 _G.stack.pushedDE = TRUE;
4195 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4197 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4208 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4213 /* Fully unroled version of mul.s. Not the most efficient.
4215 for (count = 0; count < 16; count++)
4217 if (count != 0 && active)
4219 emit2 ("add hl,hl");
4223 if (active == FALSE)
4231 emit2 ("add hl,de");
4240 if (IS_Z80 && _G.stack.pushedDE)
4243 _G.stack.pushedDE = FALSE;
4247 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4249 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4251 freeAsmop (IC_LEFT (ic), NULL, ic);
4252 freeAsmop (IC_RIGHT (ic), NULL, ic);
4253 freeAsmop (IC_RESULT (ic), NULL, ic);
4256 /*-----------------------------------------------------------------*/
4257 /* genDiv - generates code for division */
4258 /*-----------------------------------------------------------------*/
4262 /* Shouldn't occur - all done through function calls */
4263 wassertl (0, "Division is handled through support function calls");
4266 /*-----------------------------------------------------------------*/
4267 /* genMod - generates code for division */
4268 /*-----------------------------------------------------------------*/
4272 /* Shouldn't occur - all done through function calls */
4276 /*-----------------------------------------------------------------*/
4277 /* genIfxJump :- will create a jump depending on the ifx */
4278 /*-----------------------------------------------------------------*/
4280 genIfxJump (iCode * ic, char *jval)
4285 /* if true label then we jump if condition
4289 jlbl = IC_TRUE (ic);
4290 if (!strcmp (jval, "a"))
4294 else if (!strcmp (jval, "c"))
4298 else if (!strcmp (jval, "nc"))
4302 else if (!strcmp (jval, "m"))
4306 else if (!strcmp (jval, "p"))
4312 /* The buffer contains the bit on A that we should test */
4318 /* false label is present */
4319 jlbl = IC_FALSE (ic);
4320 if (!strcmp (jval, "a"))
4324 else if (!strcmp (jval, "c"))
4328 else if (!strcmp (jval, "nc"))
4332 else if (!strcmp (jval, "m"))
4336 else if (!strcmp (jval, "p"))
4342 /* The buffer contains the bit on A that we should test */
4346 /* Z80 can do a conditional long jump */
4347 if (!strcmp (jval, "a"))
4351 else if (!strcmp (jval, "c"))
4354 else if (!strcmp (jval, "nc"))
4357 else if (!strcmp (jval, "m"))
4360 else if (!strcmp (jval, "p"))
4365 emit2 ("bit %s,a", jval);
4367 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4369 /* mark the icode as generated */
4375 _getPairIdName (PAIR_ID id)
4377 return _pairs[id].name;
4382 /* if unsigned char cmp with lit, just compare */
4384 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4386 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4389 emit2 ("xor a,!immedbyte", 0x80);
4390 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4393 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4395 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4397 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4398 // Pull left into DE and right into HL
4399 aopGet (AOP(left), LSB, FALSE);
4402 aopGet (AOP(right), LSB, FALSE);
4406 if (size == 0 && sign)
4408 // Highest byte when signed needs the bits flipped
4411 emit2 ("ld a,(de)");
4412 emit2 ("xor !immedbyte", 0x80);
4414 emit2 ("ld a,(hl)");
4415 emit2 ("xor !immedbyte", 0x80);
4419 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4423 emit2 ("ld a,(de)");
4424 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4434 spillPair (PAIR_HL);
4436 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4438 setupPair (PAIR_HL, AOP (left), 0);
4439 aopGet (AOP(right), LSB, FALSE);
4443 if (size == 0 && sign)
4445 // Highest byte when signed needs the bits flipped
4448 emit2 ("ld a,(hl)");
4449 emit2 ("xor !immedbyte", 0x80);
4451 emit2 ("ld a,%d(iy)", offset);
4452 emit2 ("xor !immedbyte", 0x80);
4456 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4460 emit2 ("ld a,(hl)");
4461 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4470 spillPair (PAIR_HL);
4471 spillPair (PAIR_IY);
4475 if (AOP_TYPE (right) == AOP_LIT)
4477 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4478 /* optimize if(x < 0) or if(x >= 0) */
4483 /* No sign so it's always false */
4488 /* Just load in the top most bit */
4489 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4490 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4492 genIfxJump (ifx, "7");
4504 /* First setup h and l contaning the top most bytes XORed */
4505 bool fDidXor = FALSE;
4506 if (AOP_TYPE (left) == AOP_LIT)
4508 unsigned long lit = (unsigned long)
4509 floatFromVal (AOP (left)->aopu.aop_lit);
4510 emit2 ("ld %s,!immedbyte", _fTmp[0],
4511 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4515 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4516 emit2 ("xor a,!immedbyte", 0x80);
4517 emit2 ("ld %s,a", _fTmp[0]);
4520 if (AOP_TYPE (right) == AOP_LIT)
4522 unsigned long lit = (unsigned long)
4523 floatFromVal (AOP (right)->aopu.aop_lit);
4524 emit2 ("ld %s,!immedbyte", _fTmp[1],
4525 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4529 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4530 emit2 ("xor a,!immedbyte", 0x80);
4531 emit2 ("ld %s,a", _fTmp[1]);
4537 /* Do a long subtract */
4540 _moveA (aopGet (AOP (left), offset, FALSE));
4542 if (sign && size == 0)
4544 emit2 ("ld a,%s", _fTmp[0]);
4545 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4549 /* Subtract through, propagating the carry */
4550 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4558 /** Generic compare for > or <
4561 genCmp (operand * left, operand * right,
4562 operand * result, iCode * ifx, int sign)
4564 int size, offset = 0;
4565 unsigned long lit = 0L;
4567 /* if left & right are bit variables */
4568 if (AOP_TYPE (left) == AOP_CRY &&
4569 AOP_TYPE (right) == AOP_CRY)
4571 /* Cant happen on the Z80 */
4572 wassertl (0, "Tried to compare two bits");
4576 /* Do a long subtract of right from left. */
4577 size = max (AOP_SIZE (left), AOP_SIZE (right));
4579 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4581 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4582 // Pull left into DE and right into HL
4583 aopGet (AOP(left), LSB, FALSE);
4586 aopGet (AOP(right), LSB, FALSE);
4590 emit2 ("ld a,(de)");
4591 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4600 spillPair (PAIR_HL);
4604 if (AOP_TYPE (right) == AOP_LIT)
4606 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4607 /* optimize if(x < 0) or if(x >= 0) */
4612 /* No sign so it's always false */
4617 /* Just load in the top most bit */
4618 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4619 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4621 genIfxJump (ifx, "7");
4632 genIfxJump (ifx, "nc");
4643 _moveA (aopGet (AOP (left), offset, FALSE));
4644 /* Subtract through, propagating the carry */
4645 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4651 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4655 /* Shift the sign bit up into carry */
4662 /* if the result is used in the next
4663 ifx conditional branch then generate
4664 code a little differently */
4672 genIfxJump (ifx, "c");
4676 genIfxJump (ifx, "m");
4681 genIfxJump (ifx, "c");
4688 /* Shift the sign bit up into carry */
4693 /* leave the result in acc */
4697 /*-----------------------------------------------------------------*/
4698 /* genCmpGt :- greater than comparison */
4699 /*-----------------------------------------------------------------*/
4701 genCmpGt (iCode * ic, iCode * ifx)
4703 operand *left, *right, *result;
4704 sym_link *letype, *retype;
4707 left = IC_LEFT (ic);
4708 right = IC_RIGHT (ic);
4709 result = IC_RESULT (ic);
4711 letype = getSpec (operandType (left));
4712 retype = getSpec (operandType (right));
4713 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4714 /* assign the amsops */
4715 aopOp (left, ic, FALSE, FALSE);
4716 aopOp (right, ic, FALSE, FALSE);
4717 aopOp (result, ic, TRUE, FALSE);
4719 genCmp (right, left, result, ifx, sign);
4721 freeAsmop (left, NULL, ic);
4722 freeAsmop (right, NULL, ic);
4723 freeAsmop (result, NULL, ic);
4726 /*-----------------------------------------------------------------*/
4727 /* genCmpLt - less than comparisons */
4728 /*-----------------------------------------------------------------*/
4730 genCmpLt (iCode * ic, iCode * ifx)
4732 operand *left, *right, *result;
4733 sym_link *letype, *retype;
4736 left = IC_LEFT (ic);
4737 right = IC_RIGHT (ic);
4738 result = IC_RESULT (ic);
4740 letype = getSpec (operandType (left));
4741 retype = getSpec (operandType (right));
4742 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4744 /* assign the amsops */
4745 aopOp (left, ic, FALSE, FALSE);
4746 aopOp (right, ic, FALSE, FALSE);
4747 aopOp (result, ic, TRUE, FALSE);
4749 genCmp (left, right, result, ifx, sign);
4751 freeAsmop (left, NULL, ic);
4752 freeAsmop (right, NULL, ic);
4753 freeAsmop (result, NULL, ic);
4756 /*-----------------------------------------------------------------*/
4757 /* gencjneshort - compare and jump if not equal */
4758 /* returns pair that still needs to be popped */
4759 /*-----------------------------------------------------------------*/
4761 gencjneshort (operand * left, operand * right, symbol * lbl)
4763 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4765 unsigned long lit = 0L;
4767 /* Swap the left and right if it makes the computation easier */
4768 if (AOP_TYPE (left) == AOP_LIT)
4775 /* if the right side is a literal then anything goes */
4776 if (AOP_TYPE (right) == AOP_LIT)
4778 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4781 _moveA (aopGet (AOP (left), offset, FALSE));
4786 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4793 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4799 _moveA (aopGet (AOP (left), offset, FALSE));
4800 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4803 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4804 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4809 /* if the right side is in a register or
4810 pointed to by HL, IX or IY */
4811 else if (AOP_TYPE (right) == AOP_REG ||
4812 AOP_TYPE (right) == AOP_HL ||
4813 AOP_TYPE (right) == AOP_IY ||
4814 AOP_TYPE (right) == AOP_STK ||
4815 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4816 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4817 AOP_IS_PAIRPTR (right, PAIR_IY))
4821 _moveA (aopGet (AOP (left), offset, FALSE));
4822 if (AOP_TYPE (right) == AOP_LIT &&
4823 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4826 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4830 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4831 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4836 /* right is in direct space or a pointer reg, need both a & b */
4840 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4842 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4843 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4851 emit2 ("; direct compare");
4852 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4853 _moveA (aopGet (AOP (right), offset, FALSE));
4854 emit2 ("sub %s", _pairs[pair].l);
4855 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4860 return PAIR_INVALID;
4863 /*-----------------------------------------------------------------*/
4864 /* gencjne - compare and jump if not equal */
4865 /*-----------------------------------------------------------------*/
4867 gencjne (operand * left, operand * right, symbol * lbl)
4869 symbol *tlbl = newiTempLabel (NULL);
4871 PAIR_ID pop = gencjneshort (left, right, lbl);
4874 emit2 ("ld a,!one");
4875 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4876 emitLabel (lbl->key + 100);
4878 emitLabel (tlbl->key + 100);
4882 /*-----------------------------------------------------------------*/
4883 /* genCmpEq - generates code for equal to */
4884 /*-----------------------------------------------------------------*/
4886 genCmpEq (iCode * ic, iCode * ifx)
4888 operand *left, *right, *result;
4890 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4891 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4892 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4894 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4896 /* Swap operands if it makes the operation easier. ie if:
4897 1. Left is a literal.
4899 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4901 operand *t = IC_RIGHT (ic);
4902 IC_RIGHT (ic) = IC_LEFT (ic);
4906 if (ifx && !AOP_SIZE (result))
4909 /* if they are both bit variables */
4910 if (AOP_TYPE (left) == AOP_CRY &&
4911 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4913 wassertl (0, "Tried to compare two bits");
4918 tlbl = newiTempLabel (NULL);
4919 pop = gencjneshort (left, right, tlbl);
4923 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4924 emitLabel (tlbl->key + 100);
4929 /* PENDING: do this better */
4930 symbol *lbl = newiTempLabel (NULL);
4932 emit2 ("!shortjp !tlabel", lbl->key + 100);
4933 emitLabel (tlbl->key + 100);
4935 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4936 emitLabel (lbl->key + 100);
4939 /* mark the icode as generated */
4944 /* if they are both bit variables */
4945 if (AOP_TYPE (left) == AOP_CRY &&
4946 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4948 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4954 gencjne (left, right, newiTempLabel (NULL));
4955 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4962 genIfxJump (ifx, "a");
4965 /* if the result is used in an arithmetic operation
4966 then put the result in place */
4967 if (AOP_TYPE (result) != AOP_CRY)
4972 /* leave the result in acc */
4976 freeAsmop (left, NULL, ic);
4977 freeAsmop (right, NULL, ic);
4978 freeAsmop (result, NULL, ic);
4981 /*-----------------------------------------------------------------*/
4982 /* ifxForOp - returns the icode containing the ifx for operand */
4983 /*-----------------------------------------------------------------*/
4985 ifxForOp (operand * op, iCode * ic)
4987 /* if true symbol then needs to be assigned */
4988 if (IS_TRUE_SYMOP (op))
4991 /* if this has register type condition and
4992 the next instruction is ifx with the same operand
4993 and live to of the operand is upto the ifx only then */
4995 ic->next->op == IFX &&
4996 IC_COND (ic->next)->key == op->key &&
4997 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5003 /*-----------------------------------------------------------------*/
5004 /* genAndOp - for && operation */
5005 /*-----------------------------------------------------------------*/
5007 genAndOp (iCode * ic)
5009 operand *left, *right, *result;
5012 /* note here that && operations that are in an if statement are
5013 taken away by backPatchLabels only those used in arthmetic
5014 operations remain */
5015 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5016 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5017 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5019 /* if both are bit variables */
5020 if (AOP_TYPE (left) == AOP_CRY &&
5021 AOP_TYPE (right) == AOP_CRY)
5023 wassertl (0, "Tried to and two bits");
5027 tlbl = newiTempLabel (NULL);
5029 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5031 emitLabel (tlbl->key + 100);
5035 freeAsmop (left, NULL, ic);
5036 freeAsmop (right, NULL, ic);
5037 freeAsmop (result, NULL, ic);
5040 /*-----------------------------------------------------------------*/
5041 /* genOrOp - for || operation */
5042 /*-----------------------------------------------------------------*/
5044 genOrOp (iCode * ic)
5046 operand *left, *right, *result;
5049 /* note here that || operations that are in an
5050 if statement are taken away by backPatchLabels
5051 only those used in arthmetic 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 OR two bits");
5064 tlbl = newiTempLabel (NULL);
5066 emit2 ("!shortjp NZ,!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 /* isLiteralBit - test if lit == 2^n */
5079 /*-----------------------------------------------------------------*/
5081 isLiteralBit (unsigned long lit)
5083 unsigned long pw[32] =
5084 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5085 0x100L, 0x200L, 0x400L, 0x800L,
5086 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5087 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5088 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5089 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5090 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5093 for (idx = 0; idx < 32; idx++)
5099 /*-----------------------------------------------------------------*/
5100 /* jmpTrueOrFalse - */
5101 /*-----------------------------------------------------------------*/
5103 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5105 // ugly but optimized by peephole
5108 symbol *nlbl = newiTempLabel (NULL);
5109 emit2 ("jp !tlabel", nlbl->key + 100);
5110 emitLabel (tlbl->key + 100);
5111 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5112 emitLabel (nlbl->key + 100);
5116 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5117 emitLabel (tlbl->key + 100);
5122 /*-----------------------------------------------------------------*/
5123 /* genAnd - code for and */
5124 /*-----------------------------------------------------------------*/
5126 genAnd (iCode * ic, iCode * ifx)
5128 operand *left, *right, *result;
5129 int size, offset = 0;
5130 unsigned long lit = 0L;
5133 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5134 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5135 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5137 /* if left is a literal & right is not then exchange them */
5138 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5139 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5141 operand *tmp = right;
5146 /* if result = right then exchange them */
5147 if (sameRegs (AOP (result), AOP (right)))
5149 operand *tmp = right;
5154 /* if right is bit then exchange them */
5155 if (AOP_TYPE (right) == AOP_CRY &&
5156 AOP_TYPE (left) != AOP_CRY)
5158 operand *tmp = right;
5162 if (AOP_TYPE (right) == AOP_LIT)
5163 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5165 size = AOP_SIZE (result);
5167 if (AOP_TYPE (left) == AOP_CRY)
5169 wassertl (0, "Tried to perform an AND with a bit as an operand");
5173 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5174 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5175 if ((AOP_TYPE (right) == AOP_LIT) &&
5176 (AOP_TYPE (result) == AOP_CRY) &&
5177 (AOP_TYPE (left) != AOP_CRY))
5179 symbol *tlbl = newiTempLabel (NULL);
5180 int sizel = AOP_SIZE (left);
5183 /* PENDING: Test case for this. */
5188 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5190 _moveA (aopGet (AOP (left), offset, FALSE));
5191 if (bytelit != 0x0FFL)
5193 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5200 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5204 // bit = left & literal
5208 emit2 ("!tlabeldef", tlbl->key + 100);
5209 _G.lines.current->isLabel = 1;
5211 // if(left & literal)
5216 jmpTrueOrFalse (ifx, tlbl);
5224 /* if left is same as result */
5225 if (sameRegs (AOP (result), AOP (left)))
5227 for (; size--; offset++)
5229 if (AOP_TYPE (right) == AOP_LIT)
5231 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5236 aopPut (AOP (result), "!zero", offset);
5239 _moveA (aopGet (AOP (left), offset, FALSE));
5241 aopGet (AOP (right), offset, FALSE));
5242 aopPut (AOP (left), "a", offset);
5249 if (AOP_TYPE (left) == AOP_ACC)
5251 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5255 _moveA (aopGet (AOP (left), offset, FALSE));
5257 aopGet (AOP (right), offset, FALSE));
5258 aopPut (AOP (left), "a", offset);
5265 // left & result in different registers
5266 if (AOP_TYPE (result) == AOP_CRY)
5268 wassertl (0, "Tried to AND where the result is in carry");
5272 for (; (size--); offset++)
5275 // result = left & right
5276 if (AOP_TYPE (right) == AOP_LIT)
5278 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5280 aopPut (AOP (result),
5281 aopGet (AOP (left), offset, FALSE),
5285 else if (bytelit == 0)
5287 aopPut (AOP (result), "!zero", offset);
5291 // faster than result <- left, anl result,right
5292 // and better if result is SFR
5293 if (AOP_TYPE (left) == AOP_ACC)
5294 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5297 _moveA (aopGet (AOP (left), offset, FALSE));
5299 aopGet (AOP (right), offset, FALSE));
5301 aopPut (AOP (result), "a", offset);
5308 freeAsmop (left, NULL, ic);
5309 freeAsmop (right, NULL, ic);
5310 freeAsmop (result, NULL, ic);
5313 /*-----------------------------------------------------------------*/
5314 /* genOr - code for or */
5315 /*-----------------------------------------------------------------*/
5317 genOr (iCode * ic, iCode * ifx)
5319 operand *left, *right, *result;
5320 int size, offset = 0;
5321 unsigned long lit = 0L;
5324 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5325 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5326 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5328 /* if left is a literal & right is not then exchange them */
5329 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5330 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5332 operand *tmp = right;
5337 /* if result = right then exchange them */
5338 if (sameRegs (AOP (result), AOP (right)))
5340 operand *tmp = right;
5345 /* if right is bit then exchange them */
5346 if (AOP_TYPE (right) == AOP_CRY &&
5347 AOP_TYPE (left) != AOP_CRY)
5349 operand *tmp = right;
5353 if (AOP_TYPE (right) == AOP_LIT)
5354 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5356 size = AOP_SIZE (result);
5358 if (AOP_TYPE (left) == AOP_CRY)
5360 wassertl (0, "Tried to OR where left is a bit");
5364 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5365 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5366 if ((AOP_TYPE (right) == AOP_LIT) &&
5367 (AOP_TYPE (result) == AOP_CRY) &&
5368 (AOP_TYPE (left) != AOP_CRY))
5370 symbol *tlbl = newiTempLabel (NULL);
5371 int sizel = AOP_SIZE (left);
5375 wassertl (0, "Result is assigned to a bit");
5377 /* PENDING: Modeled after the AND code which is inefficient. */
5380 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5382 _moveA (aopGet (AOP (left), offset, FALSE));
5383 /* OR with any literal is the same as OR with itself. */
5385 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5391 jmpTrueOrFalse (ifx, tlbl);
5396 /* if left is same as result */
5397 if (sameRegs (AOP (result), AOP (left)))
5399 for (; size--; offset++)
5401 if (AOP_TYPE (right) == AOP_LIT)
5403 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5407 _moveA (aopGet (AOP (left), offset, FALSE));
5409 aopGet (AOP (right), offset, FALSE));
5410 aopPut (AOP (result), "a", offset);
5415 if (AOP_TYPE (left) == AOP_ACC)
5416 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5419 _moveA (aopGet (AOP (left), offset, FALSE));
5421 aopGet (AOP (right), offset, FALSE));
5422 aopPut (AOP (result), "a", offset);
5429 // left & result in different registers
5430 if (AOP_TYPE (result) == AOP_CRY)
5432 wassertl (0, "Result of OR is in a bit");
5435 for (; (size--); offset++)
5438 // result = left & right
5439 if (AOP_TYPE (right) == AOP_LIT)
5441 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5443 aopPut (AOP (result),
5444 aopGet (AOP (left), offset, FALSE),
5449 // faster than result <- left, anl result,right
5450 // and better if result is SFR
5451 if (AOP_TYPE (left) == AOP_ACC)
5452 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5455 _moveA (aopGet (AOP (left), offset, FALSE));
5457 aopGet (AOP (right), offset, FALSE));
5459 aopPut (AOP (result), "a", offset);
5460 /* PENDING: something weird is going on here. Add exception. */
5461 if (AOP_TYPE (result) == AOP_ACC)
5467 freeAsmop (left, NULL, ic);
5468 freeAsmop (right, NULL, ic);
5469 freeAsmop (result, NULL, ic);
5472 /*-----------------------------------------------------------------*/
5473 /* genXor - code for xclusive or */
5474 /*-----------------------------------------------------------------*/
5476 genXor (iCode * ic, iCode * ifx)
5478 operand *left, *right, *result;
5479 int size, offset = 0;
5480 unsigned long lit = 0L;
5482 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5483 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5484 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5486 /* if left is a literal & right is not then exchange them */
5487 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5488 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5490 operand *tmp = right;
5495 /* if result = right then exchange them */
5496 if (sameRegs (AOP (result), AOP (right)))
5498 operand *tmp = right;
5503 /* if right is bit then exchange them */
5504 if (AOP_TYPE (right) == AOP_CRY &&
5505 AOP_TYPE (left) != AOP_CRY)
5507 operand *tmp = right;
5511 if (AOP_TYPE (right) == AOP_LIT)
5512 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5514 size = AOP_SIZE (result);
5516 if (AOP_TYPE (left) == AOP_CRY)
5518 wassertl (0, "Tried to XOR a bit");
5522 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5523 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5524 if ((AOP_TYPE (right) == AOP_LIT) &&
5525 (AOP_TYPE (result) == AOP_CRY) &&
5526 (AOP_TYPE (left) != AOP_CRY))
5528 symbol *tlbl = newiTempLabel (NULL);
5529 int sizel = AOP_SIZE (left);
5533 /* PENDING: Test case for this. */
5534 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5538 _moveA (aopGet (AOP (left), offset, FALSE));
5539 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5540 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5545 jmpTrueOrFalse (ifx, tlbl);
5549 wassertl (0, "Result of XOR was destined for a bit");
5554 /* if left is same as result */
5555 if (sameRegs (AOP (result), AOP (left)))
5557 for (; size--; offset++)
5559 if (AOP_TYPE (right) == AOP_LIT)
5561 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5565 _moveA (aopGet (AOP (left), offset, FALSE));
5567 aopGet (AOP (right), offset, FALSE));
5568 aopPut (AOP (result), "a", offset);
5573 if (AOP_TYPE (left) == AOP_ACC)
5575 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5579 _moveA (aopGet (AOP (left), offset, FALSE));
5581 aopGet (AOP (right), offset, FALSE));
5582 aopPut (AOP (result), "a", offset);
5589 // left & result in different registers
5590 if (AOP_TYPE (result) == AOP_CRY)
5592 wassertl (0, "Result of XOR is in a bit");
5595 for (; (size--); offset++)
5598 // result = left & right
5599 if (AOP_TYPE (right) == AOP_LIT)
5601 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5603 aopPut (AOP (result),
5604 aopGet (AOP (left), offset, FALSE),
5609 // faster than result <- left, anl result,right
5610 // and better if result is SFR
5611 if (AOP_TYPE (left) == AOP_ACC)
5613 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5617 _moveA (aopGet (AOP (left), offset, FALSE));
5619 aopGet (AOP (right), offset, FALSE));
5621 aopPut (AOP (result), "a", offset);
5626 freeAsmop (left, NULL, ic);
5627 freeAsmop (right, NULL, ic);
5628 freeAsmop (result, NULL, ic);
5631 /*-----------------------------------------------------------------*/
5632 /* genInline - write the inline code out */
5633 /*-----------------------------------------------------------------*/
5635 genInline (iCode * ic)
5637 char *buffer, *bp, *bp1;
5639 _G.lines.isInline += (!options.asmpeep);
5641 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5642 strcpy (buffer, IC_INLINE (ic));
5644 /* emit each line as a code */
5669 _G.lines.isInline -= (!options.asmpeep);
5673 /*-----------------------------------------------------------------*/
5674 /* genRRC - rotate right with carry */
5675 /*-----------------------------------------------------------------*/
5682 /*-----------------------------------------------------------------*/
5683 /* genRLC - generate code for rotate left with carry */
5684 /*-----------------------------------------------------------------*/
5691 /*-----------------------------------------------------------------*/
5692 /* genGetHbit - generates code get highest order bit */
5693 /*-----------------------------------------------------------------*/
5695 genGetHbit (iCode * ic)
5697 operand *left, *result;
5698 left = IC_LEFT (ic);
5699 result = IC_RESULT (ic);
5701 aopOp (left, ic, FALSE, FALSE);
5702 aopOp (result, ic, FALSE, FALSE);
5704 /* get the highest order byte into a */
5705 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5707 if (AOP_TYPE (result) == AOP_CRY)
5715 emit2 ("and a,!one");
5720 freeAsmop (left, NULL, ic);
5721 freeAsmop (result, NULL, ic);
5725 emitRsh2 (asmop *aop, int size, int is_signed)
5731 const char *l = aopGet (aop, size, FALSE);
5734 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5744 /*-----------------------------------------------------------------*/
5745 /* shiftR2Left2Result - shift right two bytes from left to result */
5746 /*-----------------------------------------------------------------*/
5748 shiftR2Left2Result (operand * left, int offl,
5749 operand * result, int offr,
5750 int shCount, int is_signed)
5755 movLeft2Result (left, offl, result, offr, 0);
5756 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5761 /* if (AOP(result)->type == AOP_REG) { */
5763 tlbl = newiTempLabel (NULL);
5765 /* Left is already in result - so now do the shift */
5766 /* Optimizing for speed by default. */
5767 if (!optimize.codeSize || shCount <= 2)
5771 emitRsh2 (AOP (result), size, is_signed);
5776 emit2 ("ld a,!immedbyte", shCount);
5778 emitLabel (tlbl->key + 100);
5780 emitRsh2 (AOP (result), size, is_signed);
5783 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5787 /*-----------------------------------------------------------------*/
5788 /* shiftL2Left2Result - shift left two bytes from left to result */
5789 /*-----------------------------------------------------------------*/
5791 shiftL2Left2Result (operand * left, int offl,
5792 operand * result, int offr, int shCount)
5794 if (sameRegs (AOP (result), AOP (left)) &&
5795 ((offl + MSB16) == offr))
5801 /* Copy left into result */
5802 movLeft2Result (left, offl, result, offr, 0);
5803 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5809 if (getPairId (AOP (result)) == PAIR_HL)
5813 emit2 ("add hl,hl");
5820 symbol *tlbl, *tlbl1;
5823 tlbl = newiTempLabel (NULL);
5824 tlbl1 = newiTempLabel (NULL);
5826 if (AOP (result)->type == AOP_REG)
5830 for (offset = 0; offset < size; offset++)
5832 l = aopGet (AOP (result), offset, FALSE);
5836 emit2 ("sla %s", l);
5847 /* Left is already in result - so now do the shift */
5850 emit2 ("ld a,!immedbyte+1", shCount);
5851 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5852 emitLabel (tlbl->key + 100);
5857 l = aopGet (AOP (result), offset, FALSE);
5861 emit2 ("sla %s", l);
5872 emitLabel (tlbl1->key + 100);
5874 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5880 /*-----------------------------------------------------------------*/
5881 /* AccRol - rotate left accumulator by known count */
5882 /*-----------------------------------------------------------------*/
5884 AccRol (int shCount)
5886 shCount &= 0x0007; // shCount : 0..7
5963 /*-----------------------------------------------------------------*/
5964 /* AccLsh - left shift accumulator by known count */
5965 /*-----------------------------------------------------------------*/
5967 AccLsh (int shCount)
5969 static const unsigned char SLMask[] =
5971 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5980 else if (shCount == 2)
5987 /* rotate left accumulator */
5989 /* and kill the lower order bits */
5990 emit2 ("and a,!immedbyte", SLMask[shCount]);
5995 /*-----------------------------------------------------------------*/
5996 /* shiftL1Left2Result - shift left one byte from left to result */
5997 /*-----------------------------------------------------------------*/
5999 shiftL1Left2Result (operand * left, int offl,
6000 operand * result, int offr, int shCount)
6003 l = aopGet (AOP (left), offl, FALSE);
6005 /* shift left accumulator */
6007 aopPut (AOP (result), "a", offr);
6011 /*-----------------------------------------------------------------*/
6012 /* genlshTwo - left shift two bytes by known amount */
6013 /*-----------------------------------------------------------------*/
6015 genlshTwo (operand * result, operand * left, int shCount)
6017 int size = AOP_SIZE (result);
6019 wassert (size == 2);
6021 /* if shCount >= 8 */
6029 movLeft2Result (left, LSB, result, MSB16, 0);
6030 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6031 aopPut (AOP (result), "!zero", LSB);
6035 movLeft2Result (left, LSB, result, MSB16, 0);
6036 aopPut (AOP (result), "!zero", 0);
6041 aopPut (AOP (result), "!zero", LSB);
6044 /* 0 <= shCount <= 7 */
6053 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6058 /*-----------------------------------------------------------------*/
6059 /* genlshOne - left shift a one byte quantity by known count */
6060 /*-----------------------------------------------------------------*/
6062 genlshOne (operand * result, operand * left, int shCount)
6064 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6067 /*-----------------------------------------------------------------*/
6068 /* genLeftShiftLiteral - left shifting by known count */
6069 /*-----------------------------------------------------------------*/
6071 genLeftShiftLiteral (operand * left,
6076 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6079 freeAsmop (right, NULL, ic);
6081 aopOp (left, ic, FALSE, FALSE);
6082 aopOp (result, ic, FALSE, FALSE);
6084 size = getSize (operandType (result));
6086 /* I suppose that the left size >= result size */
6088 if (shCount >= (size * 8))
6092 aopPut (AOP (result), "!zero", size);
6100 genlshOne (result, left, shCount);
6103 genlshTwo (result, left, shCount);
6106 wassertl (0, "Shifting of longs is currently unsupported");
6112 freeAsmop (left, NULL, ic);
6113 freeAsmop (result, NULL, ic);
6116 /*-----------------------------------------------------------------*/
6117 /* genLeftShift - generates code for left shifting */
6118 /*-----------------------------------------------------------------*/
6120 genLeftShift (iCode * ic)
6124 symbol *tlbl, *tlbl1;
6125 operand *left, *right, *result;
6127 right = IC_RIGHT (ic);
6128 left = IC_LEFT (ic);
6129 result = IC_RESULT (ic);
6131 aopOp (right, ic, FALSE, FALSE);
6133 /* if the shift count is known then do it
6134 as efficiently as possible */
6135 if (AOP_TYPE (right) == AOP_LIT)
6137 genLeftShiftLiteral (left, right, result, ic);
6141 /* shift count is unknown then we have to form a loop get the loop
6142 count in B : Note: we take only the lower order byte since
6143 shifting more that 32 bits make no sense anyway, ( the largest
6144 size of an object can be only 32 bits ) */
6145 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6147 freeAsmop (right, NULL, ic);
6148 aopOp (left, ic, FALSE, FALSE);
6149 aopOp (result, ic, FALSE, FALSE);
6151 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6154 /* now move the left to the result if they are not the
6157 if (!sameRegs (AOP (left), AOP (result)))
6160 size = AOP_SIZE (result);
6164 l = aopGet (AOP (left), offset, FALSE);
6165 aopPut (AOP (result), l, offset);
6170 tlbl = newiTempLabel (NULL);
6171 size = AOP_SIZE (result);
6173 tlbl1 = newiTempLabel (NULL);
6175 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6178 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6179 emitLabel (tlbl->key + 100);
6180 l = aopGet (AOP (result), offset, FALSE);
6184 l = aopGet (AOP (result), offset, FALSE);
6188 emit2 ("sla %s", l);
6196 emitLabel (tlbl1->key + 100);
6198 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6200 freeAsmop (left, NULL, ic);
6201 freeAsmop (result, NULL, ic);
6204 /*-----------------------------------------------------------------*/
6205 /* genrshOne - left shift two bytes by known amount != 0 */
6206 /*-----------------------------------------------------------------*/
6208 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6211 int size = AOP_SIZE (result);
6214 wassert (size == 1);
6215 wassert (shCount < 8);
6217 l = aopGet (AOP (left), 0, FALSE);
6219 if (AOP (result)->type == AOP_REG)
6221 aopPut (AOP (result), l, 0);
6222 l = aopGet (AOP (result), 0, FALSE);
6225 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6233 emit2 ("%s a", is_signed ? "sra" : "srl");
6235 aopPut (AOP (result), "a", 0);
6239 /*-----------------------------------------------------------------*/
6240 /* AccRsh - right shift accumulator by known count */
6241 /*-----------------------------------------------------------------*/
6243 AccRsh (int shCount)
6245 static const unsigned char SRMask[] =
6247 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6252 /* rotate right accumulator */
6253 AccRol (8 - shCount);
6254 /* and kill the higher order bits */
6255 emit2 ("and a,!immedbyte", SRMask[shCount]);
6259 /*-----------------------------------------------------------------*/
6260 /* shiftR1Left2Result - shift right one byte from left to result */
6261 /*-----------------------------------------------------------------*/
6263 shiftR1Left2Result (operand * left, int offl,
6264 operand * result, int offr,
6265 int shCount, int sign)
6267 _moveA (aopGet (AOP (left), offl, FALSE));
6272 emit2 ("%s a", sign ? "sra" : "srl");
6279 aopPut (AOP (result), "a", offr);
6282 /*-----------------------------------------------------------------*/
6283 /* genrshTwo - right shift two bytes by known amount */
6284 /*-----------------------------------------------------------------*/
6286 genrshTwo (operand * result, operand * left,
6287 int shCount, int sign)
6289 /* if shCount >= 8 */
6295 shiftR1Left2Result (left, MSB16, result, LSB,
6300 movLeft2Result (left, MSB16, result, LSB, sign);
6304 /* Sign extend the result */
6305 _moveA(aopGet (AOP (result), 0, FALSE));
6309 aopPut (AOP (result), ACC_NAME, MSB16);
6313 aopPut (AOP (result), "!zero", 1);
6316 /* 0 <= shCount <= 7 */
6319 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6323 /*-----------------------------------------------------------------*/
6324 /* genRightShiftLiteral - left shifting by known count */
6325 /*-----------------------------------------------------------------*/
6327 genRightShiftLiteral (operand * left,
6333 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6336 freeAsmop (right, NULL, ic);
6338 aopOp (left, ic, FALSE, FALSE);
6339 aopOp (result, ic, FALSE, FALSE);
6341 size = getSize (operandType (result));
6343 /* I suppose that the left size >= result size */
6345 if (shCount >= (size * 8)) {
6347 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6348 _moveA(aopGet (AOP (left), 0, FALSE));
6356 aopPut (AOP (result), s, size);
6363 genrshOne (result, left, shCount, sign);
6366 genrshTwo (result, left, shCount, sign);
6369 wassertl (0, "Asked to shift right a long which should be a function call");
6372 wassertl (0, "Entered default case in right shift delegate");
6375 freeAsmop (left, NULL, ic);
6376 freeAsmop (result, NULL, ic);
6379 /*-----------------------------------------------------------------*/
6380 /* genRightShift - generate code for right shifting */
6381 /*-----------------------------------------------------------------*/
6383 genRightShift (iCode * ic)
6385 operand *right, *left, *result;
6387 int size, offset, first = 1;
6391 symbol *tlbl, *tlbl1;
6393 /* if signed then we do it the hard way preserve the
6394 sign bit moving it inwards */
6395 retype = getSpec (operandType (IC_RESULT (ic)));
6397 is_signed = !SPEC_USIGN (retype);
6399 /* signed & unsigned types are treated the same : i.e. the
6400 signed is NOT propagated inwards : quoting from the
6401 ANSI - standard : "for E1 >> E2, is equivalent to division
6402 by 2**E2 if unsigned or if it has a non-negative value,
6403 otherwise the result is implementation defined ", MY definition
6404 is that the sign does not get propagated */
6406 right = IC_RIGHT (ic);
6407 left = IC_LEFT (ic);
6408 result = IC_RESULT (ic);
6410 aopOp (right, ic, FALSE, FALSE);
6412 /* if the shift count is known then do it
6413 as efficiently as possible */
6414 if (AOP_TYPE (right) == AOP_LIT)
6416 genRightShiftLiteral (left, right, result, ic, is_signed);
6420 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6422 freeAsmop (right, NULL, ic);
6424 aopOp (left, ic, FALSE, FALSE);
6425 aopOp (result, ic, FALSE, FALSE);
6427 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6430 /* now move the left to the result if they are not the
6432 if (!sameRegs (AOP (left), AOP (result)))
6435 size = AOP_SIZE (result);
6439 l = aopGet (AOP (left), offset, FALSE);
6440 aopPut (AOP (result), l, offset);
6445 tlbl = newiTempLabel (NULL);
6446 tlbl1 = newiTempLabel (NULL);
6447 size = AOP_SIZE (result);
6450 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6453 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6454 emitLabel (tlbl->key + 100);
6457 l = aopGet (AOP (result), offset--, FALSE);
6460 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6468 emitLabel (tlbl1->key + 100);
6470 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6472 freeAsmop (left, NULL, ic);
6473 freeAsmop (result, NULL, ic);
6477 /*-----------------------------------------------------------------*/
6478 /* genUnpackBits - generates code for unpacking bits */
6479 /*-----------------------------------------------------------------*/
6481 genUnpackBits (operand * result, int pair)
6483 int offset = 0; /* result byte offset */
6484 int rsize; /* result size */
6485 int rlen = 0; /* remaining bitfield length */
6486 sym_link *etype; /* bitfield type information */
6487 int blen; /* bitfield length */
6488 int bstr; /* bitfield starting bit within byte */
6490 emitDebug ("; genUnpackBits");
6492 etype = getSpec (operandType (result));
6493 rsize = getSize (operandType (result));
6494 blen = SPEC_BLEN (etype);
6495 bstr = SPEC_BSTR (etype);
6497 /* If the bitfield length is less than a byte */
6500 emit2 ("ld a,!*pair", _pairs[pair].name);
6502 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6503 if (!SPEC_USIGN (etype))
6505 /* signed bitfield */
6506 symbol *tlbl = newiTempLabel (NULL);
6508 emit2 ("bit %d,a", blen - 1);
6509 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6510 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6511 emitLabel (tlbl->key + 100);
6513 aopPut (AOP (result), "a", offset++);
6517 /* TODO: what if pair == PAIR_DE ? */
6518 if (getPairId (AOP (result)) == PAIR_HL)
6520 wassertl (rsize == 2, "HL must be of size 2");
6521 emit2 ("ld a,!*hl");
6523 emit2 ("ld h,!*hl");
6526 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6527 if (!SPEC_USIGN (etype))
6529 /* signed bitfield */
6530 symbol *tlbl = newiTempLabel (NULL);
6532 emit2 ("bit %d,a", blen - 1);
6533 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6534 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6535 emitLabel (tlbl->key + 100);
6538 spillPair (PAIR_HL);
6542 /* Bit field did not fit in a byte. Copy all
6543 but the partial byte at the end. */
6544 for (rlen=blen;rlen>=8;rlen-=8)
6546 emit2 ("ld a,!*pair", _pairs[pair].name);
6547 aopPut (AOP (result), "a", offset++);
6550 emit2 ("inc %s", _pairs[pair].name);
6551 _G.pairs[pair].offset++;
6555 /* Handle the partial byte at the end */
6558 emit2 ("ld a,!*pair", _pairs[pair].name);
6559 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6560 if (!SPEC_USIGN (etype))
6562 /* signed bitfield */
6563 symbol *tlbl = newiTempLabel (NULL);
6565 emit2 ("bit %d,a", rlen - 1);
6566 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6567 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6568 emitLabel (tlbl->key + 100);
6570 aopPut (AOP (result), "a", offset++);
6578 if (SPEC_USIGN (etype))
6582 /* signed bitfield: sign extension with 0x00 or 0xff */
6590 aopPut (AOP (result), source, offset++);
6594 /*-----------------------------------------------------------------*/
6595 /* genGenPointerGet - get value from generic pointer space */
6596 /*-----------------------------------------------------------------*/
6598 genGenPointerGet (operand * left,
6599 operand * result, iCode * ic)
6602 sym_link *retype = getSpec (operandType (result));
6608 aopOp (left, ic, FALSE, FALSE);
6609 aopOp (result, ic, FALSE, FALSE);
6611 size = AOP_SIZE (result);
6613 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6616 if (isPtrPair (AOP (left)))
6618 tsprintf (buffer, sizeof(buffer),
6619 "!*pair", getPairName (AOP (left)));
6620 aopPut (AOP (result), buffer, 0);
6624 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6625 aopPut (AOP (result), "a", 0);
6627 freeAsmop (left, NULL, ic);
6631 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6638 tsprintf (at, sizeof(at), "!*iyx", offset);
6639 aopPut (AOP (result), at, offset);
6643 freeAsmop (left, NULL, ic);
6647 /* For now we always load into IY */
6648 /* if this is remateriazable */
6649 fetchPair (pair, AOP (left));
6651 /* if bit then unpack */
6652 if (IS_BITVAR (retype))
6654 genUnpackBits (result, pair);
6655 freeAsmop (left, NULL, ic);
6659 else if (getPairId (AOP (result)) == PAIR_HL)
6661 wassertl (size == 2, "HL must be of size 2");
6662 emit2 ("ld a,!*hl");
6664 emit2 ("ld h,!*hl");
6666 spillPair (PAIR_HL);
6668 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6670 size = AOP_SIZE (result);
6675 /* PENDING: make this better */
6676 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6678 aopPut (AOP (result), "!*hl", offset++);
6682 emit2 ("ld a,!*pair", _pairs[pair].name);
6683 aopPut (AOP (result), "a", offset++);
6687 emit2 ("inc %s", _pairs[pair].name);
6688 _G.pairs[pair].offset++;
6691 /* Fixup HL back down */
6692 for (size = AOP_SIZE (result)-1; size; size--)
6694 emit2 ("dec %s", _pairs[pair].name);
6699 size = AOP_SIZE (result);
6704 /* PENDING: make this better */
6706 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6708 aopPut (AOP (result), "!*hl", offset++);
6712 emit2 ("ld a,!*pair", _pairs[pair].name);
6713 aopPut (AOP (result), "a", offset++);
6717 emit2 ("inc %s", _pairs[pair].name);
6718 _G.pairs[pair].offset++;
6723 freeAsmop (left, NULL, ic);
6726 freeAsmop (result, NULL, ic);
6729 /*-----------------------------------------------------------------*/
6730 /* genPointerGet - generate code for pointer get */
6731 /*-----------------------------------------------------------------*/
6733 genPointerGet (iCode * ic)
6735 operand *left, *result;
6736 sym_link *type, *etype;
6738 left = IC_LEFT (ic);
6739 result = IC_RESULT (ic);
6741 /* depending on the type of pointer we need to
6742 move it to the correct pointer register */
6743 type = operandType (left);
6744 etype = getSpec (type);
6746 genGenPointerGet (left, result, ic);
6750 isRegOrLit (asmop * aop)
6752 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6758 /*-----------------------------------------------------------------*/
6759 /* genPackBits - generates code for packed bit storage */
6760 /*-----------------------------------------------------------------*/
6762 genPackBits (sym_link * etype,
6767 int offset = 0; /* source byte offset */
6768 int rlen = 0; /* remaining bitfield length */
6769 int blen; /* bitfield length */
6770 int bstr; /* bitfield starting bit within byte */
6771 int litval; /* source literal value (if AOP_LIT) */
6772 unsigned char mask; /* bitmask within current byte */
6773 int extraPair; /* a tempory register */
6774 bool needPopExtra=0; /* need to restore original value of temp reg */
6776 emitDebug ("; genPackBits","");
6778 blen = SPEC_BLEN (etype);
6779 bstr = SPEC_BSTR (etype);
6781 /* If the bitfield length is less than a byte */
6784 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6785 (unsigned char) (0xFF >> (8 - bstr)));
6787 if (AOP_TYPE (right) == AOP_LIT)
6789 /* Case with a bitfield length <8 and literal source
6791 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6793 litval &= (~mask) & 0xff;
6794 emit2 ("ld a,!*pair", _pairs[pair].name);
6795 if ((mask|litval)!=0xff)
6796 emit2 ("and a,!immedbyte", mask);
6798 emit2 ("or a,!immedbyte", litval);
6799 emit2 ("ld !*pair,a", _pairs[pair].name);
6804 /* Case with a bitfield length <8 and arbitrary source
6806 _moveA (aopGet (AOP (right), 0, FALSE));
6807 /* shift and mask source value */
6809 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6811 extraPair = getFreePairId(ic);
6812 if (extraPair == PAIR_INVALID)
6814 extraPair = PAIR_BC;
6815 if (getPairId (AOP (right)) != PAIR_BC
6816 || !isLastUse (ic, right))
6822 emit2 ("ld %s,a", _pairs[extraPair].l);
6823 emit2 ("ld a,!*pair", _pairs[pair].name);
6825 emit2 ("and a,!immedbyte", mask);
6826 emit2 ("or a,%s", _pairs[extraPair].l);
6827 emit2 ("ld !*pair,a", _pairs[pair].name);
6834 /* Bit length is greater than 7 bits. In this case, copy */
6835 /* all except the partial byte at the end */
6836 for (rlen=blen;rlen>=8;rlen-=8)
6838 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6839 emit2 ("ld !*pair,a", _pairs[pair].name);
6842 emit2 ("inc %s", _pairs[pair].name);
6843 _G.pairs[pair].offset++;
6847 /* If there was a partial byte at the end */
6850 mask = (((unsigned char) -1 << rlen) & 0xff);
6852 if (AOP_TYPE (right) == AOP_LIT)
6854 /* Case with partial byte and literal source
6856 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6857 litval >>= (blen-rlen);
6858 litval &= (~mask) & 0xff;
6859 emit2 ("ld a,!*pair", _pairs[pair].name);
6860 if ((mask|litval)!=0xff)
6861 emit2 ("and a,!immedbyte", mask);
6863 emit2 ("or a,!immedbyte", litval);
6867 /* Case with partial byte and arbitrary source
6869 _moveA (aopGet (AOP (right), offset++, FALSE));
6870 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6872 extraPair = getFreePairId(ic);
6873 if (extraPair == PAIR_INVALID)
6875 extraPair = getPairId (AOP (right));
6876 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6877 extraPair = PAIR_BC;
6879 if (getPairId (AOP (right)) != PAIR_BC
6880 || !isLastUse (ic, right))
6886 emit2 ("ld %s,a", _pairs[extraPair].l);
6887 emit2 ("ld a,!*pair", _pairs[pair].name);
6889 emit2 ("and a,!immedbyte", mask);
6890 emit2 ("or a,%s", _pairs[extraPair].l);
6895 emit2 ("ld !*pair,a", _pairs[pair].name);
6900 /*-----------------------------------------------------------------*/
6901 /* genGenPointerSet - stores the value into a pointer location */
6902 /*-----------------------------------------------------------------*/
6904 genGenPointerSet (operand * right,
6905 operand * result, iCode * ic)
6908 sym_link *retype = getSpec (operandType (right));
6909 sym_link *letype = getSpec (operandType (result));
6910 PAIR_ID pairId = PAIR_HL;
6913 aopOp (result, ic, FALSE, FALSE);
6914 aopOp (right, ic, FALSE, FALSE);
6919 size = AOP_SIZE (right);
6921 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6922 emitDebug("; isBitvar = %d", isBitvar);
6924 /* Handle the exceptions first */
6925 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6928 const char *l = aopGet (AOP (right), 0, FALSE);
6929 const char *pair = getPairName (AOP (result));
6930 if (canAssignToPtr (l) && isPtr (pair))
6932 emit2 ("ld !*pair,%s", pair, l);
6937 emit2 ("ld !*pair,a", pair);
6942 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6945 const char *l = aopGet (AOP (right), 0, FALSE);
6950 if (canAssignToPtr (l))
6952 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6956 _moveA (aopGet (AOP (right), offset, FALSE));
6957 emit2 ("ld !*iyx,a", offset);
6963 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6970 const char *l = aopGet (AOP (right), offset, FALSE);
6971 if (isRegOrLit (AOP (right)) && !IS_GB)
6973 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6978 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6982 emit2 ("inc %s", _pairs[PAIR_HL].name);
6983 _G.pairs[PAIR_HL].offset++;
6988 /* Fixup HL back down */
6989 for (size = AOP_SIZE (right)-1; size; size--)
6991 emit2 ("dec %s", _pairs[PAIR_HL].name);
6996 /* if the operand is already in dptr
6997 then we do nothing else we move the value to dptr */
6998 if (AOP_TYPE (result) != AOP_STR)
7000 fetchPair (pairId, AOP (result));
7002 /* so hl now contains the address */
7003 freeAsmop (result, NULL, ic);
7005 /* if bit then unpack */
7008 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7018 const char *l = aopGet (AOP (right), offset, FALSE);
7019 if (isRegOrLit (AOP (right)) && !IS_GB)
7021 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7026 emit2 ("ld !*pair,a", _pairs[pairId].name);
7030 emit2 ("inc %s", _pairs[pairId].name);
7031 _G.pairs[pairId].offset++;
7037 freeAsmop (right, NULL, ic);
7040 /*-----------------------------------------------------------------*/
7041 /* genPointerSet - stores the value into a pointer location */
7042 /*-----------------------------------------------------------------*/
7044 genPointerSet (iCode * ic)
7046 operand *right, *result;
7047 sym_link *type, *etype;
7049 right = IC_RIGHT (ic);
7050 result = IC_RESULT (ic);
7052 /* depending on the type of pointer we need to
7053 move it to the correct pointer register */
7054 type = operandType (result);
7055 etype = getSpec (type);
7057 genGenPointerSet (right, result, ic);
7060 /*-----------------------------------------------------------------*/
7061 /* genIfx - generate code for Ifx statement */
7062 /*-----------------------------------------------------------------*/
7064 genIfx (iCode * ic, iCode * popIc)
7066 operand *cond = IC_COND (ic);
7069 aopOp (cond, ic, FALSE, TRUE);
7071 /* get the value into acc */
7072 if (AOP_TYPE (cond) != AOP_CRY)
7076 /* the result is now in the accumulator */
7077 freeAsmop (cond, NULL, ic);
7079 /* if there was something to be popped then do it */
7083 /* if the condition is a bit variable */
7084 if (isbit && IS_ITEMP (cond) &&
7086 genIfxJump (ic, SPIL_LOC (cond)->rname);
7087 else if (isbit && !IS_ITEMP (cond))
7088 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7090 genIfxJump (ic, "a");
7095 /*-----------------------------------------------------------------*/
7096 /* genAddrOf - generates code for address of */
7097 /*-----------------------------------------------------------------*/
7099 genAddrOf (iCode * ic)
7101 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7103 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7105 /* if the operand is on the stack then we
7106 need to get the stack offset of this
7113 if (sym->stack <= 0)
7115 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7119 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7121 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7125 emit2 ("ld de,!hashedstr", sym->rname);
7126 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7134 /* if it has an offset then we need to compute it */
7136 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7138 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7139 emit2 ("add hl,sp");
7143 emit2 ("ld hl,!hashedstr", sym->rname);
7145 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7147 freeAsmop (IC_RESULT (ic), NULL, ic);
7150 /*-----------------------------------------------------------------*/
7151 /* genAssign - generate code for assignment */
7152 /*-----------------------------------------------------------------*/
7154 genAssign (iCode * ic)
7156 operand *result, *right;
7158 unsigned long lit = 0L;
7160 result = IC_RESULT (ic);
7161 right = IC_RIGHT (ic);
7163 /* Dont bother assigning if they are the same */
7164 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7166 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7170 aopOp (right, ic, FALSE, FALSE);
7171 aopOp (result, ic, TRUE, FALSE);
7173 /* if they are the same registers */
7174 if (sameRegs (AOP (right), AOP (result)))
7176 emitDebug ("; (registers are the same)");
7180 /* if the result is a bit */
7181 if (AOP_TYPE (result) == AOP_CRY)
7183 wassertl (0, "Tried to assign to a bit");
7187 size = AOP_SIZE (result);
7190 if (AOP_TYPE (right) == AOP_LIT)
7192 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7195 if (isPair (AOP (result)))
7197 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7199 else if ((size > 1) &&
7200 (AOP_TYPE (result) != AOP_REG) &&
7201 (AOP_TYPE (right) == AOP_LIT) &&
7202 !IS_FLOAT (operandType (right)) &&
7205 bool fXored = FALSE;
7207 /* Work from the top down.
7208 Done this way so that we can use the cached copy of 0
7209 in A for a fast clear */
7212 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7214 if (!fXored && size > 1)
7221 aopPut (AOP (result), "a", offset);
7225 aopPut (AOP (result), "!zero", offset);
7229 aopPut (AOP (result),
7230 aopGet (AOP (right), offset, FALSE),
7235 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7237 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7238 aopPut (AOP (result), "l", LSB);
7239 aopPut (AOP (result), "h", MSB16);
7241 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7243 /* Special case. Load into a and d, then load out. */
7244 _moveA (aopGet (AOP (right), 0, FALSE));
7245 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7246 aopPut (AOP (result), "a", 0);
7247 aopPut (AOP (result), "e", 1);
7249 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7251 /* Special case - simple memcpy */
7252 aopGet (AOP (right), LSB, FALSE);
7255 aopGet (AOP (result), LSB, FALSE);
7259 emit2 ("ld a,(de)");
7260 /* Peephole will optimise this. */
7261 emit2 ("ld (hl),a");
7269 spillPair (PAIR_HL);
7275 /* PENDING: do this check better */
7276 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7278 _moveA (aopGet (AOP (right), offset, FALSE));
7279 aopPut (AOP (result), "a", offset);
7282 aopPut (AOP (result),
7283 aopGet (AOP (right), offset, FALSE),
7290 freeAsmop (right, NULL, ic);
7291 freeAsmop (result, NULL, ic);
7294 /*-----------------------------------------------------------------*/
7295 /* genJumpTab - genrates code for jump table */
7296 /*-----------------------------------------------------------------*/
7298 genJumpTab (iCode * ic)
7303 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7304 /* get the condition into accumulator */
7305 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7308 emit2 ("ld e,%s", l);
7309 emit2 ("ld d,!zero");
7310 jtab = newiTempLabel (NULL);
7312 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7313 emit2 ("add hl,de");
7314 emit2 ("add hl,de");
7315 emit2 ("add hl,de");
7316 freeAsmop (IC_JTCOND (ic), NULL, ic);
7320 emitLabel (jtab->key + 100);
7321 /* now generate the jump labels */
7322 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7323 jtab = setNextItem (IC_JTLABELS (ic)))
7324 emit2 ("jp !tlabel", jtab->key + 100);
7327 /*-----------------------------------------------------------------*/
7328 /* genCast - gen code for casting */
7329 /*-----------------------------------------------------------------*/
7331 genCast (iCode * ic)
7333 operand *result = IC_RESULT (ic);
7334 sym_link *rtype = operandType (IC_RIGHT (ic));
7335 operand *right = IC_RIGHT (ic);
7338 /* if they are equivalent then do nothing */
7339 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7342 aopOp (right, ic, FALSE, FALSE);
7343 aopOp (result, ic, FALSE, FALSE);
7345 /* if the result is a bit */
7346 if (AOP_TYPE (result) == AOP_CRY)
7348 wassertl (0, "Tried to cast to a bit");
7351 /* if they are the same size : or less */
7352 if (AOP_SIZE (result) <= AOP_SIZE (right))
7355 /* if they are in the same place */
7356 if (sameRegs (AOP (right), AOP (result)))
7359 /* if they in different places then copy */
7360 size = AOP_SIZE (result);
7364 aopPut (AOP (result),
7365 aopGet (AOP (right), offset, FALSE),
7372 /* So we now know that the size of destination is greater
7373 than the size of the source */
7374 /* we move to result for the size of source */
7375 size = AOP_SIZE (right);
7379 aopPut (AOP (result),
7380 aopGet (AOP (right), offset, FALSE),
7385 /* now depending on the sign of the destination */
7386 size = AOP_SIZE (result) - AOP_SIZE (right);
7387 /* Unsigned or not an integral type - right fill with zeros */
7388 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7391 aopPut (AOP (result), "!zero", offset++);
7395 /* we need to extend the sign :{ */
7396 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7402 aopPut (AOP (result), "a", offset++);
7406 freeAsmop (right, NULL, ic);
7407 freeAsmop (result, NULL, ic);
7410 /*-----------------------------------------------------------------*/
7411 /* genReceive - generate code for a receive iCode */
7412 /*-----------------------------------------------------------------*/
7414 genReceive (iCode * ic)
7416 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7417 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7418 IS_TRUE_SYMOP (IC_RESULT (ic))))
7428 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7429 size = AOP_SIZE(IC_RESULT(ic));
7431 for (i = 0; i < size; i++) {
7432 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7436 freeAsmop (IC_RESULT (ic), NULL, ic);
7439 /*-----------------------------------------------------------------*/
7440 /* genDummyRead - generate code for dummy read of volatiles */
7441 /*-----------------------------------------------------------------*/
7443 genDummyRead (iCode * ic)
7449 if (op && IS_SYMOP (op))
7451 aopOp (op, ic, FALSE, FALSE);
7454 size = AOP_SIZE (op);
7459 _moveA (aopGet (AOP (op), offset, FALSE));
7463 freeAsmop (op, NULL, ic);
7467 if (op && IS_SYMOP (op))
7469 aopOp (op, ic, FALSE, FALSE);
7472 size = AOP_SIZE (op);
7477 _moveA (aopGet (AOP (op), offset, FALSE));
7481 freeAsmop (op, NULL, ic);
7485 /*-----------------------------------------------------------------*/
7486 /* genCritical - generate code for start of a critical sequence */
7487 /*-----------------------------------------------------------------*/
7489 genCritical (iCode *ic)
7491 symbol *tlbl = newiTempLabel (NULL);
7497 else if (IC_RESULT (ic))
7499 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7500 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7501 //get interrupt enable flag IFF2 into P/O
7505 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7506 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7507 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7508 emit2 ("!tlabeldef", (tlbl->key + 100));
7509 _G.lines.current->isLabel = 1;
7510 freeAsmop (IC_RESULT (ic), NULL, ic);
7514 //get interrupt enable flag IFF2 into P/O
7523 /*-----------------------------------------------------------------*/
7524 /* genEndCritical - generate code for end of a critical sequence */
7525 /*-----------------------------------------------------------------*/
7527 genEndCritical (iCode *ic)
7529 symbol *tlbl = newiTempLabel (NULL);
7535 else if (IC_RIGHT (ic))
7537 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7538 _toBoolean (IC_RIGHT (ic));
7539 //don't enable interrupts if they were off before
7540 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7542 emitLabel (tlbl->key + 100);
7543 freeAsmop (IC_RIGHT (ic), NULL, ic);
7549 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7550 //don't enable interrupts as they were off before
7551 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7553 emit2 ("!tlabeldef", (tlbl->key + 100));
7554 _G.lines.current->isLabel = 1;
7560 /** Maximum number of bytes to emit per line. */
7564 /** Context for the byte output chunker. */
7567 unsigned char buffer[DBEMIT_MAX_RUN];
7572 /** Flushes a byte chunker by writing out all in the buffer and
7576 _dbFlush(DBEMITCTX *self)
7583 sprintf(line, ".db 0x%02X", self->buffer[0]);
7585 for (i = 1; i < self->pos; i++)
7587 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7594 /** Write out another byte, buffering until a decent line is
7598 _dbEmit(DBEMITCTX *self, int c)
7600 if (self->pos == DBEMIT_MAX_RUN)
7604 self->buffer[self->pos++] = c;
7607 /** Context for a simple run length encoder. */
7611 unsigned char buffer[128];
7613 /** runLen may be equivalent to pos. */
7619 RLE_CHANGE_COST = 4,
7623 /** Flush the buffer of a run length encoder by writing out the run or
7624 data that it currently contains.
7627 _rleCommit(RLECTX *self)
7633 memset(&db, 0, sizeof(db));
7635 emit2(".db %u", self->pos);
7637 for (i = 0; i < self->pos; i++)
7639 _dbEmit(&db, self->buffer[i]);
7648 Can get either a run or a block of random stuff.
7649 Only want to change state if a good run comes in or a run ends.
7650 Detecting run end is easy.
7653 Say initial state is in run, len zero, last zero. Then if you get a
7654 few zeros then something else then a short run will be output.
7655 Seems OK. While in run mode, keep counting. While in random mode,
7656 keep a count of the run. If run hits margin, output all up to run,
7657 restart, enter run mode.
7660 /** Add another byte into the run length encoder, flushing as
7661 required. The run length encoder uses the Amiga IFF style, where
7662 a block is prefixed by its run length. A positive length means
7663 the next n bytes pass straight through. A negative length means
7664 that the next byte is repeated -n times. A zero terminates the
7668 _rleAppend(RLECTX *self, unsigned c)
7672 if (c != self->last)
7674 /* The run has stopped. See if it is worthwhile writing it out
7675 as a run. Note that the random data comes in as runs of
7678 if (self->runLen > RLE_CHANGE_COST)
7680 /* Yes, worthwhile. */
7681 /* Commit whatever was in the buffer. */
7683 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7687 /* Not worthwhile. Append to the end of the random list. */
7688 for (i = 0; i < self->runLen; i++)
7690 if (self->pos >= RLE_MAX_BLOCK)
7695 self->buffer[self->pos++] = self->last;
7703 if (self->runLen >= RLE_MAX_BLOCK)
7705 /* Commit whatever was in the buffer. */
7708 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7716 _rleFlush(RLECTX *self)
7718 _rleAppend(self, -1);
7725 /** genArrayInit - Special code for initialising an array with constant
7729 genArrayInit (iCode * ic)
7733 int elementSize = 0, eIndex, i;
7734 unsigned val, lastVal;
7738 memset(&rle, 0, sizeof(rle));
7740 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7742 _saveRegsForCall(ic, 0);
7744 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7745 emit2 ("call __initrleblock");
7747 type = operandType(IC_LEFT(ic));
7749 if (type && type->next)
7751 if (IS_SPEC(type->next) || IS_PTR(type->next))
7753 elementSize = getSize(type->next);
7755 else if (IS_ARRAY(type->next) && type->next->next)
7757 elementSize = getSize(type->next->next);
7761 printTypeChainRaw (type, NULL);
7762 wassertl (0, "Can't determine element size in genArrayInit.");
7767 wassertl (0, "Can't determine element size in genArrayInit.");
7770 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7772 iLoop = IC_ARRAYILIST(ic);
7773 lastVal = (unsigned)-1;
7775 /* Feed all the bytes into the run length encoder which will handle
7777 This works well for mixed char data, and for random int and long
7784 for (i = 0; i < ix; i++)
7786 for (eIndex = 0; eIndex < elementSize; eIndex++)
7788 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7789 _rleAppend(&rle, val);
7793 iLoop = iLoop->next;
7797 /* Mark the end of the run. */
7800 _restoreRegsAfterCall();
7804 freeAsmop (IC_LEFT(ic), NULL, ic);
7808 _swap (PAIR_ID one, PAIR_ID two)
7810 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7816 emit2 ("ld a,%s", _pairs[one].l);
7817 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7818 emit2 ("ld %s,a", _pairs[two].l);
7819 emit2 ("ld a,%s", _pairs[one].h);
7820 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7821 emit2 ("ld %s,a", _pairs[two].h);
7825 /* The problem is that we may have all three pairs used and they may
7826 be needed in a different order.
7831 hl = hl => unity, fine
7835 hl = hl hl = hl, swap de <=> bc
7843 hl = bc de = de, swap bc <=> hl
7851 hl = de bc = bc, swap hl <=> de
7856 * Any pair = pair are done last
7857 * Any pair = iTemp are done last
7858 * Any swaps can be done any time
7866 So how do we detect the cases?
7867 How about a 3x3 matrix?
7871 x x x x (Fourth for iTemp/other)
7873 First determin which mode to use by counting the number of unity and
7876 Two - Assign the pair first, then the rest
7877 One - Swap the two, then the rest
7881 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7883 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7885 PAIR_BC, PAIR_HL, PAIR_DE
7887 int i, j, nunity = 0;
7888 memset (ids, PAIR_INVALID, sizeof (ids));
7891 wassert (nparams == 3);
7893 /* First save everything that needs to be saved. */
7894 _saveRegsForCall (ic, 0);
7896 /* Loading HL first means that DE is always fine. */
7897 for (i = 0; i < nparams; i++)
7899 aopOp (pparams[i], ic, FALSE, FALSE);
7900 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7903 /* Count the number of unity or iTemp assigns. */
7904 for (i = 0; i < 3; i++)
7906 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7914 /* Any order, fall through. */
7916 else if (nunity == 2)
7918 /* One is assigned. Pull it out and assign. */
7919 for (i = 0; i < 3; i++)
7921 for (j = 0; j < NUM_PAIRS; j++)
7923 if (ids[dest[i]][j] == TRUE)
7925 /* Found it. See if it's the right one. */
7926 if (j == PAIR_INVALID || j == dest[i])
7932 fetchPair(dest[i], AOP (pparams[i]));
7939 else if (nunity == 1)
7941 /* Find the pairs to swap. */
7942 for (i = 0; i < 3; i++)
7944 for (j = 0; j < NUM_PAIRS; j++)
7946 if (ids[dest[i]][j] == TRUE)
7948 if (j == PAIR_INVALID || j == dest[i])
7963 int next = getPairId (AOP (pparams[0]));
7964 emit2 ("push %s", _pairs[next].name);
7966 if (next == dest[1])
7968 fetchPair (dest[1], AOP (pparams[1]));
7969 fetchPair (dest[2], AOP (pparams[2]));
7973 fetchPair (dest[2], AOP (pparams[2]));
7974 fetchPair (dest[1], AOP (pparams[1]));
7976 emit2 ("pop %s", _pairs[dest[0]].name);
7979 /* Finally pull out all of the iTemps */
7980 for (i = 0; i < 3; i++)
7982 if (ids[dest[i]][PAIR_INVALID] == 1)
7984 fetchPair (dest[i], AOP (pparams[i]));
7990 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7996 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8000 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8002 setupForBuiltin3 (ic, nParams, pparams);
8004 label = newiTempLabel(NULL);
8006 emitLabel (label->key);
8007 emit2 ("ld a,(hl)");
8010 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8012 freeAsmop (from, NULL, ic->next);
8013 freeAsmop (to, NULL, ic);
8017 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8019 operand *from, *to, *count;
8022 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8027 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8029 setupForBuiltin3 (ic, nParams, pparams);
8033 freeAsmop (count, NULL, ic->next->next);
8034 freeAsmop (from, NULL, ic);
8036 _restoreRegsAfterCall();
8038 /* if we need assign a result value */
8039 if ((IS_ITEMP (IC_RESULT (ic)) &&
8040 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8041 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8042 IS_TRUE_SYMOP (IC_RESULT (ic)))
8044 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8045 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8046 freeAsmop (IC_RESULT (ic), NULL, ic);
8049 freeAsmop (to, NULL, ic->next);
8052 /*-----------------------------------------------------------------*/
8053 /* genBuiltIn - calls the appropriate function to generating code */
8054 /* for a built in function */
8055 /*-----------------------------------------------------------------*/
8056 static void genBuiltIn (iCode *ic)
8058 operand *bi_parms[MAX_BUILTIN_ARGS];
8063 /* get all the arguments for a built in function */
8064 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8066 /* which function is it */
8067 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8069 if (strcmp(bif->name,"__builtin_strcpy")==0)
8071 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8073 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8075 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8079 wassertl (0, "Unknown builtin function encountered");
8083 /*-----------------------------------------------------------------*/
8084 /* genZ80Code - generate code for Z80 based controllers */
8085 /*-----------------------------------------------------------------*/
8087 genZ80Code (iCode * lic)
8095 _fReturn = _gbz80_return;
8096 _fTmp = _gbz80_return;
8100 _fReturn = _z80_return;
8101 _fTmp = _z80_return;
8104 _G.lines.head = _G.lines.current = NULL;
8106 /* if debug information required */
8107 if (options.debug && currFunc)
8109 debugFile->writeFunction (currFunc, lic);
8112 for (ic = lic; ic; ic = ic->next)
8114 _G.current_iCode = ic;
8116 if (ic->lineno && cln != ic->lineno)
8120 debugFile->writeCLine (ic);
8122 if (!options.noCcodeInAsm)
8124 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8125 printCLine(ic->filename, ic->lineno));
8129 if (options.iCodeInAsm)
8131 char *iLine = printILine(ic);
8132 emit2 (";ic:%d: %s", ic->key, iLine);
8135 /* if the result is marked as
8136 spilt and rematerializable or code for
8137 this has already been generated then
8139 if (resultRemat (ic) || ic->generated)
8142 /* depending on the operation */
8146 emitDebug ("; genNot");
8151 emitDebug ("; genCpl");
8156 emitDebug ("; genUminus");
8161 emitDebug ("; genIpush");
8166 /* IPOP happens only when trying to restore a
8167 spilt live range, if there is an ifx statement
8168 following this pop then the if statement might
8169 be using some of the registers being popped which
8170 would destroy the contents of the register so
8171 we need to check for this condition and handle it */
8173 ic->next->op == IFX &&
8174 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8176 emitDebug ("; genIfx");
8177 genIfx (ic->next, ic);
8181 emitDebug ("; genIpop");
8187 emitDebug ("; genCall");
8192 emitDebug ("; genPcall");
8197 emitDebug ("; genFunction");
8202 emitDebug ("; genEndFunction");
8203 genEndFunction (ic);
8207 emitDebug ("; genRet");
8212 emitDebug ("; genLabel");
8217 emitDebug ("; genGoto");
8222 emitDebug ("; genPlus");
8227 emitDebug ("; genMinus");
8232 emitDebug ("; genMult");
8237 emitDebug ("; genDiv");
8242 emitDebug ("; genMod");
8247 emitDebug ("; genCmpGt");
8248 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8252 emitDebug ("; genCmpLt");
8253 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8260 /* note these two are xlated by algebraic equivalence
8261 during parsing SDCC.y */
8262 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8263 "got '>=' or '<=' shouldn't have come here");
8267 emitDebug ("; genCmpEq");
8268 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8272 emitDebug ("; genAndOp");
8277 emitDebug ("; genOrOp");
8282 emitDebug ("; genXor");
8283 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8287 emitDebug ("; genOr");
8288 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8292 emitDebug ("; genAnd");
8293 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8297 emitDebug ("; genInline");
8302 emitDebug ("; genRRC");
8307 emitDebug ("; genRLC");
8312 emitDebug ("; genGetHBIT");
8317 emitDebug ("; genLeftShift");
8322 emitDebug ("; genRightShift");
8326 case GET_VALUE_AT_ADDRESS:
8327 emitDebug ("; genPointerGet");
8333 if (POINTER_SET (ic))
8335 emitDebug ("; genAssign (pointer)");
8340 emitDebug ("; genAssign");
8346 emitDebug ("; genIfx");
8351 emitDebug ("; genAddrOf");
8356 emitDebug ("; genJumpTab");
8361 emitDebug ("; genCast");
8366 emitDebug ("; genReceive");
8371 if (ic->builtinSEND)
8373 emitDebug ("; genBuiltIn");
8378 emitDebug ("; addSet");
8379 addSet (&_G.sendSet, ic);
8384 emitDebug ("; genArrayInit");
8388 case DUMMY_READ_VOLATILE:
8389 emitDebug ("; genDummyRead");
8394 emitDebug ("; genCritical");
8399 emitDebug ("; genEndCritical");
8400 genEndCritical (ic);
8409 /* now we are ready to call the
8410 peep hole optimizer */
8411 if (!options.nopeep)
8412 peepHole (&_G.lines.head);
8414 /* This is unfortunate */
8415 /* now do the actual printing */
8417 struct dbuf_s *buf = codeOutBuf;
8418 if (isInHome () && codeOutBuf == &code->oBuf)
8419 codeOutBuf = &home->oBuf;
8420 printLine (_G.lines.head, codeOutBuf);
8421 if (_G.flushStatics)
8424 _G.flushStatics = 0;
8429 freeTrace(&_G.lines.trace);
8430 freeTrace(&_G.trace.aops);
8436 _isPairUsed (iCode * ic, PAIR_ID pairId)
8442 if (bitVectBitValue (ic->rMask, D_IDX))
8444 if (bitVectBitValue (ic->rMask, E_IDX))
8454 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8457 value *val = aop->aopu.aop_lit;
8459 wassert (aop->type == AOP_LIT);
8460 wassert (!IS_FLOAT (val->type));
8462 v = (unsigned long) floatFromVal (val);
8470 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8471 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));