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);
2703 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2704 emit2 ("ld a,%s", l);
2712 freeAsmop (IC_LEFT (ic), NULL, ic);
2715 /*-----------------------------------------------------------------*/
2716 /* genIpop - recover the registers: can happen only for spilling */
2717 /*-----------------------------------------------------------------*/
2719 genIpop (iCode * ic)
2724 /* if the temp was not pushed then */
2725 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2728 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2729 size = AOP_SIZE (IC_LEFT (ic));
2730 offset = (size - 1);
2731 if (isPair (AOP (IC_LEFT (ic))))
2733 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2741 spillPair (PAIR_HL);
2742 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2746 freeAsmop (IC_LEFT (ic), NULL, ic);
2749 /* This is quite unfortunate */
2751 setArea (int inHome)
2754 static int lastArea = 0;
2756 if (_G.in_home != inHome) {
2758 const char *sz = port->mem.code_name;
2759 port->mem.code_name = "HOME";
2760 emit2("!area", CODE_NAME);
2761 port->mem.code_name = sz;
2764 emit2("!area", CODE_NAME); */
2765 _G.in_home = inHome;
2776 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2780 symbol *sym = OP_SYMBOL (op);
2782 if (sym->isspilt || sym->nRegs == 0)
2785 aopOp (op, ic, FALSE, FALSE);
2788 if (aop->type == AOP_REG)
2791 for (i = 0; i < aop->size; i++)
2793 if (pairId == PAIR_DE)
2795 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2796 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2798 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2801 else if (pairId == PAIR_BC)
2803 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2804 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2806 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2816 freeAsmop (IC_LEFT (ic), NULL, ic);
2820 /** Emit the code for a call statement
2823 emitCall (iCode * ic, bool ispcall)
2825 bool bInRet, cInRet, dInRet, eInRet;
2826 sym_link *dtype = operandType (IC_LEFT (ic));
2828 /* if caller saves & we have not saved then */
2834 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2836 /* if send set is not empty then assign */
2841 int nSend = elementsInSet(_G.sendSet);
2842 bool swapped = FALSE;
2844 int _z80_sendOrder[] = {
2849 /* Check if the parameters are swapped. If so route through hl instead. */
2850 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2852 sic = setFirstItem(_G.sendSet);
2853 sic = setNextItem(_G.sendSet);
2855 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2856 /* The second send value is loaded from one the one that holds the first
2857 send, i.e. it is overwritten. */
2858 /* Cache the first in HL, and load the second from HL instead. */
2859 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2860 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2866 for (sic = setFirstItem (_G.sendSet); sic;
2867 sic = setNextItem (_G.sendSet))
2870 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2872 size = AOP_SIZE (IC_LEFT (sic));
2873 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2874 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2876 // PENDING: Mild hack
2877 if (swapped == TRUE && send == 1) {
2879 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2882 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2884 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2887 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2891 freeAsmop (IC_LEFT (sic), NULL, sic);
2898 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2900 werror (W_INDIR_BANKED);
2902 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2904 if (isLitWord (AOP (IC_LEFT (ic))))
2906 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2910 symbol *rlbl = newiTempLabel (NULL);
2911 spillPair (PAIR_HL);
2912 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2914 _G.stack.pushed += 2;
2916 fetchHL (AOP (IC_LEFT (ic)));
2918 emit2 ("!tlabeldef", (rlbl->key + 100));
2919 _G.lines.current->isLabel = 1;
2920 _G.stack.pushed -= 2;
2922 freeAsmop (IC_LEFT (ic), NULL, ic);
2926 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2927 OP_SYMBOL (IC_LEFT (ic))->rname :
2928 OP_SYMBOL (IC_LEFT (ic))->name;
2929 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2931 emit2 ("call banked_call");
2932 emit2 ("!dws", name);
2933 emit2 ("!dw !bankimmeds", name);
2938 emit2 ("call %s", name);
2943 /* Mark the registers as restored. */
2944 _G.saves.saved = FALSE;
2946 /* if we need assign a result value */
2947 if ((IS_ITEMP (IC_RESULT (ic)) &&
2948 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2949 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2950 IS_TRUE_SYMOP (IC_RESULT (ic)))
2952 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2954 assignResultValue (IC_RESULT (ic));
2956 freeAsmop (IC_RESULT (ic), NULL, ic);
2959 /* adjust the stack for parameters if required */
2962 int i = ic->parmBytes;
2964 _G.stack.pushed -= i;
2967 emit2 ("!ldaspsp", i);
2974 emit2 ("ld iy,!immedword", i);
2975 emit2 ("add iy,sp");
2996 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2997 bInRet = bitVectBitValue(result, B_IDX);
2998 cInRet = bitVectBitValue(result, C_IDX);
2999 dInRet = bitVectBitValue(result, D_IDX);
3000 eInRet = bitVectBitValue(result, E_IDX);
3010 if (_G.stack.pushedDE)
3012 if (dInRet && eInRet)
3014 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3018 /* Only restore E */
3025 /* Only restore D */
3033 _G.stack.pushedDE = FALSE;
3036 if (_G.stack.pushedBC)
3038 if (bInRet && cInRet)
3040 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3044 /* Only restore C */
3051 /* Only restore B */
3059 _G.stack.pushedBC = FALSE;
3063 /*-----------------------------------------------------------------*/
3064 /* genCall - generates a call statement */
3065 /*-----------------------------------------------------------------*/
3067 genCall (iCode * ic)
3069 emitCall (ic, FALSE);
3072 /*-----------------------------------------------------------------*/
3073 /* genPcall - generates a call by pointer statement */
3074 /*-----------------------------------------------------------------*/
3076 genPcall (iCode * ic)
3078 emitCall (ic, TRUE);
3081 /*-----------------------------------------------------------------*/
3082 /* resultRemat - result is rematerializable */
3083 /*-----------------------------------------------------------------*/
3085 resultRemat (iCode * ic)
3087 if (SKIP_IC (ic) || ic->op == IFX)
3090 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3092 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3093 if (sym->remat && !POINTER_SET (ic))
3100 extern set *publics;
3102 /*-----------------------------------------------------------------*/
3103 /* genFunction - generated code for function entry */
3104 /*-----------------------------------------------------------------*/
3106 genFunction (iCode * ic)
3110 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3113 bool bcInUse = FALSE;
3114 bool deInUse = FALSE;
3116 setArea (IFFUNC_NONBANKED (sym->type));
3118 /* PENDING: Reset the receive offset as it
3119 doesn't seem to get reset anywhere else.
3121 _G.receiveOffset = 0;
3123 /* Record the last function name for debugging. */
3124 _G.lastFunctionName = sym->rname;
3126 /* Create the function header */
3127 emit2 ("!functionheader", sym->name);
3128 if (!IS_STATIC(sym->etype))
3130 sprintf (buffer, "%s_start", sym->rname);
3131 emit2 ("!labeldef", buffer);
3132 _G.lines.current->isLabel = 1;
3134 emit2 ("!functionlabeldef", sym->rname);
3135 _G.lines.current->isLabel = 1;
3137 ftype = operandType (IC_LEFT (ic));
3139 if (IFFUNC_ISNAKED(ftype))
3141 emitDebug("; naked function: no prologue.");
3145 /* if this is an interrupt service routine
3146 then save all potentially used registers. */
3147 if (IFFUNC_ISISR (sym->type))
3149 /* If critical function then turn interrupts off */
3150 /* except when no interrupt number is given then it implies the NMI handler */
3151 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3160 /* This is a non-ISR function.
3161 If critical function then turn interrupts off */
3162 if (IFFUNC_ISCRITICAL (sym->type))
3170 //get interrupt enable flag IFF2 into P/O
3179 if (options.profile)
3181 emit2 ("!profileenter");
3184 /* PENDING: callee-save etc */
3186 _G.stack.param_offset = 0;
3188 if (z80_opts.calleeSavesBC)
3193 /* Detect which registers are used. */
3194 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3197 for (i = 0; i < sym->regsUsed->size; i++)
3199 if (bitVectBitValue (sym->regsUsed, i))
3213 /* Other systems use DE as a temporary. */
3224 _G.stack.param_offset += 2;
3227 _G.calleeSaves.pushedBC = bcInUse;
3232 _G.stack.param_offset += 2;
3235 _G.calleeSaves.pushedDE = deInUse;
3237 /* adjust the stack for the function */
3238 _G.stack.last = sym->stack;
3241 for (sym = setFirstItem (istack->syms); sym;
3242 sym = setNextItem (istack->syms))
3244 if (sym->_isparm && !IS_REGPARM (sym->etype))
3250 sym = OP_SYMBOL (IC_LEFT (ic));
3252 _G.omitFramePtr = options.ommitFramePtr;
3253 if (IS_Z80 && !stackParm && !sym->stack)
3255 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3256 /* the above !sym->stack condition can be removed. -- EEP */
3258 emit2 ("!ldaspsp", -sym->stack);
3259 _G.omitFramePtr = TRUE;
3261 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3262 emit2 ("!enterxl", sym->stack);
3263 else if (sym->stack)
3264 emit2 ("!enterx", sym->stack);
3268 _G.stack.offset = sym->stack;
3271 /*-----------------------------------------------------------------*/
3272 /* genEndFunction - generates epilogue for functions */
3273 /*-----------------------------------------------------------------*/
3275 genEndFunction (iCode * ic)
3277 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3279 if (IFFUNC_ISNAKED(sym->type))
3281 emitDebug("; naked function: no epilogue.");
3285 /* PENDING: calleeSave */
3286 if (IS_Z80 && _G.omitFramePtr)
3288 if (_G.stack.offset)
3289 emit2 ("!ldaspsp", _G.stack.offset);
3291 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3293 emit2 ("!leavexl", _G.stack.offset);
3295 else if (_G.stack.offset)
3297 emit2 ("!leavex", _G.stack.offset);
3304 if (_G.calleeSaves.pushedDE)
3307 _G.calleeSaves.pushedDE = FALSE;
3310 if (_G.calleeSaves.pushedBC)
3313 _G.calleeSaves.pushedBC = FALSE;
3316 if (options.profile)
3318 emit2 ("!profileexit");
3321 /* if this is an interrupt service routine
3322 then save all potentially used registers. */
3323 if (IFFUNC_ISISR (sym->type))
3327 /* If critical function then turn interrupts back on */
3328 /* except when no interrupt number is given then it implies the NMI handler */
3329 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3336 /* This is a non-ISR function.
3337 If critical function then turn interrupts back on */
3338 if (IFFUNC_ISCRITICAL (sym->type))
3346 symbol *tlbl = newiTempLabel (NULL);
3349 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3350 //don't enable interrupts as they were off before
3351 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3353 emit2 ("!tlabeldef", (tlbl->key + 100));
3354 _G.lines.current->isLabel = 1;
3359 if (options.debug && currFunc)
3361 debugFile->writeEndFunction (currFunc, ic, 1);
3364 if (IFFUNC_ISISR (sym->type))
3366 /* "critical interrupt" is used to imply NMI handler */
3367 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3374 /* Both banked and non-banked just ret */
3378 if (!IS_STATIC(sym->etype))
3380 sprintf (buffer, "%s_end", sym->rname);
3381 emit2 ("!labeldef", buffer);
3382 _G.lines.current->isLabel = 1;
3385 _G.flushStatics = 1;
3386 _G.stack.pushed = 0;
3387 _G.stack.offset = 0;
3390 /*-----------------------------------------------------------------*/
3391 /* genRet - generate code for return statement */
3392 /*-----------------------------------------------------------------*/
3397 /* Errk. This is a hack until I can figure out how
3398 to cause dehl to spill on a call */
3399 int size, offset = 0;
3401 /* if we have no return value then
3402 just generate the "ret" */
3406 /* we have something to return then
3407 move the return value into place */
3408 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3409 size = AOP_SIZE (IC_LEFT (ic));
3411 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3414 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3418 emit2 ("ld de,%s", l);
3422 emit2 ("ld hl,%s", l);
3428 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3432 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3434 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3435 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3441 l = aopGet (AOP (IC_LEFT (ic)), offset,
3443 if (strcmp (_fReturn[offset], l))
3444 emit2 ("ld %s,%s", _fReturn[offset], l);
3449 freeAsmop (IC_LEFT (ic), NULL, ic);
3452 /* generate a jump to the return label
3453 if the next is not the return statement */
3454 if (!(ic->next && ic->next->op == LABEL &&
3455 IC_LABEL (ic->next) == returnLabel))
3457 emit2 ("jp !tlabel", returnLabel->key + 100);
3460 /*-----------------------------------------------------------------*/
3461 /* genLabel - generates a label */
3462 /*-----------------------------------------------------------------*/
3464 genLabel (iCode * ic)
3466 /* special case never generate */
3467 if (IC_LABEL (ic) == entryLabel)
3470 emitLabel (IC_LABEL (ic)->key + 100);
3473 /*-----------------------------------------------------------------*/
3474 /* genGoto - generates a ljmp */
3475 /*-----------------------------------------------------------------*/
3477 genGoto (iCode * ic)
3479 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3482 /*-----------------------------------------------------------------*/
3483 /* genPlusIncr :- does addition with increment if possible */
3484 /*-----------------------------------------------------------------*/
3486 genPlusIncr (iCode * ic)
3488 unsigned int icount;
3489 unsigned int size = getDataSize (IC_RESULT (ic));
3490 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3492 /* will try to generate an increment */
3493 /* if the right side is not a literal
3495 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3498 emitDebug ("; genPlusIncr");
3500 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3502 /* If result is a pair */
3503 if (resultId != PAIR_INVALID)
3505 if (isLitWord (AOP (IC_LEFT (ic))))
3507 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3510 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3512 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3514 PAIR_ID freep = getFreePairId (ic);
3515 if (freep != PAIR_INVALID)
3517 fetchPair (freep, AOP (IC_RIGHT (ic)));
3518 emit2 ("add hl,%s", _pairs[freep].name);
3524 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3525 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3532 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3536 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3540 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3545 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3547 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3548 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3552 /* if the literal value of the right hand side
3553 is greater than 4 then it is not worth it */
3557 /* if increment 16 bits in register */
3558 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3564 symbol *tlbl = NULL;
3565 tlbl = newiTempLabel (NULL);
3568 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3571 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3574 emitLabel (tlbl->key + 100);
3578 /* if the sizes are greater than 1 then we cannot */
3579 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3580 AOP_SIZE (IC_LEFT (ic)) > 1)
3583 /* If the result is in a register then we can load then increment.
3585 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3587 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3590 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3595 /* we can if the aops of the left & result match or
3596 if they are in registers and the registers are the
3598 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3602 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3610 /*-----------------------------------------------------------------*/
3611 /* outBitAcc - output a bit in acc */
3612 /*-----------------------------------------------------------------*/
3614 outBitAcc (operand * result)
3616 symbol *tlbl = newiTempLabel (NULL);
3617 /* if the result is a bit */
3618 if (AOP_TYPE (result) == AOP_CRY)
3620 wassertl (0, "Tried to write A into a bit");
3624 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3625 emit2 ("ld a,!one");
3626 emitLabel (tlbl->key + 100);
3632 couldDestroyCarry (asmop *aop)
3636 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3645 shiftIntoPair (int idx, asmop *aop)
3647 PAIR_ID id = PAIR_INVALID;
3649 wassertl (IS_Z80, "Only implemented for the Z80");
3650 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3652 emitDebug ("; Shift into pair idx %u", idx);
3658 setupPair (PAIR_HL, aop, 0);
3663 setupPair (PAIR_IY, aop, 0);
3665 emit2 ("pop %s", _pairs[id].name);
3669 setupPair (PAIR_IY, aop, 0);
3672 wassertl (0, "Internal error - hit default case");
3675 aop->type = AOP_PAIRPTR;
3676 aop->aopu.aop_pairId = id;
3677 _G.pairs[id].offset = 0;
3678 _G.pairs[id].last_type = aop->type;
3682 setupToPreserveCarry (iCode * ic)
3684 asmop *left = AOP (IC_LEFT (ic));
3685 asmop *right = AOP (IC_RIGHT (ic));
3686 asmop *result = AOP (IC_RESULT (ic));
3688 wassert (left && right);
3692 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3694 shiftIntoPair (0, right);
3695 /* check result again, in case right == result */
3696 if (couldDestroyCarry (result))
3698 if (!isPairInUse (PAIR_DE, ic))
3699 shiftIntoPair (1, result);
3701 shiftIntoPair (2, result);
3704 else if (couldDestroyCarry (right))
3706 if (getPairId (result) == PAIR_HL)
3707 _G.preserveCarry = TRUE;
3709 shiftIntoPair (0, right);
3711 else if (couldDestroyCarry (result))
3713 shiftIntoPair (0, result);
3722 /*-----------------------------------------------------------------*/
3723 /* genPlus - generates code for addition */
3724 /*-----------------------------------------------------------------*/
3726 genPlus (iCode * ic)
3728 int size, offset = 0;
3730 /* special cases :- */
3732 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3733 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3734 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3736 /* Swap the left and right operands if:
3738 if literal, literal on the right or
3739 if left requires ACC or right is already
3742 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3743 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3744 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3746 operand *t = IC_RIGHT (ic);
3747 IC_RIGHT (ic) = IC_LEFT (ic);
3751 /* if both left & right are in bit
3753 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3754 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3757 wassertl (0, "Tried to add two bits");
3760 /* if left in bit space & right literal */
3761 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3762 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3764 /* Can happen I guess */
3765 wassertl (0, "Tried to add a bit to a literal");
3768 /* if I can do an increment instead
3769 of add then GOOD for ME */
3770 if (genPlusIncr (ic) == TRUE)
3773 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3775 size = getDataSize (IC_RESULT (ic));
3777 /* Special case when left and right are constant */
3778 if (isPair (AOP (IC_RESULT (ic))))
3781 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3782 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3784 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3790 sprintf (buffer, "#(%s + %s)", left, right);
3791 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3796 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3798 /* Fetch into HL then do the add */
3799 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3800 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3802 spillPair (PAIR_HL);
3804 if (left == PAIR_HL && right != PAIR_INVALID)
3806 emit2 ("add hl,%s", _pairs[right].name);
3809 else if (right == PAIR_HL && left != PAIR_INVALID)
3811 emit2 ("add hl,%s", _pairs[left].name);
3814 else if (right != PAIR_INVALID && right != PAIR_HL)
3816 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3817 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3820 else if (left != PAIR_INVALID && left != PAIR_HL)
3822 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3823 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3832 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3834 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3835 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3837 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3842 ld hl,sp+n trashes C so we can't afford to do it during an
3843 add with stack based variables. Worst case is:
3856 So you can't afford to load up hl if either left, right, or result
3857 is on the stack (*sigh*) The alt is:
3865 Combinations in here are:
3866 * If left or right are in bc then the loss is small - trap later
3867 * If the result is in bc then the loss is also small
3871 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3872 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3873 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3875 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3876 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3877 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3878 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3880 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3882 /* Swap left and right */
3883 operand *t = IC_RIGHT (ic);
3884 IC_RIGHT (ic) = IC_LEFT (ic);
3887 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3889 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3890 emit2 ("add hl,bc");
3894 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3895 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3896 emit2 ("add hl,de");
3898 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3904 /* Be paranoid on the GB with 4 byte variables due to how C
3905 can be trashed by lda hl,n(sp).
3907 _gbz80_emitAddSubLong (ic, TRUE);
3912 setupToPreserveCarry (ic);
3916 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3918 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3921 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3924 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3928 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3931 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3934 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3936 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3940 _G.preserveCarry = FALSE;
3941 freeAsmop (IC_LEFT (ic), NULL, ic);
3942 freeAsmop (IC_RIGHT (ic), NULL, ic);
3943 freeAsmop (IC_RESULT (ic), NULL, ic);
3946 /*-----------------------------------------------------------------*/
3947 /* genMinusDec :- does subtraction with deccrement if possible */
3948 /*-----------------------------------------------------------------*/
3950 genMinusDec (iCode * ic)
3952 unsigned int icount;
3953 unsigned int size = getDataSize (IC_RESULT (ic));
3955 /* will try to generate an increment */
3956 /* if the right side is not a literal we cannot */
3957 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3960 /* if the literal value of the right hand side
3961 is greater than 4 then it is not worth it */
3962 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3965 size = getDataSize (IC_RESULT (ic));
3967 /* if decrement 16 bits in register */
3968 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3969 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3972 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3976 /* If result is a pair */
3977 if (isPair (AOP (IC_RESULT (ic))))
3979 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3981 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3985 /* if increment 16 bits in register */
3986 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3990 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3993 emit2 ("dec %s", _getTempPairName());
3996 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4002 /* if the sizes are greater than 1 then we cannot */
4003 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4004 AOP_SIZE (IC_LEFT (ic)) > 1)
4007 /* we can if the aops of the left & result match or if they are in
4008 registers and the registers are the same */
4009 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4012 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4019 /*-----------------------------------------------------------------*/
4020 /* genMinus - generates code for subtraction */
4021 /*-----------------------------------------------------------------*/
4023 genMinus (iCode * ic)
4025 int size, offset = 0;
4026 unsigned long lit = 0L;
4028 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4029 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4030 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4032 /* special cases :- */
4033 /* if both left & right are in bit space */
4034 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4035 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4037 wassertl (0, "Tried to subtract two bits");
4041 /* if I can do an decrement instead of subtract then GOOD for ME */
4042 if (genMinusDec (ic) == TRUE)
4045 size = getDataSize (IC_RESULT (ic));
4047 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4052 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4056 /* Same logic as genPlus */
4059 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4060 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4061 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4063 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4064 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4065 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4066 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4068 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4069 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4071 if (left == PAIR_INVALID && right == PAIR_INVALID)
4076 else if (right == PAIR_INVALID)
4078 else if (left == PAIR_INVALID)
4081 fetchPair (left, AOP (IC_LEFT (ic)));
4082 /* Order is important. Right may be HL */
4083 fetchPair (right, AOP (IC_RIGHT (ic)));
4085 emit2 ("ld a,%s", _pairs[left].l);
4086 emit2 ("sub a,%s", _pairs[right].l);
4088 emit2 ("ld a,%s", _pairs[left].h);
4089 emit2 ("sbc a,%s", _pairs[right].h);
4091 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4093 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4095 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4101 /* Be paranoid on the GB with 4 byte variables due to how C
4102 can be trashed by lda hl,n(sp).
4104 _gbz80_emitAddSubLong (ic, FALSE);
4109 setupToPreserveCarry (ic);
4111 /* if literal, add a,#-lit, else normal subb */
4114 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4115 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4119 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4122 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4126 /* first add without previous c */
4128 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4130 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4132 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4135 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4136 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4137 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4139 wassertl (0, "Tried to subtract on a long pointer");
4143 _G.preserveCarry = FALSE;
4144 freeAsmop (IC_LEFT (ic), NULL, ic);
4145 freeAsmop (IC_RIGHT (ic), NULL, ic);
4146 freeAsmop (IC_RESULT (ic), NULL, ic);
4149 /*-----------------------------------------------------------------*/
4150 /* genMult - generates code for multiplication */
4151 /*-----------------------------------------------------------------*/
4153 genMult (iCode * ic)
4157 /* If true then the final operation should be a subtract */
4158 bool active = FALSE;
4161 /* Shouldn't occur - all done through function calls */
4162 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4163 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4164 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4166 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4168 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4169 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4170 AOP_SIZE (IC_RESULT (ic)) > 2)
4172 wassertl (0, "Multiplication is handled through support function calls");
4175 /* Swap left and right such that right is a literal */
4176 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4178 operand *t = IC_RIGHT (ic);
4179 IC_RIGHT (ic) = IC_LEFT (ic);
4183 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4185 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4186 // wassertl (val > 0, "Multiply must be positive");
4187 wassertl (val != 1, "Can't multiply by 1");
4189 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4191 _G.stack.pushedDE = TRUE;
4194 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4196 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4207 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4212 /* Fully unroled version of mul.s. Not the most efficient.
4214 for (count = 0; count < 16; count++)
4216 if (count != 0 && active)
4218 emit2 ("add hl,hl");
4222 if (active == FALSE)
4230 emit2 ("add hl,de");
4239 if (IS_Z80 && _G.stack.pushedDE)
4242 _G.stack.pushedDE = FALSE;
4246 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4248 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4250 freeAsmop (IC_LEFT (ic), NULL, ic);
4251 freeAsmop (IC_RIGHT (ic), NULL, ic);
4252 freeAsmop (IC_RESULT (ic), NULL, ic);
4255 /*-----------------------------------------------------------------*/
4256 /* genDiv - generates code for division */
4257 /*-----------------------------------------------------------------*/
4261 /* Shouldn't occur - all done through function calls */
4262 wassertl (0, "Division is handled through support function calls");
4265 /*-----------------------------------------------------------------*/
4266 /* genMod - generates code for division */
4267 /*-----------------------------------------------------------------*/
4271 /* Shouldn't occur - all done through function calls */
4275 /*-----------------------------------------------------------------*/
4276 /* genIfxJump :- will create a jump depending on the ifx */
4277 /*-----------------------------------------------------------------*/
4279 genIfxJump (iCode * ic, char *jval)
4284 /* if true label then we jump if condition
4288 jlbl = IC_TRUE (ic);
4289 if (!strcmp (jval, "a"))
4293 else if (!strcmp (jval, "c"))
4297 else if (!strcmp (jval, "nc"))
4301 else if (!strcmp (jval, "m"))
4305 else if (!strcmp (jval, "p"))
4311 /* The buffer contains the bit on A that we should test */
4317 /* false label is present */
4318 jlbl = IC_FALSE (ic);
4319 if (!strcmp (jval, "a"))
4323 else if (!strcmp (jval, "c"))
4327 else if (!strcmp (jval, "nc"))
4331 else if (!strcmp (jval, "m"))
4335 else if (!strcmp (jval, "p"))
4341 /* The buffer contains the bit on A that we should test */
4345 /* Z80 can do a conditional long jump */
4346 if (!strcmp (jval, "a"))
4350 else if (!strcmp (jval, "c"))
4353 else if (!strcmp (jval, "nc"))
4356 else if (!strcmp (jval, "m"))
4359 else if (!strcmp (jval, "p"))
4364 emit2 ("bit %s,a", jval);
4366 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4368 /* mark the icode as generated */
4374 _getPairIdName (PAIR_ID id)
4376 return _pairs[id].name;
4381 /* if unsigned char cmp with lit, just compare */
4383 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4385 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4388 emit2 ("xor a,!immedbyte", 0x80);
4389 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4392 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4394 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4396 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4397 // Pull left into DE and right into HL
4398 aopGet (AOP(left), LSB, FALSE);
4401 aopGet (AOP(right), LSB, FALSE);
4405 if (size == 0 && sign)
4407 // Highest byte when signed needs the bits flipped
4410 emit2 ("ld a,(de)");
4411 emit2 ("xor !immedbyte", 0x80);
4413 emit2 ("ld a,(hl)");
4414 emit2 ("xor !immedbyte", 0x80);
4418 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4422 emit2 ("ld a,(de)");
4423 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4433 spillPair (PAIR_HL);
4435 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4437 setupPair (PAIR_HL, AOP (left), 0);
4438 aopGet (AOP(right), LSB, FALSE);
4442 if (size == 0 && sign)
4444 // Highest byte when signed needs the bits flipped
4447 emit2 ("ld a,(hl)");
4448 emit2 ("xor !immedbyte", 0x80);
4450 emit2 ("ld a,%d(iy)", offset);
4451 emit2 ("xor !immedbyte", 0x80);
4455 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4459 emit2 ("ld a,(hl)");
4460 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4469 spillPair (PAIR_HL);
4470 spillPair (PAIR_IY);
4474 if (AOP_TYPE (right) == AOP_LIT)
4476 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4477 /* optimize if(x < 0) or if(x >= 0) */
4482 /* No sign so it's always false */
4487 /* Just load in the top most bit */
4488 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4489 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4491 genIfxJump (ifx, "7");
4503 /* First setup h and l contaning the top most bytes XORed */
4504 bool fDidXor = FALSE;
4505 if (AOP_TYPE (left) == AOP_LIT)
4507 unsigned long lit = (unsigned long)
4508 floatFromVal (AOP (left)->aopu.aop_lit);
4509 emit2 ("ld %s,!immedbyte", _fTmp[0],
4510 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4514 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4515 emit2 ("xor a,!immedbyte", 0x80);
4516 emit2 ("ld %s,a", _fTmp[0]);
4519 if (AOP_TYPE (right) == AOP_LIT)
4521 unsigned long lit = (unsigned long)
4522 floatFromVal (AOP (right)->aopu.aop_lit);
4523 emit2 ("ld %s,!immedbyte", _fTmp[1],
4524 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4528 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4529 emit2 ("xor a,!immedbyte", 0x80);
4530 emit2 ("ld %s,a", _fTmp[1]);
4536 /* Do a long subtract */
4539 _moveA (aopGet (AOP (left), offset, FALSE));
4541 if (sign && size == 0)
4543 emit2 ("ld a,%s", _fTmp[0]);
4544 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4548 /* Subtract through, propagating the carry */
4549 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4557 /** Generic compare for > or <
4560 genCmp (operand * left, operand * right,
4561 operand * result, iCode * ifx, int sign)
4563 int size, offset = 0;
4564 unsigned long lit = 0L;
4565 bool swap_sense = FALSE;
4567 /* if left & right are bit variables */
4568 if (AOP_TYPE (left) == AOP_CRY &&
4569 AOP_TYPE (right) == AOP_CRY)
4571 /* Cant happen on the Z80 */
4572 wassertl (0, "Tried to compare two bits");
4576 /* Do a long subtract of right from left. */
4577 size = max (AOP_SIZE (left), AOP_SIZE (right));
4579 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4581 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4582 // Pull left into DE and right into HL
4583 aopGet (AOP(left), LSB, FALSE);
4586 aopGet (AOP(right), LSB, FALSE);
4590 emit2 ("ld a,(de)");
4591 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4600 spillPair (PAIR_HL);
4604 if (AOP_TYPE (right) == AOP_LIT)
4606 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4607 /* optimize if(x < 0) or if(x >= 0) */
4612 /* No sign so it's always false */
4617 /* Just load in the top most bit */
4618 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4619 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4621 genIfxJump (ifx, "7");
4632 genIfxJump (ifx, swap_sense ? "c" : "nc");
4643 _moveA (aopGet (AOP (left), offset, FALSE));
4644 /* Subtract through, propagating the carry */
4645 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4651 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4655 /* Shift the sign bit up into carry */
4658 outBitCLong (result, swap_sense);
4662 /* if the result is used in the next
4663 ifx conditional branch then generate
4664 code a little differently */
4672 genIfxJump (ifx, swap_sense ? "nc" : "c");
4676 genIfxJump (ifx, swap_sense ? "p" : "m");
4681 genIfxJump (ifx, swap_sense ? "nc" : "c");
4688 /* Shift the sign bit up into carry */
4691 outBitCLong (result, swap_sense);
4693 /* leave the result in acc */
4697 /*-----------------------------------------------------------------*/
4698 /* genCmpGt :- greater than comparison */
4699 /*-----------------------------------------------------------------*/
4701 genCmpGt (iCode * ic, iCode * ifx)
4703 operand *left, *right, *result;
4704 sym_link *letype, *retype;
4707 left = IC_LEFT (ic);
4708 right = IC_RIGHT (ic);
4709 result = IC_RESULT (ic);
4711 letype = getSpec (operandType (left));
4712 retype = getSpec (operandType (right));
4713 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4714 /* assign the amsops */
4715 aopOp (left, ic, FALSE, FALSE);
4716 aopOp (right, ic, FALSE, FALSE);
4717 aopOp (result, ic, TRUE, FALSE);
4719 genCmp (right, left, result, ifx, sign);
4721 freeAsmop (left, NULL, ic);
4722 freeAsmop (right, NULL, ic);
4723 freeAsmop (result, NULL, ic);
4726 /*-----------------------------------------------------------------*/
4727 /* genCmpLt - less than comparisons */
4728 /*-----------------------------------------------------------------*/
4730 genCmpLt (iCode * ic, iCode * ifx)
4732 operand *left, *right, *result;
4733 sym_link *letype, *retype;
4736 left = IC_LEFT (ic);
4737 right = IC_RIGHT (ic);
4738 result = IC_RESULT (ic);
4740 letype = getSpec (operandType (left));
4741 retype = getSpec (operandType (right));
4742 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4744 /* assign the amsops */
4745 aopOp (left, ic, FALSE, FALSE);
4746 aopOp (right, ic, FALSE, FALSE);
4747 aopOp (result, ic, TRUE, FALSE);
4749 genCmp (left, right, result, ifx, sign);
4751 freeAsmop (left, NULL, ic);
4752 freeAsmop (right, NULL, ic);
4753 freeAsmop (result, NULL, ic);
4756 /*-----------------------------------------------------------------*/
4757 /* gencjneshort - compare and jump if not equal */
4758 /* returns pair that still needs to be popped */
4759 /*-----------------------------------------------------------------*/
4761 gencjneshort (operand * left, operand * right, symbol * lbl)
4763 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4765 unsigned long lit = 0L;
4767 /* Swap the left and right if it makes the computation easier */
4768 if (AOP_TYPE (left) == AOP_LIT)
4775 /* if the right side is a literal then anything goes */
4776 if (AOP_TYPE (right) == AOP_LIT)
4778 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4781 _moveA (aopGet (AOP (left), offset, FALSE));
4786 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4793 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4799 _moveA (aopGet (AOP (left), offset, FALSE));
4800 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4803 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4804 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4809 /* if the right side is in a register or
4810 pointed to by HL, IX or IY */
4811 else if (AOP_TYPE (right) == AOP_REG ||
4812 AOP_TYPE (right) == AOP_HL ||
4813 AOP_TYPE (right) == AOP_IY ||
4814 AOP_TYPE (right) == AOP_STK ||
4815 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4816 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4817 AOP_IS_PAIRPTR (right, PAIR_IY))
4821 _moveA (aopGet (AOP (left), offset, FALSE));
4822 if (AOP_TYPE (right) == AOP_LIT &&
4823 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4826 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4830 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4831 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4836 /* right is in direct space or a pointer reg, need both a & b */
4840 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4842 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4843 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4851 emit2 ("; direct compare");
4852 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4853 _moveA (aopGet (AOP (right), offset, FALSE));
4854 emit2 ("sub %s", _pairs[pair].l);
4855 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4860 return PAIR_INVALID;
4863 /*-----------------------------------------------------------------*/
4864 /* gencjne - compare and jump if not equal */
4865 /*-----------------------------------------------------------------*/
4867 gencjne (operand * left, operand * right, symbol * lbl)
4869 symbol *tlbl = newiTempLabel (NULL);
4871 PAIR_ID pop = gencjneshort (left, right, lbl);
4874 emit2 ("ld a,!one");
4875 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4876 emitLabel (lbl->key + 100);
4878 emitLabel (tlbl->key + 100);
4882 /*-----------------------------------------------------------------*/
4883 /* genCmpEq - generates code for equal to */
4884 /*-----------------------------------------------------------------*/
4886 genCmpEq (iCode * ic, iCode * ifx)
4888 operand *left, *right, *result;
4890 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4891 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4892 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4894 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4896 /* Swap operands if it makes the operation easier. ie if:
4897 1. Left is a literal.
4899 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4901 operand *t = IC_RIGHT (ic);
4902 IC_RIGHT (ic) = IC_LEFT (ic);
4906 if (ifx && !AOP_SIZE (result))
4909 /* if they are both bit variables */
4910 if (AOP_TYPE (left) == AOP_CRY &&
4911 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4913 wassertl (0, "Tried to compare two bits");
4918 tlbl = newiTempLabel (NULL);
4919 pop = gencjneshort (left, right, tlbl);
4923 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4924 emitLabel (tlbl->key + 100);
4929 /* PENDING: do this better */
4930 symbol *lbl = newiTempLabel (NULL);
4932 emit2 ("!shortjp !tlabel", lbl->key + 100);
4933 emitLabel (tlbl->key + 100);
4935 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4936 emitLabel (lbl->key + 100);
4939 /* mark the icode as generated */
4944 /* if they are both bit variables */
4945 if (AOP_TYPE (left) == AOP_CRY &&
4946 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4948 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4954 gencjne (left, right, newiTempLabel (NULL));
4955 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4962 genIfxJump (ifx, "a");
4965 /* if the result is used in an arithmetic operation
4966 then put the result in place */
4967 if (AOP_TYPE (result) != AOP_CRY)
4972 /* leave the result in acc */
4976 freeAsmop (left, NULL, ic);
4977 freeAsmop (right, NULL, ic);
4978 freeAsmop (result, NULL, ic);
4981 /*-----------------------------------------------------------------*/
4982 /* ifxForOp - returns the icode containing the ifx for operand */
4983 /*-----------------------------------------------------------------*/
4985 ifxForOp (operand * op, iCode * ic)
4987 /* if true symbol then needs to be assigned */
4988 if (IS_TRUE_SYMOP (op))
4991 /* if this has register type condition and
4992 the next instruction is ifx with the same operand
4993 and live to of the operand is upto the ifx only then */
4995 ic->next->op == IFX &&
4996 IC_COND (ic->next)->key == op->key &&
4997 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5003 /*-----------------------------------------------------------------*/
5004 /* genAndOp - for && operation */
5005 /*-----------------------------------------------------------------*/
5007 genAndOp (iCode * ic)
5009 operand *left, *right, *result;
5012 /* note here that && operations that are in an if statement are
5013 taken away by backPatchLabels only those used in arthmetic
5014 operations remain */
5015 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5016 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5017 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5019 /* if both are bit variables */
5020 if (AOP_TYPE (left) == AOP_CRY &&
5021 AOP_TYPE (right) == AOP_CRY)
5023 wassertl (0, "Tried to and two bits");
5027 tlbl = newiTempLabel (NULL);
5029 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5031 emitLabel (tlbl->key + 100);
5035 freeAsmop (left, NULL, ic);
5036 freeAsmop (right, NULL, ic);
5037 freeAsmop (result, NULL, ic);
5040 /*-----------------------------------------------------------------*/
5041 /* genOrOp - for || operation */
5042 /*-----------------------------------------------------------------*/
5044 genOrOp (iCode * ic)
5046 operand *left, *right, *result;
5049 /* note here that || operations that are in an
5050 if statement are taken away by backPatchLabels
5051 only those used in arthmetic operations remain */
5052 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5053 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5054 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5056 /* if both are bit variables */
5057 if (AOP_TYPE (left) == AOP_CRY &&
5058 AOP_TYPE (right) == AOP_CRY)
5060 wassertl (0, "Tried to OR two bits");
5064 tlbl = newiTempLabel (NULL);
5066 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5068 emitLabel (tlbl->key + 100);
5072 freeAsmop (left, NULL, ic);
5073 freeAsmop (right, NULL, ic);
5074 freeAsmop (result, NULL, ic);
5077 /*-----------------------------------------------------------------*/
5078 /* isLiteralBit - test if lit == 2^n */
5079 /*-----------------------------------------------------------------*/
5081 isLiteralBit (unsigned long lit)
5083 unsigned long pw[32] =
5084 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5085 0x100L, 0x200L, 0x400L, 0x800L,
5086 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5087 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5088 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5089 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5090 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5093 for (idx = 0; idx < 32; idx++)
5099 /*-----------------------------------------------------------------*/
5100 /* jmpTrueOrFalse - */
5101 /*-----------------------------------------------------------------*/
5103 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5105 // ugly but optimized by peephole
5108 symbol *nlbl = newiTempLabel (NULL);
5109 emit2 ("jp !tlabel", nlbl->key + 100);
5110 emitLabel (tlbl->key + 100);
5111 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5112 emitLabel (nlbl->key + 100);
5116 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5117 emitLabel (tlbl->key + 100);
5122 /*-----------------------------------------------------------------*/
5123 /* genAnd - code for and */
5124 /*-----------------------------------------------------------------*/
5126 genAnd (iCode * ic, iCode * ifx)
5128 operand *left, *right, *result;
5129 int size, offset = 0;
5130 unsigned long lit = 0L;
5133 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5134 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5135 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5137 /* if left is a literal & right is not then exchange them */
5138 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5139 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5141 operand *tmp = right;
5146 /* if result = right then exchange them */
5147 if (sameRegs (AOP (result), AOP (right)))
5149 operand *tmp = right;
5154 /* if right is bit then exchange them */
5155 if (AOP_TYPE (right) == AOP_CRY &&
5156 AOP_TYPE (left) != AOP_CRY)
5158 operand *tmp = right;
5162 if (AOP_TYPE (right) == AOP_LIT)
5163 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5165 size = AOP_SIZE (result);
5167 if (AOP_TYPE (left) == AOP_CRY)
5169 wassertl (0, "Tried to perform an AND with a bit as an operand");
5173 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5174 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5175 if ((AOP_TYPE (right) == AOP_LIT) &&
5176 (AOP_TYPE (result) == AOP_CRY) &&
5177 (AOP_TYPE (left) != AOP_CRY))
5179 symbol *tlbl = newiTempLabel (NULL);
5180 int sizel = AOP_SIZE (left);
5183 /* PENDING: Test case for this. */
5188 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5190 _moveA (aopGet (AOP (left), offset, FALSE));
5191 if (bytelit != 0x0FFL)
5193 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5200 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5204 // bit = left & literal
5208 emit2 ("!tlabeldef", tlbl->key + 100);
5209 _G.lines.current->isLabel = 1;
5211 // if(left & literal)
5216 jmpTrueOrFalse (ifx, tlbl);
5224 /* if left is same as result */
5225 if (sameRegs (AOP (result), AOP (left)))
5227 for (; size--; offset++)
5229 if (AOP_TYPE (right) == AOP_LIT)
5231 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5236 aopPut (AOP (result), "!zero", offset);
5239 _moveA (aopGet (AOP (left), offset, FALSE));
5241 aopGet (AOP (right), offset, FALSE));
5242 aopPut (AOP (left), "a", offset);
5249 if (AOP_TYPE (left) == AOP_ACC)
5251 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5255 _moveA (aopGet (AOP (left), offset, FALSE));
5257 aopGet (AOP (right), offset, FALSE));
5258 aopPut (AOP (left), "a", offset);
5265 // left & result in different registers
5266 if (AOP_TYPE (result) == AOP_CRY)
5268 wassertl (0, "Tried to AND where the result is in carry");
5272 for (; (size--); offset++)
5275 // result = left & right
5276 if (AOP_TYPE (right) == AOP_LIT)
5278 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5280 aopPut (AOP (result),
5281 aopGet (AOP (left), offset, FALSE),
5285 else if (bytelit == 0)
5287 aopPut (AOP (result), "!zero", offset);
5291 // faster than result <- left, anl result,right
5292 // and better if result is SFR
5293 if (AOP_TYPE (left) == AOP_ACC)
5294 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5297 _moveA (aopGet (AOP (left), offset, FALSE));
5299 aopGet (AOP (right), offset, FALSE));
5301 aopPut (AOP (result), "a", offset);
5308 freeAsmop (left, NULL, ic);
5309 freeAsmop (right, NULL, ic);
5310 freeAsmop (result, NULL, ic);
5313 /*-----------------------------------------------------------------*/
5314 /* genOr - code for or */
5315 /*-----------------------------------------------------------------*/
5317 genOr (iCode * ic, iCode * ifx)
5319 operand *left, *right, *result;
5320 int size, offset = 0;
5321 unsigned long lit = 0L;
5324 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5325 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5326 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5328 /* if left is a literal & right is not then exchange them */
5329 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5330 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5332 operand *tmp = right;
5337 /* if result = right then exchange them */
5338 if (sameRegs (AOP (result), AOP (right)))
5340 operand *tmp = right;
5345 /* if right is bit then exchange them */
5346 if (AOP_TYPE (right) == AOP_CRY &&
5347 AOP_TYPE (left) != AOP_CRY)
5349 operand *tmp = right;
5353 if (AOP_TYPE (right) == AOP_LIT)
5354 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5356 size = AOP_SIZE (result);
5358 if (AOP_TYPE (left) == AOP_CRY)
5360 wassertl (0, "Tried to OR where left is a bit");
5364 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5365 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5366 if ((AOP_TYPE (right) == AOP_LIT) &&
5367 (AOP_TYPE (result) == AOP_CRY) &&
5368 (AOP_TYPE (left) != AOP_CRY))
5370 symbol *tlbl = newiTempLabel (NULL);
5371 int sizel = AOP_SIZE (left);
5375 wassertl (0, "Result is assigned to a bit");
5377 /* PENDING: Modeled after the AND code which is inefficient. */
5380 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5382 _moveA (aopGet (AOP (left), offset, FALSE));
5383 /* OR with any literal is the same as OR with itself. */
5385 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5391 jmpTrueOrFalse (ifx, tlbl);
5396 /* if left is same as result */
5397 if (sameRegs (AOP (result), AOP (left)))
5399 for (; size--; offset++)
5401 if (AOP_TYPE (right) == AOP_LIT)
5403 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5407 _moveA (aopGet (AOP (left), offset, FALSE));
5409 aopGet (AOP (right), offset, FALSE));
5410 aopPut (AOP (result), "a", offset);
5415 if (AOP_TYPE (left) == AOP_ACC)
5416 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5419 _moveA (aopGet (AOP (left), offset, FALSE));
5421 aopGet (AOP (right), offset, FALSE));
5422 aopPut (AOP (result), "a", offset);
5429 // left & result in different registers
5430 if (AOP_TYPE (result) == AOP_CRY)
5432 wassertl (0, "Result of OR is in a bit");
5435 for (; (size--); offset++)
5438 // result = left & right
5439 if (AOP_TYPE (right) == AOP_LIT)
5441 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5443 aopPut (AOP (result),
5444 aopGet (AOP (left), offset, FALSE),
5449 // faster than result <- left, anl result,right
5450 // and better if result is SFR
5451 if (AOP_TYPE (left) == AOP_ACC)
5452 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5455 _moveA (aopGet (AOP (left), offset, FALSE));
5457 aopGet (AOP (right), offset, FALSE));
5459 aopPut (AOP (result), "a", offset);
5460 /* PENDING: something weird is going on here. Add exception. */
5461 if (AOP_TYPE (result) == AOP_ACC)
5467 freeAsmop (left, NULL, ic);
5468 freeAsmop (right, NULL, ic);
5469 freeAsmop (result, NULL, ic);
5472 /*-----------------------------------------------------------------*/
5473 /* genXor - code for xclusive or */
5474 /*-----------------------------------------------------------------*/
5476 genXor (iCode * ic, iCode * ifx)
5478 operand *left, *right, *result;
5479 int size, offset = 0;
5480 unsigned long lit = 0L;
5482 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5483 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5484 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5486 /* if left is a literal & right is not then exchange them */
5487 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5488 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5490 operand *tmp = right;
5495 /* if result = right then exchange them */
5496 if (sameRegs (AOP (result), AOP (right)))
5498 operand *tmp = right;
5503 /* if right is bit then exchange them */
5504 if (AOP_TYPE (right) == AOP_CRY &&
5505 AOP_TYPE (left) != AOP_CRY)
5507 operand *tmp = right;
5511 if (AOP_TYPE (right) == AOP_LIT)
5512 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5514 size = AOP_SIZE (result);
5516 if (AOP_TYPE (left) == AOP_CRY)
5518 wassertl (0, "Tried to XOR a bit");
5522 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5523 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5524 if ((AOP_TYPE (right) == AOP_LIT) &&
5525 (AOP_TYPE (result) == AOP_CRY) &&
5526 (AOP_TYPE (left) != AOP_CRY))
5528 symbol *tlbl = newiTempLabel (NULL);
5529 int sizel = AOP_SIZE (left);
5533 /* PENDING: Test case for this. */
5534 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5538 _moveA (aopGet (AOP (left), offset, FALSE));
5539 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5540 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5545 jmpTrueOrFalse (ifx, tlbl);
5549 wassertl (0, "Result of XOR was destined for a bit");
5554 /* if left is same as result */
5555 if (sameRegs (AOP (result), AOP (left)))
5557 for (; size--; offset++)
5559 if (AOP_TYPE (right) == AOP_LIT)
5561 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5565 _moveA (aopGet (AOP (left), offset, FALSE));
5567 aopGet (AOP (right), offset, FALSE));
5568 aopPut (AOP (result), "a", offset);
5573 if (AOP_TYPE (left) == AOP_ACC)
5575 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5579 _moveA (aopGet (AOP (left), offset, FALSE));
5581 aopGet (AOP (right), offset, FALSE));
5582 aopPut (AOP (result), "a", offset);
5589 // left & result in different registers
5590 if (AOP_TYPE (result) == AOP_CRY)
5592 wassertl (0, "Result of XOR is in a bit");
5595 for (; (size--); offset++)
5598 // result = left & right
5599 if (AOP_TYPE (right) == AOP_LIT)
5601 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5603 aopPut (AOP (result),
5604 aopGet (AOP (left), offset, FALSE),
5609 // faster than result <- left, anl result,right
5610 // and better if result is SFR
5611 if (AOP_TYPE (left) == AOP_ACC)
5613 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5617 _moveA (aopGet (AOP (left), offset, FALSE));
5619 aopGet (AOP (right), offset, FALSE));
5621 aopPut (AOP (result), "a", offset);
5626 freeAsmop (left, NULL, ic);
5627 freeAsmop (right, NULL, ic);
5628 freeAsmop (result, NULL, ic);
5631 /*-----------------------------------------------------------------*/
5632 /* genInline - write the inline code out */
5633 /*-----------------------------------------------------------------*/
5635 genInline (iCode * ic)
5637 char *buffer, *bp, *bp1;
5639 _G.lines.isInline += (!options.asmpeep);
5641 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5642 strcpy (buffer, IC_INLINE (ic));
5644 /* emit each line as a code */
5669 _G.lines.isInline -= (!options.asmpeep);
5673 /*-----------------------------------------------------------------*/
5674 /* genRRC - rotate right with carry */
5675 /*-----------------------------------------------------------------*/
5682 /*-----------------------------------------------------------------*/
5683 /* genRLC - generate code for rotate left with carry */
5684 /*-----------------------------------------------------------------*/
5691 /*-----------------------------------------------------------------*/
5692 /* genGetHbit - generates code get highest order bit */
5693 /*-----------------------------------------------------------------*/
5695 genGetHbit (iCode * ic)
5697 operand *left, *result;
5698 left = IC_LEFT (ic);
5699 result = IC_RESULT (ic);
5701 aopOp (left, ic, FALSE, FALSE);
5702 aopOp (result, ic, FALSE, FALSE);
5704 /* get the highest order byte into a */
5705 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5707 if (AOP_TYPE (result) == AOP_CRY)
5715 emit2 ("and a,!one");
5720 freeAsmop (left, NULL, ic);
5721 freeAsmop (result, NULL, ic);
5725 emitRsh2 (asmop *aop, int size, int is_signed)
5731 const char *l = aopGet (aop, size, FALSE);
5734 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5744 /*-----------------------------------------------------------------*/
5745 /* shiftR2Left2Result - shift right two bytes from left to result */
5746 /*-----------------------------------------------------------------*/
5748 shiftR2Left2Result (operand * left, int offl,
5749 operand * result, int offr,
5750 int shCount, int is_signed)
5753 symbol *tlbl, *tlbl1;
5755 movLeft2Result (left, offl, result, offr, 0);
5756 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5761 /* if (AOP(result)->type == AOP_REG) { */
5763 tlbl = newiTempLabel (NULL);
5764 tlbl1 = newiTempLabel (NULL);
5766 /* Left is already in result - so now do the shift */
5771 emitRsh2 (AOP (result), size, is_signed);
5776 emit2 ("ld a,!immedbyte+1", shCount);
5777 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5778 emitLabel (tlbl->key + 100);
5780 emitRsh2 (AOP (result), size, is_signed);
5782 emitLabel (tlbl1->key + 100);
5784 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5788 /*-----------------------------------------------------------------*/
5789 /* shiftL2Left2Result - shift left two bytes from left to result */
5790 /*-----------------------------------------------------------------*/
5792 shiftL2Left2Result (operand * left, int offl,
5793 operand * result, int offr, int shCount)
5795 if (sameRegs (AOP (result), AOP (left)) &&
5796 ((offl + MSB16) == offr))
5802 /* Copy left into result */
5803 movLeft2Result (left, offl, result, offr, 0);
5804 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5810 if (getPairId (AOP (result)) == PAIR_HL)
5814 emit2 ("add hl,hl");
5821 symbol *tlbl, *tlbl1;
5824 tlbl = newiTempLabel (NULL);
5825 tlbl1 = newiTempLabel (NULL);
5827 if (AOP (result)->type == AOP_REG)
5831 for (offset = 0; offset < size; offset++)
5833 l = aopGet (AOP (result), offset, FALSE);
5837 emit2 ("sla %s", l);
5848 /* Left is already in result - so now do the shift */
5851 emit2 ("ld a,!immedbyte+1", shCount);
5852 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5853 emitLabel (tlbl->key + 100);
5858 l = aopGet (AOP (result), offset, FALSE);
5862 emit2 ("sla %s", l);
5873 emitLabel (tlbl1->key + 100);
5875 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5881 /*-----------------------------------------------------------------*/
5882 /* AccRol - rotate left accumulator by known count */
5883 /*-----------------------------------------------------------------*/
5885 AccRol (int shCount)
5887 shCount &= 0x0007; // shCount : 0..7
5964 /*-----------------------------------------------------------------*/
5965 /* AccLsh - left shift accumulator by known count */
5966 /*-----------------------------------------------------------------*/
5968 AccLsh (int shCount)
5970 static const unsigned char SLMask[] =
5972 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5981 else if (shCount == 2)
5988 /* rotate left accumulator */
5990 /* and kill the lower order bits */
5991 emit2 ("and a,!immedbyte", SLMask[shCount]);
5996 /*-----------------------------------------------------------------*/
5997 /* shiftL1Left2Result - shift left one byte from left to result */
5998 /*-----------------------------------------------------------------*/
6000 shiftL1Left2Result (operand * left, int offl,
6001 operand * result, int offr, int shCount)
6004 l = aopGet (AOP (left), offl, FALSE);
6006 /* shift left accumulator */
6008 aopPut (AOP (result), "a", offr);
6012 /*-----------------------------------------------------------------*/
6013 /* genlshTwo - left shift two bytes by known amount */
6014 /*-----------------------------------------------------------------*/
6016 genlshTwo (operand * result, operand * left, int shCount)
6018 int size = AOP_SIZE (result);
6020 wassert (size == 2);
6022 /* if shCount >= 8 */
6030 movLeft2Result (left, LSB, result, MSB16, 0);
6031 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6032 aopPut (AOP (result), "!zero", LSB);
6036 movLeft2Result (left, LSB, result, MSB16, 0);
6037 aopPut (AOP (result), "!zero", 0);
6042 aopPut (AOP (result), "!zero", LSB);
6045 /* 0 <= shCount <= 7 */
6054 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6059 /*-----------------------------------------------------------------*/
6060 /* genlshOne - left shift a one byte quantity by known count */
6061 /*-----------------------------------------------------------------*/
6063 genlshOne (operand * result, operand * left, int shCount)
6065 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6068 /*-----------------------------------------------------------------*/
6069 /* genLeftShiftLiteral - left shifting by known count */
6070 /*-----------------------------------------------------------------*/
6072 genLeftShiftLiteral (operand * left,
6077 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6080 freeAsmop (right, NULL, ic);
6082 aopOp (left, ic, FALSE, FALSE);
6083 aopOp (result, ic, FALSE, FALSE);
6085 size = getSize (operandType (result));
6087 /* I suppose that the left size >= result size */
6089 if (shCount >= (size * 8))
6093 aopPut (AOP (result), "!zero", size);
6101 genlshOne (result, left, shCount);
6104 genlshTwo (result, left, shCount);
6107 wassertl (0, "Shifting of longs is currently unsupported");
6113 freeAsmop (left, NULL, ic);
6114 freeAsmop (result, NULL, ic);
6117 /*-----------------------------------------------------------------*/
6118 /* genLeftShift - generates code for left shifting */
6119 /*-----------------------------------------------------------------*/
6121 genLeftShift (iCode * ic)
6125 symbol *tlbl, *tlbl1;
6126 operand *left, *right, *result;
6128 right = IC_RIGHT (ic);
6129 left = IC_LEFT (ic);
6130 result = IC_RESULT (ic);
6132 aopOp (right, ic, FALSE, FALSE);
6134 /* if the shift count is known then do it
6135 as efficiently as possible */
6136 if (AOP_TYPE (right) == AOP_LIT)
6138 genLeftShiftLiteral (left, right, result, ic);
6142 /* shift count is unknown then we have to form a loop get the loop
6143 count in B : Note: we take only the lower order byte since
6144 shifting more that 32 bits make no sense anyway, ( the largest
6145 size of an object can be only 32 bits ) */
6146 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6148 freeAsmop (right, NULL, ic);
6149 aopOp (left, ic, FALSE, FALSE);
6150 aopOp (result, ic, FALSE, FALSE);
6152 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6155 /* now move the left to the result if they are not the
6158 if (!sameRegs (AOP (left), AOP (result)))
6161 size = AOP_SIZE (result);
6165 l = aopGet (AOP (left), offset, FALSE);
6166 aopPut (AOP (result), l, offset);
6171 tlbl = newiTempLabel (NULL);
6172 size = AOP_SIZE (result);
6174 tlbl1 = newiTempLabel (NULL);
6176 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6179 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6180 emitLabel (tlbl->key + 100);
6181 l = aopGet (AOP (result), offset, FALSE);
6185 l = aopGet (AOP (result), offset, FALSE);
6189 emit2 ("sla %s", l);
6197 emitLabel (tlbl1->key + 100);
6199 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6201 freeAsmop (left, NULL, ic);
6202 freeAsmop (result, NULL, ic);
6205 /*-----------------------------------------------------------------*/
6206 /* genrshOne - left shift two bytes by known amount != 0 */
6207 /*-----------------------------------------------------------------*/
6209 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6212 int size = AOP_SIZE (result);
6215 wassert (size == 1);
6216 wassert (shCount < 8);
6218 l = aopGet (AOP (left), 0, FALSE);
6220 if (AOP (result)->type == AOP_REG)
6222 aopPut (AOP (result), l, 0);
6223 l = aopGet (AOP (result), 0, FALSE);
6226 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6234 emit2 ("%s a", is_signed ? "sra" : "srl");
6236 aopPut (AOP (result), "a", 0);
6240 /*-----------------------------------------------------------------*/
6241 /* AccRsh - right shift accumulator by known count */
6242 /*-----------------------------------------------------------------*/
6244 AccRsh (int shCount)
6246 static const unsigned char SRMask[] =
6248 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6253 /* rotate right accumulator */
6254 AccRol (8 - shCount);
6255 /* and kill the higher order bits */
6256 emit2 ("and a,!immedbyte", SRMask[shCount]);
6260 /*-----------------------------------------------------------------*/
6261 /* shiftR1Left2Result - shift right one byte from left to result */
6262 /*-----------------------------------------------------------------*/
6264 shiftR1Left2Result (operand * left, int offl,
6265 operand * result, int offr,
6266 int shCount, int sign)
6268 _moveA (aopGet (AOP (left), offl, FALSE));
6273 emit2 ("%s a", sign ? "sra" : "srl");
6280 aopPut (AOP (result), "a", offr);
6283 /*-----------------------------------------------------------------*/
6284 /* genrshTwo - right shift two bytes by known amount */
6285 /*-----------------------------------------------------------------*/
6287 genrshTwo (operand * result, operand * left,
6288 int shCount, int sign)
6290 /* if shCount >= 8 */
6296 shiftR1Left2Result (left, MSB16, result, LSB,
6301 movLeft2Result (left, MSB16, result, LSB, sign);
6305 /* Sign extend the result */
6306 _moveA(aopGet (AOP (result), 0, FALSE));
6310 aopPut (AOP (result), ACC_NAME, MSB16);
6314 aopPut (AOP (result), "!zero", 1);
6317 /* 0 <= shCount <= 7 */
6320 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6324 /*-----------------------------------------------------------------*/
6325 /* genRightShiftLiteral - left shifting by known count */
6326 /*-----------------------------------------------------------------*/
6328 genRightShiftLiteral (operand * left,
6334 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6337 freeAsmop (right, NULL, ic);
6339 aopOp (left, ic, FALSE, FALSE);
6340 aopOp (result, ic, FALSE, FALSE);
6342 size = getSize (operandType (result));
6344 /* I suppose that the left size >= result size */
6346 if (shCount >= (size * 8)) {
6348 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6349 _moveA(aopGet (AOP (left), 0, FALSE));
6357 aopPut (AOP (result), s, size);
6364 genrshOne (result, left, shCount, sign);
6367 genrshTwo (result, left, shCount, sign);
6370 wassertl (0, "Asked to shift right a long which should be a function call");
6373 wassertl (0, "Entered default case in right shift delegate");
6376 freeAsmop (left, NULL, ic);
6377 freeAsmop (result, NULL, ic);
6380 /*-----------------------------------------------------------------*/
6381 /* genRightShift - generate code for right shifting */
6382 /*-----------------------------------------------------------------*/
6384 genRightShift (iCode * ic)
6386 operand *right, *left, *result;
6388 int size, offset, first = 1;
6392 symbol *tlbl, *tlbl1;
6394 /* if signed then we do it the hard way preserve the
6395 sign bit moving it inwards */
6396 retype = getSpec (operandType (IC_RESULT (ic)));
6398 is_signed = !SPEC_USIGN (retype);
6400 /* signed & unsigned types are treated the same : i.e. the
6401 signed is NOT propagated inwards : quoting from the
6402 ANSI - standard : "for E1 >> E2, is equivalent to division
6403 by 2**E2 if unsigned or if it has a non-negative value,
6404 otherwise the result is implementation defined ", MY definition
6405 is that the sign does not get propagated */
6407 right = IC_RIGHT (ic);
6408 left = IC_LEFT (ic);
6409 result = IC_RESULT (ic);
6411 aopOp (right, ic, FALSE, FALSE);
6413 /* if the shift count is known then do it
6414 as efficiently as possible */
6415 if (AOP_TYPE (right) == AOP_LIT)
6417 genRightShiftLiteral (left, right, result, ic, is_signed);
6421 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6423 freeAsmop (right, NULL, ic);
6425 aopOp (left, ic, FALSE, FALSE);
6426 aopOp (result, ic, FALSE, FALSE);
6428 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6431 /* now move the left to the result if they are not the
6433 if (!sameRegs (AOP (left), AOP (result)))
6436 size = AOP_SIZE (result);
6440 l = aopGet (AOP (left), offset, FALSE);
6441 aopPut (AOP (result), l, offset);
6446 tlbl = newiTempLabel (NULL);
6447 tlbl1 = newiTempLabel (NULL);
6448 size = AOP_SIZE (result);
6451 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6454 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6455 emitLabel (tlbl->key + 100);
6458 l = aopGet (AOP (result), offset--, FALSE);
6461 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6469 emitLabel (tlbl1->key + 100);
6471 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6473 freeAsmop (left, NULL, ic);
6474 freeAsmop (result, NULL, ic);
6478 /*-----------------------------------------------------------------*/
6479 /* genUnpackBits - generates code for unpacking bits */
6480 /*-----------------------------------------------------------------*/
6482 genUnpackBits (operand * result, int pair)
6484 int offset = 0; /* result byte offset */
6485 int rsize; /* result size */
6486 int rlen = 0; /* remaining bitfield length */
6487 sym_link *etype; /* bitfield type information */
6488 int blen; /* bitfield length */
6489 int bstr; /* bitfield starting bit within byte */
6491 emitDebug ("; genUnpackBits");
6493 etype = getSpec (operandType (result));
6494 rsize = getSize (operandType (result));
6495 blen = SPEC_BLEN (etype);
6496 bstr = SPEC_BSTR (etype);
6498 /* If the bitfield length is less than a byte */
6501 emit2 ("ld a,!*pair", _pairs[pair].name);
6503 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6504 if (!SPEC_USIGN (etype))
6506 /* signed bitfield */
6507 symbol *tlbl = newiTempLabel (NULL);
6509 emit2 ("bit %d,a", blen - 1);
6510 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6511 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6512 emitLabel (tlbl->key + 100);
6514 aopPut (AOP (result), "a", offset++);
6518 /* TODO: what if pair == PAIR_DE ? */
6519 if (getPairId (AOP (result)) == PAIR_HL)
6521 wassertl (rsize == 2, "HL must be of size 2");
6522 emit2 ("ld a,!*hl");
6524 emit2 ("ld h,!*hl");
6527 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6528 if (!SPEC_USIGN (etype))
6530 /* signed bitfield */
6531 symbol *tlbl = newiTempLabel (NULL);
6533 emit2 ("bit %d,a", blen - 1);
6534 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6535 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6536 emitLabel (tlbl->key + 100);
6539 spillPair (PAIR_HL);
6543 /* Bit field did not fit in a byte. Copy all
6544 but the partial byte at the end. */
6545 for (rlen=blen;rlen>=8;rlen-=8)
6547 emit2 ("ld a,!*pair", _pairs[pair].name);
6548 aopPut (AOP (result), "a", offset++);
6551 emit2 ("inc %s", _pairs[pair].name);
6552 _G.pairs[pair].offset++;
6556 /* Handle the partial byte at the end */
6559 emit2 ("ld a,!*pair", _pairs[pair].name);
6560 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6561 if (!SPEC_USIGN (etype))
6563 /* signed bitfield */
6564 symbol *tlbl = newiTempLabel (NULL);
6566 emit2 ("bit %d,a", rlen - 1);
6567 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6568 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6569 emitLabel (tlbl->key + 100);
6571 aopPut (AOP (result), "a", offset++);
6579 if (SPEC_USIGN (etype))
6583 /* signed bitfield: sign extension with 0x00 or 0xff */
6591 aopPut (AOP (result), source, offset++);
6595 /*-----------------------------------------------------------------*/
6596 /* genGenPointerGet - get value from generic pointer space */
6597 /*-----------------------------------------------------------------*/
6599 genGenPointerGet (operand * left,
6600 operand * result, iCode * ic)
6603 sym_link *retype = getSpec (operandType (result));
6609 aopOp (left, ic, FALSE, FALSE);
6610 aopOp (result, ic, FALSE, FALSE);
6612 size = AOP_SIZE (result);
6614 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6617 if (isPtrPair (AOP (left)))
6619 tsprintf (buffer, sizeof(buffer),
6620 "!*pair", getPairName (AOP (left)));
6621 aopPut (AOP (result), buffer, 0);
6625 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6626 aopPut (AOP (result), "a", 0);
6628 freeAsmop (left, NULL, ic);
6632 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6639 tsprintf (at, sizeof(at), "!*iyx", offset);
6640 aopPut (AOP (result), at, offset);
6644 freeAsmop (left, NULL, ic);
6648 /* For now we always load into IY */
6649 /* if this is remateriazable */
6650 fetchPair (pair, AOP (left));
6652 /* if bit then unpack */
6653 if (IS_BITVAR (retype))
6655 genUnpackBits (result, pair);
6656 freeAsmop (left, NULL, ic);
6660 else if (getPairId (AOP (result)) == PAIR_HL)
6662 wassertl (size == 2, "HL must be of size 2");
6663 emit2 ("ld a,!*hl");
6665 emit2 ("ld h,!*hl");
6667 spillPair (PAIR_HL);
6669 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6671 size = AOP_SIZE (result);
6676 /* PENDING: make this better */
6677 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6679 aopPut (AOP (result), "!*hl", offset++);
6683 emit2 ("ld a,!*pair", _pairs[pair].name);
6684 aopPut (AOP (result), "a", offset++);
6688 emit2 ("inc %s", _pairs[pair].name);
6689 _G.pairs[pair].offset++;
6692 /* Fixup HL back down */
6693 for (size = AOP_SIZE (result)-1; size; size--)
6695 emit2 ("dec %s", _pairs[pair].name);
6700 size = AOP_SIZE (result);
6705 /* PENDING: make this better */
6707 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6709 aopPut (AOP (result), "!*hl", offset++);
6713 emit2 ("ld a,!*pair", _pairs[pair].name);
6714 aopPut (AOP (result), "a", offset++);
6718 emit2 ("inc %s", _pairs[pair].name);
6719 _G.pairs[pair].offset++;
6724 freeAsmop (left, NULL, ic);
6727 freeAsmop (result, NULL, ic);
6730 /*-----------------------------------------------------------------*/
6731 /* genPointerGet - generate code for pointer get */
6732 /*-----------------------------------------------------------------*/
6734 genPointerGet (iCode * ic)
6736 operand *left, *result;
6737 sym_link *type, *etype;
6739 left = IC_LEFT (ic);
6740 result = IC_RESULT (ic);
6742 /* depending on the type of pointer we need to
6743 move it to the correct pointer register */
6744 type = operandType (left);
6745 etype = getSpec (type);
6747 genGenPointerGet (left, result, ic);
6751 isRegOrLit (asmop * aop)
6753 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6759 /*-----------------------------------------------------------------*/
6760 /* genPackBits - generates code for packed bit storage */
6761 /*-----------------------------------------------------------------*/
6763 genPackBits (sym_link * etype,
6768 int offset = 0; /* source byte offset */
6769 int rlen = 0; /* remaining bitfield length */
6770 int blen; /* bitfield length */
6771 int bstr; /* bitfield starting bit within byte */
6772 int litval; /* source literal value (if AOP_LIT) */
6773 unsigned char mask; /* bitmask within current byte */
6774 int extraPair; /* a tempory register */
6775 bool needPopExtra=0; /* need to restore original value of temp reg */
6777 emitDebug ("; genPackBits","");
6779 blen = SPEC_BLEN (etype);
6780 bstr = SPEC_BSTR (etype);
6782 /* If the bitfield length is less than a byte */
6785 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6786 (unsigned char) (0xFF >> (8 - bstr)));
6788 if (AOP_TYPE (right) == AOP_LIT)
6790 /* Case with a bitfield length <8 and literal source
6792 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6794 litval &= (~mask) & 0xff;
6795 emit2 ("ld a,!*pair", _pairs[pair].name);
6796 if ((mask|litval)!=0xff)
6797 emit2 ("and a,!immedbyte", mask);
6799 emit2 ("or a,!immedbyte", litval);
6800 emit2 ("ld !*pair,a", _pairs[pair].name);
6805 /* Case with a bitfield length <8 and arbitrary source
6807 _moveA (aopGet (AOP (right), 0, FALSE));
6808 /* shift and mask source value */
6810 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6812 extraPair = getFreePairId(ic);
6813 if (extraPair == PAIR_INVALID)
6815 extraPair = PAIR_BC;
6816 if (getPairId (AOP (right)) != PAIR_BC
6817 || !isLastUse (ic, right))
6823 emit2 ("ld %s,a", _pairs[extraPair].l);
6824 emit2 ("ld a,!*pair", _pairs[pair].name);
6826 emit2 ("and a,!immedbyte", mask);
6827 emit2 ("or a,%s", _pairs[extraPair].l);
6828 emit2 ("ld !*pair,a", _pairs[pair].name);
6835 /* Bit length is greater than 7 bits. In this case, copy */
6836 /* all except the partial byte at the end */
6837 for (rlen=blen;rlen>=8;rlen-=8)
6839 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6840 emit2 ("ld !*pair,a", _pairs[pair].name);
6843 emit2 ("inc %s", _pairs[pair].name);
6844 _G.pairs[pair].offset++;
6848 /* If there was a partial byte at the end */
6851 mask = (((unsigned char) -1 << rlen) & 0xff);
6853 if (AOP_TYPE (right) == AOP_LIT)
6855 /* Case with partial byte and literal source
6857 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6858 litval >>= (blen-rlen);
6859 litval &= (~mask) & 0xff;
6860 emit2 ("ld a,!*pair", _pairs[pair].name);
6861 if ((mask|litval)!=0xff)
6862 emit2 ("and a,!immedbyte", mask);
6864 emit2 ("or a,!immedbyte", litval);
6868 /* Case with partial byte and arbitrary source
6870 _moveA (aopGet (AOP (right), offset++, FALSE));
6871 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6873 extraPair = getFreePairId(ic);
6874 if (extraPair == PAIR_INVALID)
6876 extraPair = getPairId (AOP (right));
6877 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6878 extraPair = PAIR_BC;
6880 if (getPairId (AOP (right)) != PAIR_BC
6881 || !isLastUse (ic, right))
6887 emit2 ("ld %s,a", _pairs[extraPair].l);
6888 emit2 ("ld a,!*pair", _pairs[pair].name);
6890 emit2 ("and a,!immedbyte", mask);
6891 emit2 ("or a,%s", _pairs[extraPair].l);
6896 emit2 ("ld !*pair,a", _pairs[pair].name);
6901 /*-----------------------------------------------------------------*/
6902 /* genGenPointerSet - stores the value into a pointer location */
6903 /*-----------------------------------------------------------------*/
6905 genGenPointerSet (operand * right,
6906 operand * result, iCode * ic)
6909 sym_link *retype = getSpec (operandType (right));
6910 sym_link *letype = getSpec (operandType (result));
6911 PAIR_ID pairId = PAIR_HL;
6914 aopOp (result, ic, FALSE, FALSE);
6915 aopOp (right, ic, FALSE, FALSE);
6920 size = AOP_SIZE (right);
6922 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6923 emitDebug("; isBitvar = %d", isBitvar);
6925 /* Handle the exceptions first */
6926 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6929 const char *l = aopGet (AOP (right), 0, FALSE);
6930 const char *pair = getPairName (AOP (result));
6931 if (canAssignToPtr (l) && isPtr (pair))
6933 emit2 ("ld !*pair,%s", pair, l);
6938 emit2 ("ld !*pair,a", pair);
6943 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6946 const char *l = aopGet (AOP (right), 0, FALSE);
6951 if (canAssignToPtr (l))
6953 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6957 _moveA (aopGet (AOP (right), offset, FALSE));
6958 emit2 ("ld !*iyx,a", offset);
6964 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6971 const char *l = aopGet (AOP (right), offset, FALSE);
6972 if (isRegOrLit (AOP (right)) && !IS_GB)
6974 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6979 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6983 emit2 ("inc %s", _pairs[PAIR_HL].name);
6984 _G.pairs[PAIR_HL].offset++;
6989 /* Fixup HL back down */
6990 for (size = AOP_SIZE (right)-1; size; size--)
6992 emit2 ("dec %s", _pairs[PAIR_HL].name);
6997 /* if the operand is already in dptr
6998 then we do nothing else we move the value to dptr */
6999 if (AOP_TYPE (result) != AOP_STR)
7001 fetchPair (pairId, AOP (result));
7003 /* so hl now contains the address */
7004 freeAsmop (result, NULL, ic);
7006 /* if bit then unpack */
7009 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7019 const char *l = aopGet (AOP (right), offset, FALSE);
7020 if (isRegOrLit (AOP (right)) && !IS_GB)
7022 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7027 emit2 ("ld !*pair,a", _pairs[pairId].name);
7031 emit2 ("inc %s", _pairs[pairId].name);
7032 _G.pairs[pairId].offset++;
7038 freeAsmop (right, NULL, ic);
7041 /*-----------------------------------------------------------------*/
7042 /* genPointerSet - stores the value into a pointer location */
7043 /*-----------------------------------------------------------------*/
7045 genPointerSet (iCode * ic)
7047 operand *right, *result;
7048 sym_link *type, *etype;
7050 right = IC_RIGHT (ic);
7051 result = IC_RESULT (ic);
7053 /* depending on the type of pointer we need to
7054 move it to the correct pointer register */
7055 type = operandType (result);
7056 etype = getSpec (type);
7058 genGenPointerSet (right, result, ic);
7061 /*-----------------------------------------------------------------*/
7062 /* genIfx - generate code for Ifx statement */
7063 /*-----------------------------------------------------------------*/
7065 genIfx (iCode * ic, iCode * popIc)
7067 operand *cond = IC_COND (ic);
7070 aopOp (cond, ic, FALSE, TRUE);
7072 /* get the value into acc */
7073 if (AOP_TYPE (cond) != AOP_CRY)
7077 /* the result is now in the accumulator */
7078 freeAsmop (cond, NULL, ic);
7080 /* if there was something to be popped then do it */
7084 /* if the condition is a bit variable */
7085 if (isbit && IS_ITEMP (cond) &&
7087 genIfxJump (ic, SPIL_LOC (cond)->rname);
7088 else if (isbit && !IS_ITEMP (cond))
7089 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7091 genIfxJump (ic, "a");
7096 /*-----------------------------------------------------------------*/
7097 /* genAddrOf - generates code for address of */
7098 /*-----------------------------------------------------------------*/
7100 genAddrOf (iCode * ic)
7102 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7104 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7106 /* if the operand is on the stack then we
7107 need to get the stack offset of this
7114 if (sym->stack <= 0)
7116 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7120 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7122 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7126 emit2 ("ld de,!hashedstr", sym->rname);
7127 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7135 /* if it has an offset then we need to compute it */
7137 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7139 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7140 emit2 ("add hl,sp");
7144 emit2 ("ld hl,!hashedstr", sym->rname);
7146 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7148 freeAsmop (IC_RESULT (ic), NULL, ic);
7151 /*-----------------------------------------------------------------*/
7152 /* genAssign - generate code for assignment */
7153 /*-----------------------------------------------------------------*/
7155 genAssign (iCode * ic)
7157 operand *result, *right;
7159 unsigned long lit = 0L;
7161 result = IC_RESULT (ic);
7162 right = IC_RIGHT (ic);
7164 /* Dont bother assigning if they are the same */
7165 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7167 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7171 aopOp (right, ic, FALSE, FALSE);
7172 aopOp (result, ic, TRUE, FALSE);
7174 /* if they are the same registers */
7175 if (sameRegs (AOP (right), AOP (result)))
7177 emitDebug ("; (registers are the same)");
7181 /* if the result is a bit */
7182 if (AOP_TYPE (result) == AOP_CRY)
7184 wassertl (0, "Tried to assign to a bit");
7188 size = AOP_SIZE (result);
7191 if (AOP_TYPE (right) == AOP_LIT)
7193 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7196 if (isPair (AOP (result)))
7198 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7200 else if ((size > 1) &&
7201 (AOP_TYPE (result) != AOP_REG) &&
7202 (AOP_TYPE (right) == AOP_LIT) &&
7203 !IS_FLOAT (operandType (right)) &&
7206 bool fXored = FALSE;
7208 /* Work from the top down.
7209 Done this way so that we can use the cached copy of 0
7210 in A for a fast clear */
7213 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7215 if (!fXored && size > 1)
7222 aopPut (AOP (result), "a", offset);
7226 aopPut (AOP (result), "!zero", offset);
7230 aopPut (AOP (result),
7231 aopGet (AOP (right), offset, FALSE),
7236 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7238 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7239 aopPut (AOP (result), "l", LSB);
7240 aopPut (AOP (result), "h", MSB16);
7242 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7244 /* Special case. Load into a and d, then load out. */
7245 _moveA (aopGet (AOP (right), 0, FALSE));
7246 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7247 aopPut (AOP (result), "a", 0);
7248 aopPut (AOP (result), "e", 1);
7250 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7252 /* Special case - simple memcpy */
7253 aopGet (AOP (right), LSB, FALSE);
7256 aopGet (AOP (result), LSB, FALSE);
7260 emit2 ("ld a,(de)");
7261 /* Peephole will optimise this. */
7262 emit2 ("ld (hl),a");
7270 spillPair (PAIR_HL);
7276 /* PENDING: do this check better */
7277 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7279 _moveA (aopGet (AOP (right), offset, FALSE));
7280 aopPut (AOP (result), "a", offset);
7283 aopPut (AOP (result),
7284 aopGet (AOP (right), offset, FALSE),
7291 freeAsmop (right, NULL, ic);
7292 freeAsmop (result, NULL, ic);
7295 /*-----------------------------------------------------------------*/
7296 /* genJumpTab - genrates code for jump table */
7297 /*-----------------------------------------------------------------*/
7299 genJumpTab (iCode * ic)
7304 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7305 /* get the condition into accumulator */
7306 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7309 emit2 ("ld e,%s", l);
7310 emit2 ("ld d,!zero");
7311 jtab = newiTempLabel (NULL);
7313 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7314 emit2 ("add hl,de");
7315 emit2 ("add hl,de");
7316 emit2 ("add hl,de");
7317 freeAsmop (IC_JTCOND (ic), NULL, ic);
7321 emitLabel (jtab->key + 100);
7322 /* now generate the jump labels */
7323 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7324 jtab = setNextItem (IC_JTLABELS (ic)))
7325 emit2 ("jp !tlabel", jtab->key + 100);
7328 /*-----------------------------------------------------------------*/
7329 /* genCast - gen code for casting */
7330 /*-----------------------------------------------------------------*/
7332 genCast (iCode * ic)
7334 operand *result = IC_RESULT (ic);
7335 sym_link *rtype = operandType (IC_RIGHT (ic));
7336 operand *right = IC_RIGHT (ic);
7339 /* if they are equivalent then do nothing */
7340 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7343 aopOp (right, ic, FALSE, FALSE);
7344 aopOp (result, ic, FALSE, FALSE);
7346 /* if the result is a bit */
7347 if (AOP_TYPE (result) == AOP_CRY)
7349 wassertl (0, "Tried to cast to a bit");
7352 /* if they are the same size : or less */
7353 if (AOP_SIZE (result) <= AOP_SIZE (right))
7356 /* if they are in the same place */
7357 if (sameRegs (AOP (right), AOP (result)))
7360 /* if they in different places then copy */
7361 size = AOP_SIZE (result);
7365 aopPut (AOP (result),
7366 aopGet (AOP (right), offset, FALSE),
7373 /* So we now know that the size of destination is greater
7374 than the size of the source */
7375 /* we move to result for the size of source */
7376 size = AOP_SIZE (right);
7380 aopPut (AOP (result),
7381 aopGet (AOP (right), offset, FALSE),
7386 /* now depending on the sign of the destination */
7387 size = AOP_SIZE (result) - AOP_SIZE (right);
7388 /* Unsigned or not an integral type - right fill with zeros */
7389 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7392 aopPut (AOP (result), "!zero", offset++);
7396 /* we need to extend the sign :{ */
7397 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7403 aopPut (AOP (result), "a", offset++);
7407 freeAsmop (right, NULL, ic);
7408 freeAsmop (result, NULL, ic);
7411 /*-----------------------------------------------------------------*/
7412 /* genReceive - generate code for a receive iCode */
7413 /*-----------------------------------------------------------------*/
7415 genReceive (iCode * ic)
7417 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7418 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7419 IS_TRUE_SYMOP (IC_RESULT (ic))))
7429 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7430 size = AOP_SIZE(IC_RESULT(ic));
7432 for (i = 0; i < size; i++) {
7433 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7437 freeAsmop (IC_RESULT (ic), NULL, ic);
7440 /*-----------------------------------------------------------------*/
7441 /* genDummyRead - generate code for dummy read of volatiles */
7442 /*-----------------------------------------------------------------*/
7444 genDummyRead (iCode * ic)
7450 if (op && IS_SYMOP (op))
7452 aopOp (op, ic, FALSE, FALSE);
7455 size = AOP_SIZE (op);
7460 _moveA (aopGet (AOP (op), offset, FALSE));
7464 freeAsmop (op, NULL, ic);
7468 if (op && IS_SYMOP (op))
7470 aopOp (op, ic, FALSE, FALSE);
7473 size = AOP_SIZE (op);
7478 _moveA (aopGet (AOP (op), offset, FALSE));
7482 freeAsmop (op, NULL, ic);
7486 /*-----------------------------------------------------------------*/
7487 /* genCritical - generate code for start of a critical sequence */
7488 /*-----------------------------------------------------------------*/
7490 genCritical (iCode *ic)
7492 symbol *tlbl = newiTempLabel (NULL);
7498 else if (IC_RESULT (ic))
7500 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7501 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7502 //get interrupt enable flag IFF2 into P/O
7506 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7507 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7508 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7509 emit2 ("!tlabeldef", (tlbl->key + 100));
7510 _G.lines.current->isLabel = 1;
7511 freeAsmop (IC_RESULT (ic), NULL, ic);
7515 //get interrupt enable flag IFF2 into P/O
7524 /*-----------------------------------------------------------------*/
7525 /* genEndCritical - generate code for end of a critical sequence */
7526 /*-----------------------------------------------------------------*/
7528 genEndCritical (iCode *ic)
7530 symbol *tlbl = newiTempLabel (NULL);
7536 else if (IC_RIGHT (ic))
7538 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7539 _toBoolean (IC_RIGHT (ic));
7540 //don't enable interrupts if they were off before
7541 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7543 emitLabel (tlbl->key + 100);
7544 freeAsmop (IC_RIGHT (ic), NULL, ic);
7550 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7551 //don't enable interrupts as they were off before
7552 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7554 emit2 ("!tlabeldef", (tlbl->key + 100));
7555 _G.lines.current->isLabel = 1;
7561 /** Maximum number of bytes to emit per line. */
7565 /** Context for the byte output chunker. */
7568 unsigned char buffer[DBEMIT_MAX_RUN];
7573 /** Flushes a byte chunker by writing out all in the buffer and
7577 _dbFlush(DBEMITCTX *self)
7584 sprintf(line, ".db 0x%02X", self->buffer[0]);
7586 for (i = 1; i < self->pos; i++)
7588 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7595 /** Write out another byte, buffering until a decent line is
7599 _dbEmit(DBEMITCTX *self, int c)
7601 if (self->pos == DBEMIT_MAX_RUN)
7605 self->buffer[self->pos++] = c;
7608 /** Context for a simple run length encoder. */
7612 unsigned char buffer[128];
7614 /** runLen may be equivalent to pos. */
7620 RLE_CHANGE_COST = 4,
7624 /** Flush the buffer of a run length encoder by writing out the run or
7625 data that it currently contains.
7628 _rleCommit(RLECTX *self)
7634 memset(&db, 0, sizeof(db));
7636 emit2(".db %u", self->pos);
7638 for (i = 0; i < self->pos; i++)
7640 _dbEmit(&db, self->buffer[i]);
7649 Can get either a run or a block of random stuff.
7650 Only want to change state if a good run comes in or a run ends.
7651 Detecting run end is easy.
7654 Say initial state is in run, len zero, last zero. Then if you get a
7655 few zeros then something else then a short run will be output.
7656 Seems OK. While in run mode, keep counting. While in random mode,
7657 keep a count of the run. If run hits margin, output all up to run,
7658 restart, enter run mode.
7661 /** Add another byte into the run length encoder, flushing as
7662 required. The run length encoder uses the Amiga IFF style, where
7663 a block is prefixed by its run length. A positive length means
7664 the next n bytes pass straight through. A negative length means
7665 that the next byte is repeated -n times. A zero terminates the
7669 _rleAppend(RLECTX *self, unsigned c)
7673 if (c != self->last)
7675 /* The run has stopped. See if it is worthwhile writing it out
7676 as a run. Note that the random data comes in as runs of
7679 if (self->runLen > RLE_CHANGE_COST)
7681 /* Yes, worthwhile. */
7682 /* Commit whatever was in the buffer. */
7684 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7688 /* Not worthwhile. Append to the end of the random list. */
7689 for (i = 0; i < self->runLen; i++)
7691 if (self->pos >= RLE_MAX_BLOCK)
7696 self->buffer[self->pos++] = self->last;
7704 if (self->runLen >= RLE_MAX_BLOCK)
7706 /* Commit whatever was in the buffer. */
7709 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7717 _rleFlush(RLECTX *self)
7719 _rleAppend(self, -1);
7726 /** genArrayInit - Special code for initialising an array with constant
7730 genArrayInit (iCode * ic)
7734 int elementSize = 0, eIndex, i;
7735 unsigned val, lastVal;
7739 memset(&rle, 0, sizeof(rle));
7741 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7743 _saveRegsForCall(ic, 0);
7745 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7746 emit2 ("call __initrleblock");
7748 type = operandType(IC_LEFT(ic));
7750 if (type && type->next)
7752 if (IS_SPEC(type->next) || IS_PTR(type->next))
7754 elementSize = getSize(type->next);
7756 else if (IS_ARRAY(type->next) && type->next->next)
7758 elementSize = getSize(type->next->next);
7762 printTypeChainRaw (type, NULL);
7763 wassertl (0, "Can't determine element size in genArrayInit.");
7768 wassertl (0, "Can't determine element size in genArrayInit.");
7771 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7773 iLoop = IC_ARRAYILIST(ic);
7774 lastVal = (unsigned)-1;
7776 /* Feed all the bytes into the run length encoder which will handle
7778 This works well for mixed char data, and for random int and long
7785 for (i = 0; i < ix; i++)
7787 for (eIndex = 0; eIndex < elementSize; eIndex++)
7789 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7790 _rleAppend(&rle, val);
7794 iLoop = iLoop->next;
7798 /* Mark the end of the run. */
7801 _restoreRegsAfterCall();
7805 freeAsmop (IC_LEFT(ic), NULL, ic);
7809 _swap (PAIR_ID one, PAIR_ID two)
7811 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7817 emit2 ("ld a,%s", _pairs[one].l);
7818 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7819 emit2 ("ld %s,a", _pairs[two].l);
7820 emit2 ("ld a,%s", _pairs[one].h);
7821 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7822 emit2 ("ld %s,a", _pairs[two].h);
7826 /* The problem is that we may have all three pairs used and they may
7827 be needed in a different order.
7832 hl = hl => unity, fine
7836 hl = hl hl = hl, swap de <=> bc
7844 hl = bc de = de, swap bc <=> hl
7852 hl = de bc = bc, swap hl <=> de
7857 * Any pair = pair are done last
7858 * Any pair = iTemp are done last
7859 * Any swaps can be done any time
7867 So how do we detect the cases?
7868 How about a 3x3 matrix?
7872 x x x x (Fourth for iTemp/other)
7874 First determin which mode to use by counting the number of unity and
7877 Two - Assign the pair first, then the rest
7878 One - Swap the two, then the rest
7882 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7884 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7886 PAIR_BC, PAIR_HL, PAIR_DE
7888 int i, j, nunity = 0;
7889 memset (ids, PAIR_INVALID, sizeof (ids));
7892 wassert (nparams == 3);
7894 /* First save everything that needs to be saved. */
7895 _saveRegsForCall (ic, 0);
7897 /* Loading HL first means that DE is always fine. */
7898 for (i = 0; i < nparams; i++)
7900 aopOp (pparams[i], ic, FALSE, FALSE);
7901 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7904 /* Count the number of unity or iTemp assigns. */
7905 for (i = 0; i < 3; i++)
7907 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7915 /* Any order, fall through. */
7917 else if (nunity == 2)
7919 /* One is assigned. Pull it out and assign. */
7920 for (i = 0; i < 3; i++)
7922 for (j = 0; j < NUM_PAIRS; j++)
7924 if (ids[dest[i]][j] == TRUE)
7926 /* Found it. See if it's the right one. */
7927 if (j == PAIR_INVALID || j == dest[i])
7933 fetchPair(dest[i], AOP (pparams[i]));
7940 else if (nunity == 1)
7942 /* Find the pairs to swap. */
7943 for (i = 0; i < 3; i++)
7945 for (j = 0; j < NUM_PAIRS; j++)
7947 if (ids[dest[i]][j] == TRUE)
7949 if (j == PAIR_INVALID || j == dest[i])
7964 int next = getPairId (AOP (pparams[0]));
7965 emit2 ("push %s", _pairs[next].name);
7967 if (next == dest[1])
7969 fetchPair (dest[1], AOP (pparams[1]));
7970 fetchPair (dest[2], AOP (pparams[2]));
7974 fetchPair (dest[2], AOP (pparams[2]));
7975 fetchPair (dest[1], AOP (pparams[1]));
7977 emit2 ("pop %s", _pairs[dest[0]].name);
7980 /* Finally pull out all of the iTemps */
7981 for (i = 0; i < 3; i++)
7983 if (ids[dest[i]][PAIR_INVALID] == 1)
7985 fetchPair (dest[i], AOP (pparams[i]));
7991 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7997 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8001 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8003 setupForBuiltin3 (ic, nParams, pparams);
8005 label = newiTempLabel(NULL);
8007 emitLabel (label->key);
8008 emit2 ("ld a,(hl)");
8011 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8013 freeAsmop (from, NULL, ic->next);
8014 freeAsmop (to, NULL, ic);
8018 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8020 operand *from, *to, *count;
8023 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8028 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8030 setupForBuiltin3 (ic, nParams, pparams);
8034 freeAsmop (count, NULL, ic->next->next);
8035 freeAsmop (from, NULL, ic);
8037 _restoreRegsAfterCall();
8039 /* if we need assign a result value */
8040 if ((IS_ITEMP (IC_RESULT (ic)) &&
8041 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8042 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8043 IS_TRUE_SYMOP (IC_RESULT (ic)))
8045 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8046 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8047 freeAsmop (IC_RESULT (ic), NULL, ic);
8050 freeAsmop (to, NULL, ic->next);
8053 /*-----------------------------------------------------------------*/
8054 /* genBuiltIn - calls the appropriate function to generating code */
8055 /* for a built in function */
8056 /*-----------------------------------------------------------------*/
8057 static void genBuiltIn (iCode *ic)
8059 operand *bi_parms[MAX_BUILTIN_ARGS];
8064 /* get all the arguments for a built in function */
8065 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8067 /* which function is it */
8068 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8070 if (strcmp(bif->name,"__builtin_strcpy")==0)
8072 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8074 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8076 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8080 wassertl (0, "Unknown builtin function encountered");
8084 /*-----------------------------------------------------------------*/
8085 /* genZ80Code - generate code for Z80 based controllers */
8086 /*-----------------------------------------------------------------*/
8088 genZ80Code (iCode * lic)
8096 _fReturn = _gbz80_return;
8097 _fTmp = _gbz80_return;
8101 _fReturn = _z80_return;
8102 _fTmp = _z80_return;
8105 _G.lines.head = _G.lines.current = NULL;
8107 /* if debug information required */
8108 if (options.debug && currFunc)
8110 debugFile->writeFunction (currFunc, lic);
8113 for (ic = lic; ic; ic = ic->next)
8115 _G.current_iCode = ic;
8117 if (ic->lineno && cln != ic->lineno)
8121 debugFile->writeCLine (ic);
8123 if (!options.noCcodeInAsm)
8125 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8126 printCLine(ic->filename, ic->lineno));
8130 if (options.iCodeInAsm)
8132 char *iLine = printILine(ic);
8133 emit2 (";ic:%d: %s", ic->key, iLine);
8136 /* if the result is marked as
8137 spilt and rematerializable or code for
8138 this has already been generated then
8140 if (resultRemat (ic) || ic->generated)
8143 /* depending on the operation */
8147 emitDebug ("; genNot");
8152 emitDebug ("; genCpl");
8157 emitDebug ("; genUminus");
8162 emitDebug ("; genIpush");
8167 /* IPOP happens only when trying to restore a
8168 spilt live range, if there is an ifx statement
8169 following this pop then the if statement might
8170 be using some of the registers being popped which
8171 would destroy the contents of the register so
8172 we need to check for this condition and handle it */
8174 ic->next->op == IFX &&
8175 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8177 emitDebug ("; genIfx");
8178 genIfx (ic->next, ic);
8182 emitDebug ("; genIpop");
8188 emitDebug ("; genCall");
8193 emitDebug ("; genPcall");
8198 emitDebug ("; genFunction");
8203 emitDebug ("; genEndFunction");
8204 genEndFunction (ic);
8208 emitDebug ("; genRet");
8213 emitDebug ("; genLabel");
8218 emitDebug ("; genGoto");
8223 emitDebug ("; genPlus");
8228 emitDebug ("; genMinus");
8233 emitDebug ("; genMult");
8238 emitDebug ("; genDiv");
8243 emitDebug ("; genMod");
8248 emitDebug ("; genCmpGt");
8249 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8253 emitDebug ("; genCmpLt");
8254 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8261 /* note these two are xlated by algebraic equivalence
8262 during parsing SDCC.y */
8263 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8264 "got '>=' or '<=' shouldn't have come here");
8268 emitDebug ("; genCmpEq");
8269 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8273 emitDebug ("; genAndOp");
8278 emitDebug ("; genOrOp");
8283 emitDebug ("; genXor");
8284 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8288 emitDebug ("; genOr");
8289 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8293 emitDebug ("; genAnd");
8294 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8298 emitDebug ("; genInline");
8303 emitDebug ("; genRRC");
8308 emitDebug ("; genRLC");
8313 emitDebug ("; genGetHBIT");
8318 emitDebug ("; genLeftShift");
8323 emitDebug ("; genRightShift");
8327 case GET_VALUE_AT_ADDRESS:
8328 emitDebug ("; genPointerGet");
8334 if (POINTER_SET (ic))
8336 emitDebug ("; genAssign (pointer)");
8341 emitDebug ("; genAssign");
8347 emitDebug ("; genIfx");
8352 emitDebug ("; genAddrOf");
8357 emitDebug ("; genJumpTab");
8362 emitDebug ("; genCast");
8367 emitDebug ("; genReceive");
8372 if (ic->builtinSEND)
8374 emitDebug ("; genBuiltIn");
8379 emitDebug ("; addSet");
8380 addSet (&_G.sendSet, ic);
8385 emitDebug ("; genArrayInit");
8389 case DUMMY_READ_VOLATILE:
8390 emitDebug ("; genDummyRead");
8395 emitDebug ("; genCritical");
8400 emitDebug ("; genEndCritical");
8401 genEndCritical (ic);
8410 /* now we are ready to call the
8411 peep hole optimizer */
8412 if (!options.nopeep)
8413 peepHole (&_G.lines.head);
8415 /* This is unfortunate */
8416 /* now do the actual printing */
8418 struct dbuf_s *buf = codeOutBuf;
8419 if (isInHome () && codeOutBuf == &code->oBuf)
8420 codeOutBuf = &home->oBuf;
8421 printLine (_G.lines.head, codeOutBuf);
8422 if (_G.flushStatics)
8425 _G.flushStatics = 0;
8430 freeTrace(&_G.lines.trace);
8431 freeTrace(&_G.trace.aops);
8437 _isPairUsed (iCode * ic, PAIR_ID pairId)
8443 if (bitVectBitValue (ic->rMask, D_IDX))
8445 if (bitVectBitValue (ic->rMask, E_IDX))
8455 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8458 value *val = aop->aopu.aop_lit;
8460 wassert (aop->type == AOP_LIT);
8461 wassert (!IS_FLOAT (val->type));
8463 v = (unsigned long) floatFromVal (val);
8471 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8472 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));