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 outBitCLong (operand * result, bool swap_sense)
2235 /* if the result is bit */
2236 if (AOP_TYPE (result) == AOP_CRY)
2238 wassertl (0, "Tried to write carry to a bit");
2242 emit2 ("ld a,!zero");
2245 emit2 ("xor a,!immedbyte", 1);
2251 outBitC (operand * result)
2253 outBitCLong (result, FALSE);
2256 /*-----------------------------------------------------------------*/
2257 /* toBoolean - emit code for orl a,operator(sizeop) */
2258 /*-----------------------------------------------------------------*/
2260 _toBoolean (operand * oper)
2262 int size = AOP_SIZE (oper);
2266 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2269 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2273 if (AOP (oper)->type != AOP_ACC)
2276 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2282 /*-----------------------------------------------------------------*/
2283 /* genNot - generate code for ! operation */
2284 /*-----------------------------------------------------------------*/
2289 /* assign asmOps to operand & result */
2290 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2291 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2293 /* if in bit space then a special case */
2294 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2296 wassertl (0, "Tried to negate a bit");
2299 _toBoolean (IC_LEFT (ic));
2304 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2305 emit2 ("sub a,!one");
2306 outBitC (IC_RESULT (ic));
2308 /* release the aops */
2309 freeAsmop (IC_LEFT (ic), NULL, ic);
2310 freeAsmop (IC_RESULT (ic), NULL, ic);
2313 /*-----------------------------------------------------------------*/
2314 /* genCpl - generate code for complement */
2315 /*-----------------------------------------------------------------*/
2323 /* assign asmOps to operand & result */
2324 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2325 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2327 /* if both are in bit space then
2329 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2330 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2332 wassertl (0, "Left and the result are in bit space");
2335 size = AOP_SIZE (IC_RESULT (ic));
2338 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2341 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2344 /* release the aops */
2345 freeAsmop (IC_LEFT (ic), NULL, ic);
2346 freeAsmop (IC_RESULT (ic), NULL, ic);
2350 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2357 store de into result
2362 store de into result
2364 const char *first = isAdd ? "add" : "sub";
2365 const char *later = isAdd ? "adc" : "sbc";
2367 wassertl (IS_GB, "Code is only relevent to the gbz80");
2368 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2370 fetchPair (PAIR_DE, left);
2373 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2376 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2379 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2380 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2382 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2383 aopGet (right, MSB24, FALSE);
2387 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2390 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2392 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2393 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2397 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2399 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2402 /*-----------------------------------------------------------------*/
2403 /* genUminusFloat - unary minus for floating points */
2404 /*-----------------------------------------------------------------*/
2406 genUminusFloat (operand * op, operand * result)
2408 int size, offset = 0;
2410 emitDebug("; genUminusFloat");
2412 /* for this we just need to flip the
2413 first bit then copy the rest in place */
2414 size = AOP_SIZE (op) - 1;
2416 _moveA(aopGet (AOP (op), MSB32, FALSE));
2418 emit2("xor a,!immedbyte", 0x80);
2419 aopPut (AOP (result), "a", MSB32);
2423 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2428 /*-----------------------------------------------------------------*/
2429 /* genUminus - unary minus code generation */
2430 /*-----------------------------------------------------------------*/
2432 genUminus (iCode * ic)
2435 sym_link *optype, *rtype;
2438 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2439 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2441 /* if both in bit space then special
2443 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2444 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2446 wassertl (0, "Left and right are in bit space");
2450 optype = operandType (IC_LEFT (ic));
2451 rtype = operandType (IC_RESULT (ic));
2453 /* if float then do float stuff */
2454 if (IS_FLOAT (optype))
2456 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2460 /* otherwise subtract from zero */
2461 size = AOP_SIZE (IC_LEFT (ic));
2463 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2465 /* Create a new asmop with value zero */
2466 asmop *azero = newAsmop (AOP_SIMPLELIT);
2467 azero->aopu.aop_simplelit = 0;
2469 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2477 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2478 emit2 ("ld a,!zero");
2479 emit2 ("sbc a,%s", l);
2480 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2483 /* if any remaining bytes in the result */
2484 /* we just need to propagate the sign */
2485 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2490 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2494 /* release the aops */
2495 freeAsmop (IC_LEFT (ic), NULL, ic);
2496 freeAsmop (IC_RESULT (ic), NULL, ic);
2499 /*-----------------------------------------------------------------*/
2500 /* assignResultValue - */
2501 /*-----------------------------------------------------------------*/
2503 assignResultValue (operand * oper)
2505 int size = AOP_SIZE (oper);
2508 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2509 topInA = requiresHL (AOP (oper));
2511 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2513 /* We do it the hard way here. */
2515 aopPut (AOP (oper), _fReturn[0], 0);
2516 aopPut (AOP (oper), _fReturn[1], 1);
2518 aopPut (AOP (oper), _fReturn[0], 2);
2519 aopPut (AOP (oper), _fReturn[1], 3);
2523 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2524 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2527 _emitMove ("a", _fReturn[size-1]);
2528 _emitMove (_fReturn[size-1], _fReturn[size]);
2529 _emitMove (_fReturn[size], "a");
2530 aopPut (AOP (oper), _fReturn[size], size-1);
2535 aopPut (AOP (oper), _fReturn[size], size);
2540 /** Simple restore that doesn't take into account what is used in the
2544 _restoreRegsAfterCall(void)
2546 if (_G.stack.pushedDE)
2549 _G.stack.pushedDE = FALSE;
2551 if (_G.stack.pushedBC)
2554 _G.stack.pushedBC = FALSE;
2556 _G.saves.saved = FALSE;
2560 _saveRegsForCall(iCode *ic, int sendSetSize)
2563 o Stack parameters are pushed before this function enters
2564 o DE and BC may be used in this function.
2565 o HL and DE may be used to return the result.
2566 o HL and DE may be used to send variables.
2567 o DE and BC may be used to store the result value.
2568 o HL may be used in computing the sent value of DE
2569 o The iPushes for other parameters occur before any addSets
2571 Logic: (to be run inside the first iPush or if none, before sending)
2572 o Compute if DE and/or BC are in use over the call
2573 o Compute if DE is used in the send set
2574 o Compute if DE and/or BC are used to hold the result value
2575 o If (DE is used, or in the send set) and is not used in the result, push.
2576 o If BC is used and is not in the result, push
2578 o If DE is used in the send set, fetch
2579 o If HL is used in the send set, fetch
2583 if (_G.saves.saved == FALSE) {
2584 bool deInUse, bcInUse;
2586 bool bcInRet = FALSE, deInRet = FALSE;
2589 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2590 z80_rUmaskForOp (IC_RESULT(ic)));
2592 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2593 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2595 deSending = (sendSetSize > 1);
2597 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2599 if (bcInUse && bcInRet == FALSE) {
2601 _G.stack.pushedBC = TRUE;
2603 if (deInUse && deInRet == FALSE) {
2605 _G.stack.pushedDE = TRUE;
2608 _G.saves.saved = TRUE;
2611 /* Already saved. */
2615 /*-----------------------------------------------------------------*/
2616 /* genIpush - genrate code for pushing this gets a little complex */
2617 /*-----------------------------------------------------------------*/
2619 genIpush (iCode * ic)
2621 int size, offset = 0;
2624 /* if this is not a parm push : ie. it is spill push
2625 and spill push is always done on the local stack */
2628 wassertl(0, "Encountered an unsupported spill push.");
2632 if (_G.saves.saved == FALSE) {
2633 /* Caller saves, and this is the first iPush. */
2634 /* Scan ahead until we find the function that we are pushing parameters to.
2635 Count the number of addSets on the way to figure out what registers
2636 are used in the send set.
2639 iCode *walk = ic->next;
2642 if (walk->op == SEND) {
2645 else if (walk->op == CALL || walk->op == PCALL) {
2654 _saveRegsForCall(walk, nAddSets);
2657 /* Already saved by another iPush. */
2660 /* then do the push */
2661 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2663 size = AOP_SIZE (IC_LEFT (ic));
2665 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2667 _G.stack.pushed += 2;
2668 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2674 fetchHL (AOP (IC_LEFT (ic)));
2676 spillPair (PAIR_HL);
2677 _G.stack.pushed += 2;
2682 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2684 spillPair (PAIR_HL);
2685 _G.stack.pushed += 2;
2686 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2688 spillPair (PAIR_HL);
2689 _G.stack.pushed += 2;
2695 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2697 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2699 emit2 ("ld a,(%s)", l);
2704 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2705 if (!strcmp(l, "b"))
2707 else if (!strcmp(l, "d"))
2709 else if (!strcmp(l, "h"))
2713 emit2 ("ld a,%s", l);
2722 freeAsmop (IC_LEFT (ic), NULL, ic);
2725 /*-----------------------------------------------------------------*/
2726 /* genIpop - recover the registers: can happen only for spilling */
2727 /*-----------------------------------------------------------------*/
2729 genIpop (iCode * ic)
2734 /* if the temp was not pushed then */
2735 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2738 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2739 size = AOP_SIZE (IC_LEFT (ic));
2740 offset = (size - 1);
2741 if (isPair (AOP (IC_LEFT (ic))))
2743 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2751 spillPair (PAIR_HL);
2752 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2756 freeAsmop (IC_LEFT (ic), NULL, ic);
2759 /* This is quite unfortunate */
2761 setArea (int inHome)
2764 static int lastArea = 0;
2766 if (_G.in_home != inHome) {
2768 const char *sz = port->mem.code_name;
2769 port->mem.code_name = "HOME";
2770 emit2("!area", CODE_NAME);
2771 port->mem.code_name = sz;
2774 emit2("!area", CODE_NAME); */
2775 _G.in_home = inHome;
2786 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2790 symbol *sym = OP_SYMBOL (op);
2792 if (sym->isspilt || sym->nRegs == 0)
2795 aopOp (op, ic, FALSE, FALSE);
2798 if (aop->type == AOP_REG)
2801 for (i = 0; i < aop->size; i++)
2803 if (pairId == PAIR_DE)
2805 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2806 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2808 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2811 else if (pairId == PAIR_BC)
2813 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2814 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2816 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2826 freeAsmop (IC_LEFT (ic), NULL, ic);
2830 /** Emit the code for a call statement
2833 emitCall (iCode * ic, bool ispcall)
2835 bool bInRet, cInRet, dInRet, eInRet;
2836 sym_link *dtype = operandType (IC_LEFT (ic));
2838 /* if caller saves & we have not saved then */
2844 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2846 /* if send set is not empty then assign */
2851 int nSend = elementsInSet(_G.sendSet);
2852 bool swapped = FALSE;
2854 int _z80_sendOrder[] = {
2859 /* Check if the parameters are swapped. If so route through hl instead. */
2860 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2862 sic = setFirstItem(_G.sendSet);
2863 sic = setNextItem(_G.sendSet);
2865 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2866 /* The second send value is loaded from one the one that holds the first
2867 send, i.e. it is overwritten. */
2868 /* Cache the first in HL, and load the second from HL instead. */
2869 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2870 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2876 for (sic = setFirstItem (_G.sendSet); sic;
2877 sic = setNextItem (_G.sendSet))
2880 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2882 size = AOP_SIZE (IC_LEFT (sic));
2883 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2884 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2886 // PENDING: Mild hack
2887 if (swapped == TRUE && send == 1) {
2889 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2892 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2894 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2897 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2901 freeAsmop (IC_LEFT (sic), NULL, sic);
2908 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2910 werror (W_INDIR_BANKED);
2912 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2914 if (isLitWord (AOP (IC_LEFT (ic))))
2916 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2920 symbol *rlbl = newiTempLabel (NULL);
2921 spillPair (PAIR_HL);
2922 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2924 _G.stack.pushed += 2;
2926 fetchHL (AOP (IC_LEFT (ic)));
2928 emit2 ("!tlabeldef", (rlbl->key + 100));
2929 _G.lines.current->isLabel = 1;
2930 _G.stack.pushed -= 2;
2932 freeAsmop (IC_LEFT (ic), NULL, ic);
2936 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2937 OP_SYMBOL (IC_LEFT (ic))->rname :
2938 OP_SYMBOL (IC_LEFT (ic))->name;
2939 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2941 emit2 ("call banked_call");
2942 emit2 ("!dws", name);
2943 emit2 ("!dw !bankimmeds", name);
2948 emit2 ("call %s", name);
2953 /* Mark the registers as restored. */
2954 _G.saves.saved = FALSE;
2956 /* if we need assign a result value */
2957 if ((IS_ITEMP (IC_RESULT (ic)) &&
2958 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2959 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2960 IS_TRUE_SYMOP (IC_RESULT (ic)))
2962 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2964 assignResultValue (IC_RESULT (ic));
2966 freeAsmop (IC_RESULT (ic), NULL, ic);
2969 /* adjust the stack for parameters if required */
2972 int i = ic->parmBytes;
2974 _G.stack.pushed -= i;
2977 emit2 ("!ldaspsp", i);
2984 emit2 ("ld iy,!immedword", i);
2985 emit2 ("add iy,sp");
3006 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3007 bInRet = bitVectBitValue(result, B_IDX);
3008 cInRet = bitVectBitValue(result, C_IDX);
3009 dInRet = bitVectBitValue(result, D_IDX);
3010 eInRet = bitVectBitValue(result, E_IDX);
3020 if (_G.stack.pushedDE)
3022 if (dInRet && eInRet)
3024 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3028 /* Only restore E */
3035 /* Only restore D */
3043 _G.stack.pushedDE = FALSE;
3046 if (_G.stack.pushedBC)
3048 if (bInRet && cInRet)
3050 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3054 /* Only restore C */
3061 /* Only restore B */
3069 _G.stack.pushedBC = FALSE;
3073 /*-----------------------------------------------------------------*/
3074 /* genCall - generates a call statement */
3075 /*-----------------------------------------------------------------*/
3077 genCall (iCode * ic)
3079 emitCall (ic, FALSE);
3082 /*-----------------------------------------------------------------*/
3083 /* genPcall - generates a call by pointer statement */
3084 /*-----------------------------------------------------------------*/
3086 genPcall (iCode * ic)
3088 emitCall (ic, TRUE);
3091 /*-----------------------------------------------------------------*/
3092 /* resultRemat - result is rematerializable */
3093 /*-----------------------------------------------------------------*/
3095 resultRemat (iCode * ic)
3097 if (SKIP_IC (ic) || ic->op == IFX)
3100 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3102 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3103 if (sym->remat && !POINTER_SET (ic))
3110 extern set *publics;
3112 /*-----------------------------------------------------------------*/
3113 /* genFunction - generated code for function entry */
3114 /*-----------------------------------------------------------------*/
3116 genFunction (iCode * ic)
3120 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3123 bool bcInUse = FALSE;
3124 bool deInUse = FALSE;
3126 setArea (IFFUNC_NONBANKED (sym->type));
3128 /* PENDING: Reset the receive offset as it
3129 doesn't seem to get reset anywhere else.
3131 _G.receiveOffset = 0;
3133 /* Record the last function name for debugging. */
3134 _G.lastFunctionName = sym->rname;
3136 /* Create the function header */
3137 emit2 ("!functionheader", sym->name);
3138 if (!IS_STATIC(sym->etype))
3140 sprintf (buffer, "%s_start", sym->rname);
3141 emit2 ("!labeldef", buffer);
3142 _G.lines.current->isLabel = 1;
3144 emit2 ("!functionlabeldef", sym->rname);
3145 _G.lines.current->isLabel = 1;
3147 ftype = operandType (IC_LEFT (ic));
3149 if (IFFUNC_ISNAKED(ftype))
3151 emitDebug("; naked function: no prologue.");
3155 /* if this is an interrupt service routine
3156 then save all potentially used registers. */
3157 if (IFFUNC_ISISR (sym->type))
3159 /* If critical function then turn interrupts off */
3160 /* except when no interrupt number is given then it implies the NMI handler */
3161 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3170 /* This is a non-ISR function.
3171 If critical function then turn interrupts off */
3172 if (IFFUNC_ISCRITICAL (sym->type))
3180 //get interrupt enable flag IFF2 into P/O
3189 if (options.profile)
3191 emit2 ("!profileenter");
3194 /* PENDING: callee-save etc */
3196 _G.stack.param_offset = 0;
3198 if (z80_opts.calleeSavesBC)
3203 /* Detect which registers are used. */
3204 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3207 for (i = 0; i < sym->regsUsed->size; i++)
3209 if (bitVectBitValue (sym->regsUsed, i))
3223 /* Other systems use DE as a temporary. */
3234 _G.stack.param_offset += 2;
3237 _G.calleeSaves.pushedBC = bcInUse;
3242 _G.stack.param_offset += 2;
3245 _G.calleeSaves.pushedDE = deInUse;
3247 /* adjust the stack for the function */
3248 _G.stack.last = sym->stack;
3251 for (sym = setFirstItem (istack->syms); sym;
3252 sym = setNextItem (istack->syms))
3254 if (sym->_isparm && !IS_REGPARM (sym->etype))
3260 sym = OP_SYMBOL (IC_LEFT (ic));
3262 _G.omitFramePtr = options.ommitFramePtr;
3263 if (IS_Z80 && !stackParm && !sym->stack)
3265 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3266 /* the above !sym->stack condition can be removed. -- EEP */
3268 emit2 ("!ldaspsp", -sym->stack);
3269 _G.omitFramePtr = TRUE;
3271 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3272 emit2 ("!enterxl", sym->stack);
3273 else if (sym->stack)
3274 emit2 ("!enterx", sym->stack);
3278 _G.stack.offset = sym->stack;
3281 /*-----------------------------------------------------------------*/
3282 /* genEndFunction - generates epilogue for functions */
3283 /*-----------------------------------------------------------------*/
3285 genEndFunction (iCode * ic)
3287 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3289 if (IFFUNC_ISNAKED(sym->type))
3291 emitDebug("; naked function: no epilogue.");
3295 /* PENDING: calleeSave */
3296 if (IS_Z80 && _G.omitFramePtr)
3298 if (_G.stack.offset)
3299 emit2 ("!ldaspsp", _G.stack.offset);
3301 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3303 emit2 ("!leavexl", _G.stack.offset);
3305 else if (_G.stack.offset)
3307 emit2 ("!leavex", _G.stack.offset);
3314 if (_G.calleeSaves.pushedDE)
3317 _G.calleeSaves.pushedDE = FALSE;
3320 if (_G.calleeSaves.pushedBC)
3323 _G.calleeSaves.pushedBC = FALSE;
3326 if (options.profile)
3328 emit2 ("!profileexit");
3331 /* if this is an interrupt service routine
3332 then save all potentially used registers. */
3333 if (IFFUNC_ISISR (sym->type))
3337 /* If critical function then turn interrupts back on */
3338 /* except when no interrupt number is given then it implies the NMI handler */
3339 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3346 /* This is a non-ISR function.
3347 If critical function then turn interrupts back on */
3348 if (IFFUNC_ISCRITICAL (sym->type))
3356 symbol *tlbl = newiTempLabel (NULL);
3359 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3360 //don't enable interrupts as they were off before
3361 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3363 emit2 ("!tlabeldef", (tlbl->key + 100));
3364 _G.lines.current->isLabel = 1;
3369 if (options.debug && currFunc)
3371 debugFile->writeEndFunction (currFunc, ic, 1);
3374 if (IFFUNC_ISISR (sym->type))
3376 /* "critical interrupt" is used to imply NMI handler */
3377 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3384 /* Both banked and non-banked just ret */
3388 if (!IS_STATIC(sym->etype))
3390 sprintf (buffer, "%s_end", sym->rname);
3391 emit2 ("!labeldef", buffer);
3392 _G.lines.current->isLabel = 1;
3395 _G.flushStatics = 1;
3396 _G.stack.pushed = 0;
3397 _G.stack.offset = 0;
3400 /*-----------------------------------------------------------------*/
3401 /* genRet - generate code for return statement */
3402 /*-----------------------------------------------------------------*/
3407 /* Errk. This is a hack until I can figure out how
3408 to cause dehl to spill on a call */
3409 int size, offset = 0;
3411 /* if we have no return value then
3412 just generate the "ret" */
3416 /* we have something to return then
3417 move the return value into place */
3418 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3419 size = AOP_SIZE (IC_LEFT (ic));
3421 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3424 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3428 emit2 ("ld de,%s", l);
3432 emit2 ("ld hl,%s", l);
3438 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3442 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3444 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3445 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3451 l = aopGet (AOP (IC_LEFT (ic)), offset,
3453 if (strcmp (_fReturn[offset], l))
3454 emit2 ("ld %s,%s", _fReturn[offset], l);
3459 freeAsmop (IC_LEFT (ic), NULL, ic);
3462 /* generate a jump to the return label
3463 if the next is not the return statement */
3464 if (!(ic->next && ic->next->op == LABEL &&
3465 IC_LABEL (ic->next) == returnLabel))
3467 emit2 ("jp !tlabel", returnLabel->key + 100);
3470 /*-----------------------------------------------------------------*/
3471 /* genLabel - generates a label */
3472 /*-----------------------------------------------------------------*/
3474 genLabel (iCode * ic)
3476 /* special case never generate */
3477 if (IC_LABEL (ic) == entryLabel)
3480 emitLabel (IC_LABEL (ic)->key + 100);
3483 /*-----------------------------------------------------------------*/
3484 /* genGoto - generates a ljmp */
3485 /*-----------------------------------------------------------------*/
3487 genGoto (iCode * ic)
3489 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3492 /*-----------------------------------------------------------------*/
3493 /* genPlusIncr :- does addition with increment if possible */
3494 /*-----------------------------------------------------------------*/
3496 genPlusIncr (iCode * ic)
3498 unsigned int icount;
3499 unsigned int size = getDataSize (IC_RESULT (ic));
3500 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3502 /* will try to generate an increment */
3503 /* if the right side is not a literal
3505 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3508 emitDebug ("; genPlusIncr");
3510 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3512 /* If result is a pair */
3513 if (resultId != PAIR_INVALID)
3515 if (isLitWord (AOP (IC_LEFT (ic))))
3517 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3520 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3522 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3524 PAIR_ID freep = getFreePairId (ic);
3525 if (freep != PAIR_INVALID)
3527 fetchPair (freep, AOP (IC_RIGHT (ic)));
3528 emit2 ("add hl,%s", _pairs[freep].name);
3534 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3535 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3542 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3546 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3550 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3555 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3557 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3558 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3562 /* if the literal value of the right hand side
3563 is greater than 4 then it is not worth it */
3567 /* if increment 16 bits in register */
3568 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3574 symbol *tlbl = NULL;
3575 tlbl = newiTempLabel (NULL);
3578 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3581 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3584 emitLabel (tlbl->key + 100);
3588 /* if the sizes are greater than 1 then we cannot */
3589 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3590 AOP_SIZE (IC_LEFT (ic)) > 1)
3593 /* If the result is in a register then we can load then increment.
3595 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3597 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3600 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3605 /* we can if the aops of the left & result match or
3606 if they are in registers and the registers are the
3608 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3612 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3620 /*-----------------------------------------------------------------*/
3621 /* outBitAcc - output a bit in acc */
3622 /*-----------------------------------------------------------------*/
3624 outBitAcc (operand * result)
3626 symbol *tlbl = newiTempLabel (NULL);
3627 /* if the result is a bit */
3628 if (AOP_TYPE (result) == AOP_CRY)
3630 wassertl (0, "Tried to write A into a bit");
3634 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3635 emit2 ("ld a,!one");
3636 emitLabel (tlbl->key + 100);
3642 couldDestroyCarry (asmop *aop)
3646 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3655 shiftIntoPair (int idx, asmop *aop)
3657 PAIR_ID id = PAIR_INVALID;
3659 wassertl (IS_Z80, "Only implemented for the Z80");
3660 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3662 emitDebug ("; Shift into pair idx %u", idx);
3668 setupPair (PAIR_HL, aop, 0);
3673 setupPair (PAIR_IY, aop, 0);
3675 emit2 ("pop %s", _pairs[id].name);
3679 setupPair (PAIR_IY, aop, 0);
3682 wassertl (0, "Internal error - hit default case");
3685 aop->type = AOP_PAIRPTR;
3686 aop->aopu.aop_pairId = id;
3687 _G.pairs[id].offset = 0;
3688 _G.pairs[id].last_type = aop->type;
3692 setupToPreserveCarry (iCode * ic)
3694 asmop *left = AOP (IC_LEFT (ic));
3695 asmop *right = AOP (IC_RIGHT (ic));
3696 asmop *result = AOP (IC_RESULT (ic));
3698 wassert (left && right);
3702 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3704 shiftIntoPair (0, right);
3705 /* check result again, in case right == result */
3706 if (couldDestroyCarry (result))
3708 if (!isPairInUse (PAIR_DE, ic))
3709 shiftIntoPair (1, result);
3711 shiftIntoPair (2, result);
3714 else if (couldDestroyCarry (right))
3716 if (getPairId (result) == PAIR_HL)
3717 _G.preserveCarry = TRUE;
3719 shiftIntoPair (0, right);
3721 else if (couldDestroyCarry (result))
3723 shiftIntoPair (0, result);
3732 /*-----------------------------------------------------------------*/
3733 /* genPlus - generates code for addition */
3734 /*-----------------------------------------------------------------*/
3736 genPlus (iCode * ic)
3738 int size, offset = 0;
3740 /* special cases :- */
3742 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3743 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3744 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3746 /* Swap the left and right operands if:
3748 if literal, literal on the right or
3749 if left requires ACC or right is already
3752 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3753 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3754 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3756 operand *t = IC_RIGHT (ic);
3757 IC_RIGHT (ic) = IC_LEFT (ic);
3761 /* if both left & right are in bit
3763 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3764 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3767 wassertl (0, "Tried to add two bits");
3770 /* if left in bit space & right literal */
3771 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3772 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3774 /* Can happen I guess */
3775 wassertl (0, "Tried to add a bit to a literal");
3778 /* if I can do an increment instead
3779 of add then GOOD for ME */
3780 if (genPlusIncr (ic) == TRUE)
3783 size = getDataSize (IC_RESULT (ic));
3785 /* Special case when left and right are constant */
3786 if (isPair (AOP (IC_RESULT (ic))))
3789 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3790 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3792 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3798 sprintf (buffer, "#(%s + %s)", left, right);
3799 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3804 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3806 /* Fetch into HL then do the add */
3807 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3808 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3810 spillPair (PAIR_HL);
3812 if (left == PAIR_HL && right != PAIR_INVALID)
3814 emit2 ("add hl,%s", _pairs[right].name);
3817 else if (right == PAIR_HL && left != PAIR_INVALID)
3819 emit2 ("add hl,%s", _pairs[left].name);
3822 else if (right != PAIR_INVALID && right != PAIR_HL)
3824 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3825 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3828 else if (left != PAIR_INVALID && left != PAIR_HL)
3830 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3831 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3840 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3842 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3843 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3845 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3850 ld hl,sp+n trashes C so we can't afford to do it during an
3851 add with stack based variables. Worst case is:
3864 So you can't afford to load up hl if either left, right, or result
3865 is on the stack (*sigh*) The alt is:
3873 Combinations in here are:
3874 * If left or right are in bc then the loss is small - trap later
3875 * If the result is in bc then the loss is also small
3879 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3880 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3881 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3883 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3884 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3885 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3886 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3888 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3890 /* Swap left and right */
3891 operand *t = IC_RIGHT (ic);
3892 IC_RIGHT (ic) = IC_LEFT (ic);
3895 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3897 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3898 emit2 ("add hl,bc");
3902 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3903 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3904 emit2 ("add hl,de");
3906 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3912 /* Be paranoid on the GB with 4 byte variables due to how C
3913 can be trashed by lda hl,n(sp).
3915 _gbz80_emitAddSubLong (ic, TRUE);
3920 setupToPreserveCarry (ic);
3924 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3926 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3929 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3932 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3936 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3939 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3942 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3944 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3948 _G.preserveCarry = FALSE;
3949 freeAsmop (IC_LEFT (ic), NULL, ic);
3950 freeAsmop (IC_RIGHT (ic), NULL, ic);
3951 freeAsmop (IC_RESULT (ic), NULL, ic);
3954 /*-----------------------------------------------------------------*/
3955 /* genMinusDec :- does subtraction with deccrement if possible */
3956 /*-----------------------------------------------------------------*/
3958 genMinusDec (iCode * ic)
3960 unsigned int icount;
3961 unsigned int size = getDataSize (IC_RESULT (ic));
3963 /* will try to generate an increment */
3964 /* if the right side is not a literal we cannot */
3965 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3968 /* if the literal value of the right hand side
3969 is greater than 4 then it is not worth it */
3970 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3973 size = getDataSize (IC_RESULT (ic));
3975 /* if decrement 16 bits in register */
3976 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3977 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3980 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3984 /* If result is a pair */
3985 if (isPair (AOP (IC_RESULT (ic))))
3987 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3989 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3993 /* if increment 16 bits in register */
3994 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3998 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4001 emit2 ("dec %s", _getTempPairName());
4004 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4010 /* if the sizes are greater than 1 then we cannot */
4011 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4012 AOP_SIZE (IC_LEFT (ic)) > 1)
4015 /* we can if the aops of the left & result match or if they are in
4016 registers and the registers are the same */
4017 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4020 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4027 /*-----------------------------------------------------------------*/
4028 /* genMinus - generates code for subtraction */
4029 /*-----------------------------------------------------------------*/
4031 genMinus (iCode * ic)
4033 int size, offset = 0;
4034 unsigned long lit = 0L;
4036 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4037 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4038 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4040 /* special cases :- */
4041 /* if both left & right are in bit space */
4042 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4043 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4045 wassertl (0, "Tried to subtract two bits");
4049 /* if I can do an decrement instead of subtract then GOOD for ME */
4050 if (genMinusDec (ic) == TRUE)
4053 size = getDataSize (IC_RESULT (ic));
4055 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4060 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4064 /* Same logic as genPlus */
4067 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4068 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4069 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4071 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4072 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4073 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4074 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4076 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4077 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4079 if (left == PAIR_INVALID && right == PAIR_INVALID)
4084 else if (right == PAIR_INVALID)
4086 else if (left == PAIR_INVALID)
4089 fetchPair (left, AOP (IC_LEFT (ic)));
4090 /* Order is important. Right may be HL */
4091 fetchPair (right, AOP (IC_RIGHT (ic)));
4093 emit2 ("ld a,%s", _pairs[left].l);
4094 emit2 ("sub a,%s", _pairs[right].l);
4096 emit2 ("ld a,%s", _pairs[left].h);
4097 emit2 ("sbc a,%s", _pairs[right].h);
4099 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4101 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4103 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4109 /* Be paranoid on the GB with 4 byte variables due to how C
4110 can be trashed by lda hl,n(sp).
4112 _gbz80_emitAddSubLong (ic, FALSE);
4117 setupToPreserveCarry (ic);
4119 /* if literal, add a,#-lit, else normal subb */
4122 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4123 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4127 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4130 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4134 /* first add without previous c */
4136 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4138 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4140 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4143 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4144 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4145 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4147 wassertl (0, "Tried to subtract on a long pointer");
4151 _G.preserveCarry = FALSE;
4152 freeAsmop (IC_LEFT (ic), NULL, ic);
4153 freeAsmop (IC_RIGHT (ic), NULL, ic);
4154 freeAsmop (IC_RESULT (ic), NULL, ic);
4157 /*-----------------------------------------------------------------*/
4158 /* genMult - generates code for multiplication */
4159 /*-----------------------------------------------------------------*/
4161 genMult (iCode * ic)
4165 /* If true then the final operation should be a subtract */
4166 bool active = FALSE;
4169 /* Shouldn't occur - all done through function calls */
4170 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4171 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4172 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4174 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4176 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4177 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4178 AOP_SIZE (IC_RESULT (ic)) > 2)
4180 wassertl (0, "Multiplication is handled through support function calls");
4183 /* Swap left and right such that right is a literal */
4184 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4186 operand *t = IC_RIGHT (ic);
4187 IC_RIGHT (ic) = IC_LEFT (ic);
4191 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4193 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4194 // wassertl (val > 0, "Multiply must be positive");
4195 wassertl (val != 1, "Can't multiply by 1");
4197 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4199 _G.stack.pushedDE = TRUE;
4202 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4204 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4215 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4220 /* Fully unroled version of mul.s. Not the most efficient.
4222 for (count = 0; count < 16; count++)
4224 if (count != 0 && active)
4226 emit2 ("add hl,hl");
4230 if (active == FALSE)
4238 emit2 ("add hl,de");
4247 if (IS_Z80 && _G.stack.pushedDE)
4250 _G.stack.pushedDE = FALSE;
4254 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4256 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4258 freeAsmop (IC_LEFT (ic), NULL, ic);
4259 freeAsmop (IC_RIGHT (ic), NULL, ic);
4260 freeAsmop (IC_RESULT (ic), NULL, ic);
4263 /*-----------------------------------------------------------------*/
4264 /* genDiv - generates code for division */
4265 /*-----------------------------------------------------------------*/
4269 /* Shouldn't occur - all done through function calls */
4270 wassertl (0, "Division is handled through support function calls");
4273 /*-----------------------------------------------------------------*/
4274 /* genMod - generates code for division */
4275 /*-----------------------------------------------------------------*/
4279 /* Shouldn't occur - all done through function calls */
4283 /*-----------------------------------------------------------------*/
4284 /* genIfxJump :- will create a jump depending on the ifx */
4285 /*-----------------------------------------------------------------*/
4287 genIfxJump (iCode * ic, char *jval)
4292 /* if true label then we jump if condition
4296 jlbl = IC_TRUE (ic);
4297 if (!strcmp (jval, "a"))
4301 else if (!strcmp (jval, "c"))
4305 else if (!strcmp (jval, "nc"))
4309 else if (!strcmp (jval, "m"))
4313 else if (!strcmp (jval, "p"))
4319 /* The buffer contains the bit on A that we should test */
4325 /* false label is present */
4326 jlbl = IC_FALSE (ic);
4327 if (!strcmp (jval, "a"))
4331 else if (!strcmp (jval, "c"))
4335 else if (!strcmp (jval, "nc"))
4339 else if (!strcmp (jval, "m"))
4343 else if (!strcmp (jval, "p"))
4349 /* The buffer contains the bit on A that we should test */
4353 /* Z80 can do a conditional long jump */
4354 if (!strcmp (jval, "a"))
4358 else if (!strcmp (jval, "c"))
4361 else if (!strcmp (jval, "nc"))
4364 else if (!strcmp (jval, "m"))
4367 else if (!strcmp (jval, "p"))
4372 emit2 ("bit %s,a", jval);
4374 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4376 /* mark the icode as generated */
4382 _getPairIdName (PAIR_ID id)
4384 return _pairs[id].name;
4389 /* if unsigned char cmp with lit, just compare */
4391 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4393 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4396 emit2 ("xor a,!immedbyte", 0x80);
4397 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4400 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4402 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4404 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4405 // Pull left into DE and right into HL
4406 aopGet (AOP(left), LSB, FALSE);
4409 aopGet (AOP(right), LSB, FALSE);
4413 if (size == 0 && sign)
4415 // Highest byte when signed needs the bits flipped
4418 emit2 ("ld a,(de)");
4419 emit2 ("xor !immedbyte", 0x80);
4421 emit2 ("ld a,(hl)");
4422 emit2 ("xor !immedbyte", 0x80);
4426 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4430 emit2 ("ld a,(de)");
4431 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4441 spillPair (PAIR_HL);
4443 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4445 setupPair (PAIR_HL, AOP (left), 0);
4446 aopGet (AOP(right), LSB, FALSE);
4450 if (size == 0 && sign)
4452 // Highest byte when signed needs the bits flipped
4455 emit2 ("ld a,(hl)");
4456 emit2 ("xor !immedbyte", 0x80);
4458 emit2 ("ld a,%d(iy)", offset);
4459 emit2 ("xor !immedbyte", 0x80);
4463 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4467 emit2 ("ld a,(hl)");
4468 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4477 spillPair (PAIR_HL);
4478 spillPair (PAIR_IY);
4482 if (AOP_TYPE (right) == AOP_LIT)
4484 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4485 /* optimize if(x < 0) or if(x >= 0) */
4490 /* No sign so it's always false */
4495 /* Just load in the top most bit */
4496 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4497 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4499 genIfxJump (ifx, "7");
4511 /* First setup h and l contaning the top most bytes XORed */
4512 bool fDidXor = FALSE;
4513 if (AOP_TYPE (left) == AOP_LIT)
4515 unsigned long lit = (unsigned long)
4516 floatFromVal (AOP (left)->aopu.aop_lit);
4517 emit2 ("ld %s,!immedbyte", _fTmp[0],
4518 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4522 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4523 emit2 ("xor a,!immedbyte", 0x80);
4524 emit2 ("ld %s,a", _fTmp[0]);
4527 if (AOP_TYPE (right) == AOP_LIT)
4529 unsigned long lit = (unsigned long)
4530 floatFromVal (AOP (right)->aopu.aop_lit);
4531 emit2 ("ld %s,!immedbyte", _fTmp[1],
4532 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4536 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4537 emit2 ("xor a,!immedbyte", 0x80);
4538 emit2 ("ld %s,a", _fTmp[1]);
4544 /* Do a long subtract */
4547 _moveA (aopGet (AOP (left), offset, FALSE));
4549 if (sign && size == 0)
4551 emit2 ("ld a,%s", _fTmp[0]);
4552 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4556 /* Subtract through, propagating the carry */
4557 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4565 /** Generic compare for > or <
4568 genCmp (operand * left, operand * right,
4569 operand * result, iCode * ifx, int sign)
4571 int size, offset = 0;
4572 unsigned long lit = 0L;
4573 bool swap_sense = FALSE;
4575 /* if left & right are bit variables */
4576 if (AOP_TYPE (left) == AOP_CRY &&
4577 AOP_TYPE (right) == AOP_CRY)
4579 /* Cant happen on the Z80 */
4580 wassertl (0, "Tried to compare two bits");
4584 /* Do a long subtract of right from left. */
4585 size = max (AOP_SIZE (left), AOP_SIZE (right));
4587 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4589 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4590 // Pull left into DE and right into HL
4591 aopGet (AOP(left), LSB, FALSE);
4594 aopGet (AOP(right), LSB, FALSE);
4598 emit2 ("ld a,(de)");
4599 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4608 spillPair (PAIR_HL);
4612 if (AOP_TYPE (right) == AOP_LIT)
4614 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4615 /* optimize if(x < 0) or if(x >= 0) */
4620 /* No sign so it's always false */
4625 /* Just load in the top most bit */
4626 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4627 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4629 genIfxJump (ifx, "7");
4640 genIfxJump (ifx, swap_sense ? "c" : "nc");
4651 _moveA (aopGet (AOP (left), offset, FALSE));
4652 /* Subtract through, propagating the carry */
4653 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4659 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4663 /* Shift the sign bit up into carry */
4666 outBitCLong (result, swap_sense);
4670 /* if the result is used in the next
4671 ifx conditional branch then generate
4672 code a little differently */
4680 genIfxJump (ifx, swap_sense ? "nc" : "c");
4684 genIfxJump (ifx, swap_sense ? "p" : "m");
4689 genIfxJump (ifx, swap_sense ? "nc" : "c");
4696 /* Shift the sign bit up into carry */
4699 outBitCLong (result, swap_sense);
4701 /* leave the result in acc */
4705 /*-----------------------------------------------------------------*/
4706 /* genCmpGt :- greater than comparison */
4707 /*-----------------------------------------------------------------*/
4709 genCmpGt (iCode * ic, iCode * ifx)
4711 operand *left, *right, *result;
4712 sym_link *letype, *retype;
4715 left = IC_LEFT (ic);
4716 right = IC_RIGHT (ic);
4717 result = IC_RESULT (ic);
4719 letype = getSpec (operandType (left));
4720 retype = getSpec (operandType (right));
4721 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4722 /* assign the amsops */
4723 aopOp (left, ic, FALSE, FALSE);
4724 aopOp (right, ic, FALSE, FALSE);
4725 aopOp (result, ic, TRUE, FALSE);
4727 genCmp (right, left, result, ifx, sign);
4729 freeAsmop (left, NULL, ic);
4730 freeAsmop (right, NULL, ic);
4731 freeAsmop (result, NULL, ic);
4734 /*-----------------------------------------------------------------*/
4735 /* genCmpLt - less than comparisons */
4736 /*-----------------------------------------------------------------*/
4738 genCmpLt (iCode * ic, iCode * ifx)
4740 operand *left, *right, *result;
4741 sym_link *letype, *retype;
4744 left = IC_LEFT (ic);
4745 right = IC_RIGHT (ic);
4746 result = IC_RESULT (ic);
4748 letype = getSpec (operandType (left));
4749 retype = getSpec (operandType (right));
4750 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4752 /* assign the amsops */
4753 aopOp (left, ic, FALSE, FALSE);
4754 aopOp (right, ic, FALSE, FALSE);
4755 aopOp (result, ic, TRUE, FALSE);
4757 genCmp (left, right, result, ifx, sign);
4759 freeAsmop (left, NULL, ic);
4760 freeAsmop (right, NULL, ic);
4761 freeAsmop (result, NULL, ic);
4764 /*-----------------------------------------------------------------*/
4765 /* gencjneshort - compare and jump if not equal */
4766 /* returns pair that still needs to be popped */
4767 /*-----------------------------------------------------------------*/
4769 gencjneshort (operand * left, operand * right, symbol * lbl)
4771 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4773 unsigned long lit = 0L;
4775 /* Swap the left and right if it makes the computation easier */
4776 if (AOP_TYPE (left) == AOP_LIT)
4783 /* if the right side is a literal then anything goes */
4784 if (AOP_TYPE (right) == AOP_LIT)
4786 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4789 _moveA (aopGet (AOP (left), offset, FALSE));
4794 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4801 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4807 _moveA (aopGet (AOP (left), offset, FALSE));
4808 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4811 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4812 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4817 /* if the right side is in a register or
4818 pointed to by HL, IX or IY */
4819 else if (AOP_TYPE (right) == AOP_REG ||
4820 AOP_TYPE (right) == AOP_HL ||
4821 AOP_TYPE (right) == AOP_IY ||
4822 AOP_TYPE (right) == AOP_STK ||
4823 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4824 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4825 AOP_IS_PAIRPTR (right, PAIR_IY))
4829 _moveA (aopGet (AOP (left), offset, FALSE));
4830 if (AOP_TYPE (right) == AOP_LIT &&
4831 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4834 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4838 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4839 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4844 /* right is in direct space or a pointer reg, need both a & b */
4848 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4850 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4851 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4859 emit2 ("; direct compare");
4860 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4861 _moveA (aopGet (AOP (right), offset, FALSE));
4862 emit2 ("sub %s", _pairs[pair].l);
4863 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4868 return PAIR_INVALID;
4871 /*-----------------------------------------------------------------*/
4872 /* gencjne - compare and jump if not equal */
4873 /*-----------------------------------------------------------------*/
4875 gencjne (operand * left, operand * right, symbol * lbl)
4877 symbol *tlbl = newiTempLabel (NULL);
4879 PAIR_ID pop = gencjneshort (left, right, lbl);
4882 emit2 ("ld a,!one");
4883 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4884 emitLabel (lbl->key + 100);
4886 emitLabel (tlbl->key + 100);
4890 /*-----------------------------------------------------------------*/
4891 /* genCmpEq - generates code for equal to */
4892 /*-----------------------------------------------------------------*/
4894 genCmpEq (iCode * ic, iCode * ifx)
4896 operand *left, *right, *result;
4898 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4899 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4900 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4902 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4904 /* Swap operands if it makes the operation easier. ie if:
4905 1. Left is a literal.
4907 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4909 operand *t = IC_RIGHT (ic);
4910 IC_RIGHT (ic) = IC_LEFT (ic);
4914 if (ifx && !AOP_SIZE (result))
4917 /* if they are both bit variables */
4918 if (AOP_TYPE (left) == AOP_CRY &&
4919 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4921 wassertl (0, "Tried to compare two bits");
4926 tlbl = newiTempLabel (NULL);
4927 pop = gencjneshort (left, right, tlbl);
4931 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4932 emitLabel (tlbl->key + 100);
4937 /* PENDING: do this better */
4938 symbol *lbl = newiTempLabel (NULL);
4940 emit2 ("!shortjp !tlabel", lbl->key + 100);
4941 emitLabel (tlbl->key + 100);
4943 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4944 emitLabel (lbl->key + 100);
4947 /* mark the icode as generated */
4952 /* if they are both bit variables */
4953 if (AOP_TYPE (left) == AOP_CRY &&
4954 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4956 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4962 gencjne (left, right, newiTempLabel (NULL));
4963 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4970 genIfxJump (ifx, "a");
4973 /* if the result is used in an arithmetic operation
4974 then put the result in place */
4975 if (AOP_TYPE (result) != AOP_CRY)
4980 /* leave the result in acc */
4984 freeAsmop (left, NULL, ic);
4985 freeAsmop (right, NULL, ic);
4986 freeAsmop (result, NULL, ic);
4989 /*-----------------------------------------------------------------*/
4990 /* ifxForOp - returns the icode containing the ifx for operand */
4991 /*-----------------------------------------------------------------*/
4993 ifxForOp (operand * op, iCode * ic)
4995 /* if true symbol then needs to be assigned */
4996 if (IS_TRUE_SYMOP (op))
4999 /* if this has register type condition and
5000 the next instruction is ifx with the same operand
5001 and live to of the operand is upto the ifx only then */
5003 ic->next->op == IFX &&
5004 IC_COND (ic->next)->key == op->key &&
5005 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5011 /*-----------------------------------------------------------------*/
5012 /* genAndOp - for && operation */
5013 /*-----------------------------------------------------------------*/
5015 genAndOp (iCode * ic)
5017 operand *left, *right, *result;
5020 /* note here that && operations that are in an if statement are
5021 taken away by backPatchLabels only those used in arthmetic
5022 operations remain */
5023 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5024 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5025 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5027 /* if both are bit variables */
5028 if (AOP_TYPE (left) == AOP_CRY &&
5029 AOP_TYPE (right) == AOP_CRY)
5031 wassertl (0, "Tried to and two bits");
5035 tlbl = newiTempLabel (NULL);
5037 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5039 emitLabel (tlbl->key + 100);
5043 freeAsmop (left, NULL, ic);
5044 freeAsmop (right, NULL, ic);
5045 freeAsmop (result, NULL, ic);
5048 /*-----------------------------------------------------------------*/
5049 /* genOrOp - for || operation */
5050 /*-----------------------------------------------------------------*/
5052 genOrOp (iCode * ic)
5054 operand *left, *right, *result;
5057 /* note here that || operations that are in an
5058 if statement are taken away by backPatchLabels
5059 only those used in arthmetic operations remain */
5060 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5061 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5062 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5064 /* if both are bit variables */
5065 if (AOP_TYPE (left) == AOP_CRY &&
5066 AOP_TYPE (right) == AOP_CRY)
5068 wassertl (0, "Tried to OR two bits");
5072 tlbl = newiTempLabel (NULL);
5074 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5076 emitLabel (tlbl->key + 100);
5080 freeAsmop (left, NULL, ic);
5081 freeAsmop (right, NULL, ic);
5082 freeAsmop (result, NULL, ic);
5085 /*-----------------------------------------------------------------*/
5086 /* isLiteralBit - test if lit == 2^n */
5087 /*-----------------------------------------------------------------*/
5089 isLiteralBit (unsigned long lit)
5091 unsigned long pw[32] =
5092 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5093 0x100L, 0x200L, 0x400L, 0x800L,
5094 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5095 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5096 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5097 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5098 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5101 for (idx = 0; idx < 32; idx++)
5107 /*-----------------------------------------------------------------*/
5108 /* jmpTrueOrFalse - */
5109 /*-----------------------------------------------------------------*/
5111 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5113 // ugly but optimized by peephole
5116 symbol *nlbl = newiTempLabel (NULL);
5117 emit2 ("jp !tlabel", nlbl->key + 100);
5118 emitLabel (tlbl->key + 100);
5119 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5120 emitLabel (nlbl->key + 100);
5124 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5125 emitLabel (tlbl->key + 100);
5130 /*-----------------------------------------------------------------*/
5131 /* genAnd - code for and */
5132 /*-----------------------------------------------------------------*/
5134 genAnd (iCode * ic, iCode * ifx)
5136 operand *left, *right, *result;
5137 int size, offset = 0;
5138 unsigned long lit = 0L;
5141 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5142 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5143 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5145 /* if left is a literal & right is not then exchange them */
5146 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5147 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5149 operand *tmp = right;
5154 /* if result = right then exchange them */
5155 if (sameRegs (AOP (result), AOP (right)))
5157 operand *tmp = right;
5162 /* if right is bit then exchange them */
5163 if (AOP_TYPE (right) == AOP_CRY &&
5164 AOP_TYPE (left) != AOP_CRY)
5166 operand *tmp = right;
5170 if (AOP_TYPE (right) == AOP_LIT)
5171 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5173 size = AOP_SIZE (result);
5175 if (AOP_TYPE (left) == AOP_CRY)
5177 wassertl (0, "Tried to perform an AND with a bit as an operand");
5181 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5182 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5183 if ((AOP_TYPE (right) == AOP_LIT) &&
5184 (AOP_TYPE (result) == AOP_CRY) &&
5185 (AOP_TYPE (left) != AOP_CRY))
5187 symbol *tlbl = newiTempLabel (NULL);
5188 int sizel = AOP_SIZE (left);
5191 /* PENDING: Test case for this. */
5196 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5198 _moveA (aopGet (AOP (left), offset, FALSE));
5199 if (bytelit != 0x0FFL)
5201 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5208 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5212 // bit = left & literal
5216 emit2 ("!tlabeldef", tlbl->key + 100);
5217 _G.lines.current->isLabel = 1;
5219 // if(left & literal)
5224 jmpTrueOrFalse (ifx, tlbl);
5232 /* if left is same as result */
5233 if (sameRegs (AOP (result), AOP (left)))
5235 for (; size--; offset++)
5237 if (AOP_TYPE (right) == AOP_LIT)
5239 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5244 aopPut (AOP (result), "!zero", offset);
5247 _moveA (aopGet (AOP (left), offset, FALSE));
5249 aopGet (AOP (right), offset, FALSE));
5250 aopPut (AOP (left), "a", offset);
5257 if (AOP_TYPE (left) == AOP_ACC)
5259 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5263 _moveA (aopGet (AOP (left), offset, FALSE));
5265 aopGet (AOP (right), offset, FALSE));
5266 aopPut (AOP (left), "a", offset);
5273 // left & result in different registers
5274 if (AOP_TYPE (result) == AOP_CRY)
5276 wassertl (0, "Tried to AND where the result is in carry");
5280 for (; (size--); offset++)
5283 // result = left & right
5284 if (AOP_TYPE (right) == AOP_LIT)
5286 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5288 aopPut (AOP (result),
5289 aopGet (AOP (left), offset, FALSE),
5293 else if (bytelit == 0)
5295 aopPut (AOP (result), "!zero", offset);
5299 // faster than result <- left, anl result,right
5300 // and better if result is SFR
5301 if (AOP_TYPE (left) == AOP_ACC)
5302 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5305 _moveA (aopGet (AOP (left), offset, FALSE));
5307 aopGet (AOP (right), offset, FALSE));
5309 aopPut (AOP (result), "a", offset);
5316 freeAsmop (left, NULL, ic);
5317 freeAsmop (right, NULL, ic);
5318 freeAsmop (result, NULL, ic);
5321 /*-----------------------------------------------------------------*/
5322 /* genOr - code for or */
5323 /*-----------------------------------------------------------------*/
5325 genOr (iCode * ic, iCode * ifx)
5327 operand *left, *right, *result;
5328 int size, offset = 0;
5329 unsigned long lit = 0L;
5332 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5333 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5334 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5336 /* if left is a literal & right is not then exchange them */
5337 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5338 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5340 operand *tmp = right;
5345 /* if result = right then exchange them */
5346 if (sameRegs (AOP (result), AOP (right)))
5348 operand *tmp = right;
5353 /* if right is bit then exchange them */
5354 if (AOP_TYPE (right) == AOP_CRY &&
5355 AOP_TYPE (left) != AOP_CRY)
5357 operand *tmp = right;
5361 if (AOP_TYPE (right) == AOP_LIT)
5362 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5364 size = AOP_SIZE (result);
5366 if (AOP_TYPE (left) == AOP_CRY)
5368 wassertl (0, "Tried to OR where left is a bit");
5372 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5373 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5374 if ((AOP_TYPE (right) == AOP_LIT) &&
5375 (AOP_TYPE (result) == AOP_CRY) &&
5376 (AOP_TYPE (left) != AOP_CRY))
5378 symbol *tlbl = newiTempLabel (NULL);
5379 int sizel = AOP_SIZE (left);
5383 wassertl (0, "Result is assigned to a bit");
5385 /* PENDING: Modeled after the AND code which is inefficient. */
5388 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5390 _moveA (aopGet (AOP (left), offset, FALSE));
5391 /* OR with any literal is the same as OR with itself. */
5393 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5399 jmpTrueOrFalse (ifx, tlbl);
5404 /* if left is same as result */
5405 if (sameRegs (AOP (result), AOP (left)))
5407 for (; size--; offset++)
5409 if (AOP_TYPE (right) == AOP_LIT)
5411 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5415 _moveA (aopGet (AOP (left), offset, FALSE));
5417 aopGet (AOP (right), offset, FALSE));
5418 aopPut (AOP (result), "a", offset);
5423 if (AOP_TYPE (left) == AOP_ACC)
5424 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5427 _moveA (aopGet (AOP (left), offset, FALSE));
5429 aopGet (AOP (right), offset, FALSE));
5430 aopPut (AOP (result), "a", offset);
5437 // left & result in different registers
5438 if (AOP_TYPE (result) == AOP_CRY)
5440 wassertl (0, "Result of OR is in a bit");
5443 for (; (size--); offset++)
5446 // result = left & right
5447 if (AOP_TYPE (right) == AOP_LIT)
5449 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5451 aopPut (AOP (result),
5452 aopGet (AOP (left), offset, FALSE),
5457 // faster than result <- left, anl result,right
5458 // and better if result is SFR
5459 if (AOP_TYPE (left) == AOP_ACC)
5460 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5463 _moveA (aopGet (AOP (left), offset, FALSE));
5465 aopGet (AOP (right), offset, FALSE));
5467 aopPut (AOP (result), "a", offset);
5468 /* PENDING: something weird is going on here. Add exception. */
5469 if (AOP_TYPE (result) == AOP_ACC)
5475 freeAsmop (left, NULL, ic);
5476 freeAsmop (right, NULL, ic);
5477 freeAsmop (result, NULL, ic);
5480 /*-----------------------------------------------------------------*/
5481 /* genXor - code for xclusive or */
5482 /*-----------------------------------------------------------------*/
5484 genXor (iCode * ic, iCode * ifx)
5486 operand *left, *right, *result;
5487 int size, offset = 0;
5488 unsigned long lit = 0L;
5490 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5491 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5492 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5494 /* if left is a literal & right is not then exchange them */
5495 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5496 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5498 operand *tmp = right;
5503 /* if result = right then exchange them */
5504 if (sameRegs (AOP (result), AOP (right)))
5506 operand *tmp = right;
5511 /* if right is bit then exchange them */
5512 if (AOP_TYPE (right) == AOP_CRY &&
5513 AOP_TYPE (left) != AOP_CRY)
5515 operand *tmp = right;
5519 if (AOP_TYPE (right) == AOP_LIT)
5520 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5522 size = AOP_SIZE (result);
5524 if (AOP_TYPE (left) == AOP_CRY)
5526 wassertl (0, "Tried to XOR a bit");
5530 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5531 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5532 if ((AOP_TYPE (right) == AOP_LIT) &&
5533 (AOP_TYPE (result) == AOP_CRY) &&
5534 (AOP_TYPE (left) != AOP_CRY))
5536 symbol *tlbl = newiTempLabel (NULL);
5537 int sizel = AOP_SIZE (left);
5541 /* PENDING: Test case for this. */
5542 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5546 _moveA (aopGet (AOP (left), offset, FALSE));
5547 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5548 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5553 jmpTrueOrFalse (ifx, tlbl);
5557 wassertl (0, "Result of XOR was destined for a bit");
5562 /* if left is same as result */
5563 if (sameRegs (AOP (result), AOP (left)))
5565 for (; size--; offset++)
5567 if (AOP_TYPE (right) == AOP_LIT)
5569 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5573 _moveA (aopGet (AOP (left), offset, FALSE));
5575 aopGet (AOP (right), offset, FALSE));
5576 aopPut (AOP (result), "a", offset);
5581 if (AOP_TYPE (left) == AOP_ACC)
5583 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5587 _moveA (aopGet (AOP (left), offset, FALSE));
5589 aopGet (AOP (right), offset, FALSE));
5590 aopPut (AOP (result), "a", offset);
5597 // left & result in different registers
5598 if (AOP_TYPE (result) == AOP_CRY)
5600 wassertl (0, "Result of XOR is in a bit");
5603 for (; (size--); offset++)
5606 // result = left & right
5607 if (AOP_TYPE (right) == AOP_LIT)
5609 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5611 aopPut (AOP (result),
5612 aopGet (AOP (left), offset, FALSE),
5617 // faster than result <- left, anl result,right
5618 // and better if result is SFR
5619 if (AOP_TYPE (left) == AOP_ACC)
5621 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5625 _moveA (aopGet (AOP (left), offset, FALSE));
5627 aopGet (AOP (right), offset, FALSE));
5629 aopPut (AOP (result), "a", offset);
5634 freeAsmop (left, NULL, ic);
5635 freeAsmop (right, NULL, ic);
5636 freeAsmop (result, NULL, ic);
5639 /*-----------------------------------------------------------------*/
5640 /* genInline - write the inline code out */
5641 /*-----------------------------------------------------------------*/
5643 genInline (iCode * ic)
5645 char *buffer, *bp, *bp1;
5647 _G.lines.isInline += (!options.asmpeep);
5649 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5650 strcpy (buffer, IC_INLINE (ic));
5652 /* emit each line as a code */
5677 _G.lines.isInline -= (!options.asmpeep);
5681 /*-----------------------------------------------------------------*/
5682 /* genRRC - rotate right with carry */
5683 /*-----------------------------------------------------------------*/
5690 /*-----------------------------------------------------------------*/
5691 /* genRLC - generate code for rotate left with carry */
5692 /*-----------------------------------------------------------------*/
5699 /*-----------------------------------------------------------------*/
5700 /* genGetHbit - generates code get highest order bit */
5701 /*-----------------------------------------------------------------*/
5703 genGetHbit (iCode * ic)
5705 operand *left, *result;
5706 left = IC_LEFT (ic);
5707 result = IC_RESULT (ic);
5709 aopOp (left, ic, FALSE, FALSE);
5710 aopOp (result, ic, FALSE, FALSE);
5712 /* get the highest order byte into a */
5713 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5715 if (AOP_TYPE (result) == AOP_CRY)
5723 emit2 ("and a,!one");
5728 freeAsmop (left, NULL, ic);
5729 freeAsmop (result, NULL, ic);
5733 emitRsh2 (asmop *aop, int size, int is_signed)
5739 const char *l = aopGet (aop, size, FALSE);
5742 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5752 /*-----------------------------------------------------------------*/
5753 /* shiftR2Left2Result - shift right two bytes from left to result */
5754 /*-----------------------------------------------------------------*/
5756 shiftR2Left2Result (operand * left, int offl,
5757 operand * result, int offr,
5758 int shCount, int is_signed)
5763 movLeft2Result (left, offl, result, offr, 0);
5764 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5769 /* if (AOP(result)->type == AOP_REG) { */
5771 tlbl = newiTempLabel (NULL);
5773 /* Left is already in result - so now do the shift */
5774 /* Optimizing for speed by default. */
5775 if (!optimize.codeSize || shCount <= 2)
5779 emitRsh2 (AOP (result), size, is_signed);
5784 emit2 ("ld a,!immedbyte", shCount);
5786 emitLabel (tlbl->key + 100);
5788 emitRsh2 (AOP (result), size, is_signed);
5791 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5795 /*-----------------------------------------------------------------*/
5796 /* shiftL2Left2Result - shift left two bytes from left to result */
5797 /*-----------------------------------------------------------------*/
5799 shiftL2Left2Result (operand * left, int offl,
5800 operand * result, int offr, int shCount)
5802 if (sameRegs (AOP (result), AOP (left)) &&
5803 ((offl + MSB16) == offr))
5809 /* Copy left into result */
5810 movLeft2Result (left, offl, result, offr, 0);
5811 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5817 if (getPairId (AOP (result)) == PAIR_HL)
5821 emit2 ("add hl,hl");
5828 symbol *tlbl, *tlbl1;
5831 tlbl = newiTempLabel (NULL);
5832 tlbl1 = newiTempLabel (NULL);
5834 if (AOP (result)->type == AOP_REG)
5838 for (offset = 0; offset < size; offset++)
5840 l = aopGet (AOP (result), offset, FALSE);
5844 emit2 ("sla %s", l);
5855 /* Left is already in result - so now do the shift */
5858 emit2 ("ld a,!immedbyte+1", shCount);
5859 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5860 emitLabel (tlbl->key + 100);
5865 l = aopGet (AOP (result), offset, FALSE);
5869 emit2 ("sla %s", l);
5880 emitLabel (tlbl1->key + 100);
5882 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5888 /*-----------------------------------------------------------------*/
5889 /* AccRol - rotate left accumulator by known count */
5890 /*-----------------------------------------------------------------*/
5892 AccRol (int shCount)
5894 shCount &= 0x0007; // shCount : 0..7
5971 /*-----------------------------------------------------------------*/
5972 /* AccLsh - left shift accumulator by known count */
5973 /*-----------------------------------------------------------------*/
5975 AccLsh (int shCount)
5977 static const unsigned char SLMask[] =
5979 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5988 else if (shCount == 2)
5995 /* rotate left accumulator */
5997 /* and kill the lower order bits */
5998 emit2 ("and a,!immedbyte", SLMask[shCount]);
6003 /*-----------------------------------------------------------------*/
6004 /* shiftL1Left2Result - shift left one byte from left to result */
6005 /*-----------------------------------------------------------------*/
6007 shiftL1Left2Result (operand * left, int offl,
6008 operand * result, int offr, int shCount)
6011 l = aopGet (AOP (left), offl, FALSE);
6013 /* shift left accumulator */
6015 aopPut (AOP (result), "a", offr);
6019 /*-----------------------------------------------------------------*/
6020 /* genlshTwo - left shift two bytes by known amount */
6021 /*-----------------------------------------------------------------*/
6023 genlshTwo (operand * result, operand * left, int shCount)
6025 int size = AOP_SIZE (result);
6027 wassert (size == 2);
6029 /* if shCount >= 8 */
6037 movLeft2Result (left, LSB, result, MSB16, 0);
6038 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6039 aopPut (AOP (result), "!zero", LSB);
6043 movLeft2Result (left, LSB, result, MSB16, 0);
6044 aopPut (AOP (result), "!zero", 0);
6049 aopPut (AOP (result), "!zero", LSB);
6052 /* 0 <= shCount <= 7 */
6061 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6066 /*-----------------------------------------------------------------*/
6067 /* genlshOne - left shift a one byte quantity by known count */
6068 /*-----------------------------------------------------------------*/
6070 genlshOne (operand * result, operand * left, int shCount)
6072 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6075 /*-----------------------------------------------------------------*/
6076 /* genLeftShiftLiteral - left shifting by known count */
6077 /*-----------------------------------------------------------------*/
6079 genLeftShiftLiteral (operand * left,
6084 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6087 freeAsmop (right, NULL, ic);
6089 aopOp (left, ic, FALSE, FALSE);
6090 aopOp (result, ic, FALSE, FALSE);
6092 size = getSize (operandType (result));
6094 /* I suppose that the left size >= result size */
6096 if (shCount >= (size * 8))
6100 aopPut (AOP (result), "!zero", size);
6108 genlshOne (result, left, shCount);
6111 genlshTwo (result, left, shCount);
6114 wassertl (0, "Shifting of longs is currently unsupported");
6120 freeAsmop (left, NULL, ic);
6121 freeAsmop (result, NULL, ic);
6124 /*-----------------------------------------------------------------*/
6125 /* genLeftShift - generates code for left shifting */
6126 /*-----------------------------------------------------------------*/
6128 genLeftShift (iCode * ic)
6132 symbol *tlbl, *tlbl1;
6133 operand *left, *right, *result;
6135 right = IC_RIGHT (ic);
6136 left = IC_LEFT (ic);
6137 result = IC_RESULT (ic);
6139 aopOp (right, ic, FALSE, FALSE);
6141 /* if the shift count is known then do it
6142 as efficiently as possible */
6143 if (AOP_TYPE (right) == AOP_LIT)
6145 genLeftShiftLiteral (left, right, result, ic);
6149 /* shift count is unknown then we have to form a loop get the loop
6150 count in B : Note: we take only the lower order byte since
6151 shifting more that 32 bits make no sense anyway, ( the largest
6152 size of an object can be only 32 bits ) */
6153 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6155 freeAsmop (right, NULL, ic);
6156 aopOp (left, ic, FALSE, FALSE);
6157 aopOp (result, ic, FALSE, FALSE);
6159 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6162 /* now move the left to the result if they are not the
6165 if (!sameRegs (AOP (left), AOP (result)))
6168 size = AOP_SIZE (result);
6172 l = aopGet (AOP (left), offset, FALSE);
6173 aopPut (AOP (result), l, offset);
6178 tlbl = newiTempLabel (NULL);
6179 size = AOP_SIZE (result);
6181 tlbl1 = newiTempLabel (NULL);
6183 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6186 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6187 emitLabel (tlbl->key + 100);
6188 l = aopGet (AOP (result), offset, FALSE);
6192 l = aopGet (AOP (result), offset, FALSE);
6196 emit2 ("sla %s", l);
6204 emitLabel (tlbl1->key + 100);
6206 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6208 freeAsmop (left, NULL, ic);
6209 freeAsmop (result, NULL, ic);
6212 /*-----------------------------------------------------------------*/
6213 /* genrshOne - left shift two bytes by known amount != 0 */
6214 /*-----------------------------------------------------------------*/
6216 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6219 int size = AOP_SIZE (result);
6222 wassert (size == 1);
6223 wassert (shCount < 8);
6225 l = aopGet (AOP (left), 0, FALSE);
6227 if (AOP (result)->type == AOP_REG)
6229 aopPut (AOP (result), l, 0);
6230 l = aopGet (AOP (result), 0, FALSE);
6233 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6241 emit2 ("%s a", is_signed ? "sra" : "srl");
6243 aopPut (AOP (result), "a", 0);
6247 /*-----------------------------------------------------------------*/
6248 /* AccRsh - right shift accumulator by known count */
6249 /*-----------------------------------------------------------------*/
6251 AccRsh (int shCount)
6253 static const unsigned char SRMask[] =
6255 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6260 /* rotate right accumulator */
6261 AccRol (8 - shCount);
6262 /* and kill the higher order bits */
6263 emit2 ("and a,!immedbyte", SRMask[shCount]);
6267 /*-----------------------------------------------------------------*/
6268 /* shiftR1Left2Result - shift right one byte from left to result */
6269 /*-----------------------------------------------------------------*/
6271 shiftR1Left2Result (operand * left, int offl,
6272 operand * result, int offr,
6273 int shCount, int sign)
6275 _moveA (aopGet (AOP (left), offl, FALSE));
6280 emit2 ("%s a", sign ? "sra" : "srl");
6287 aopPut (AOP (result), "a", offr);
6290 /*-----------------------------------------------------------------*/
6291 /* genrshTwo - right shift two bytes by known amount */
6292 /*-----------------------------------------------------------------*/
6294 genrshTwo (operand * result, operand * left,
6295 int shCount, int sign)
6297 /* if shCount >= 8 */
6303 shiftR1Left2Result (left, MSB16, result, LSB,
6308 movLeft2Result (left, MSB16, result, LSB, sign);
6312 /* Sign extend the result */
6313 _moveA(aopGet (AOP (result), 0, FALSE));
6317 aopPut (AOP (result), ACC_NAME, MSB16);
6321 aopPut (AOP (result), "!zero", 1);
6324 /* 0 <= shCount <= 7 */
6327 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6331 /*-----------------------------------------------------------------*/
6332 /* genRightShiftLiteral - left shifting by known count */
6333 /*-----------------------------------------------------------------*/
6335 genRightShiftLiteral (operand * left,
6341 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6344 freeAsmop (right, NULL, ic);
6346 aopOp (left, ic, FALSE, FALSE);
6347 aopOp (result, ic, FALSE, FALSE);
6349 size = getSize (operandType (result));
6351 /* I suppose that the left size >= result size */
6353 if (shCount >= (size * 8)) {
6355 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6356 _moveA(aopGet (AOP (left), 0, FALSE));
6364 aopPut (AOP (result), s, size);
6371 genrshOne (result, left, shCount, sign);
6374 genrshTwo (result, left, shCount, sign);
6377 wassertl (0, "Asked to shift right a long which should be a function call");
6380 wassertl (0, "Entered default case in right shift delegate");
6383 freeAsmop (left, NULL, ic);
6384 freeAsmop (result, NULL, ic);
6387 /*-----------------------------------------------------------------*/
6388 /* genRightShift - generate code for right shifting */
6389 /*-----------------------------------------------------------------*/
6391 genRightShift (iCode * ic)
6393 operand *right, *left, *result;
6395 int size, offset, first = 1;
6399 symbol *tlbl, *tlbl1;
6401 /* if signed then we do it the hard way preserve the
6402 sign bit moving it inwards */
6403 retype = getSpec (operandType (IC_RESULT (ic)));
6405 is_signed = !SPEC_USIGN (retype);
6407 /* signed & unsigned types are treated the same : i.e. the
6408 signed is NOT propagated inwards : quoting from the
6409 ANSI - standard : "for E1 >> E2, is equivalent to division
6410 by 2**E2 if unsigned or if it has a non-negative value,
6411 otherwise the result is implementation defined ", MY definition
6412 is that the sign does not get propagated */
6414 right = IC_RIGHT (ic);
6415 left = IC_LEFT (ic);
6416 result = IC_RESULT (ic);
6418 aopOp (right, ic, FALSE, FALSE);
6420 /* if the shift count is known then do it
6421 as efficiently as possible */
6422 if (AOP_TYPE (right) == AOP_LIT)
6424 genRightShiftLiteral (left, right, result, ic, is_signed);
6428 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6430 freeAsmop (right, NULL, ic);
6432 aopOp (left, ic, FALSE, FALSE);
6433 aopOp (result, ic, FALSE, FALSE);
6435 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6438 /* now move the left to the result if they are not the
6440 if (!sameRegs (AOP (left), AOP (result)))
6443 size = AOP_SIZE (result);
6447 l = aopGet (AOP (left), offset, FALSE);
6448 aopPut (AOP (result), l, offset);
6453 tlbl = newiTempLabel (NULL);
6454 tlbl1 = newiTempLabel (NULL);
6455 size = AOP_SIZE (result);
6458 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6461 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6462 emitLabel (tlbl->key + 100);
6465 l = aopGet (AOP (result), offset--, FALSE);
6468 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6476 emitLabel (tlbl1->key + 100);
6478 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6480 freeAsmop (left, NULL, ic);
6481 freeAsmop (result, NULL, ic);
6485 /*-----------------------------------------------------------------*/
6486 /* genUnpackBits - generates code for unpacking bits */
6487 /*-----------------------------------------------------------------*/
6489 genUnpackBits (operand * result, int pair)
6491 int offset = 0; /* result byte offset */
6492 int rsize; /* result size */
6493 int rlen = 0; /* remaining bitfield length */
6494 sym_link *etype; /* bitfield type information */
6495 int blen; /* bitfield length */
6496 int bstr; /* bitfield starting bit within byte */
6498 emitDebug ("; genUnpackBits");
6500 etype = getSpec (operandType (result));
6501 rsize = getSize (operandType (result));
6502 blen = SPEC_BLEN (etype);
6503 bstr = SPEC_BSTR (etype);
6505 /* If the bitfield length is less than a byte */
6508 emit2 ("ld a,!*pair", _pairs[pair].name);
6510 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6511 if (!SPEC_USIGN (etype))
6513 /* signed bitfield */
6514 symbol *tlbl = newiTempLabel (NULL);
6516 emit2 ("bit %d,a", blen - 1);
6517 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6518 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6519 emitLabel (tlbl->key + 100);
6521 aopPut (AOP (result), "a", offset++);
6525 /* TODO: what if pair == PAIR_DE ? */
6526 if (getPairId (AOP (result)) == PAIR_HL)
6528 wassertl (rsize == 2, "HL must be of size 2");
6529 emit2 ("ld a,!*hl");
6531 emit2 ("ld h,!*hl");
6534 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6535 if (!SPEC_USIGN (etype))
6537 /* signed bitfield */
6538 symbol *tlbl = newiTempLabel (NULL);
6540 emit2 ("bit %d,a", blen - 1);
6541 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6542 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6543 emitLabel (tlbl->key + 100);
6546 spillPair (PAIR_HL);
6550 /* Bit field did not fit in a byte. Copy all
6551 but the partial byte at the end. */
6552 for (rlen=blen;rlen>=8;rlen-=8)
6554 emit2 ("ld a,!*pair", _pairs[pair].name);
6555 aopPut (AOP (result), "a", offset++);
6558 emit2 ("inc %s", _pairs[pair].name);
6559 _G.pairs[pair].offset++;
6563 /* Handle the partial byte at the end */
6566 emit2 ("ld a,!*pair", _pairs[pair].name);
6567 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6568 if (!SPEC_USIGN (etype))
6570 /* signed bitfield */
6571 symbol *tlbl = newiTempLabel (NULL);
6573 emit2 ("bit %d,a", rlen - 1);
6574 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6575 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6576 emitLabel (tlbl->key + 100);
6578 aopPut (AOP (result), "a", offset++);
6586 if (SPEC_USIGN (etype))
6590 /* signed bitfield: sign extension with 0x00 or 0xff */
6598 aopPut (AOP (result), source, offset++);
6602 /*-----------------------------------------------------------------*/
6603 /* genGenPointerGet - get value from generic pointer space */
6604 /*-----------------------------------------------------------------*/
6606 genGenPointerGet (operand * left,
6607 operand * result, iCode * ic)
6610 sym_link *retype = getSpec (operandType (result));
6616 aopOp (left, ic, FALSE, FALSE);
6617 aopOp (result, ic, FALSE, FALSE);
6619 size = AOP_SIZE (result);
6621 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6624 if (isPtrPair (AOP (left)))
6626 tsprintf (buffer, sizeof(buffer),
6627 "!*pair", getPairName (AOP (left)));
6628 aopPut (AOP (result), buffer, 0);
6632 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6633 aopPut (AOP (result), "a", 0);
6635 freeAsmop (left, NULL, ic);
6639 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6646 tsprintf (at, sizeof(at), "!*iyx", offset);
6647 aopPut (AOP (result), at, offset);
6651 freeAsmop (left, NULL, ic);
6655 /* For now we always load into IY */
6656 /* if this is remateriazable */
6657 fetchPair (pair, AOP (left));
6659 /* if bit then unpack */
6660 if (IS_BITVAR (retype))
6662 genUnpackBits (result, pair);
6663 freeAsmop (left, NULL, ic);
6667 else if (getPairId (AOP (result)) == PAIR_HL)
6669 wassertl (size == 2, "HL must be of size 2");
6670 emit2 ("ld a,!*hl");
6672 emit2 ("ld h,!*hl");
6674 spillPair (PAIR_HL);
6676 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6678 size = AOP_SIZE (result);
6683 /* PENDING: make this better */
6684 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6686 aopPut (AOP (result), "!*hl", offset++);
6690 emit2 ("ld a,!*pair", _pairs[pair].name);
6691 aopPut (AOP (result), "a", offset++);
6695 emit2 ("inc %s", _pairs[pair].name);
6696 _G.pairs[pair].offset++;
6699 /* Fixup HL back down */
6700 for (size = AOP_SIZE (result)-1; size; size--)
6702 emit2 ("dec %s", _pairs[pair].name);
6707 size = AOP_SIZE (result);
6712 /* PENDING: make this better */
6714 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6716 aopPut (AOP (result), "!*hl", offset++);
6720 emit2 ("ld a,!*pair", _pairs[pair].name);
6721 aopPut (AOP (result), "a", offset++);
6725 emit2 ("inc %s", _pairs[pair].name);
6726 _G.pairs[pair].offset++;
6731 freeAsmop (left, NULL, ic);
6734 freeAsmop (result, NULL, ic);
6737 /*-----------------------------------------------------------------*/
6738 /* genPointerGet - generate code for pointer get */
6739 /*-----------------------------------------------------------------*/
6741 genPointerGet (iCode * ic)
6743 operand *left, *result;
6744 sym_link *type, *etype;
6746 left = IC_LEFT (ic);
6747 result = IC_RESULT (ic);
6749 /* depending on the type of pointer we need to
6750 move it to the correct pointer register */
6751 type = operandType (left);
6752 etype = getSpec (type);
6754 genGenPointerGet (left, result, ic);
6758 isRegOrLit (asmop * aop)
6760 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6766 /*-----------------------------------------------------------------*/
6767 /* genPackBits - generates code for packed bit storage */
6768 /*-----------------------------------------------------------------*/
6770 genPackBits (sym_link * etype,
6775 int offset = 0; /* source byte offset */
6776 int rlen = 0; /* remaining bitfield length */
6777 int blen; /* bitfield length */
6778 int bstr; /* bitfield starting bit within byte */
6779 int litval; /* source literal value (if AOP_LIT) */
6780 unsigned char mask; /* bitmask within current byte */
6781 int extraPair; /* a tempory register */
6782 bool needPopExtra=0; /* need to restore original value of temp reg */
6784 emitDebug ("; genPackBits","");
6786 blen = SPEC_BLEN (etype);
6787 bstr = SPEC_BSTR (etype);
6789 /* If the bitfield length is less than a byte */
6792 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6793 (unsigned char) (0xFF >> (8 - bstr)));
6795 if (AOP_TYPE (right) == AOP_LIT)
6797 /* Case with a bitfield length <8 and literal source
6799 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6801 litval &= (~mask) & 0xff;
6802 emit2 ("ld a,!*pair", _pairs[pair].name);
6803 if ((mask|litval)!=0xff)
6804 emit2 ("and a,!immedbyte", mask);
6806 emit2 ("or a,!immedbyte", litval);
6807 emit2 ("ld !*pair,a", _pairs[pair].name);
6812 /* Case with a bitfield length <8 and arbitrary source
6814 _moveA (aopGet (AOP (right), 0, FALSE));
6815 /* shift and mask source value */
6817 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6819 extraPair = getFreePairId(ic);
6820 if (extraPair == PAIR_INVALID)
6822 extraPair = PAIR_BC;
6823 if (getPairId (AOP (right)) != PAIR_BC
6824 || !isLastUse (ic, right))
6830 emit2 ("ld %s,a", _pairs[extraPair].l);
6831 emit2 ("ld a,!*pair", _pairs[pair].name);
6833 emit2 ("and a,!immedbyte", mask);
6834 emit2 ("or a,%s", _pairs[extraPair].l);
6835 emit2 ("ld !*pair,a", _pairs[pair].name);
6842 /* Bit length is greater than 7 bits. In this case, copy */
6843 /* all except the partial byte at the end */
6844 for (rlen=blen;rlen>=8;rlen-=8)
6846 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6847 emit2 ("ld !*pair,a", _pairs[pair].name);
6850 emit2 ("inc %s", _pairs[pair].name);
6851 _G.pairs[pair].offset++;
6855 /* If there was a partial byte at the end */
6858 mask = (((unsigned char) -1 << rlen) & 0xff);
6860 if (AOP_TYPE (right) == AOP_LIT)
6862 /* Case with partial byte and literal source
6864 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6865 litval >>= (blen-rlen);
6866 litval &= (~mask) & 0xff;
6867 emit2 ("ld a,!*pair", _pairs[pair].name);
6868 if ((mask|litval)!=0xff)
6869 emit2 ("and a,!immedbyte", mask);
6871 emit2 ("or a,!immedbyte", litval);
6875 /* Case with partial byte and arbitrary source
6877 _moveA (aopGet (AOP (right), offset++, FALSE));
6878 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6880 extraPair = getFreePairId(ic);
6881 if (extraPair == PAIR_INVALID)
6883 extraPair = getPairId (AOP (right));
6884 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6885 extraPair = PAIR_BC;
6887 if (getPairId (AOP (right)) != PAIR_BC
6888 || !isLastUse (ic, right))
6894 emit2 ("ld %s,a", _pairs[extraPair].l);
6895 emit2 ("ld a,!*pair", _pairs[pair].name);
6897 emit2 ("and a,!immedbyte", mask);
6898 emit2 ("or a,%s", _pairs[extraPair].l);
6903 emit2 ("ld !*pair,a", _pairs[pair].name);
6908 /*-----------------------------------------------------------------*/
6909 /* genGenPointerSet - stores the value into a pointer location */
6910 /*-----------------------------------------------------------------*/
6912 genGenPointerSet (operand * right,
6913 operand * result, iCode * ic)
6916 sym_link *retype = getSpec (operandType (right));
6917 sym_link *letype = getSpec (operandType (result));
6918 PAIR_ID pairId = PAIR_HL;
6921 aopOp (result, ic, FALSE, FALSE);
6922 aopOp (right, ic, FALSE, FALSE);
6927 size = AOP_SIZE (right);
6929 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6930 emitDebug("; isBitvar = %d", isBitvar);
6932 /* Handle the exceptions first */
6933 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6936 const char *l = aopGet (AOP (right), 0, FALSE);
6937 const char *pair = getPairName (AOP (result));
6938 if (canAssignToPtr (l) && isPtr (pair))
6940 emit2 ("ld !*pair,%s", pair, l);
6945 emit2 ("ld !*pair,a", pair);
6950 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6953 const char *l = aopGet (AOP (right), 0, FALSE);
6958 if (canAssignToPtr (l))
6960 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6964 _moveA (aopGet (AOP (right), offset, FALSE));
6965 emit2 ("ld !*iyx,a", offset);
6971 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6978 const char *l = aopGet (AOP (right), offset, FALSE);
6979 if (isRegOrLit (AOP (right)) && !IS_GB)
6981 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6986 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6990 emit2 ("inc %s", _pairs[PAIR_HL].name);
6991 _G.pairs[PAIR_HL].offset++;
6996 /* Fixup HL back down */
6997 for (size = AOP_SIZE (right)-1; size; size--)
6999 emit2 ("dec %s", _pairs[PAIR_HL].name);
7004 /* if the operand is already in dptr
7005 then we do nothing else we move the value to dptr */
7006 if (AOP_TYPE (result) != AOP_STR)
7008 fetchPair (pairId, AOP (result));
7010 /* so hl now contains the address */
7011 freeAsmop (result, NULL, ic);
7013 /* if bit then unpack */
7016 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7026 const char *l = aopGet (AOP (right), offset, FALSE);
7027 if (isRegOrLit (AOP (right)) && !IS_GB)
7029 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7034 emit2 ("ld !*pair,a", _pairs[pairId].name);
7038 emit2 ("inc %s", _pairs[pairId].name);
7039 _G.pairs[pairId].offset++;
7045 freeAsmop (right, NULL, ic);
7048 /*-----------------------------------------------------------------*/
7049 /* genPointerSet - stores the value into a pointer location */
7050 /*-----------------------------------------------------------------*/
7052 genPointerSet (iCode * ic)
7054 operand *right, *result;
7055 sym_link *type, *etype;
7057 right = IC_RIGHT (ic);
7058 result = IC_RESULT (ic);
7060 /* depending on the type of pointer we need to
7061 move it to the correct pointer register */
7062 type = operandType (result);
7063 etype = getSpec (type);
7065 genGenPointerSet (right, result, ic);
7068 /*-----------------------------------------------------------------*/
7069 /* genIfx - generate code for Ifx statement */
7070 /*-----------------------------------------------------------------*/
7072 genIfx (iCode * ic, iCode * popIc)
7074 operand *cond = IC_COND (ic);
7077 aopOp (cond, ic, FALSE, TRUE);
7079 /* get the value into acc */
7080 if (AOP_TYPE (cond) != AOP_CRY)
7084 /* the result is now in the accumulator */
7085 freeAsmop (cond, NULL, ic);
7087 /* if there was something to be popped then do it */
7091 /* if the condition is a bit variable */
7092 if (isbit && IS_ITEMP (cond) &&
7094 genIfxJump (ic, SPIL_LOC (cond)->rname);
7095 else if (isbit && !IS_ITEMP (cond))
7096 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7098 genIfxJump (ic, "a");
7103 /*-----------------------------------------------------------------*/
7104 /* genAddrOf - generates code for address of */
7105 /*-----------------------------------------------------------------*/
7107 genAddrOf (iCode * ic)
7109 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7111 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7113 /* if the operand is on the stack then we
7114 need to get the stack offset of this
7121 if (sym->stack <= 0)
7123 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7127 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7129 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7133 emit2 ("ld de,!hashedstr", sym->rname);
7134 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7142 /* if it has an offset then we need to compute it */
7144 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7146 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7147 emit2 ("add hl,sp");
7151 emit2 ("ld hl,!hashedstr", sym->rname);
7153 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7155 freeAsmop (IC_RESULT (ic), NULL, ic);
7158 /*-----------------------------------------------------------------*/
7159 /* genAssign - generate code for assignment */
7160 /*-----------------------------------------------------------------*/
7162 genAssign (iCode * ic)
7164 operand *result, *right;
7166 unsigned long lit = 0L;
7168 result = IC_RESULT (ic);
7169 right = IC_RIGHT (ic);
7171 /* Dont bother assigning if they are the same */
7172 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7174 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7178 aopOp (right, ic, FALSE, FALSE);
7179 aopOp (result, ic, TRUE, FALSE);
7181 /* if they are the same registers */
7182 if (sameRegs (AOP (right), AOP (result)))
7184 emitDebug ("; (registers are the same)");
7188 /* if the result is a bit */
7189 if (AOP_TYPE (result) == AOP_CRY)
7191 wassertl (0, "Tried to assign to a bit");
7195 size = AOP_SIZE (result);
7198 if (AOP_TYPE (right) == AOP_LIT)
7200 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7203 if (isPair (AOP (result)))
7205 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7207 else if ((size > 1) &&
7208 (AOP_TYPE (result) != AOP_REG) &&
7209 (AOP_TYPE (right) == AOP_LIT) &&
7210 !IS_FLOAT (operandType (right)) &&
7213 bool fXored = FALSE;
7215 /* Work from the top down.
7216 Done this way so that we can use the cached copy of 0
7217 in A for a fast clear */
7220 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7222 if (!fXored && size > 1)
7229 aopPut (AOP (result), "a", offset);
7233 aopPut (AOP (result), "!zero", offset);
7237 aopPut (AOP (result),
7238 aopGet (AOP (right), offset, FALSE),
7243 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7245 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7246 aopPut (AOP (result), "l", LSB);
7247 aopPut (AOP (result), "h", MSB16);
7249 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7251 /* Special case. Load into a and d, then load out. */
7252 _moveA (aopGet (AOP (right), 0, FALSE));
7253 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7254 aopPut (AOP (result), "a", 0);
7255 aopPut (AOP (result), "e", 1);
7257 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7259 /* Special case - simple memcpy */
7260 aopGet (AOP (right), LSB, FALSE);
7263 aopGet (AOP (result), LSB, FALSE);
7267 emit2 ("ld a,(de)");
7268 /* Peephole will optimise this. */
7269 emit2 ("ld (hl),a");
7277 spillPair (PAIR_HL);
7283 /* PENDING: do this check better */
7284 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7286 _moveA (aopGet (AOP (right), offset, FALSE));
7287 aopPut (AOP (result), "a", offset);
7290 aopPut (AOP (result),
7291 aopGet (AOP (right), offset, FALSE),
7298 freeAsmop (right, NULL, ic);
7299 freeAsmop (result, NULL, ic);
7302 /*-----------------------------------------------------------------*/
7303 /* genJumpTab - genrates code for jump table */
7304 /*-----------------------------------------------------------------*/
7306 genJumpTab (iCode * ic)
7311 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7312 /* get the condition into accumulator */
7313 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7316 emit2 ("ld e,%s", l);
7317 emit2 ("ld d,!zero");
7318 jtab = newiTempLabel (NULL);
7320 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7321 emit2 ("add hl,de");
7322 emit2 ("add hl,de");
7323 emit2 ("add hl,de");
7324 freeAsmop (IC_JTCOND (ic), NULL, ic);
7328 emitLabel (jtab->key + 100);
7329 /* now generate the jump labels */
7330 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7331 jtab = setNextItem (IC_JTLABELS (ic)))
7332 emit2 ("jp !tlabel", jtab->key + 100);
7335 /*-----------------------------------------------------------------*/
7336 /* genCast - gen code for casting */
7337 /*-----------------------------------------------------------------*/
7339 genCast (iCode * ic)
7341 operand *result = IC_RESULT (ic);
7342 sym_link *rtype = operandType (IC_RIGHT (ic));
7343 operand *right = IC_RIGHT (ic);
7346 /* if they are equivalent then do nothing */
7347 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7350 aopOp (right, ic, FALSE, FALSE);
7351 aopOp (result, ic, FALSE, FALSE);
7353 /* if the result is a bit */
7354 if (AOP_TYPE (result) == AOP_CRY)
7356 wassertl (0, "Tried to cast to a bit");
7359 /* if they are the same size : or less */
7360 if (AOP_SIZE (result) <= AOP_SIZE (right))
7363 /* if they are in the same place */
7364 if (sameRegs (AOP (right), AOP (result)))
7367 /* if they in different places then copy */
7368 size = AOP_SIZE (result);
7372 aopPut (AOP (result),
7373 aopGet (AOP (right), offset, FALSE),
7380 /* So we now know that the size of destination is greater
7381 than the size of the source */
7382 /* we move to result for the size of source */
7383 size = AOP_SIZE (right);
7387 aopPut (AOP (result),
7388 aopGet (AOP (right), offset, FALSE),
7393 /* now depending on the sign of the destination */
7394 size = AOP_SIZE (result) - AOP_SIZE (right);
7395 /* Unsigned or not an integral type - right fill with zeros */
7396 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7399 aopPut (AOP (result), "!zero", offset++);
7403 /* we need to extend the sign :{ */
7404 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7410 aopPut (AOP (result), "a", offset++);
7414 freeAsmop (right, NULL, ic);
7415 freeAsmop (result, NULL, ic);
7418 /*-----------------------------------------------------------------*/
7419 /* genReceive - generate code for a receive iCode */
7420 /*-----------------------------------------------------------------*/
7422 genReceive (iCode * ic)
7424 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7425 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7426 IS_TRUE_SYMOP (IC_RESULT (ic))))
7436 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7437 size = AOP_SIZE(IC_RESULT(ic));
7439 for (i = 0; i < size; i++) {
7440 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7444 freeAsmop (IC_RESULT (ic), NULL, ic);
7447 /*-----------------------------------------------------------------*/
7448 /* genDummyRead - generate code for dummy read of volatiles */
7449 /*-----------------------------------------------------------------*/
7451 genDummyRead (iCode * ic)
7457 if (op && IS_SYMOP (op))
7459 aopOp (op, ic, FALSE, FALSE);
7462 size = AOP_SIZE (op);
7467 _moveA (aopGet (AOP (op), offset, FALSE));
7471 freeAsmop (op, NULL, ic);
7475 if (op && IS_SYMOP (op))
7477 aopOp (op, ic, FALSE, FALSE);
7480 size = AOP_SIZE (op);
7485 _moveA (aopGet (AOP (op), offset, FALSE));
7489 freeAsmop (op, NULL, ic);
7493 /*-----------------------------------------------------------------*/
7494 /* genCritical - generate code for start of a critical sequence */
7495 /*-----------------------------------------------------------------*/
7497 genCritical (iCode *ic)
7499 symbol *tlbl = newiTempLabel (NULL);
7505 else if (IC_RESULT (ic))
7507 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7508 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7509 //get interrupt enable flag IFF2 into P/O
7513 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7514 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7515 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7516 emit2 ("!tlabeldef", (tlbl->key + 100));
7517 _G.lines.current->isLabel = 1;
7518 freeAsmop (IC_RESULT (ic), NULL, ic);
7522 //get interrupt enable flag IFF2 into P/O
7531 /*-----------------------------------------------------------------*/
7532 /* genEndCritical - generate code for end of a critical sequence */
7533 /*-----------------------------------------------------------------*/
7535 genEndCritical (iCode *ic)
7537 symbol *tlbl = newiTempLabel (NULL);
7543 else if (IC_RIGHT (ic))
7545 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7546 _toBoolean (IC_RIGHT (ic));
7547 //don't enable interrupts if they were off before
7548 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7550 emitLabel (tlbl->key + 100);
7551 freeAsmop (IC_RIGHT (ic), NULL, ic);
7557 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7558 //don't enable interrupts as they were off before
7559 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7561 emit2 ("!tlabeldef", (tlbl->key + 100));
7562 _G.lines.current->isLabel = 1;
7568 /** Maximum number of bytes to emit per line. */
7572 /** Context for the byte output chunker. */
7575 unsigned char buffer[DBEMIT_MAX_RUN];
7580 /** Flushes a byte chunker by writing out all in the buffer and
7584 _dbFlush(DBEMITCTX *self)
7591 sprintf(line, ".db 0x%02X", self->buffer[0]);
7593 for (i = 1; i < self->pos; i++)
7595 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7602 /** Write out another byte, buffering until a decent line is
7606 _dbEmit(DBEMITCTX *self, int c)
7608 if (self->pos == DBEMIT_MAX_RUN)
7612 self->buffer[self->pos++] = c;
7615 /** Context for a simple run length encoder. */
7619 unsigned char buffer[128];
7621 /** runLen may be equivalent to pos. */
7627 RLE_CHANGE_COST = 4,
7631 /** Flush the buffer of a run length encoder by writing out the run or
7632 data that it currently contains.
7635 _rleCommit(RLECTX *self)
7641 memset(&db, 0, sizeof(db));
7643 emit2(".db %u", self->pos);
7645 for (i = 0; i < self->pos; i++)
7647 _dbEmit(&db, self->buffer[i]);
7656 Can get either a run or a block of random stuff.
7657 Only want to change state if a good run comes in or a run ends.
7658 Detecting run end is easy.
7661 Say initial state is in run, len zero, last zero. Then if you get a
7662 few zeros then something else then a short run will be output.
7663 Seems OK. While in run mode, keep counting. While in random mode,
7664 keep a count of the run. If run hits margin, output all up to run,
7665 restart, enter run mode.
7668 /** Add another byte into the run length encoder, flushing as
7669 required. The run length encoder uses the Amiga IFF style, where
7670 a block is prefixed by its run length. A positive length means
7671 the next n bytes pass straight through. A negative length means
7672 that the next byte is repeated -n times. A zero terminates the
7676 _rleAppend(RLECTX *self, unsigned c)
7680 if (c != self->last)
7682 /* The run has stopped. See if it is worthwhile writing it out
7683 as a run. Note that the random data comes in as runs of
7686 if (self->runLen > RLE_CHANGE_COST)
7688 /* Yes, worthwhile. */
7689 /* Commit whatever was in the buffer. */
7691 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7695 /* Not worthwhile. Append to the end of the random list. */
7696 for (i = 0; i < self->runLen; i++)
7698 if (self->pos >= RLE_MAX_BLOCK)
7703 self->buffer[self->pos++] = self->last;
7711 if (self->runLen >= RLE_MAX_BLOCK)
7713 /* Commit whatever was in the buffer. */
7716 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7724 _rleFlush(RLECTX *self)
7726 _rleAppend(self, -1);
7733 /** genArrayInit - Special code for initialising an array with constant
7737 genArrayInit (iCode * ic)
7741 int elementSize = 0, eIndex, i;
7742 unsigned val, lastVal;
7746 memset(&rle, 0, sizeof(rle));
7748 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7750 _saveRegsForCall(ic, 0);
7752 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7753 emit2 ("call __initrleblock");
7755 type = operandType(IC_LEFT(ic));
7757 if (type && type->next)
7759 if (IS_SPEC(type->next) || IS_PTR(type->next))
7761 elementSize = getSize(type->next);
7763 else if (IS_ARRAY(type->next) && type->next->next)
7765 elementSize = getSize(type->next->next);
7769 printTypeChainRaw (type, NULL);
7770 wassertl (0, "Can't determine element size in genArrayInit.");
7775 wassertl (0, "Can't determine element size in genArrayInit.");
7778 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7780 iLoop = IC_ARRAYILIST(ic);
7781 lastVal = (unsigned)-1;
7783 /* Feed all the bytes into the run length encoder which will handle
7785 This works well for mixed char data, and for random int and long
7792 for (i = 0; i < ix; i++)
7794 for (eIndex = 0; eIndex < elementSize; eIndex++)
7796 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7797 _rleAppend(&rle, val);
7801 iLoop = iLoop->next;
7805 /* Mark the end of the run. */
7808 _restoreRegsAfterCall();
7812 freeAsmop (IC_LEFT(ic), NULL, ic);
7816 _swap (PAIR_ID one, PAIR_ID two)
7818 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7824 emit2 ("ld a,%s", _pairs[one].l);
7825 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7826 emit2 ("ld %s,a", _pairs[two].l);
7827 emit2 ("ld a,%s", _pairs[one].h);
7828 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7829 emit2 ("ld %s,a", _pairs[two].h);
7833 /* The problem is that we may have all three pairs used and they may
7834 be needed in a different order.
7839 hl = hl => unity, fine
7843 hl = hl hl = hl, swap de <=> bc
7851 hl = bc de = de, swap bc <=> hl
7859 hl = de bc = bc, swap hl <=> de
7864 * Any pair = pair are done last
7865 * Any pair = iTemp are done last
7866 * Any swaps can be done any time
7874 So how do we detect the cases?
7875 How about a 3x3 matrix?
7879 x x x x (Fourth for iTemp/other)
7881 First determin which mode to use by counting the number of unity and
7884 Two - Assign the pair first, then the rest
7885 One - Swap the two, then the rest
7889 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7891 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7893 PAIR_BC, PAIR_HL, PAIR_DE
7895 int i, j, nunity = 0;
7896 memset (ids, PAIR_INVALID, sizeof (ids));
7899 wassert (nparams == 3);
7901 /* First save everything that needs to be saved. */
7902 _saveRegsForCall (ic, 0);
7904 /* Loading HL first means that DE is always fine. */
7905 for (i = 0; i < nparams; i++)
7907 aopOp (pparams[i], ic, FALSE, FALSE);
7908 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7911 /* Count the number of unity or iTemp assigns. */
7912 for (i = 0; i < 3; i++)
7914 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7922 /* Any order, fall through. */
7924 else if (nunity == 2)
7926 /* One is assigned. Pull it out and assign. */
7927 for (i = 0; i < 3; i++)
7929 for (j = 0; j < NUM_PAIRS; j++)
7931 if (ids[dest[i]][j] == TRUE)
7933 /* Found it. See if it's the right one. */
7934 if (j == PAIR_INVALID || j == dest[i])
7940 fetchPair(dest[i], AOP (pparams[i]));
7947 else if (nunity == 1)
7949 /* Find the pairs to swap. */
7950 for (i = 0; i < 3; i++)
7952 for (j = 0; j < NUM_PAIRS; j++)
7954 if (ids[dest[i]][j] == TRUE)
7956 if (j == PAIR_INVALID || j == dest[i])
7971 int next = getPairId (AOP (pparams[0]));
7972 emit2 ("push %s", _pairs[next].name);
7974 if (next == dest[1])
7976 fetchPair (dest[1], AOP (pparams[1]));
7977 fetchPair (dest[2], AOP (pparams[2]));
7981 fetchPair (dest[2], AOP (pparams[2]));
7982 fetchPair (dest[1], AOP (pparams[1]));
7984 emit2 ("pop %s", _pairs[dest[0]].name);
7987 /* Finally pull out all of the iTemps */
7988 for (i = 0; i < 3; i++)
7990 if (ids[dest[i]][PAIR_INVALID] == 1)
7992 fetchPair (dest[i], AOP (pparams[i]));
7998 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8004 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8008 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8010 setupForBuiltin3 (ic, nParams, pparams);
8012 label = newiTempLabel(NULL);
8014 emitLabel (label->key);
8015 emit2 ("ld a,(hl)");
8018 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8020 freeAsmop (from, NULL, ic->next);
8021 freeAsmop (to, NULL, ic);
8025 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8027 operand *from, *to, *count;
8030 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8035 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8037 setupForBuiltin3 (ic, nParams, pparams);
8041 freeAsmop (count, NULL, ic->next->next);
8042 freeAsmop (from, NULL, ic);
8044 _restoreRegsAfterCall();
8046 /* if we need assign a result value */
8047 if ((IS_ITEMP (IC_RESULT (ic)) &&
8048 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8049 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8050 IS_TRUE_SYMOP (IC_RESULT (ic)))
8052 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8053 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8054 freeAsmop (IC_RESULT (ic), NULL, ic);
8057 freeAsmop (to, NULL, ic->next);
8060 /*-----------------------------------------------------------------*/
8061 /* genBuiltIn - calls the appropriate function to generating code */
8062 /* for a built in function */
8063 /*-----------------------------------------------------------------*/
8064 static void genBuiltIn (iCode *ic)
8066 operand *bi_parms[MAX_BUILTIN_ARGS];
8071 /* get all the arguments for a built in function */
8072 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8074 /* which function is it */
8075 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8077 if (strcmp(bif->name,"__builtin_strcpy")==0)
8079 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8081 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8083 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8087 wassertl (0, "Unknown builtin function encountered");
8091 /*-----------------------------------------------------------------*/
8092 /* genZ80Code - generate code for Z80 based controllers */
8093 /*-----------------------------------------------------------------*/
8095 genZ80Code (iCode * lic)
8103 _fReturn = _gbz80_return;
8104 _fTmp = _gbz80_return;
8108 _fReturn = _z80_return;
8109 _fTmp = _z80_return;
8112 _G.lines.head = _G.lines.current = NULL;
8114 /* if debug information required */
8115 if (options.debug && currFunc)
8117 debugFile->writeFunction (currFunc, lic);
8120 for (ic = lic; ic; ic = ic->next)
8122 _G.current_iCode = ic;
8124 if (ic->lineno && cln != ic->lineno)
8128 debugFile->writeCLine (ic);
8130 if (!options.noCcodeInAsm)
8132 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8133 printCLine(ic->filename, ic->lineno));
8137 if (options.iCodeInAsm)
8139 char *iLine = printILine(ic);
8140 emit2 (";ic:%d: %s", ic->key, iLine);
8143 /* if the result is marked as
8144 spilt and rematerializable or code for
8145 this has already been generated then
8147 if (resultRemat (ic) || ic->generated)
8150 /* depending on the operation */
8154 emitDebug ("; genNot");
8159 emitDebug ("; genCpl");
8164 emitDebug ("; genUminus");
8169 emitDebug ("; genIpush");
8174 /* IPOP happens only when trying to restore a
8175 spilt live range, if there is an ifx statement
8176 following this pop then the if statement might
8177 be using some of the registers being popped which
8178 would destroy the contents of the register so
8179 we need to check for this condition and handle it */
8181 ic->next->op == IFX &&
8182 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8184 emitDebug ("; genIfx");
8185 genIfx (ic->next, ic);
8189 emitDebug ("; genIpop");
8195 emitDebug ("; genCall");
8200 emitDebug ("; genPcall");
8205 emitDebug ("; genFunction");
8210 emitDebug ("; genEndFunction");
8211 genEndFunction (ic);
8215 emitDebug ("; genRet");
8220 emitDebug ("; genLabel");
8225 emitDebug ("; genGoto");
8230 emitDebug ("; genPlus");
8235 emitDebug ("; genMinus");
8240 emitDebug ("; genMult");
8245 emitDebug ("; genDiv");
8250 emitDebug ("; genMod");
8255 emitDebug ("; genCmpGt");
8256 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8260 emitDebug ("; genCmpLt");
8261 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8268 /* note these two are xlated by algebraic equivalence
8269 during parsing SDCC.y */
8270 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8271 "got '>=' or '<=' shouldn't have come here");
8275 emitDebug ("; genCmpEq");
8276 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8280 emitDebug ("; genAndOp");
8285 emitDebug ("; genOrOp");
8290 emitDebug ("; genXor");
8291 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8295 emitDebug ("; genOr");
8296 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8300 emitDebug ("; genAnd");
8301 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8305 emitDebug ("; genInline");
8310 emitDebug ("; genRRC");
8315 emitDebug ("; genRLC");
8320 emitDebug ("; genGetHBIT");
8325 emitDebug ("; genLeftShift");
8330 emitDebug ("; genRightShift");
8334 case GET_VALUE_AT_ADDRESS:
8335 emitDebug ("; genPointerGet");
8341 if (POINTER_SET (ic))
8343 emitDebug ("; genAssign (pointer)");
8348 emitDebug ("; genAssign");
8354 emitDebug ("; genIfx");
8359 emitDebug ("; genAddrOf");
8364 emitDebug ("; genJumpTab");
8369 emitDebug ("; genCast");
8374 emitDebug ("; genReceive");
8379 if (ic->builtinSEND)
8381 emitDebug ("; genBuiltIn");
8386 emitDebug ("; addSet");
8387 addSet (&_G.sendSet, ic);
8392 emitDebug ("; genArrayInit");
8396 case DUMMY_READ_VOLATILE:
8397 emitDebug ("; genDummyRead");
8402 emitDebug ("; genCritical");
8407 emitDebug ("; genEndCritical");
8408 genEndCritical (ic);
8417 /* now we are ready to call the
8418 peep hole optimizer */
8419 if (!options.nopeep)
8420 peepHole (&_G.lines.head);
8422 /* This is unfortunate */
8423 /* now do the actual printing */
8425 struct dbuf_s *buf = codeOutBuf;
8426 if (isInHome () && codeOutBuf == &code->oBuf)
8427 codeOutBuf = &home->oBuf;
8428 printLine (_G.lines.head, codeOutBuf);
8429 if (_G.flushStatics)
8432 _G.flushStatics = 0;
8437 freeTrace(&_G.lines.trace);
8438 freeTrace(&_G.trace.aops);
8444 _isPairUsed (iCode * ic, PAIR_ID pairId)
8450 if (bitVectBitValue (ic->rMask, D_IDX))
8452 if (bitVectBitValue (ic->rMask, E_IDX))
8462 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8465 value *val = aop->aopu.aop_lit;
8467 wassert (aop->type == AOP_LIT);
8468 wassert (!IS_FLOAT (val->type));
8470 v = (unsigned long) floatFromVal (val);
8478 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8479 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));