1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
91 #include "SDCCglobl.h"
92 #include "SDCCpeeph.h"
97 /* This is the down and dirty file with all kinds of kludgy & hacky
98 stuff. This is what it is all about CODE GENERATION for a specific MCU.
99 Some of the routines may be reusable, will have to see */
101 /* Z80 calling convention description.
102 Parameters are passed right to left. As the stack grows downwards,
103 the parameters are arranged in left to right in memory.
104 Parameters may be passed in the HL and DE registers with one
106 PENDING: What if the parameter is a long?
107 Everything is caller saves. i.e. the caller must save any registers
108 that it wants to preserve over the call.
109 GB: The return value is returned in DEHL. DE is normally used as a
110 working register pair. Caller saves allows it to be used for a
112 va args functions do not use register parameters. All arguments
113 are passed on the stack.
114 IX is used as an index register to the top of the local variable
115 area. ix-0 is the top most local variable.
120 /* Set to enable debugging trace statements in the output assembly code. */
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129 { "c", "b", "e", "d" };
131 static char **_fReturn;
134 extern struct dbuf_s *codeOutBuf;
142 /** Enum covering all the possible register pairs.
161 } _pairs[NUM_PAIRS] = {
162 { "??1", "?2", "?3" },
167 { "iy", "iyl", "iyh" },
168 { "ix", "ixl", "ixh" }
172 #define ACC_NAME _pairs[PAIR_AF].h
182 /** Code generator persistent data.
186 /** Used to optimised setting up of a pair by remebering what it
187 contains and adjusting instead of reloading where possible.
216 const char *lastFunctionName;
217 iCode *current_iCode;
224 /** TRUE if the registers have already been saved. */
243 static const char *aopGet (asmop * aop, int offset, bool bit16);
245 static const char *aopNames[] = {
266 isLastUse (iCode *ic, operand *op)
268 bitVect *uses = bitVectCopy (OP_USES (op));
270 while (!bitVectIsZero (uses))
272 if (bitVectFirstBit (uses) == ic->key)
274 if (bitVectnBitsOn (uses) == 1)
283 bitVectUnSetBit (uses, bitVectFirstBit (uses));
303 _getTempPairName(void)
305 return _pairs[_getTempPairId()].name;
309 isPairInUse (PAIR_ID id, iCode *ic)
313 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
315 else if (id == PAIR_BC)
317 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
321 wassertl (0, "Only implemented for DE and BC");
327 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
331 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
335 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
339 wassertl (0, "Only implemented for DE");
345 getFreePairId (iCode *ic)
347 if (!isPairInUse (PAIR_BC, ic))
351 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
364 /* Clean up the line so that it is 'prettier' */
365 if (strchr (buf, ':'))
367 /* Is a label - cant do anything */
370 /* Change the first (and probably only) ' ' to a tab so
385 _newLineNode (const char *line)
389 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
390 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
396 _vemit2 (const char *szFormat, va_list ap)
401 dbuf_init(&dbuf, INITIAL_INLINEASM);
403 dbuf_tvprintf (&dbuf, szFormat, ap);
405 buffer = dbuf_c_str(&dbuf);
407 _tidyUp ((char *)buffer);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
413 _G.lines.current->isDebug = _G.lines.isDebug;
414 _G.lines.current->ic = _G.current_iCode;
415 _G.lines.current->isComment = (*buffer == ';');
421 emit2 (const char *szFormat,...)
425 va_start (ap, szFormat);
427 _vemit2 (szFormat, ap);
433 emitDebug (const char *szFormat,...)
439 va_start (ap, szFormat);
441 _vemit2 (szFormat, ap);
447 /*-----------------------------------------------------------------*/
448 /* z80_emitDebuggerSymbol - associate the current code location */
449 /* with a debugger symbol */
450 /*-----------------------------------------------------------------*/
452 z80_emitDebuggerSymbol (char * debugSym)
454 _G.lines.isDebug = 1;
455 emit2 ("%s !equ .", debugSym);
456 emit2 ("!global", debugSym);
457 _G.lines.isDebug = 0;
460 /*-----------------------------------------------------------------*/
461 /* emit2 - writes the code into a file : for now it is simple */
462 /*-----------------------------------------------------------------*/
464 _emit2 (const char *inst, const char *fmt,...)
467 char lb[INITIAL_INLINEASM];
474 sprintf (lb, "%s\t", inst);
475 vsprintf (lb + (strlen (lb)), fmt, ap);
478 vsprintf (lb, fmt, ap);
480 while (isspace (*lbp))
485 _G.lines.current = (_G.lines.current ?
486 connectLine (_G.lines.current, _newLineNode (lb)) :
487 (_G.lines.head = _newLineNode (lb)));
489 _G.lines.current->isInline = _G.lines.isInline;
490 _G.lines.current->ic = _G.current_iCode;
495 _emitMove(const char *to, const char *from)
497 if (STRCASECMP(to, from) != 0)
499 emit2("ld %s,%s", to, from);
504 // Could leave this to the peephole, but sometimes the peephole is inhibited.
509 aopDump(const char *plabel, asmop *aop)
515 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
520 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
523 for (i=aop->size-1;i>=0;i--)
524 *rbp++ = *(aop->aopu.aop_reg[i]->name);
526 emitDebug("; reg = %s", regbuf);
529 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
532 /* No information. */
538 _moveA(const char *moveFrom)
540 // Let the peephole optimiser take care of redundent loads
541 _emitMove(ACC_NAME, moveFrom);
551 getPairName (asmop * aop)
553 if (aop->type == AOP_REG)
555 switch (aop->aopu.aop_reg[0]->rIdx)
568 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
571 for (i = 0; i < NUM_PAIRS; i++)
573 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
575 return _pairs[i].name;
579 wassertl (0, "Tried to get the pair name of something that isn't a pair");
584 getPairId (asmop * aop)
588 if (aop->type == AOP_REG)
590 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
594 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
598 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
603 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
606 for (i = 0; i < NUM_PAIRS; i++)
608 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
618 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
622 return (getPairId (aop) != PAIR_INVALID);
625 /** Returns TRUE if the registers used in aop cannot be split into high
628 isUnsplitable (asmop * aop)
630 switch (getPairId (aop))
642 isPtrPair (asmop * aop)
644 PAIR_ID pairId = getPairId (aop);
657 spillPair (PAIR_ID pairId)
659 _G.pairs[pairId].last_type = AOP_INVALID;
660 _G.pairs[pairId].base = NULL;
663 /* Given a register name, spill the pair (if any) the register is part of */
665 spillPairReg (const char *regname)
667 if (strlen(regname)==1)
687 /** Push a register pair onto the stack */
689 genPairPush (asmop * aop)
691 emit2 ("push %s", getPairName (aop));
695 _push (PAIR_ID pairId)
697 emit2 ("push %s", _pairs[pairId].name);
698 _G.stack.pushed += 2;
702 _pop (PAIR_ID pairId)
704 if (pairId != PAIR_INVALID)
706 emit2 ("pop %s", _pairs[pairId].name);
707 _G.stack.pushed -= 2;
713 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
726 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
733 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
734 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
737 wassertl (0, "Tried to move a nonphysical pair");
739 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
740 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
741 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
745 /*-----------------------------------------------------------------*/
746 /* newAsmop - creates a new asmOp */
747 /*-----------------------------------------------------------------*/
749 newAsmop (short type)
753 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
758 /*-----------------------------------------------------------------*/
759 /* aopForSym - for a true symbol */
760 /*-----------------------------------------------------------------*/
762 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
769 wassert (sym->etype);
771 space = SPEC_OCLS (sym->etype);
773 /* if already has one */
779 /* Assign depending on the storage class */
780 if (sym->onStack || sym->iaccess)
782 /* The pointer that is used depends on how big the offset is.
783 Normally everything is AOP_STK, but for offsets of < -128 or
784 > 127 on the Z80 an extended stack pointer is used.
786 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
788 emitDebug ("; AOP_EXSTK for %s", sym->rname);
789 sym->aop = aop = newAsmop (AOP_EXSTK);
793 emitDebug ("; AOP_STK for %s", sym->rname);
794 sym->aop = aop = newAsmop (AOP_STK);
797 aop->size = getSize (sym->type);
798 aop->aopu.aop_stk = sym->stack;
802 /* special case for a function */
803 if (IS_FUNC (sym->type))
805 sym->aop = aop = newAsmop (AOP_IMMD);
806 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
811 if( IN_REGSP( space ))
812 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
815 /* if it is in direct space */
818 sym->aop = aop = newAsmop (AOP_SFR);
819 aop->aopu.aop_dir = sym->rname;
820 aop->size = getSize (sym->type);
821 emitDebug ("; AOP_SFR for %s", sym->rname);
826 { /*.p.t.20030716 adding SFR support to the Z80 port */
827 aop = newAsmop (AOP_SFR);
829 aop->aopu.aop_dir = sym->rname;
830 aop->size = getSize( sym->type );
831 aop->paged = FUNC_REGBANK(sym->type);
832 aop->bcInUse = isPairInUse( PAIR_BC, ic );
833 aop->deInUse = isPairInUse( PAIR_DE, ic );
834 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
840 /* only remaining is far space */
841 /* in which case DPTR gets the address */
844 emitDebug ("; AOP_HL for %s", sym->rname);
845 sym->aop = aop = newAsmop (AOP_HL);
849 sym->aop = aop = newAsmop (AOP_IY);
851 aop->size = getSize (sym->type);
852 aop->aopu.aop_dir = sym->rname;
854 /* if it is in code space */
855 if (IN_CODESPACE (space))
861 /*-----------------------------------------------------------------*/
862 /* aopForRemat - rematerialzes an object */
863 /*-----------------------------------------------------------------*/
865 aopForRemat (symbol * sym)
868 iCode *ic = sym->rematiCode;
869 asmop *aop = newAsmop (AOP_IMMD);
873 /* if plus or minus print the right hand side */
874 if (ic->op == '+' || ic->op == '-')
876 /* PENDING: for re-target */
877 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
880 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
883 /* we reached the end */
884 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
888 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
892 /*-----------------------------------------------------------------*/
893 /* regsInCommon - two operands have some registers in common */
894 /*-----------------------------------------------------------------*/
896 regsInCommon (operand * op1, operand * op2)
901 /* if they have registers in common */
902 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
905 sym1 = OP_SYMBOL (op1);
906 sym2 = OP_SYMBOL (op2);
908 if (sym1->nRegs == 0 || sym2->nRegs == 0)
911 for (i = 0; i < sym1->nRegs; i++)
917 for (j = 0; j < sym2->nRegs; j++)
922 if (sym2->regs[j] == sym1->regs[i])
930 /*-----------------------------------------------------------------*/
931 /* operandsEqu - equivalent */
932 /*-----------------------------------------------------------------*/
934 operandsEqu (operand * op1, operand * op2)
938 /* if they not symbols */
939 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
942 sym1 = OP_SYMBOL (op1);
943 sym2 = OP_SYMBOL (op2);
945 /* if both are itemps & one is spilt
946 and the other is not then false */
947 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
948 sym1->isspilt != sym2->isspilt)
951 /* if they are the same */
955 if (sym1->rname[0] && sym2->rname[0]
956 && strcmp (sym1->rname, sym2->rname) == 0)
959 /* if left is a tmp & right is not */
960 if (IS_ITEMP (op1) &&
963 (sym1->usl.spillLoc == sym2))
966 if (IS_ITEMP (op2) &&
970 (sym2->usl.spillLoc == sym1))
976 /*-----------------------------------------------------------------*/
977 /* sameRegs - two asmops have the same registers */
978 /*-----------------------------------------------------------------*/
980 sameRegs (asmop * aop1, asmop * aop2)
984 if (aop1->type == AOP_SFR ||
985 aop2->type == AOP_SFR)
991 if (aop1->type != AOP_REG ||
992 aop2->type != AOP_REG)
995 if (aop1->size != aop2->size)
998 for (i = 0; i < aop1->size; i++)
999 if (aop1->aopu.aop_reg[i] !=
1000 aop2->aopu.aop_reg[i])
1006 /*-----------------------------------------------------------------*/
1007 /* aopOp - allocates an asmop for an operand : */
1008 /*-----------------------------------------------------------------*/
1010 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1019 /* if this a literal */
1020 if (IS_OP_LITERAL (op))
1022 op->aop = aop = newAsmop (AOP_LIT);
1023 aop->aopu.aop_lit = op->operand.valOperand;
1024 aop->size = getSize (operandType (op));
1028 /* if already has a asmop then continue */
1031 if (op->aop->type == AOP_SFR)
1033 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1034 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1039 /* if the underlying symbol has a aop */
1040 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1042 op->aop = OP_SYMBOL (op)->aop;
1043 if (op->aop->type == AOP_SFR)
1045 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1046 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1051 /* if this is a true symbol */
1052 if (IS_TRUE_SYMOP (op))
1054 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1058 /* this is a temporary : this has
1064 e) can be a return use only */
1066 sym = OP_SYMBOL (op);
1068 /* if the type is a conditional */
1069 if (sym->regType == REG_CND)
1071 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1076 /* if it is spilt then two situations
1078 b) has a spill location */
1079 if (sym->isspilt || sym->nRegs == 0)
1081 /* rematerialize it NOW */
1084 sym->aop = op->aop = aop =
1086 aop->size = getSize (sym->type);
1093 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1094 aop->size = getSize (sym->type);
1095 for (i = 0; i < 4; i++)
1096 aop->aopu.aop_str[i] = _fReturn[i];
1102 if (sym->accuse == ACCUSE_A)
1104 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1105 aop->size = getSize (sym->type);
1106 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1108 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1110 else if (sym->accuse == ACCUSE_SCRATCH)
1112 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1113 aop->size = getSize (sym->type);
1114 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1115 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1116 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1118 else if (sym->accuse == ACCUSE_IY)
1120 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1121 aop->size = getSize (sym->type);
1122 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1123 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1124 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1128 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1133 if (sym->usl.spillLoc)
1135 asmop *oldAsmOp = NULL;
1137 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1139 /* force a new aop if sizes differ */
1140 oldAsmOp = sym->usl.spillLoc->aop;
1141 sym->usl.spillLoc->aop = NULL;
1143 sym->aop = op->aop = aop =
1144 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1145 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1147 /* Don't reuse the new aop, go with the last one */
1148 sym->usl.spillLoc->aop = oldAsmOp;
1150 aop->size = getSize (sym->type);
1154 /* else must be a dummy iTemp */
1155 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1156 aop->size = getSize (sym->type);
1160 /* must be in a register */
1161 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1162 aop->size = sym->nRegs;
1163 for (i = 0; i < sym->nRegs; i++)
1164 aop->aopu.aop_reg[i] = sym->regs[i];
1167 /*-----------------------------------------------------------------*/
1168 /* freeAsmop - free up the asmop given to an operand */
1169 /*----------------------------------------------------------------*/
1171 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1188 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1190 _pop (aop->aopu.aop_pairId);
1193 if (getPairId (aop) == PAIR_HL)
1195 spillPair (PAIR_HL);
1199 /* all other cases just dealloc */
1205 OP_SYMBOL (op)->aop = NULL;
1206 /* if the symbol has a spill */
1208 SPIL_LOC (op)->aop = NULL;
1215 isLitWord (asmop * aop)
1217 /* if (aop->size != 2)
1230 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1232 /* depending on type */
1238 /* PENDING: for re-target */
1241 tsprintf (buffer, sizeof(buffer),
1242 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1244 else if (offset == 0)
1246 tsprintf (buffer, sizeof(buffer),
1247 "%s", aop->aopu.aop_immd);
1251 tsprintf (buffer, sizeof(buffer),
1252 "%s + %d", aop->aopu.aop_immd, offset);
1254 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1258 value *val = aop->aopu.aop_lit;
1259 /* if it is a float then it gets tricky */
1260 /* otherwise it is fairly simple */
1261 if (!IS_FLOAT (val->type))
1263 unsigned long v = ulFromVal (val);
1269 else if (offset == 0)
1275 wassertl(0, "Encountered an invalid offset while fetching a literal");
1279 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1281 tsprintf (buffer, sizeof(buffer), "!constword", v);
1283 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1294 /* it is type float */
1295 fl.f = (float) floatFromVal (val);
1297 #ifdef WORDS_BIGENDIAN
1298 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1300 i = fl.c[offset] | (fl.c[offset+1]<<8);
1303 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1305 tsprintf (buffer, sizeof(buffer), "!constword", i);
1307 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1316 aopGetWord (asmop * aop, int offset)
1318 return aopGetLitWordLong (aop, offset, TRUE);
1322 isPtr (const char *s)
1324 if (!strcmp (s, "hl"))
1326 if (!strcmp (s, "ix"))
1328 if (!strcmp (s, "iy"))
1334 adjustPair (const char *pair, int *pold, int new)
1340 emit2 ("inc %s", pair);
1345 emit2 ("dec %s", pair);
1353 spillPair (PAIR_HL);
1354 spillPair (PAIR_IY);
1358 requiresHL (asmop * aop)
1374 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1376 const char *l, *base;
1377 const char *pair = _pairs[pairId].name;
1378 l = aopGetLitWordLong (left, offset, FALSE);
1379 base = aopGetLitWordLong (left, 0, FALSE);
1380 wassert (l && pair && base);
1384 if (pairId == PAIR_HL || pairId == PAIR_IY)
1386 if (_G.pairs[pairId].last_type == left->type)
1388 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1390 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1392 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1395 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1402 _G.pairs[pairId].last_type = left->type;
1403 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1404 _G.pairs[pairId].offset = offset;
1406 /* Both a lit on the right and a true symbol on the left */
1407 emit2 ("ld %s,!hashedstr", pair, l);
1411 makeFreePairId (iCode *ic, bool *pisUsed)
1417 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1421 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1439 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1441 /* if this is remateriazable */
1442 if (isLitWord (aop)) {
1443 fetchLitPair (pairId, aop, offset);
1447 if (getPairId (aop) == pairId)
1451 /* we need to get it byte by byte */
1452 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1453 aopGet (aop, offset, FALSE);
1454 switch (aop->size - offset) {
1456 emit2 ("ld l,!*hl");
1457 emit2 ("ld h,!immedbyte", 0);
1460 // PENDING: Requires that you are only fetching two bytes.
1463 emit2 ("ld h,!*hl");
1467 wassertl (0, "Attempted to fetch too much data into HL");
1471 else if (IS_Z80 && aop->type == AOP_IY) {
1472 /* Instead of fetching relative to IY, just grab directly
1473 from the address IY refers to */
1474 char *l = aopGetLitWordLong (aop, offset, FALSE);
1476 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1478 if (aop->size < 2) {
1479 emit2("ld %s,!zero", _pairs[pairId].h);
1482 else if (pairId == PAIR_IY)
1486 emit2 ("push %s", _pairs[getPairId(aop)].name);
1492 PAIR_ID id = makeFreePairId (ic, &isUsed);
1495 /* Can't load into parts, so load into HL then exchange. */
1496 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1497 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1498 emit2 ("push %s", _pairs[id].name);
1504 else if (isUnsplitable(aop))
1506 emit2("push %s", _pairs[getPairId(aop)].name);
1507 emit2("pop %s", _pairs[pairId].name);
1511 /* Swapping register contents within register pair */
1512 if(!strcmp(aopGet (aop, offset, FALSE), _pairs[pairId].h))
1514 emit2 ("ld a,%s",aopGet (aop, offset + 1, FALSE));
1515 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1516 emit2 ("ld %s,a", _pairs[pairId].h);
1520 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1521 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1524 /* PENDING: check? */
1525 if (pairId == PAIR_HL)
1526 spillPair (PAIR_HL);
1531 fetchPair (PAIR_ID pairId, asmop * aop)
1533 fetchPairLong (pairId, aop, NULL, 0);
1537 fetchHL (asmop * aop)
1539 fetchPair (PAIR_HL, aop);
1543 setupPairFromSP (PAIR_ID id, int offset)
1545 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1547 if (_G.preserveCarry)
1553 if (offset < INT8MIN || offset > INT8MAX)
1555 emit2 ("ld hl,!immedword", offset);
1556 emit2 ("add hl,sp");
1560 emit2 ("!ldahlsp", offset);
1563 if (_G.preserveCarry)
1571 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1576 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1577 fetchLitPair (pairId, aop, 0);
1581 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1583 fetchLitPair (pairId, aop, offset);
1584 _G.pairs[pairId].offset = offset;
1588 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1589 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1592 int offset = aop->aopu.aop_stk + _G.stack.offset;
1594 if (_G.pairs[pairId].last_type == aop->type &&
1595 _G.pairs[pairId].offset == offset)
1601 /* PENDING: Do this better. */
1602 if (_G.preserveCarry)
1604 sprintf (buffer, "%d", offset + _G.stack.pushed);
1605 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1606 emit2 ("add %s,sp", _pairs[pairId].name);
1607 _G.pairs[pairId].last_type = aop->type;
1608 _G.pairs[pairId].offset = offset;
1609 if (_G.preserveCarry)
1617 /* Doesnt include _G.stack.pushed */
1618 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1620 if (aop->aopu.aop_stk > 0)
1622 abso += _G.stack.param_offset;
1624 assert (pairId == PAIR_HL);
1625 /* In some cases we can still inc or dec hl */
1626 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1628 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1632 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1634 _G.pairs[pairId].offset = abso;
1639 if (pairId != aop->aopu.aop_pairId)
1640 genMovePairPair(aop->aopu.aop_pairId, pairId);
1641 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1647 _G.pairs[pairId].last_type = aop->type;
1653 emit2 ("!tlabeldef", key);
1654 _G.lines.current->isLabel = 1;
1658 /*-----------------------------------------------------------------*/
1659 /* aopGet - for fetching value of the aop */
1660 /*-----------------------------------------------------------------*/
1662 aopGet (asmop * aop, int offset, bool bit16)
1664 // char *s = buffer;
1666 /* offset is greater than size then zero */
1667 /* PENDING: this seems a bit screwed in some pointer cases. */
1668 if (offset > (aop->size - 1) &&
1669 aop->type != AOP_LIT)
1671 tsprintf (buffer, sizeof(buffer), "!zero");
1672 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1675 /* depending on type */
1679 tsprintf (buffer, sizeof(buffer), "!zero");
1680 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1683 /* PENDING: re-target */
1685 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1690 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1693 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1696 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1699 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1702 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1706 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1707 SNPRINTF (buffer, sizeof(buffer), "a");
1709 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1715 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1716 SNPRINTF (buffer, sizeof(buffer), "a");
1718 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1721 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1724 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1725 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1726 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1728 else if( z80_opts.port_mode == 180 )
1729 { /* z180 in0/out0 mode */
1730 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1734 emit2( "in a,(%s)", aop->aopu.aop_dir );
1737 SNPRINTF (buffer, sizeof(buffer), "a");
1739 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1743 return aop->aopu.aop_reg[offset]->name;
1747 setupPair (PAIR_HL, aop, offset);
1748 tsprintf (buffer, sizeof(buffer), "!*hl");
1750 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1754 setupPair (PAIR_IY, aop, offset);
1755 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1757 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1761 setupPair (PAIR_IY, aop, offset);
1762 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1764 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1769 setupPair (PAIR_HL, aop, offset);
1770 tsprintf (buffer, sizeof(buffer), "!*hl");
1774 if (aop->aopu.aop_stk >= 0)
1775 offset += _G.stack.param_offset;
1776 tsprintf (buffer, sizeof(buffer),
1777 "!*ixx", aop->aopu.aop_stk + offset);
1780 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1783 wassertl (0, "Tried to fetch from a bit variable");
1792 tsprintf(buffer, sizeof(buffer), "!zero");
1793 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1797 wassert (offset < 2);
1798 return aop->aopu.aop_str[offset];
1801 return aopLiteral (aop->aopu.aop_lit, offset);
1805 unsigned long v = aop->aopu.aop_simplelit;
1808 tsprintf (buffer, sizeof(buffer),
1809 "!immedbyte", (unsigned int) v & 0xff);
1811 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1815 return aop->aopu.aop_str[offset];
1818 setupPair (aop->aopu.aop_pairId, aop, offset);
1819 if (aop->aopu.aop_pairId==PAIR_IX)
1820 SNPRINTF (buffer, sizeof(buffer),
1822 else if (aop->aopu.aop_pairId==PAIR_IY)
1823 SNPRINTF (buffer, sizeof(buffer),
1826 SNPRINTF (buffer, sizeof(buffer),
1827 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1829 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1834 wassertl (0, "aopget got unsupported aop->type");
1839 isRegString (const char *s)
1841 if (!strcmp (s, "b") ||
1853 isConstant (const char *s)
1855 /* This is a bit of a hack... */
1856 return (*s == '#' || *s == '$');
1860 canAssignToPtr (const char *s)
1862 if (isRegString (s))
1869 /*-----------------------------------------------------------------*/
1870 /* aopPut - puts a string for a aop */
1871 /*-----------------------------------------------------------------*/
1873 aopPut (asmop * aop, const char *s, int offset)
1877 if (aop->size && offset > (aop->size - 1))
1879 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1880 "aopPut got offset > aop->size");
1885 tsprintf(buffer2, sizeof(buffer2), s);
1888 /* will assign value to value */
1889 /* depending on where it is ofcourse */
1893 _moveA (s); /* in case s is volatile */
1899 if (strcmp (s, "a"))
1900 emit2 ("ld a,%s", s);
1901 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1908 if (strcmp (s, "a"))
1909 emit2 ("ld a,%s", s);
1910 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1913 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1920 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1921 && s[0] != 'h' && s[0] != 'l'))
1923 emit2( "ld a,%s", s );
1927 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1928 emit2( "out (c),%s", s );
1933 spillPair (PAIR_BC);
1935 else if( z80_opts.port_mode == 180 )
1936 { /* z180 in0/out0 mode */
1937 emit2( "ld a,%s", s );
1938 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1942 emit2( "ld a,%s", s );
1943 emit2( "out (%s),a", aop->aopu.aop_dir );
1949 if (!strcmp (s, "!*hl"))
1950 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1953 aop->aopu.aop_reg[offset]->name, s);
1954 spillPairReg(aop->aopu.aop_reg[offset]->name);
1959 if (!canAssignToPtr (s))
1961 emit2 ("ld a,%s", s);
1962 setupPair (PAIR_IY, aop, offset);
1963 emit2 ("ld !*iyx,a", offset);
1967 setupPair (PAIR_IY, aop, offset);
1968 emit2 ("ld !*iyx,%s", offset, s);
1974 /* PENDING: for re-target */
1975 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1977 emit2 ("ld a,!*hl");
1980 setupPair (PAIR_HL, aop, offset);
1982 emit2 ("ld !*hl,%s", s);
1987 if (!canAssignToPtr (s))
1989 emit2 ("ld a,%s", s);
1990 setupPair (PAIR_IY, aop, offset);
1991 emit2 ("ld !*iyx,a", offset);
1995 setupPair (PAIR_IY, aop, offset);
1996 emit2 ("ld !*iyx,%s", offset, s);
2003 /* PENDING: re-target */
2004 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2006 emit2 ("ld a,!*hl");
2009 setupPair (PAIR_HL, aop, offset);
2010 if (!canAssignToPtr (s))
2012 emit2 ("ld a,%s", s);
2013 emit2 ("ld !*hl,a");
2016 emit2 ("ld !*hl,%s", s);
2020 if (aop->aopu.aop_stk >= 0)
2021 offset += _G.stack.param_offset;
2022 if (!canAssignToPtr (s))
2024 emit2 ("ld a,%s", s);
2025 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2029 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2035 /* if bit variable */
2036 if (!aop->aopu.aop_dir)
2038 emit2 ("ld a,!zero");
2043 /* In bit space but not in C - cant happen */
2044 wassertl (0, "Tried to write into a bit variable");
2050 if (strcmp (aop->aopu.aop_str[offset], s))
2052 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2054 spillPairReg(aop->aopu.aop_str[offset]);
2059 if (!offset && (strcmp (s, "acc") == 0))
2063 wassertl (0, "Tried to access past the end of A");
2067 if (strcmp (aop->aopu.aop_str[offset], s))
2069 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2070 spillPairReg(aop->aopu.aop_str[offset]);
2076 wassert (offset < 2);
2077 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2078 spillPairReg(aop->aopu.aop_str[offset]);
2082 setupPair (aop->aopu.aop_pairId, aop, offset);
2083 if (aop->aopu.aop_pairId==PAIR_IX)
2084 emit2 ("ld !*ixx,%s", 0, s);
2085 else if (aop->aopu.aop_pairId==PAIR_IY)
2086 emit2 ("ld !*iyx,%s", 0, s);
2088 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2092 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2093 "aopPut got unsupported aop->type");
2098 #define AOP(op) op->aop
2099 #define AOP_TYPE(op) AOP(op)->type
2100 #define AOP_SIZE(op) AOP(op)->size
2101 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2102 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2105 commitPair (asmop * aop, PAIR_ID id)
2107 /* PENDING: Verify this. */
2108 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2112 aopPut (aop, "a", 0);
2113 aopPut (aop, "d", 1);
2118 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2120 char *l = aopGetLitWordLong (aop, 0, FALSE);
2123 emit2 ("ld (%s),%s", l, _pairs[id].name);
2127 aopPut (aop, _pairs[id].l, 0);
2128 aopPut (aop, _pairs[id].h, 1);
2133 /*-----------------------------------------------------------------*/
2134 /* getDataSize - get the operand data size */
2135 /*-----------------------------------------------------------------*/
2137 getDataSize (operand * op)
2140 size = AOP_SIZE (op);
2144 wassertl (0, "Somehow got a three byte data pointer");
2149 /*-----------------------------------------------------------------*/
2150 /* movLeft2Result - move byte from left to result */
2151 /*-----------------------------------------------------------------*/
2153 movLeft2Result (operand * left, int offl,
2154 operand * result, int offr, int sign)
2158 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2160 l = aopGet (AOP (left), offl, FALSE);
2164 aopPut (AOP (result), l, offr);
2168 if (getDataSize (left) == offl + 1)
2170 emit2 ("ld a,%s", l);
2171 aopPut (AOP (result), "a", offr);
2178 movLeft2ResultLong (operand * left, int offl,
2179 operand * result, int offr, int sign,
2184 movLeft2Result (left, offl, result, offr, sign);
2188 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2189 wassertl (size == 2, "Only implemented for two bytes or one");
2191 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2193 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2194 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2196 spillPair (PAIR_HL);
2198 else if ( getPairId ( AOP (result)) == PAIR_IY)
2200 PAIR_ID id = getPairId (AOP (left));
2201 if (id != PAIR_INVALID)
2203 emit2("push %s", _pairs[id].name);
2214 movLeft2Result (left, offl, result, offr, sign);
2215 movLeft2Result (left, offl+1, result, offr+1, sign);
2220 /** Put Acc into a register set
2223 outAcc (operand * result)
2226 size = getDataSize (result);
2229 aopPut (AOP (result), "a", 0);
2232 /* unsigned or positive */
2235 aopPut (AOP (result), "!zero", offset++);
2240 /** Take the value in carry and put it into a register
2243 outBitC (operand * result)
2245 /* if the result is bit */
2246 if (AOP_TYPE (result) == AOP_CRY)
2248 if (!IS_OP_RUONLY (result))
2249 aopPut (AOP (result), "c", 0);
2253 emit2 ("ld a,!zero");
2259 /*-----------------------------------------------------------------*/
2260 /* toBoolean - emit code for orl a,operator(sizeop) */
2261 /*-----------------------------------------------------------------*/
2263 _toBoolean (operand * oper)
2265 int size = AOP_SIZE (oper);
2269 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2272 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2276 if (AOP (oper)->type != AOP_ACC)
2279 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2285 /*-----------------------------------------------------------------*/
2286 /* genNot - generate code for ! operation */
2287 /*-----------------------------------------------------------------*/
2292 /* assign asmOps to operand & result */
2293 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2294 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2296 /* if in bit space then a special case */
2297 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2299 wassertl (0, "Tried to negate a bit");
2302 _toBoolean (IC_LEFT (ic));
2307 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2308 emit2 ("sub a,!one");
2309 outBitC (IC_RESULT (ic));
2311 /* release the aops */
2312 freeAsmop (IC_LEFT (ic), NULL, ic);
2313 freeAsmop (IC_RESULT (ic), NULL, ic);
2316 /*-----------------------------------------------------------------*/
2317 /* genCpl - generate code for complement */
2318 /*-----------------------------------------------------------------*/
2326 /* assign asmOps to operand & result */
2327 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2328 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2330 /* if both are in bit space then
2332 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2333 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2335 wassertl (0, "Left and the result are in bit space");
2338 size = AOP_SIZE (IC_RESULT (ic));
2341 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2344 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2347 /* release the aops */
2348 freeAsmop (IC_LEFT (ic), NULL, ic);
2349 freeAsmop (IC_RESULT (ic), NULL, ic);
2353 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2360 store de into result
2365 store de into result
2367 const char *first = isAdd ? "add" : "sub";
2368 const char *later = isAdd ? "adc" : "sbc";
2370 wassertl (IS_GB, "Code is only relevent to the gbz80");
2371 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2373 fetchPair (PAIR_DE, left);
2376 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2379 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2382 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2383 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2385 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2386 aopGet (right, MSB24, FALSE);
2390 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2393 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2395 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2396 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2400 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2402 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2405 /*-----------------------------------------------------------------*/
2406 /* genUminusFloat - unary minus for floating points */
2407 /*-----------------------------------------------------------------*/
2409 genUminusFloat (operand * op, operand * result)
2411 int size, offset = 0;
2413 emitDebug("; genUminusFloat");
2415 /* for this we just need to flip the
2416 first bit then copy the rest in place */
2417 size = AOP_SIZE (op) - 1;
2419 _moveA(aopGet (AOP (op), MSB32, FALSE));
2421 emit2("xor a,!immedbyte", 0x80);
2422 aopPut (AOP (result), "a", MSB32);
2426 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2431 /*-----------------------------------------------------------------*/
2432 /* genUminus - unary minus code generation */
2433 /*-----------------------------------------------------------------*/
2435 genUminus (iCode * ic)
2438 sym_link *optype, *rtype;
2441 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2442 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2444 /* if both in bit space then special
2446 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2447 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2449 wassertl (0, "Left and right are in bit space");
2453 optype = operandType (IC_LEFT (ic));
2454 rtype = operandType (IC_RESULT (ic));
2456 /* if float then do float stuff */
2457 if (IS_FLOAT (optype))
2459 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2463 /* otherwise subtract from zero */
2464 size = AOP_SIZE (IC_LEFT (ic));
2466 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2468 /* Create a new asmop with value zero */
2469 asmop *azero = newAsmop (AOP_SIMPLELIT);
2470 azero->aopu.aop_simplelit = 0;
2472 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2480 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2481 emit2 ("ld a,!zero");
2482 emit2 ("sbc a,%s", l);
2483 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2486 /* if any remaining bytes in the result */
2487 /* we just need to propagate the sign */
2488 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2493 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2497 /* release the aops */
2498 freeAsmop (IC_LEFT (ic), NULL, ic);
2499 freeAsmop (IC_RESULT (ic), NULL, ic);
2502 /*-----------------------------------------------------------------*/
2503 /* assignResultValue - */
2504 /*-----------------------------------------------------------------*/
2506 assignResultValue (operand * oper)
2508 int size = AOP_SIZE (oper);
2511 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2512 topInA = requiresHL (AOP (oper));
2514 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2516 /* We do it the hard way here. */
2518 aopPut (AOP (oper), _fReturn[0], 0);
2519 aopPut (AOP (oper), _fReturn[1], 1);
2521 aopPut (AOP (oper), _fReturn[0], 2);
2522 aopPut (AOP (oper), _fReturn[1], 3);
2526 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2527 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2530 _emitMove ("a", _fReturn[size-1]);
2531 _emitMove (_fReturn[size-1], _fReturn[size]);
2532 _emitMove (_fReturn[size], "a");
2533 aopPut (AOP (oper), _fReturn[size], size-1);
2538 aopPut (AOP (oper), _fReturn[size], size);
2543 /** Simple restore that doesn't take into account what is used in the
2547 _restoreRegsAfterCall(void)
2549 if (_G.stack.pushedDE)
2552 _G.stack.pushedDE = FALSE;
2554 if (_G.stack.pushedBC)
2557 _G.stack.pushedBC = FALSE;
2559 _G.saves.saved = FALSE;
2563 _saveRegsForCall(iCode *ic, int sendSetSize)
2566 o Stack parameters are pushed before this function enters
2567 o DE and BC may be used in this function.
2568 o HL and DE may be used to return the result.
2569 o HL and DE may be used to send variables.
2570 o DE and BC may be used to store the result value.
2571 o HL may be used in computing the sent value of DE
2572 o The iPushes for other parameters occur before any addSets
2574 Logic: (to be run inside the first iPush or if none, before sending)
2575 o Compute if DE and/or BC are in use over the call
2576 o Compute if DE is used in the send set
2577 o Compute if DE and/or BC are used to hold the result value
2578 o If (DE is used, or in the send set) and is not used in the result, push.
2579 o If BC is used and is not in the result, push
2581 o If DE is used in the send set, fetch
2582 o If HL is used in the send set, fetch
2586 if (_G.saves.saved == FALSE) {
2587 bool deInUse, bcInUse;
2589 bool bcInRet = FALSE, deInRet = FALSE;
2592 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2593 z80_rUmaskForOp (IC_RESULT(ic)));
2595 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2596 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2598 deSending = (sendSetSize > 1);
2600 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2602 if (bcInUse && bcInRet == FALSE) {
2604 _G.stack.pushedBC = TRUE;
2606 if (deInUse && deInRet == FALSE) {
2608 _G.stack.pushedDE = TRUE;
2611 _G.saves.saved = TRUE;
2614 /* Already saved. */
2618 /*-----------------------------------------------------------------*/
2619 /* genIpush - genrate code for pushing this gets a little complex */
2620 /*-----------------------------------------------------------------*/
2622 genIpush (iCode * ic)
2624 int size, offset = 0;
2627 /* if this is not a parm push : ie. it is spill push
2628 and spill push is always done on the local stack */
2631 wassertl(0, "Encountered an unsupported spill push.");
2635 if (_G.saves.saved == FALSE) {
2636 /* Caller saves, and this is the first iPush. */
2637 /* Scan ahead until we find the function that we are pushing parameters to.
2638 Count the number of addSets on the way to figure out what registers
2639 are used in the send set.
2642 iCode *walk = ic->next;
2645 if (walk->op == SEND) {
2648 else if (walk->op == CALL || walk->op == PCALL) {
2657 _saveRegsForCall(walk, nAddSets);
2660 /* Already saved by another iPush. */
2663 /* then do the push */
2664 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2666 size = AOP_SIZE (IC_LEFT (ic));
2668 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2670 _G.stack.pushed += 2;
2671 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2677 fetchHL (AOP (IC_LEFT (ic)));
2679 spillPair (PAIR_HL);
2680 _G.stack.pushed += 2;
2685 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2687 spillPair (PAIR_HL);
2688 _G.stack.pushed += 2;
2689 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2691 spillPair (PAIR_HL);
2692 _G.stack.pushed += 2;
2698 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2700 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2702 emit2 ("ld a,(%s)", l);
2707 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2708 if (!strcmp(l, "b"))
2710 else if (!strcmp(l, "d"))
2712 else if (!strcmp(l, "h"))
2716 emit2 ("ld a,%s", l);
2725 freeAsmop (IC_LEFT (ic), NULL, ic);
2728 /*-----------------------------------------------------------------*/
2729 /* genIpop - recover the registers: can happen only for spilling */
2730 /*-----------------------------------------------------------------*/
2732 genIpop (iCode * ic)
2737 /* if the temp was not pushed then */
2738 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2741 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2742 size = AOP_SIZE (IC_LEFT (ic));
2743 offset = (size - 1);
2744 if (isPair (AOP (IC_LEFT (ic))))
2746 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2754 spillPair (PAIR_HL);
2755 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2759 freeAsmop (IC_LEFT (ic), NULL, ic);
2762 /* This is quite unfortunate */
2764 setArea (int inHome)
2767 static int lastArea = 0;
2769 if (_G.in_home != inHome) {
2771 const char *sz = port->mem.code_name;
2772 port->mem.code_name = "HOME";
2773 emit2("!area", CODE_NAME);
2774 port->mem.code_name = sz;
2777 emit2("!area", CODE_NAME); */
2778 _G.in_home = inHome;
2789 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2793 symbol *sym = OP_SYMBOL (op);
2795 if (sym->isspilt || sym->nRegs == 0)
2798 aopOp (op, ic, FALSE, FALSE);
2801 if (aop->type == AOP_REG)
2804 for (i = 0; i < aop->size; i++)
2806 if (pairId == PAIR_DE)
2808 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2809 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2811 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2814 else if (pairId == PAIR_BC)
2816 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2817 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2819 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2829 freeAsmop (IC_LEFT (ic), NULL, ic);
2833 /** Emit the code for a call statement
2836 emitCall (iCode * ic, bool ispcall)
2838 bool bInRet, cInRet, dInRet, eInRet;
2839 sym_link *dtype = operandType (IC_LEFT (ic));
2841 /* if caller saves & we have not saved then */
2847 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2849 /* if send set is not empty then assign */
2854 int nSend = elementsInSet(_G.sendSet);
2855 bool swapped = FALSE;
2857 int _z80_sendOrder[] = {
2862 /* Check if the parameters are swapped. If so route through hl instead. */
2863 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2865 sic = setFirstItem(_G.sendSet);
2866 sic = setNextItem(_G.sendSet);
2868 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2869 /* The second send value is loaded from one the one that holds the first
2870 send, i.e. it is overwritten. */
2871 /* Cache the first in HL, and load the second from HL instead. */
2872 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2873 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2879 for (sic = setFirstItem (_G.sendSet); sic;
2880 sic = setNextItem (_G.sendSet))
2883 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2885 size = AOP_SIZE (IC_LEFT (sic));
2886 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2887 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2889 // PENDING: Mild hack
2890 if (swapped == TRUE && send == 1) {
2892 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2895 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2897 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2900 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2904 freeAsmop (IC_LEFT (sic), NULL, sic);
2911 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2913 werror (W_INDIR_BANKED);
2915 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2917 if (isLitWord (AOP (IC_LEFT (ic))))
2919 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2923 symbol *rlbl = newiTempLabel (NULL);
2924 spillPair (PAIR_HL);
2925 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2927 _G.stack.pushed += 2;
2929 fetchHL (AOP (IC_LEFT (ic)));
2931 emit2 ("!tlabeldef", (rlbl->key + 100));
2932 _G.lines.current->isLabel = 1;
2933 _G.stack.pushed -= 2;
2935 freeAsmop (IC_LEFT (ic), NULL, ic);
2939 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2940 OP_SYMBOL (IC_LEFT (ic))->rname :
2941 OP_SYMBOL (IC_LEFT (ic))->name;
2942 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2944 emit2 ("call banked_call");
2945 emit2 ("!dws", name);
2946 emit2 ("!dw !bankimmeds", name);
2951 emit2 ("call %s", name);
2956 /* Mark the registers as restored. */
2957 _G.saves.saved = FALSE;
2959 /* if we need assign a result value */
2960 if ((IS_ITEMP (IC_RESULT (ic)) &&
2961 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2962 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2963 IS_TRUE_SYMOP (IC_RESULT (ic)))
2965 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2967 assignResultValue (IC_RESULT (ic));
2969 freeAsmop (IC_RESULT (ic), NULL, ic);
2972 /* adjust the stack for parameters if required */
2975 int i = ic->parmBytes;
2977 _G.stack.pushed -= i;
2980 emit2 ("!ldaspsp", i);
2987 emit2 ("ld iy,!immedword", i);
2988 emit2 ("add iy,sp");
3009 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3010 bInRet = bitVectBitValue(result, B_IDX);
3011 cInRet = bitVectBitValue(result, C_IDX);
3012 dInRet = bitVectBitValue(result, D_IDX);
3013 eInRet = bitVectBitValue(result, E_IDX);
3023 if (_G.stack.pushedDE)
3025 if (dInRet && eInRet)
3027 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3031 /* Only restore E */
3038 /* Only restore D */
3046 _G.stack.pushedDE = FALSE;
3049 if (_G.stack.pushedBC)
3051 if (bInRet && cInRet)
3053 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3057 /* Only restore C */
3064 /* Only restore B */
3072 _G.stack.pushedBC = FALSE;
3076 /*-----------------------------------------------------------------*/
3077 /* genCall - generates a call statement */
3078 /*-----------------------------------------------------------------*/
3080 genCall (iCode * ic)
3082 emitCall (ic, FALSE);
3085 /*-----------------------------------------------------------------*/
3086 /* genPcall - generates a call by pointer statement */
3087 /*-----------------------------------------------------------------*/
3089 genPcall (iCode * ic)
3091 emitCall (ic, TRUE);
3094 /*-----------------------------------------------------------------*/
3095 /* resultRemat - result is rematerializable */
3096 /*-----------------------------------------------------------------*/
3098 resultRemat (iCode * ic)
3100 if (SKIP_IC (ic) || ic->op == IFX)
3103 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3105 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3106 if (sym->remat && !POINTER_SET (ic))
3113 extern set *publics;
3115 /*-----------------------------------------------------------------*/
3116 /* genFunction - generated code for function entry */
3117 /*-----------------------------------------------------------------*/
3119 genFunction (iCode * ic)
3123 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3126 bool bcInUse = FALSE;
3127 bool deInUse = FALSE;
3129 setArea (IFFUNC_NONBANKED (sym->type));
3131 /* PENDING: Reset the receive offset as it
3132 doesn't seem to get reset anywhere else.
3134 _G.receiveOffset = 0;
3136 /* Record the last function name for debugging. */
3137 _G.lastFunctionName = sym->rname;
3139 /* Create the function header */
3140 emit2 ("!functionheader", sym->name);
3141 if (!IS_STATIC(sym->etype))
3143 sprintf (buffer, "%s_start", sym->rname);
3144 emit2 ("!labeldef", buffer);
3145 _G.lines.current->isLabel = 1;
3147 emit2 ("!functionlabeldef", sym->rname);
3148 _G.lines.current->isLabel = 1;
3150 ftype = operandType (IC_LEFT (ic));
3152 if (IFFUNC_ISNAKED(ftype))
3154 emitDebug("; naked function: no prologue.");
3158 /* if this is an interrupt service routine
3159 then save all potentially used registers. */
3160 if (IFFUNC_ISISR (sym->type))
3162 /* If critical function then turn interrupts off */
3163 /* except when no interrupt number is given then it implies the NMI handler */
3164 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3173 /* This is a non-ISR function.
3174 If critical function then turn interrupts off */
3175 if (IFFUNC_ISCRITICAL (sym->type))
3183 //get interrupt enable flag IFF2 into P/O
3192 if (options.profile)
3194 emit2 ("!profileenter");
3197 /* PENDING: callee-save etc */
3199 _G.stack.param_offset = 0;
3201 if (z80_opts.calleeSavesBC)
3206 /* Detect which registers are used. */
3207 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3210 for (i = 0; i < sym->regsUsed->size; i++)
3212 if (bitVectBitValue (sym->regsUsed, i))
3226 /* Other systems use DE as a temporary. */
3237 _G.stack.param_offset += 2;
3240 _G.calleeSaves.pushedBC = bcInUse;
3245 _G.stack.param_offset += 2;
3248 _G.calleeSaves.pushedDE = deInUse;
3250 /* adjust the stack for the function */
3251 _G.stack.last = sym->stack;
3254 for (sym = setFirstItem (istack->syms); sym;
3255 sym = setNextItem (istack->syms))
3257 if (sym->_isparm && !IS_REGPARM (sym->etype))
3263 sym = OP_SYMBOL (IC_LEFT (ic));
3265 _G.omitFramePtr = options.ommitFramePtr;
3266 if (IS_Z80 && !stackParm && !sym->stack)
3268 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3269 /* the above !sym->stack condition can be removed. -- EEP */
3271 emit2 ("!ldaspsp", -sym->stack);
3272 _G.omitFramePtr = TRUE;
3274 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3275 emit2 ("!enterxl", sym->stack);
3276 else if (sym->stack)
3277 emit2 ("!enterx", sym->stack);
3281 _G.stack.offset = sym->stack;
3284 /*-----------------------------------------------------------------*/
3285 /* genEndFunction - generates epilogue for functions */
3286 /*-----------------------------------------------------------------*/
3288 genEndFunction (iCode * ic)
3290 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3292 if (IFFUNC_ISNAKED(sym->type))
3294 emitDebug("; naked function: no epilogue.");
3298 /* PENDING: calleeSave */
3299 if (IS_Z80 && _G.omitFramePtr)
3301 if (_G.stack.offset)
3302 emit2 ("!ldaspsp", _G.stack.offset);
3304 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3306 emit2 ("!leavexl", _G.stack.offset);
3308 else if (_G.stack.offset)
3310 emit2 ("!leavex", _G.stack.offset);
3317 if (_G.calleeSaves.pushedDE)
3320 _G.calleeSaves.pushedDE = FALSE;
3323 if (_G.calleeSaves.pushedBC)
3326 _G.calleeSaves.pushedBC = FALSE;
3329 if (options.profile)
3331 emit2 ("!profileexit");
3334 /* if this is an interrupt service routine
3335 then save all potentially used registers. */
3336 if (IFFUNC_ISISR (sym->type))
3340 /* If critical function then turn interrupts back on */
3341 /* except when no interrupt number is given then it implies the NMI handler */
3342 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3349 /* This is a non-ISR function.
3350 If critical function then turn interrupts back on */
3351 if (IFFUNC_ISCRITICAL (sym->type))
3359 symbol *tlbl = newiTempLabel (NULL);
3362 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3363 //don't enable interrupts as they were off before
3364 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3366 emit2 ("!tlabeldef", (tlbl->key + 100));
3367 _G.lines.current->isLabel = 1;
3372 if (options.debug && currFunc)
3374 debugFile->writeEndFunction (currFunc, ic, 1);
3377 if (IFFUNC_ISISR (sym->type))
3379 /* "critical interrupt" is used to imply NMI handler */
3380 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3387 /* Both banked and non-banked just ret */
3391 if (!IS_STATIC(sym->etype))
3393 sprintf (buffer, "%s_end", sym->rname);
3394 emit2 ("!labeldef", buffer);
3395 _G.lines.current->isLabel = 1;
3398 _G.flushStatics = 1;
3399 _G.stack.pushed = 0;
3400 _G.stack.offset = 0;
3403 /*-----------------------------------------------------------------*/
3404 /* genRet - generate code for return statement */
3405 /*-----------------------------------------------------------------*/
3410 /* Errk. This is a hack until I can figure out how
3411 to cause dehl to spill on a call */
3412 int size, offset = 0;
3414 /* if we have no return value then
3415 just generate the "ret" */
3419 /* we have something to return then
3420 move the return value into place */
3421 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3422 size = AOP_SIZE (IC_LEFT (ic));
3424 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3427 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3431 emit2 ("ld de,%s", l);
3435 emit2 ("ld hl,%s", l);
3441 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3445 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3447 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3448 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3454 l = aopGet (AOP (IC_LEFT (ic)), offset,
3456 if (strcmp (_fReturn[offset], l))
3457 emit2 ("ld %s,%s", _fReturn[offset], l);
3462 freeAsmop (IC_LEFT (ic), NULL, ic);
3465 /* generate a jump to the return label
3466 if the next is not the return statement */
3467 if (!(ic->next && ic->next->op == LABEL &&
3468 IC_LABEL (ic->next) == returnLabel))
3470 emit2 ("jp !tlabel", returnLabel->key + 100);
3473 /*-----------------------------------------------------------------*/
3474 /* genLabel - generates a label */
3475 /*-----------------------------------------------------------------*/
3477 genLabel (iCode * ic)
3479 /* special case never generate */
3480 if (IC_LABEL (ic) == entryLabel)
3483 emitLabel (IC_LABEL (ic)->key + 100);
3486 /*-----------------------------------------------------------------*/
3487 /* genGoto - generates a ljmp */
3488 /*-----------------------------------------------------------------*/
3490 genGoto (iCode * ic)
3492 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3495 /*-----------------------------------------------------------------*/
3496 /* genPlusIncr :- does addition with increment if possible */
3497 /*-----------------------------------------------------------------*/
3499 genPlusIncr (iCode * ic)
3501 unsigned int icount;
3502 unsigned int size = getDataSize (IC_RESULT (ic));
3503 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3505 /* will try to generate an increment */
3506 /* if the right side is not a literal
3508 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3511 emitDebug ("; genPlusIncr");
3513 icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3515 /* If result is a pair */
3516 if (resultId != PAIR_INVALID)
3518 if (isLitWord (AOP (IC_LEFT (ic))))
3520 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3523 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3525 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3527 PAIR_ID freep = getFreePairId (ic);
3528 if (freep != PAIR_INVALID)
3530 fetchPair (freep, AOP (IC_RIGHT (ic)));
3531 emit2 ("add hl,%s", _pairs[freep].name);
3537 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3538 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3545 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3549 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3553 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3558 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3560 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3561 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3565 /* if the literal value of the right hand side
3566 is greater than 4 then it is not worth it */
3570 /* if increment 16 bits in register */
3571 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3577 symbol *tlbl = NULL;
3578 tlbl = newiTempLabel (NULL);
3581 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3584 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3587 emitLabel (tlbl->key + 100);
3591 /* if the sizes are greater than 1 then we cannot */
3592 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3593 AOP_SIZE (IC_LEFT (ic)) > 1)
3596 /* If the result is in a register then we can load then increment.
3598 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3600 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3603 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3608 /* we can if the aops of the left & result match or
3609 if they are in registers and the registers are the
3611 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3615 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3623 /*-----------------------------------------------------------------*/
3624 /* outBitAcc - output a bit in acc */
3625 /*-----------------------------------------------------------------*/
3627 outBitAcc (operand * result)
3629 symbol *tlbl = newiTempLabel (NULL);
3630 /* if the result is a bit */
3631 if (AOP_TYPE (result) == AOP_CRY)
3633 wassertl (0, "Tried to write A into a bit");
3637 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3638 emit2 ("ld a,!one");
3639 emitLabel (tlbl->key + 100);
3645 couldDestroyCarry (asmop *aop)
3649 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3658 shiftIntoPair (int idx, asmop *aop)
3660 PAIR_ID id = PAIR_INVALID;
3662 wassertl (IS_Z80, "Only implemented for the Z80");
3663 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3665 emitDebug ("; Shift into pair idx %u", idx);
3671 setupPair (PAIR_HL, aop, 0);
3676 setupPair (PAIR_IY, aop, 0);
3678 emit2 ("pop %s", _pairs[id].name);
3682 setupPair (PAIR_IY, aop, 0);
3685 wassertl (0, "Internal error - hit default case");
3688 aop->type = AOP_PAIRPTR;
3689 aop->aopu.aop_pairId = id;
3690 _G.pairs[id].offset = 0;
3691 _G.pairs[id].last_type = aop->type;
3695 setupToPreserveCarry (iCode * ic)
3697 asmop *left = AOP (IC_LEFT (ic));
3698 asmop *right = AOP (IC_RIGHT (ic));
3699 asmop *result = AOP (IC_RESULT (ic));
3701 wassert (left && right);
3705 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3707 shiftIntoPair (0, right);
3708 /* check result again, in case right == result */
3709 if (couldDestroyCarry (result))
3711 if (!isPairInUse (PAIR_DE, ic))
3712 shiftIntoPair (1, result);
3714 shiftIntoPair (2, result);
3717 else if (couldDestroyCarry (right))
3719 if (getPairId (result) == PAIR_HL)
3720 _G.preserveCarry = TRUE;
3722 shiftIntoPair (0, right);
3724 else if (couldDestroyCarry (result))
3726 shiftIntoPair (0, result);
3735 /*-----------------------------------------------------------------*/
3736 /* genPlus - generates code for addition */
3737 /*-----------------------------------------------------------------*/
3739 genPlus (iCode * ic)
3741 int size, offset = 0;
3743 /* special cases :- */
3745 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3746 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3747 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3749 /* Swap the left and right operands if:
3751 if literal, literal on the right or
3752 if left requires ACC or right is already
3755 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3756 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3757 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3759 operand *t = IC_RIGHT (ic);
3760 IC_RIGHT (ic) = IC_LEFT (ic);
3764 /* if both left & right are in bit
3766 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3767 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3770 wassertl (0, "Tried to add two bits");
3773 /* if left in bit space & right literal */
3774 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3775 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3777 /* Can happen I guess */
3778 wassertl (0, "Tried to add a bit to a literal");
3781 /* if I can do an increment instead
3782 of add then GOOD for ME */
3783 if (genPlusIncr (ic) == TRUE)
3786 size = getDataSize (IC_RESULT (ic));
3788 /* Special case when left and right are constant */
3789 if (isPair (AOP (IC_RESULT (ic))))
3792 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3793 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3795 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3801 sprintf (buffer, "#(%s + %s)", left, right);
3802 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3807 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3809 /* Fetch into HL then do the add */
3810 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3811 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3813 spillPair (PAIR_HL);
3815 if (left == PAIR_HL && right != PAIR_INVALID)
3817 emit2 ("add hl,%s", _pairs[right].name);
3820 else if (right == PAIR_HL && left != PAIR_INVALID)
3822 emit2 ("add hl,%s", _pairs[left].name);
3825 else if (right != PAIR_INVALID && right != PAIR_HL)
3827 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3828 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3831 else if (left != PAIR_INVALID && left != PAIR_HL)
3833 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3834 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3843 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3845 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3846 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3848 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3853 ld hl,sp+n trashes C so we can't afford to do it during an
3854 add with stack based variables. Worst case is:
3867 So you can't afford to load up hl if either left, right, or result
3868 is on the stack (*sigh*) The alt is:
3876 Combinations in here are:
3877 * If left or right are in bc then the loss is small - trap later
3878 * If the result is in bc then the loss is also small
3882 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3883 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3884 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3886 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3887 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3888 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3889 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3891 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3893 /* Swap left and right */
3894 operand *t = IC_RIGHT (ic);
3895 IC_RIGHT (ic) = IC_LEFT (ic);
3898 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3900 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3901 emit2 ("add hl,bc");
3905 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3906 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3907 emit2 ("add hl,de");
3909 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3915 /* Be paranoid on the GB with 4 byte variables due to how C
3916 can be trashed by lda hl,n(sp).
3918 _gbz80_emitAddSubLong (ic, TRUE);
3923 setupToPreserveCarry (ic);
3927 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3929 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3932 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3935 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3939 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3942 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3945 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3947 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3951 _G.preserveCarry = FALSE;
3952 freeAsmop (IC_LEFT (ic), NULL, ic);
3953 freeAsmop (IC_RIGHT (ic), NULL, ic);
3954 freeAsmop (IC_RESULT (ic), NULL, ic);
3957 /*-----------------------------------------------------------------*/
3958 /* genMinusDec :- does subtraction with deccrement if possible */
3959 /*-----------------------------------------------------------------*/
3961 genMinusDec (iCode * ic)
3963 unsigned int icount;
3964 unsigned int size = getDataSize (IC_RESULT (ic));
3966 /* will try to generate an increment */
3967 /* if the right side is not a literal we cannot */
3968 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3971 /* if the literal value of the right hand side
3972 is greater than 4 then it is not worth it */
3973 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3976 size = getDataSize (IC_RESULT (ic));
3978 /* if decrement 16 bits in register */
3979 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3980 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3983 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3987 /* If result is a pair */
3988 if (isPair (AOP (IC_RESULT (ic))))
3990 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3992 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3996 /* if increment 16 bits in register */
3997 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4001 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4004 emit2 ("dec %s", _getTempPairName());
4007 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4013 /* if the sizes are greater than 1 then we cannot */
4014 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4015 AOP_SIZE (IC_LEFT (ic)) > 1)
4018 /* we can if the aops of the left & result match or if they are in
4019 registers and the registers are the same */
4020 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4023 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4030 /*-----------------------------------------------------------------*/
4031 /* genMinus - generates code for subtraction */
4032 /*-----------------------------------------------------------------*/
4034 genMinus (iCode * ic)
4036 int size, offset = 0;
4037 unsigned long lit = 0L;
4039 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4040 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4041 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4043 /* special cases :- */
4044 /* if both left & right are in bit space */
4045 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4046 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4048 wassertl (0, "Tried to subtract two bits");
4052 /* if I can do an decrement instead of subtract then GOOD for ME */
4053 if (genMinusDec (ic) == TRUE)
4056 size = getDataSize (IC_RESULT (ic));
4058 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4063 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4067 /* Same logic as genPlus */
4070 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4071 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4072 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4074 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4075 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4076 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4077 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4079 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4080 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4082 if (left == PAIR_INVALID && right == PAIR_INVALID)
4087 else if (right == PAIR_INVALID)
4089 else if (left == PAIR_INVALID)
4092 fetchPair (left, AOP (IC_LEFT (ic)));
4093 /* Order is important. Right may be HL */
4094 fetchPair (right, AOP (IC_RIGHT (ic)));
4096 emit2 ("ld a,%s", _pairs[left].l);
4097 emit2 ("sub a,%s", _pairs[right].l);
4099 emit2 ("ld a,%s", _pairs[left].h);
4100 emit2 ("sbc a,%s", _pairs[right].h);
4102 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4104 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4106 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4112 /* Be paranoid on the GB with 4 byte variables due to how C
4113 can be trashed by lda hl,n(sp).
4115 _gbz80_emitAddSubLong (ic, FALSE);
4120 setupToPreserveCarry (ic);
4122 /* if literal, add a,#-lit, else normal subb */
4125 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4126 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4130 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4133 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4137 /* first add without previous c */
4139 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4141 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4143 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4146 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4147 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4148 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4150 wassertl (0, "Tried to subtract on a long pointer");
4154 _G.preserveCarry = FALSE;
4155 freeAsmop (IC_LEFT (ic), NULL, ic);
4156 freeAsmop (IC_RIGHT (ic), NULL, ic);
4157 freeAsmop (IC_RESULT (ic), NULL, ic);
4160 /*-----------------------------------------------------------------*/
4161 /* genMult - generates code for multiplication */
4162 /*-----------------------------------------------------------------*/
4164 genMult (iCode * ic)
4168 /* If true then the final operation should be a subtract */
4169 bool active = FALSE;
4172 /* Shouldn't occur - all done through function calls */
4173 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4174 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4175 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4177 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4179 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4180 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4181 AOP_SIZE (IC_RESULT (ic)) > 2)
4183 wassertl (0, "Multiplication is handled through support function calls");
4186 /* Swap left and right such that right is a literal */
4187 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4189 operand *t = IC_RIGHT (ic);
4190 IC_RIGHT (ic) = IC_LEFT (ic);
4194 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4196 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4197 // wassertl (val > 0, "Multiply must be positive");
4198 wassertl (val != 1, "Can't multiply by 1");
4200 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4202 _G.stack.pushedDE = TRUE;
4205 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4207 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4218 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4223 /* Fully unroled version of mul.s. Not the most efficient.
4225 for (count = 0; count < 16; count++)
4227 if (count != 0 && active)
4229 emit2 ("add hl,hl");
4233 if (active == FALSE)
4241 emit2 ("add hl,de");
4250 if (IS_Z80 && _G.stack.pushedDE)
4253 _G.stack.pushedDE = FALSE;
4257 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4259 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4261 freeAsmop (IC_LEFT (ic), NULL, ic);
4262 freeAsmop (IC_RIGHT (ic), NULL, ic);
4263 freeAsmop (IC_RESULT (ic), NULL, ic);
4266 /*-----------------------------------------------------------------*/
4267 /* genDiv - generates code for division */
4268 /*-----------------------------------------------------------------*/
4272 /* Shouldn't occur - all done through function calls */
4273 wassertl (0, "Division is handled through support function calls");
4276 /*-----------------------------------------------------------------*/
4277 /* genMod - generates code for division */
4278 /*-----------------------------------------------------------------*/
4282 /* Shouldn't occur - all done through function calls */
4286 /*-----------------------------------------------------------------*/
4287 /* genIfxJump :- will create a jump depending on the ifx */
4288 /*-----------------------------------------------------------------*/
4290 genIfxJump (iCode * ic, char *jval)
4295 /* if true label then we jump if condition
4299 jlbl = IC_TRUE (ic);
4300 if (!strcmp (jval, "a"))
4304 else if (!strcmp (jval, "c"))
4308 else if (!strcmp (jval, "nc"))
4312 else if (!strcmp (jval, "m"))
4316 else if (!strcmp (jval, "p"))
4322 /* The buffer contains the bit on A that we should test */
4328 /* false label is present */
4329 jlbl = IC_FALSE (ic);
4330 if (!strcmp (jval, "a"))
4334 else if (!strcmp (jval, "c"))
4338 else if (!strcmp (jval, "nc"))
4342 else if (!strcmp (jval, "m"))
4346 else if (!strcmp (jval, "p"))
4352 /* The buffer contains the bit on A that we should test */
4356 /* Z80 can do a conditional long jump */
4357 if (!strcmp (jval, "a"))
4361 else if (!strcmp (jval, "c"))
4364 else if (!strcmp (jval, "nc"))
4367 else if (!strcmp (jval, "m"))
4370 else if (!strcmp (jval, "p"))
4375 emit2 ("bit %s,a", jval);
4377 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4379 /* mark the icode as generated */
4385 _getPairIdName (PAIR_ID id)
4387 return _pairs[id].name;
4392 /* if unsigned char cmp with lit, just compare */
4394 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4396 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4399 emit2 ("xor a,!immedbyte", 0x80);
4400 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4403 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4405 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4407 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4408 // Pull left into DE and right into HL
4409 aopGet (AOP(left), LSB, FALSE);
4412 aopGet (AOP(right), LSB, FALSE);
4416 if (size == 0 && sign)
4418 // Highest byte when signed needs the bits flipped
4421 emit2 ("ld a,(de)");
4422 emit2 ("xor !immedbyte", 0x80);
4424 emit2 ("ld a,(hl)");
4425 emit2 ("xor !immedbyte", 0x80);
4429 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4433 emit2 ("ld a,(de)");
4434 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4444 spillPair (PAIR_HL);
4446 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4448 setupPair (PAIR_HL, AOP (left), 0);
4449 aopGet (AOP(right), LSB, FALSE);
4453 if (size == 0 && sign)
4455 // Highest byte when signed needs the bits flipped
4458 emit2 ("ld a,(hl)");
4459 emit2 ("xor !immedbyte", 0x80);
4461 emit2 ("ld a,%d(iy)", offset);
4462 emit2 ("xor !immedbyte", 0x80);
4466 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4470 emit2 ("ld a,(hl)");
4471 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4480 spillPair (PAIR_HL);
4481 spillPair (PAIR_IY);
4485 if (AOP_TYPE (right) == AOP_LIT)
4487 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4488 /* optimize if(x < 0) or if(x >= 0) */
4493 /* No sign so it's always false */
4498 /* Just load in the top most bit */
4499 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4500 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4502 genIfxJump (ifx, "7");
4514 /* First setup h and l contaning the top most bytes XORed */
4515 bool fDidXor = FALSE;
4516 if (AOP_TYPE (left) == AOP_LIT)
4518 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4519 emit2 ("ld %s,!immedbyte", _fTmp[0],
4520 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4524 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4525 emit2 ("xor a,!immedbyte", 0x80);
4526 emit2 ("ld %s,a", _fTmp[0]);
4529 if (AOP_TYPE (right) == AOP_LIT)
4531 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4532 emit2 ("ld %s,!immedbyte", _fTmp[1],
4533 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4537 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4538 emit2 ("xor a,!immedbyte", 0x80);
4539 emit2 ("ld %s,a", _fTmp[1]);
4545 /* Do a long subtract */
4548 _moveA (aopGet (AOP (left), offset, FALSE));
4550 if (sign && size == 0)
4552 emit2 ("ld a,%s", _fTmp[0]);
4553 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4557 /* Subtract through, propagating the carry */
4558 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4566 /** Generic compare for > or <
4569 genCmp (operand * left, operand * right,
4570 operand * result, iCode * ifx, int sign)
4572 int size, offset = 0;
4573 unsigned long lit = 0L;
4575 /* if left & right are bit variables */
4576 if (AOP_TYPE (left) == AOP_CRY &&
4577 AOP_TYPE (right) == AOP_CRY)
4579 /* Cant happen on the Z80 */
4580 wassertl (0, "Tried to compare two bits");
4584 /* Do a long subtract of right from left. */
4585 size = max (AOP_SIZE (left), AOP_SIZE (right));
4587 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4589 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4590 // Pull left into DE and right into HL
4591 aopGet (AOP(left), LSB, FALSE);
4594 aopGet (AOP(right), LSB, FALSE);
4598 emit2 ("ld a,(de)");
4599 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4608 spillPair (PAIR_HL);
4612 if (AOP_TYPE (right) == AOP_LIT)
4614 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4615 /* optimize if(x < 0) or if(x >= 0) */
4620 /* No sign so it's always false */
4625 /* Just load in the top most bit */
4626 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4627 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4629 genIfxJump (ifx, "7");
4640 genIfxJump (ifx, "nc");
4651 _moveA (aopGet (AOP (left), offset, FALSE));
4652 /* Subtract through, propagating the carry */
4653 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4659 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4663 /* Shift the sign bit up into carry */
4670 /* if the result is used in the next
4671 ifx conditional branch then generate
4672 code a little differently */
4680 genIfxJump (ifx, "c");
4684 genIfxJump (ifx, "m");
4689 genIfxJump (ifx, "c");
4696 /* Shift the sign bit up into carry */
4701 /* leave the result in acc */
4705 /*-----------------------------------------------------------------*/
4706 /* genCmpGt :- greater than comparison */
4707 /*-----------------------------------------------------------------*/
4709 genCmpGt (iCode * ic, iCode * ifx)
4711 operand *left, *right, *result;
4712 sym_link *letype, *retype;
4715 left = IC_LEFT (ic);
4716 right = IC_RIGHT (ic);
4717 result = IC_RESULT (ic);
4719 letype = getSpec (operandType (left));
4720 retype = getSpec (operandType (right));
4721 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4722 /* assign the amsops */
4723 aopOp (left, ic, FALSE, FALSE);
4724 aopOp (right, ic, FALSE, FALSE);
4725 aopOp (result, ic, TRUE, FALSE);
4727 genCmp (right, left, result, ifx, sign);
4729 freeAsmop (left, NULL, ic);
4730 freeAsmop (right, NULL, ic);
4731 freeAsmop (result, NULL, ic);
4734 /*-----------------------------------------------------------------*/
4735 /* genCmpLt - less than comparisons */
4736 /*-----------------------------------------------------------------*/
4738 genCmpLt (iCode * ic, iCode * ifx)
4740 operand *left, *right, *result;
4741 sym_link *letype, *retype;
4744 left = IC_LEFT (ic);
4745 right = IC_RIGHT (ic);
4746 result = IC_RESULT (ic);
4748 letype = getSpec (operandType (left));
4749 retype = getSpec (operandType (right));
4750 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4752 /* assign the amsops */
4753 aopOp (left, ic, FALSE, FALSE);
4754 aopOp (right, ic, FALSE, FALSE);
4755 aopOp (result, ic, TRUE, FALSE);
4757 genCmp (left, right, result, ifx, sign);
4759 freeAsmop (left, NULL, ic);
4760 freeAsmop (right, NULL, ic);
4761 freeAsmop (result, NULL, ic);
4764 /*-----------------------------------------------------------------*/
4765 /* gencjneshort - compare and jump if not equal */
4766 /* returns pair that still needs to be popped */
4767 /*-----------------------------------------------------------------*/
4769 gencjneshort (operand * left, operand * right, symbol * lbl)
4771 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4773 unsigned long lit = 0L;
4775 /* Swap the left and right if it makes the computation easier */
4776 if (AOP_TYPE (left) == AOP_LIT)
4783 /* if the right side is a literal then anything goes */
4784 if (AOP_TYPE (right) == AOP_LIT)
4786 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4789 _moveA (aopGet (AOP (left), offset, FALSE));
4794 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4801 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4807 _moveA (aopGet (AOP (left), offset, FALSE));
4808 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4811 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4812 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4817 /* if the right side is in a register or
4818 pointed to by HL, IX or IY */
4819 else if (AOP_TYPE (right) == AOP_REG ||
4820 AOP_TYPE (right) == AOP_HL ||
4821 AOP_TYPE (right) == AOP_IY ||
4822 AOP_TYPE (right) == AOP_STK ||
4823 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4824 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4825 AOP_IS_PAIRPTR (right, PAIR_IY))
4829 _moveA (aopGet (AOP (left), offset, FALSE));
4830 if (AOP_TYPE (right) == AOP_LIT &&
4831 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4834 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4838 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4839 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4844 /* right is in direct space or a pointer reg, need both a & b */
4848 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4850 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4851 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4859 emit2 ("; direct compare");
4860 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4861 _moveA (aopGet (AOP (right), offset, FALSE));
4862 emit2 ("sub %s", _pairs[pair].l);
4863 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4868 return PAIR_INVALID;
4871 /*-----------------------------------------------------------------*/
4872 /* gencjne - compare and jump if not equal */
4873 /*-----------------------------------------------------------------*/
4875 gencjne (operand * left, operand * right, symbol * lbl)
4877 symbol *tlbl = newiTempLabel (NULL);
4879 PAIR_ID pop = gencjneshort (left, right, lbl);
4882 emit2 ("ld a,!one");
4883 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4884 emitLabel (lbl->key + 100);
4886 emitLabel (tlbl->key + 100);
4890 /*-----------------------------------------------------------------*/
4891 /* genCmpEq - generates code for equal to */
4892 /*-----------------------------------------------------------------*/
4894 genCmpEq (iCode * ic, iCode * ifx)
4896 operand *left, *right, *result;
4898 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4899 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4900 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4902 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4904 /* Swap operands if it makes the operation easier. ie if:
4905 1. Left is a literal.
4907 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4909 operand *t = IC_RIGHT (ic);
4910 IC_RIGHT (ic) = IC_LEFT (ic);
4914 if (ifx && !AOP_SIZE (result))
4917 /* if they are both bit variables */
4918 if (AOP_TYPE (left) == AOP_CRY &&
4919 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4921 wassertl (0, "Tried to compare two bits");
4926 tlbl = newiTempLabel (NULL);
4927 pop = gencjneshort (left, right, tlbl);
4931 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4932 emitLabel (tlbl->key + 100);
4937 /* PENDING: do this better */
4938 symbol *lbl = newiTempLabel (NULL);
4940 emit2 ("!shortjp !tlabel", lbl->key + 100);
4941 emitLabel (tlbl->key + 100);
4943 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4944 emitLabel (lbl->key + 100);
4947 /* mark the icode as generated */
4952 /* if they are both bit variables */
4953 if (AOP_TYPE (left) == AOP_CRY &&
4954 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4956 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4962 gencjne (left, right, newiTempLabel (NULL));
4963 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4970 genIfxJump (ifx, "a");
4973 /* if the result is used in an arithmetic operation
4974 then put the result in place */
4975 if (AOP_TYPE (result) != AOP_CRY)
4980 /* leave the result in acc */
4984 freeAsmop (left, NULL, ic);
4985 freeAsmop (right, NULL, ic);
4986 freeAsmop (result, NULL, ic);
4989 /*-----------------------------------------------------------------*/
4990 /* ifxForOp - returns the icode containing the ifx for operand */
4991 /*-----------------------------------------------------------------*/
4993 ifxForOp (operand * op, iCode * ic)
4995 /* if true symbol then needs to be assigned */
4996 if (IS_TRUE_SYMOP (op))
4999 /* if this has register type condition and
5000 the next instruction is ifx with the same operand
5001 and live to of the operand is upto the ifx only then */
5003 ic->next->op == IFX &&
5004 IC_COND (ic->next)->key == op->key &&
5005 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5011 /*-----------------------------------------------------------------*/
5012 /* genAndOp - for && operation */
5013 /*-----------------------------------------------------------------*/
5015 genAndOp (iCode * ic)
5017 operand *left, *right, *result;
5020 /* note here that && operations that are in an if statement are
5021 taken away by backPatchLabels only those used in arthmetic
5022 operations remain */
5023 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5024 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5025 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5027 /* if both are bit variables */
5028 if (AOP_TYPE (left) == AOP_CRY &&
5029 AOP_TYPE (right) == AOP_CRY)
5031 wassertl (0, "Tried to and two bits");
5035 tlbl = newiTempLabel (NULL);
5037 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5039 emitLabel (tlbl->key + 100);
5043 freeAsmop (left, NULL, ic);
5044 freeAsmop (right, NULL, ic);
5045 freeAsmop (result, NULL, ic);
5048 /*-----------------------------------------------------------------*/
5049 /* genOrOp - for || operation */
5050 /*-----------------------------------------------------------------*/
5052 genOrOp (iCode * ic)
5054 operand *left, *right, *result;
5057 /* note here that || operations that are in an
5058 if statement are taken away by backPatchLabels
5059 only those used in arthmetic operations remain */
5060 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5061 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5062 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5064 /* if both are bit variables */
5065 if (AOP_TYPE (left) == AOP_CRY &&
5066 AOP_TYPE (right) == AOP_CRY)
5068 wassertl (0, "Tried to OR two bits");
5072 tlbl = newiTempLabel (NULL);
5074 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5076 emitLabel (tlbl->key + 100);
5080 freeAsmop (left, NULL, ic);
5081 freeAsmop (right, NULL, ic);
5082 freeAsmop (result, NULL, ic);
5085 /*-----------------------------------------------------------------*/
5086 /* isLiteralBit - test if lit == 2^n */
5087 /*-----------------------------------------------------------------*/
5089 isLiteralBit (unsigned long lit)
5091 unsigned long pw[32] =
5092 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5093 0x100L, 0x200L, 0x400L, 0x800L,
5094 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5095 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5096 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5097 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5098 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5101 for (idx = 0; idx < 32; idx++)
5107 /*-----------------------------------------------------------------*/
5108 /* jmpTrueOrFalse - */
5109 /*-----------------------------------------------------------------*/
5111 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5113 // ugly but optimized by peephole
5116 symbol *nlbl = newiTempLabel (NULL);
5117 emit2 ("jp !tlabel", nlbl->key + 100);
5118 emitLabel (tlbl->key + 100);
5119 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5120 emitLabel (nlbl->key + 100);
5124 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5125 emitLabel (tlbl->key + 100);
5130 /*-----------------------------------------------------------------*/
5131 /* genAnd - code for and */
5132 /*-----------------------------------------------------------------*/
5134 genAnd (iCode * ic, iCode * ifx)
5136 operand *left, *right, *result;
5137 int size, offset = 0;
5138 unsigned long lit = 0L;
5141 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5142 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5143 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5145 /* if left is a literal & right is not then exchange them */
5146 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5147 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5149 operand *tmp = right;
5154 /* if result = right then exchange them */
5155 if (sameRegs (AOP (result), AOP (right)))
5157 operand *tmp = right;
5162 /* if right is bit then exchange them */
5163 if (AOP_TYPE (right) == AOP_CRY &&
5164 AOP_TYPE (left) != AOP_CRY)
5166 operand *tmp = right;
5170 if (AOP_TYPE (right) == AOP_LIT)
5171 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5173 size = AOP_SIZE (result);
5175 if (AOP_TYPE (left) == AOP_CRY)
5177 wassertl (0, "Tried to perform an AND with a bit as an operand");
5181 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5182 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5183 if ((AOP_TYPE (right) == AOP_LIT) &&
5184 (AOP_TYPE (result) == AOP_CRY) &&
5185 (AOP_TYPE (left) != AOP_CRY))
5187 symbol *tlbl = newiTempLabel (NULL);
5188 int sizel = AOP_SIZE (left);
5191 /* PENDING: Test case for this. */
5196 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5198 _moveA (aopGet (AOP (left), offset, FALSE));
5199 if (bytelit != 0x0FFL)
5201 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5208 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5212 // bit = left & literal
5216 emit2 ("!tlabeldef", tlbl->key + 100);
5217 _G.lines.current->isLabel = 1;
5219 // if(left & literal)
5224 jmpTrueOrFalse (ifx, tlbl);
5232 /* if left is same as result */
5233 if (sameRegs (AOP (result), AOP (left)))
5235 for (; size--; offset++)
5237 if (AOP_TYPE (right) == AOP_LIT)
5239 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5244 aopPut (AOP (result), "!zero", offset);
5247 _moveA (aopGet (AOP (left), offset, FALSE));
5249 aopGet (AOP (right), offset, FALSE));
5250 aopPut (AOP (left), "a", offset);
5257 if (AOP_TYPE (left) == AOP_ACC)
5259 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5263 _moveA (aopGet (AOP (left), offset, FALSE));
5265 aopGet (AOP (right), offset, FALSE));
5266 aopPut (AOP (left), "a", offset);
5273 // left & result in different registers
5274 if (AOP_TYPE (result) == AOP_CRY)
5276 wassertl (0, "Tried to AND where the result is in carry");
5280 for (; (size--); offset++)
5283 // result = left & right
5284 if (AOP_TYPE (right) == AOP_LIT)
5286 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5288 aopPut (AOP (result),
5289 aopGet (AOP (left), offset, FALSE),
5293 else if (bytelit == 0)
5295 aopPut (AOP (result), "!zero", offset);
5299 // faster than result <- left, anl result,right
5300 // and better if result is SFR
5301 if (AOP_TYPE (left) == AOP_ACC)
5302 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5305 _moveA (aopGet (AOP (left), offset, FALSE));
5307 aopGet (AOP (right), offset, FALSE));
5309 aopPut (AOP (result), "a", offset);
5316 freeAsmop (left, NULL, ic);
5317 freeAsmop (right, NULL, ic);
5318 freeAsmop (result, NULL, ic);
5321 /*-----------------------------------------------------------------*/
5322 /* genOr - code for or */
5323 /*-----------------------------------------------------------------*/
5325 genOr (iCode * ic, iCode * ifx)
5327 operand *left, *right, *result;
5328 int size, offset = 0;
5329 unsigned long lit = 0L;
5332 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5333 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5334 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5336 /* if left is a literal & right is not then exchange them */
5337 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5338 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5340 operand *tmp = right;
5345 /* if result = right then exchange them */
5346 if (sameRegs (AOP (result), AOP (right)))
5348 operand *tmp = right;
5353 /* if right is bit then exchange them */
5354 if (AOP_TYPE (right) == AOP_CRY &&
5355 AOP_TYPE (left) != AOP_CRY)
5357 operand *tmp = right;
5361 if (AOP_TYPE (right) == AOP_LIT)
5362 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5364 size = AOP_SIZE (result);
5366 if (AOP_TYPE (left) == AOP_CRY)
5368 wassertl (0, "Tried to OR where left is a bit");
5372 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5373 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5374 if ((AOP_TYPE (right) == AOP_LIT) &&
5375 (AOP_TYPE (result) == AOP_CRY) &&
5376 (AOP_TYPE (left) != AOP_CRY))
5378 symbol *tlbl = newiTempLabel (NULL);
5379 int sizel = AOP_SIZE (left);
5383 wassertl (0, "Result is assigned to a bit");
5385 /* PENDING: Modeled after the AND code which is inefficient. */
5388 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5390 _moveA (aopGet (AOP (left), offset, FALSE));
5391 /* OR with any literal is the same as OR with itself. */
5393 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5399 jmpTrueOrFalse (ifx, tlbl);
5404 /* if left is same as result */
5405 if (sameRegs (AOP (result), AOP (left)))
5407 for (; size--; offset++)
5409 if (AOP_TYPE (right) == AOP_LIT)
5411 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5415 _moveA (aopGet (AOP (left), offset, FALSE));
5417 aopGet (AOP (right), offset, FALSE));
5418 aopPut (AOP (result), "a", offset);
5423 if (AOP_TYPE (left) == AOP_ACC)
5424 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5427 _moveA (aopGet (AOP (left), offset, FALSE));
5429 aopGet (AOP (right), offset, FALSE));
5430 aopPut (AOP (result), "a", offset);
5437 // left & result in different registers
5438 if (AOP_TYPE (result) == AOP_CRY)
5440 wassertl (0, "Result of OR is in a bit");
5443 for (; (size--); offset++)
5446 // result = left & right
5447 if (AOP_TYPE (right) == AOP_LIT)
5449 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5451 aopPut (AOP (result),
5452 aopGet (AOP (left), offset, FALSE),
5457 // faster than result <- left, anl result,right
5458 // and better if result is SFR
5459 if (AOP_TYPE (left) == AOP_ACC)
5460 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5463 _moveA (aopGet (AOP (left), offset, FALSE));
5465 aopGet (AOP (right), offset, FALSE));
5467 aopPut (AOP (result), "a", offset);
5468 /* PENDING: something weird is going on here. Add exception. */
5469 if (AOP_TYPE (result) == AOP_ACC)
5475 freeAsmop (left, NULL, ic);
5476 freeAsmop (right, NULL, ic);
5477 freeAsmop (result, NULL, ic);
5480 /*-----------------------------------------------------------------*/
5481 /* genXor - code for xclusive or */
5482 /*-----------------------------------------------------------------*/
5484 genXor (iCode * ic, iCode * ifx)
5486 operand *left, *right, *result;
5487 int size, offset = 0;
5488 unsigned long lit = 0L;
5490 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5491 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5492 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5494 /* if left is a literal & right is not then exchange them */
5495 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5496 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5498 operand *tmp = right;
5503 /* if result = right then exchange them */
5504 if (sameRegs (AOP (result), AOP (right)))
5506 operand *tmp = right;
5511 /* if right is bit then exchange them */
5512 if (AOP_TYPE (right) == AOP_CRY &&
5513 AOP_TYPE (left) != AOP_CRY)
5515 operand *tmp = right;
5519 if (AOP_TYPE (right) == AOP_LIT)
5520 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5522 size = AOP_SIZE (result);
5524 if (AOP_TYPE (left) == AOP_CRY)
5526 wassertl (0, "Tried to XOR a bit");
5530 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5531 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5532 if ((AOP_TYPE (right) == AOP_LIT) &&
5533 (AOP_TYPE (result) == AOP_CRY) &&
5534 (AOP_TYPE (left) != AOP_CRY))
5536 symbol *tlbl = newiTempLabel (NULL);
5537 int sizel = AOP_SIZE (left);
5541 /* PENDING: Test case for this. */
5542 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5546 _moveA (aopGet (AOP (left), offset, FALSE));
5547 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5548 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5553 jmpTrueOrFalse (ifx, tlbl);
5557 wassertl (0, "Result of XOR was destined for a bit");
5562 /* if left is same as result */
5563 if (sameRegs (AOP (result), AOP (left)))
5565 for (; size--; offset++)
5567 if (AOP_TYPE (right) == AOP_LIT)
5569 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5573 _moveA (aopGet (AOP (left), offset, FALSE));
5575 aopGet (AOP (right), offset, FALSE));
5576 aopPut (AOP (result), "a", offset);
5581 if (AOP_TYPE (left) == AOP_ACC)
5583 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5587 _moveA (aopGet (AOP (left), offset, FALSE));
5589 aopGet (AOP (right), offset, FALSE));
5590 aopPut (AOP (result), "a", offset);
5597 // left & result in different registers
5598 if (AOP_TYPE (result) == AOP_CRY)
5600 wassertl (0, "Result of XOR is in a bit");
5603 for (; (size--); offset++)
5606 // result = left & right
5607 if (AOP_TYPE (right) == AOP_LIT)
5609 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5611 aopPut (AOP (result),
5612 aopGet (AOP (left), offset, FALSE),
5617 // faster than result <- left, anl result,right
5618 // and better if result is SFR
5619 if (AOP_TYPE (left) == AOP_ACC)
5621 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5625 _moveA (aopGet (AOP (left), offset, FALSE));
5627 aopGet (AOP (right), offset, FALSE));
5629 aopPut (AOP (result), "a", offset);
5634 freeAsmop (left, NULL, ic);
5635 freeAsmop (right, NULL, ic);
5636 freeAsmop (result, NULL, ic);
5639 /*-----------------------------------------------------------------*/
5640 /* genInline - write the inline code out */
5641 /*-----------------------------------------------------------------*/
5643 genInline (iCode * ic)
5645 char *buffer, *bp, *bp1;
5646 bool inComment = FALSE;
5648 _G.lines.isInline += (!options.asmpeep);
5650 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5652 /* emit each line as a code */
5670 /* Add \n for labels, not dirs such as c:\mydir */
5671 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5689 _G.lines.isInline -= (!options.asmpeep);
5693 /*-----------------------------------------------------------------*/
5694 /* genRRC - rotate right with carry */
5695 /*-----------------------------------------------------------------*/
5702 /*-----------------------------------------------------------------*/
5703 /* genRLC - generate code for rotate left with carry */
5704 /*-----------------------------------------------------------------*/
5711 /*-----------------------------------------------------------------*/
5712 /* genGetHbit - generates code get highest order bit */
5713 /*-----------------------------------------------------------------*/
5715 genGetHbit (iCode * ic)
5717 operand *left, *result;
5718 left = IC_LEFT (ic);
5719 result = IC_RESULT (ic);
5721 aopOp (left, ic, FALSE, FALSE);
5722 aopOp (result, ic, FALSE, FALSE);
5724 /* get the highest order byte into a */
5725 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5727 if (AOP_TYPE (result) == AOP_CRY)
5735 emit2 ("and a,!one");
5740 freeAsmop (left, NULL, ic);
5741 freeAsmop (result, NULL, ic);
5745 emitRsh2 (asmop *aop, int size, int is_signed)
5751 const char *l = aopGet (aop, size, FALSE);
5754 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5764 /*-----------------------------------------------------------------*/
5765 /* shiftR2Left2Result - shift right two bytes from left to result */
5766 /*-----------------------------------------------------------------*/
5768 shiftR2Left2Result (operand * left, int offl,
5769 operand * result, int offr,
5770 int shCount, int is_signed)
5775 movLeft2Result (left, offl, result, offr, 0);
5776 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5781 /* if (AOP(result)->type == AOP_REG) { */
5783 tlbl = newiTempLabel (NULL);
5785 /* Left is already in result - so now do the shift */
5786 /* Optimizing for speed by default. */
5787 if (!optimize.codeSize || shCount <= 2)
5791 emitRsh2 (AOP (result), size, is_signed);
5796 emit2 ("ld a,!immedbyte", shCount);
5798 emitLabel (tlbl->key + 100);
5800 emitRsh2 (AOP (result), size, is_signed);
5803 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5807 /*-----------------------------------------------------------------*/
5808 /* shiftL2Left2Result - shift left two bytes from left to result */
5809 /*-----------------------------------------------------------------*/
5811 shiftL2Left2Result (operand * left, int offl,
5812 operand * result, int offr, int shCount)
5814 if (sameRegs (AOP (result), AOP (left)) &&
5815 ((offl + MSB16) == offr))
5821 /* Copy left into result */
5822 movLeft2Result (left, offl, result, offr, 0);
5823 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5829 if (getPairId (AOP (result)) == PAIR_HL)
5833 emit2 ("add hl,hl");
5840 symbol *tlbl, *tlbl1;
5843 tlbl = newiTempLabel (NULL);
5844 tlbl1 = newiTempLabel (NULL);
5846 if (AOP (result)->type == AOP_REG)
5850 for (offset = 0; offset < size; offset++)
5852 l = aopGet (AOP (result), offset, FALSE);
5856 emit2 ("sla %s", l);
5867 /* Left is already in result - so now do the shift */
5870 emit2 ("ld a,!immedbyte+1", shCount);
5871 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5872 emitLabel (tlbl->key + 100);
5877 l = aopGet (AOP (result), offset, FALSE);
5881 emit2 ("sla %s", l);
5892 emitLabel (tlbl1->key + 100);
5894 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5900 /*-----------------------------------------------------------------*/
5901 /* AccRol - rotate left accumulator by known count */
5902 /*-----------------------------------------------------------------*/
5904 AccRol (int shCount)
5906 shCount &= 0x0007; // shCount : 0..7
5983 /*-----------------------------------------------------------------*/
5984 /* AccLsh - left shift accumulator by known count */
5985 /*-----------------------------------------------------------------*/
5987 AccLsh (int shCount)
5989 static const unsigned char SLMask[] =
5991 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6000 else if (shCount == 2)
6007 /* rotate left accumulator */
6009 /* and kill the lower order bits */
6010 emit2 ("and a,!immedbyte", SLMask[shCount]);
6015 /*-----------------------------------------------------------------*/
6016 /* shiftL1Left2Result - shift left one byte from left to result */
6017 /*-----------------------------------------------------------------*/
6019 shiftL1Left2Result (operand * left, int offl,
6020 operand * result, int offr, int shCount)
6024 /* If operand and result are the same we can shift in place.
6025 However shifting in acc using add is cheaper than shifting
6026 in place using sla; when shifting by more than 2 shifting in
6027 acc is worth the additional effort for loading from/to acc. */
6028 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6031 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6035 l = aopGet (AOP (left), offl, FALSE);
6037 /* shift left accumulator */
6039 aopPut (AOP (result), "a", offr);
6043 /*-----------------------------------------------------------------*/
6044 /* genlshTwo - left shift two bytes by known amount */
6045 /*-----------------------------------------------------------------*/
6047 genlshTwo (operand * result, operand * left, int shCount)
6049 int size = AOP_SIZE (result);
6051 wassert (size == 2);
6053 /* if shCount >= 8 */
6061 movLeft2Result (left, LSB, result, MSB16, 0);
6062 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6063 aopPut (AOP (result), "!zero", LSB);
6067 movLeft2Result (left, LSB, result, MSB16, 0);
6068 aopPut (AOP (result), "!zero", 0);
6073 aopPut (AOP (result), "!zero", LSB);
6076 /* 0 <= shCount <= 7 */
6085 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6090 /*-----------------------------------------------------------------*/
6091 /* genlshOne - left shift a one byte quantity by known count */
6092 /*-----------------------------------------------------------------*/
6094 genlshOne (operand * result, operand * left, int shCount)
6096 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6099 /*-----------------------------------------------------------------*/
6100 /* genLeftShiftLiteral - left shifting by known count */
6101 /*-----------------------------------------------------------------*/
6103 genLeftShiftLiteral (operand * left,
6108 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6111 freeAsmop (right, NULL, ic);
6113 aopOp (left, ic, FALSE, FALSE);
6114 aopOp (result, ic, FALSE, FALSE);
6116 size = getSize (operandType (result));
6118 /* I suppose that the left size >= result size */
6120 if (shCount >= (size * 8))
6124 aopPut (AOP (result), "!zero", size);
6132 genlshOne (result, left, shCount);
6135 genlshTwo (result, left, shCount);
6138 wassertl (0, "Shifting of longs is currently unsupported");
6144 freeAsmop (left, NULL, ic);
6145 freeAsmop (result, NULL, ic);
6148 /*-----------------------------------------------------------------*/
6149 /* genLeftShift - generates code for left shifting */
6150 /*-----------------------------------------------------------------*/
6152 genLeftShift (iCode * ic)
6156 symbol *tlbl, *tlbl1;
6157 operand *left, *right, *result;
6159 right = IC_RIGHT (ic);
6160 left = IC_LEFT (ic);
6161 result = IC_RESULT (ic);
6163 aopOp (right, ic, FALSE, FALSE);
6165 /* if the shift count is known then do it
6166 as efficiently as possible */
6167 if (AOP_TYPE (right) == AOP_LIT)
6169 genLeftShiftLiteral (left, right, result, ic);
6173 /* shift count is unknown then we have to form a loop get the loop
6174 count in B : Note: we take only the lower order byte since
6175 shifting more that 32 bits make no sense anyway, ( the largest
6176 size of an object can be only 32 bits ) */
6177 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6179 freeAsmop (right, NULL, ic);
6180 aopOp (left, ic, FALSE, FALSE);
6181 aopOp (result, ic, FALSE, FALSE);
6183 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6186 /* now move the left to the result if they are not the
6189 if (!sameRegs (AOP (left), AOP (result)))
6192 size = AOP_SIZE (result);
6196 l = aopGet (AOP (left), offset, FALSE);
6197 aopPut (AOP (result), l, offset);
6202 tlbl = newiTempLabel (NULL);
6203 size = AOP_SIZE (result);
6205 tlbl1 = newiTempLabel (NULL);
6207 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6210 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6211 emitLabel (tlbl->key + 100);
6212 l = aopGet (AOP (result), offset, FALSE);
6216 l = aopGet (AOP (result), offset, FALSE);
6220 emit2 ("sla %s", l);
6228 emitLabel (tlbl1->key + 100);
6230 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6232 freeAsmop (left, NULL, ic);
6233 freeAsmop (result, NULL, ic);
6236 /*-----------------------------------------------------------------*/
6237 /* genrshOne - left shift two bytes by known amount != 0 */
6238 /*-----------------------------------------------------------------*/
6240 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6243 int size = AOP_SIZE (result);
6246 wassert (size == 1);
6247 wassert (shCount < 8);
6249 l = aopGet (AOP (left), 0, FALSE);
6251 if (AOP (result)->type == AOP_REG)
6253 aopPut (AOP (result), l, 0);
6254 l = aopGet (AOP (result), 0, FALSE);
6257 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6265 emit2 ("%s a", is_signed ? "sra" : "srl");
6267 aopPut (AOP (result), "a", 0);
6271 /*-----------------------------------------------------------------*/
6272 /* AccRsh - right shift accumulator by known count */
6273 /*-----------------------------------------------------------------*/
6275 AccRsh (int shCount)
6277 static const unsigned char SRMask[] =
6279 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6284 /* rotate right accumulator */
6285 AccRol (8 - shCount);
6286 /* and kill the higher order bits */
6287 emit2 ("and a,!immedbyte", SRMask[shCount]);
6291 /*-----------------------------------------------------------------*/
6292 /* shiftR1Left2Result - shift right one byte from left to result */
6293 /*-----------------------------------------------------------------*/
6295 shiftR1Left2Result (operand * left, int offl,
6296 operand * result, int offr,
6297 int shCount, int sign)
6299 _moveA (aopGet (AOP (left), offl, FALSE));
6304 emit2 ("%s a", sign ? "sra" : "srl");
6311 aopPut (AOP (result), "a", offr);
6314 /*-----------------------------------------------------------------*/
6315 /* genrshTwo - right shift two bytes by known amount */
6316 /*-----------------------------------------------------------------*/
6318 genrshTwo (operand * result, operand * left,
6319 int shCount, int sign)
6321 /* if shCount >= 8 */
6327 shiftR1Left2Result (left, MSB16, result, LSB,
6332 movLeft2Result (left, MSB16, result, LSB, sign);
6336 /* Sign extend the result */
6337 _moveA(aopGet (AOP (result), 0, FALSE));
6341 aopPut (AOP (result), ACC_NAME, MSB16);
6345 aopPut (AOP (result), "!zero", 1);
6348 /* 0 <= shCount <= 7 */
6351 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6355 /*-----------------------------------------------------------------*/
6356 /* genRightShiftLiteral - left shifting by known count */
6357 /*-----------------------------------------------------------------*/
6359 genRightShiftLiteral (operand * left,
6365 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6368 freeAsmop (right, NULL, ic);
6370 aopOp (left, ic, FALSE, FALSE);
6371 aopOp (result, ic, FALSE, FALSE);
6373 size = getSize (operandType (result));
6375 /* I suppose that the left size >= result size */
6377 if (shCount >= (size * 8)) {
6379 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6380 _moveA(aopGet (AOP (left), 0, FALSE));
6388 aopPut (AOP (result), s, size);
6395 genrshOne (result, left, shCount, sign);
6398 genrshTwo (result, left, shCount, sign);
6401 wassertl (0, "Asked to shift right a long which should be a function call");
6404 wassertl (0, "Entered default case in right shift delegate");
6407 freeAsmop (left, NULL, ic);
6408 freeAsmop (result, NULL, ic);
6411 /*-----------------------------------------------------------------*/
6412 /* genRightShift - generate code for right shifting */
6413 /*-----------------------------------------------------------------*/
6415 genRightShift (iCode * ic)
6417 operand *right, *left, *result;
6419 int size, offset, first = 1;
6423 symbol *tlbl, *tlbl1;
6425 /* if signed then we do it the hard way preserve the
6426 sign bit moving it inwards */
6427 retype = getSpec (operandType (IC_RESULT (ic)));
6429 is_signed = !SPEC_USIGN (retype);
6431 /* signed & unsigned types are treated the same : i.e. the
6432 signed is NOT propagated inwards : quoting from the
6433 ANSI - standard : "for E1 >> E2, is equivalent to division
6434 by 2**E2 if unsigned or if it has a non-negative value,
6435 otherwise the result is implementation defined ", MY definition
6436 is that the sign does not get propagated */
6438 right = IC_RIGHT (ic);
6439 left = IC_LEFT (ic);
6440 result = IC_RESULT (ic);
6442 aopOp (right, ic, FALSE, FALSE);
6444 /* if the shift count is known then do it
6445 as efficiently as possible */
6446 if (AOP_TYPE (right) == AOP_LIT)
6448 genRightShiftLiteral (left, right, result, ic, is_signed);
6452 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6454 freeAsmop (right, NULL, ic);
6456 aopOp (left, ic, FALSE, FALSE);
6457 aopOp (result, ic, FALSE, FALSE);
6459 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6462 /* now move the left to the result if they are not the
6464 if (!sameRegs (AOP (left), AOP (result)))
6467 size = AOP_SIZE (result);
6471 l = aopGet (AOP (left), offset, FALSE);
6472 aopPut (AOP (result), l, offset);
6477 tlbl = newiTempLabel (NULL);
6478 tlbl1 = newiTempLabel (NULL);
6479 size = AOP_SIZE (result);
6482 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6485 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6486 emitLabel (tlbl->key + 100);
6489 l = aopGet (AOP (result), offset--, FALSE);
6492 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6500 emitLabel (tlbl1->key + 100);
6502 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6504 freeAsmop (left, NULL, ic);
6505 freeAsmop (result, NULL, ic);
6509 /*-----------------------------------------------------------------*/
6510 /* genUnpackBits - generates code for unpacking bits */
6511 /*-----------------------------------------------------------------*/
6513 genUnpackBits (operand * result, int pair)
6515 int offset = 0; /* result byte offset */
6516 int rsize; /* result size */
6517 int rlen = 0; /* remaining bitfield length */
6518 sym_link *etype; /* bitfield type information */
6519 int blen; /* bitfield length */
6520 int bstr; /* bitfield starting bit within byte */
6522 emitDebug ("; genUnpackBits");
6524 etype = getSpec (operandType (result));
6525 rsize = getSize (operandType (result));
6526 blen = SPEC_BLEN (etype);
6527 bstr = SPEC_BSTR (etype);
6529 /* If the bitfield length is less than a byte */
6532 emit2 ("ld a,!*pair", _pairs[pair].name);
6534 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6535 if (!SPEC_USIGN (etype))
6537 /* signed bitfield */
6538 symbol *tlbl = newiTempLabel (NULL);
6540 emit2 ("bit %d,a", blen - 1);
6541 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6542 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6543 emitLabel (tlbl->key + 100);
6545 aopPut (AOP (result), "a", offset++);
6549 /* TODO: what if pair == PAIR_DE ? */
6550 if (getPairId (AOP (result)) == PAIR_HL)
6552 wassertl (rsize == 2, "HL must be of size 2");
6553 emit2 ("ld a,!*hl");
6555 emit2 ("ld h,!*hl");
6558 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6559 if (!SPEC_USIGN (etype))
6561 /* signed bitfield */
6562 symbol *tlbl = newiTempLabel (NULL);
6564 emit2 ("bit %d,a", blen - 1);
6565 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6566 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6567 emitLabel (tlbl->key + 100);
6570 spillPair (PAIR_HL);
6574 /* Bit field did not fit in a byte. Copy all
6575 but the partial byte at the end. */
6576 for (rlen=blen;rlen>=8;rlen-=8)
6578 emit2 ("ld a,!*pair", _pairs[pair].name);
6579 aopPut (AOP (result), "a", offset++);
6582 emit2 ("inc %s", _pairs[pair].name);
6583 _G.pairs[pair].offset++;
6587 /* Handle the partial byte at the end */
6590 emit2 ("ld a,!*pair", _pairs[pair].name);
6591 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6592 if (!SPEC_USIGN (etype))
6594 /* signed bitfield */
6595 symbol *tlbl = newiTempLabel (NULL);
6597 emit2 ("bit %d,a", rlen - 1);
6598 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6599 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6600 emitLabel (tlbl->key + 100);
6602 aopPut (AOP (result), "a", offset++);
6610 if (SPEC_USIGN (etype))
6614 /* signed bitfield: sign extension with 0x00 or 0xff */
6622 aopPut (AOP (result), source, offset++);
6626 /*-----------------------------------------------------------------*/
6627 /* genGenPointerGet - get value from generic pointer space */
6628 /*-----------------------------------------------------------------*/
6630 genGenPointerGet (operand * left,
6631 operand * result, iCode * ic)
6634 sym_link *retype = getSpec (operandType (result));
6640 aopOp (left, ic, FALSE, FALSE);
6641 aopOp (result, ic, FALSE, FALSE);
6643 size = AOP_SIZE (result);
6645 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6648 if (isPtrPair (AOP (left)))
6650 tsprintf (buffer, sizeof(buffer),
6651 "!*pair", getPairName (AOP (left)));
6652 aopPut (AOP (result), buffer, 0);
6656 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6657 aopPut (AOP (result), "a", 0);
6659 freeAsmop (left, NULL, ic);
6663 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6670 tsprintf (at, sizeof(at), "!*iyx", offset);
6671 aopPut (AOP (result), at, offset);
6675 freeAsmop (left, NULL, ic);
6679 /* For now we always load into IY */
6680 /* if this is remateriazable */
6681 fetchPair (pair, AOP (left));
6683 /* if bit then unpack */
6684 if (IS_BITVAR (retype))
6686 genUnpackBits (result, pair);
6687 freeAsmop (left, NULL, ic);
6691 else if (getPairId (AOP (result)) == PAIR_HL)
6693 wassertl (size == 2, "HL must be of size 2");
6694 emit2 ("ld a,!*hl");
6696 emit2 ("ld h,!*hl");
6698 spillPair (PAIR_HL);
6700 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6702 size = AOP_SIZE (result);
6707 /* PENDING: make this better */
6708 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6710 aopPut (AOP (result), "!*hl", offset++);
6714 emit2 ("ld a,!*pair", _pairs[pair].name);
6715 aopPut (AOP (result), "a", offset++);
6719 emit2 ("inc %s", _pairs[pair].name);
6720 _G.pairs[pair].offset++;
6723 /* Fixup HL back down */
6724 for (size = AOP_SIZE (result)-1; size; size--)
6726 emit2 ("dec %s", _pairs[pair].name);
6731 size = AOP_SIZE (result);
6736 /* PENDING: make this better */
6738 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6740 aopPut (AOP (result), "!*hl", offset++);
6744 emit2 ("ld a,!*pair", _pairs[pair].name);
6745 aopPut (AOP (result), "a", offset++);
6749 emit2 ("inc %s", _pairs[pair].name);
6750 _G.pairs[pair].offset++;
6755 freeAsmop (left, NULL, ic);
6758 freeAsmop (result, NULL, ic);
6761 /*-----------------------------------------------------------------*/
6762 /* genPointerGet - generate code for pointer get */
6763 /*-----------------------------------------------------------------*/
6765 genPointerGet (iCode * ic)
6767 operand *left, *result;
6768 sym_link *type, *etype;
6770 left = IC_LEFT (ic);
6771 result = IC_RESULT (ic);
6773 /* depending on the type of pointer we need to
6774 move it to the correct pointer register */
6775 type = operandType (left);
6776 etype = getSpec (type);
6778 genGenPointerGet (left, result, ic);
6782 isRegOrLit (asmop * aop)
6784 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6790 /*-----------------------------------------------------------------*/
6791 /* genPackBits - generates code for packed bit storage */
6792 /*-----------------------------------------------------------------*/
6794 genPackBits (sym_link * etype,
6799 int offset = 0; /* source byte offset */
6800 int rlen = 0; /* remaining bitfield length */
6801 int blen; /* bitfield length */
6802 int bstr; /* bitfield starting bit within byte */
6803 int litval; /* source literal value (if AOP_LIT) */
6804 unsigned char mask; /* bitmask within current byte */
6805 int extraPair; /* a tempory register */
6806 bool needPopExtra=0; /* need to restore original value of temp reg */
6808 emitDebug ("; genPackBits","");
6810 blen = SPEC_BLEN (etype);
6811 bstr = SPEC_BSTR (etype);
6813 /* If the bitfield length is less than a byte */
6816 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6817 (unsigned char) (0xFF >> (8 - bstr)));
6819 if (AOP_TYPE (right) == AOP_LIT)
6821 /* Case with a bitfield length <8 and literal source
6823 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6825 litval &= (~mask) & 0xff;
6826 emit2 ("ld a,!*pair", _pairs[pair].name);
6827 if ((mask|litval)!=0xff)
6828 emit2 ("and a,!immedbyte", mask);
6830 emit2 ("or a,!immedbyte", litval);
6831 emit2 ("ld !*pair,a", _pairs[pair].name);
6836 /* Case with a bitfield length <8 and arbitrary source
6838 _moveA (aopGet (AOP (right), 0, FALSE));
6839 /* shift and mask source value */
6841 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6843 extraPair = getFreePairId(ic);
6844 if (extraPair == PAIR_INVALID)
6846 extraPair = PAIR_BC;
6847 if (getPairId (AOP (right)) != PAIR_BC
6848 || !isLastUse (ic, right))
6854 emit2 ("ld %s,a", _pairs[extraPair].l);
6855 emit2 ("ld a,!*pair", _pairs[pair].name);
6857 emit2 ("and a,!immedbyte", mask);
6858 emit2 ("or a,%s", _pairs[extraPair].l);
6859 emit2 ("ld !*pair,a", _pairs[pair].name);
6866 /* Bit length is greater than 7 bits. In this case, copy */
6867 /* all except the partial byte at the end */
6868 for (rlen=blen;rlen>=8;rlen-=8)
6870 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6871 emit2 ("ld !*pair,a", _pairs[pair].name);
6874 emit2 ("inc %s", _pairs[pair].name);
6875 _G.pairs[pair].offset++;
6879 /* If there was a partial byte at the end */
6882 mask = (((unsigned char) -1 << rlen) & 0xff);
6884 if (AOP_TYPE (right) == AOP_LIT)
6886 /* Case with partial byte and literal source
6888 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6889 litval >>= (blen-rlen);
6890 litval &= (~mask) & 0xff;
6891 emit2 ("ld a,!*pair", _pairs[pair].name);
6892 if ((mask|litval)!=0xff)
6893 emit2 ("and a,!immedbyte", mask);
6895 emit2 ("or a,!immedbyte", litval);
6899 /* Case with partial byte and arbitrary source
6901 _moveA (aopGet (AOP (right), offset++, FALSE));
6902 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6904 extraPair = getFreePairId(ic);
6905 if (extraPair == PAIR_INVALID)
6907 extraPair = getPairId (AOP (right));
6908 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6909 extraPair = PAIR_BC;
6911 if (getPairId (AOP (right)) != PAIR_BC
6912 || !isLastUse (ic, right))
6918 emit2 ("ld %s,a", _pairs[extraPair].l);
6919 emit2 ("ld a,!*pair", _pairs[pair].name);
6921 emit2 ("and a,!immedbyte", mask);
6922 emit2 ("or a,%s", _pairs[extraPair].l);
6927 emit2 ("ld !*pair,a", _pairs[pair].name);
6932 /*-----------------------------------------------------------------*/
6933 /* genGenPointerSet - stores the value into a pointer location */
6934 /*-----------------------------------------------------------------*/
6936 genGenPointerSet (operand * right,
6937 operand * result, iCode * ic)
6940 sym_link *retype = getSpec (operandType (right));
6941 sym_link *letype = getSpec (operandType (result));
6942 PAIR_ID pairId = PAIR_HL;
6945 aopOp (result, ic, FALSE, FALSE);
6946 aopOp (right, ic, FALSE, FALSE);
6951 size = AOP_SIZE (right);
6953 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6954 emitDebug("; isBitvar = %d", isBitvar);
6956 /* Handle the exceptions first */
6957 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6960 const char *l = aopGet (AOP (right), 0, FALSE);
6961 const char *pair = getPairName (AOP (result));
6962 if (canAssignToPtr (l) && isPtr (pair))
6964 emit2 ("ld !*pair,%s", pair, l);
6969 emit2 ("ld !*pair,a", pair);
6974 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6977 const char *l = aopGet (AOP (right), 0, FALSE);
6982 if (canAssignToPtr (l))
6984 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6988 _moveA (aopGet (AOP (right), offset, FALSE));
6989 emit2 ("ld !*iyx,a", offset);
6995 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7002 const char *l = aopGet (AOP (right), offset, FALSE);
7003 if (isRegOrLit (AOP (right)) && !IS_GB)
7005 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7010 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7014 emit2 ("inc %s", _pairs[PAIR_HL].name);
7015 _G.pairs[PAIR_HL].offset++;
7020 /* Fixup HL back down */
7021 for (size = AOP_SIZE (right)-1; size; size--)
7023 emit2 ("dec %s", _pairs[PAIR_HL].name);
7028 /* if the operand is already in dptr
7029 then we do nothing else we move the value to dptr */
7030 if (AOP_TYPE (result) != AOP_STR)
7032 fetchPair (pairId, AOP (result));
7034 /* so hl now contains the address */
7035 freeAsmop (result, NULL, ic);
7037 /* if bit then unpack */
7040 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7050 const char *l = aopGet (AOP (right), offset, FALSE);
7051 if (isRegOrLit (AOP (right)) && !IS_GB)
7053 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7058 emit2 ("ld !*pair,a", _pairs[pairId].name);
7062 emit2 ("inc %s", _pairs[pairId].name);
7063 _G.pairs[pairId].offset++;
7069 freeAsmop (right, NULL, ic);
7072 /*-----------------------------------------------------------------*/
7073 /* genPointerSet - stores the value into a pointer location */
7074 /*-----------------------------------------------------------------*/
7076 genPointerSet (iCode * ic)
7078 operand *right, *result;
7079 sym_link *type, *etype;
7081 right = IC_RIGHT (ic);
7082 result = IC_RESULT (ic);
7084 /* depending on the type of pointer we need to
7085 move it to the correct pointer register */
7086 type = operandType (result);
7087 etype = getSpec (type);
7089 genGenPointerSet (right, result, ic);
7092 /*-----------------------------------------------------------------*/
7093 /* genIfx - generate code for Ifx statement */
7094 /*-----------------------------------------------------------------*/
7096 genIfx (iCode * ic, iCode * popIc)
7098 operand *cond = IC_COND (ic);
7101 aopOp (cond, ic, FALSE, TRUE);
7103 /* get the value into acc */
7104 if (AOP_TYPE (cond) != AOP_CRY)
7108 /* the result is now in the accumulator */
7109 freeAsmop (cond, NULL, ic);
7111 /* if there was something to be popped then do it */
7115 /* if the condition is a bit variable */
7116 if (isbit && IS_ITEMP (cond) &&
7118 genIfxJump (ic, SPIL_LOC (cond)->rname);
7119 else if (isbit && !IS_ITEMP (cond))
7120 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7122 genIfxJump (ic, "a");
7127 /*-----------------------------------------------------------------*/
7128 /* genAddrOf - generates code for address of */
7129 /*-----------------------------------------------------------------*/
7131 genAddrOf (iCode * ic)
7133 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7135 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7137 /* if the operand is on the stack then we
7138 need to get the stack offset of this
7145 if (sym->stack <= 0)
7147 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7151 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7153 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7157 emit2 ("ld de,!hashedstr", sym->rname);
7158 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7166 /* if it has an offset then we need to compute it */
7168 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7170 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7171 emit2 ("add hl,sp");
7175 emit2 ("ld hl,!hashedstr", sym->rname);
7177 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7179 freeAsmop (IC_RESULT (ic), NULL, ic);
7182 /*-----------------------------------------------------------------*/
7183 /* genAssign - generate code for assignment */
7184 /*-----------------------------------------------------------------*/
7186 genAssign (iCode * ic)
7188 operand *result, *right;
7190 unsigned long lit = 0L;
7192 result = IC_RESULT (ic);
7193 right = IC_RIGHT (ic);
7195 /* Dont bother assigning if they are the same */
7196 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7198 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7202 aopOp (right, ic, FALSE, FALSE);
7203 aopOp (result, ic, TRUE, FALSE);
7205 /* if they are the same registers */
7206 if (sameRegs (AOP (right), AOP (result)))
7208 emitDebug ("; (registers are the same)");
7212 /* if the result is a bit */
7213 if (AOP_TYPE (result) == AOP_CRY)
7215 wassertl (0, "Tried to assign to a bit");
7219 size = AOP_SIZE (result);
7222 if (AOP_TYPE (right) == AOP_LIT)
7224 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7227 if (isPair (AOP (result)))
7229 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7231 else if ((size > 1) &&
7232 (AOP_TYPE (result) != AOP_REG) &&
7233 (AOP_TYPE (right) == AOP_LIT) &&
7234 !IS_FLOAT (operandType (right)) &&
7237 bool fXored = FALSE;
7239 /* Work from the top down.
7240 Done this way so that we can use the cached copy of 0
7241 in A for a fast clear */
7244 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7246 if (!fXored && size > 1)
7253 aopPut (AOP (result), "a", offset);
7257 aopPut (AOP (result), "!zero", offset);
7261 aopPut (AOP (result),
7262 aopGet (AOP (right), offset, FALSE),
7267 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7269 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7270 aopPut (AOP (result), "l", LSB);
7271 aopPut (AOP (result), "h", MSB16);
7273 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7275 /* Special case. Load into a and d, then load out. */
7276 _moveA (aopGet (AOP (right), 0, FALSE));
7277 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7278 aopPut (AOP (result), "a", 0);
7279 aopPut (AOP (result), "e", 1);
7281 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7283 /* Special case - simple memcpy */
7284 aopGet (AOP (right), LSB, FALSE);
7287 aopGet (AOP (result), LSB, FALSE);
7291 emit2 ("ld a,(de)");
7292 /* Peephole will optimise this. */
7293 emit2 ("ld (hl),a");
7301 spillPair (PAIR_HL);
7307 /* PENDING: do this check better */
7308 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7310 _moveA (aopGet (AOP (right), offset, FALSE));
7311 aopPut (AOP (result), "a", offset);
7314 aopPut (AOP (result),
7315 aopGet (AOP (right), offset, FALSE),
7322 freeAsmop (right, NULL, ic);
7323 freeAsmop (result, NULL, ic);
7326 /*-----------------------------------------------------------------*/
7327 /* genJumpTab - genrates code for jump table */
7328 /*-----------------------------------------------------------------*/
7330 genJumpTab (iCode * ic)
7335 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7336 /* get the condition into accumulator */
7337 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7340 emit2 ("ld e,%s", l);
7341 emit2 ("ld d,!zero");
7342 jtab = newiTempLabel (NULL);
7344 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7345 emit2 ("add hl,de");
7346 emit2 ("add hl,de");
7347 emit2 ("add hl,de");
7348 freeAsmop (IC_JTCOND (ic), NULL, ic);
7352 emitLabel (jtab->key + 100);
7353 /* now generate the jump labels */
7354 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7355 jtab = setNextItem (IC_JTLABELS (ic)))
7356 emit2 ("jp !tlabel", jtab->key + 100);
7359 /*-----------------------------------------------------------------*/
7360 /* genCast - gen code for casting */
7361 /*-----------------------------------------------------------------*/
7363 genCast (iCode * ic)
7365 operand *result = IC_RESULT (ic);
7366 sym_link *rtype = operandType (IC_RIGHT (ic));
7367 operand *right = IC_RIGHT (ic);
7370 /* if they are equivalent then do nothing */
7371 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7374 aopOp (right, ic, FALSE, FALSE);
7375 aopOp (result, ic, FALSE, FALSE);
7377 /* if the result is a bit */
7378 if (AOP_TYPE (result) == AOP_CRY)
7380 wassertl (0, "Tried to cast to a bit");
7383 /* if they are the same size : or less */
7384 if (AOP_SIZE (result) <= AOP_SIZE (right))
7387 /* if they are in the same place */
7388 if (sameRegs (AOP (right), AOP (result)))
7391 /* if they in different places then copy */
7392 size = AOP_SIZE (result);
7396 aopPut (AOP (result),
7397 aopGet (AOP (right), offset, FALSE),
7404 /* So we now know that the size of destination is greater
7405 than the size of the source */
7406 /* we move to result for the size of source */
7407 size = AOP_SIZE (right);
7411 aopPut (AOP (result),
7412 aopGet (AOP (right), offset, FALSE),
7417 /* now depending on the sign of the destination */
7418 size = AOP_SIZE (result) - AOP_SIZE (right);
7419 /* Unsigned or not an integral type - right fill with zeros */
7420 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7423 aopPut (AOP (result), "!zero", offset++);
7427 /* we need to extend the sign :{ */
7428 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7434 aopPut (AOP (result), "a", offset++);
7438 freeAsmop (right, NULL, ic);
7439 freeAsmop (result, NULL, ic);
7442 /*-----------------------------------------------------------------*/
7443 /* genReceive - generate code for a receive iCode */
7444 /*-----------------------------------------------------------------*/
7446 genReceive (iCode * ic)
7448 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7449 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7450 IS_TRUE_SYMOP (IC_RESULT (ic))))
7460 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7461 size = AOP_SIZE(IC_RESULT(ic));
7463 for (i = 0; i < size; i++) {
7464 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7468 freeAsmop (IC_RESULT (ic), NULL, ic);
7471 /*-----------------------------------------------------------------*/
7472 /* genDummyRead - generate code for dummy read of volatiles */
7473 /*-----------------------------------------------------------------*/
7475 genDummyRead (iCode * ic)
7481 if (op && IS_SYMOP (op))
7483 aopOp (op, ic, FALSE, FALSE);
7486 size = AOP_SIZE (op);
7491 _moveA (aopGet (AOP (op), offset, FALSE));
7495 freeAsmop (op, NULL, ic);
7499 if (op && IS_SYMOP (op))
7501 aopOp (op, ic, FALSE, FALSE);
7504 size = AOP_SIZE (op);
7509 _moveA (aopGet (AOP (op), offset, FALSE));
7513 freeAsmop (op, NULL, ic);
7517 /*-----------------------------------------------------------------*/
7518 /* genCritical - generate code for start of a critical sequence */
7519 /*-----------------------------------------------------------------*/
7521 genCritical (iCode *ic)
7523 symbol *tlbl = newiTempLabel (NULL);
7529 else if (IC_RESULT (ic))
7531 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7532 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7533 //get interrupt enable flag IFF2 into P/O
7537 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7538 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7539 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7540 emit2 ("!tlabeldef", (tlbl->key + 100));
7541 _G.lines.current->isLabel = 1;
7542 freeAsmop (IC_RESULT (ic), NULL, ic);
7546 //get interrupt enable flag IFF2 into P/O
7555 /*-----------------------------------------------------------------*/
7556 /* genEndCritical - generate code for end of a critical sequence */
7557 /*-----------------------------------------------------------------*/
7559 genEndCritical (iCode *ic)
7561 symbol *tlbl = newiTempLabel (NULL);
7567 else if (IC_RIGHT (ic))
7569 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7570 _toBoolean (IC_RIGHT (ic));
7571 //don't enable interrupts if they were off before
7572 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7574 emitLabel (tlbl->key + 100);
7575 freeAsmop (IC_RIGHT (ic), NULL, ic);
7581 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7582 //don't enable interrupts as they were off before
7583 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7585 emit2 ("!tlabeldef", (tlbl->key + 100));
7586 _G.lines.current->isLabel = 1;
7592 /** Maximum number of bytes to emit per line. */
7596 /** Context for the byte output chunker. */
7599 unsigned char buffer[DBEMIT_MAX_RUN];
7604 /** Flushes a byte chunker by writing out all in the buffer and
7608 _dbFlush(DBEMITCTX *self)
7615 sprintf(line, ".db 0x%02X", self->buffer[0]);
7617 for (i = 1; i < self->pos; i++)
7619 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7626 /** Write out another byte, buffering until a decent line is
7630 _dbEmit(DBEMITCTX *self, int c)
7632 if (self->pos == DBEMIT_MAX_RUN)
7636 self->buffer[self->pos++] = c;
7639 /** Context for a simple run length encoder. */
7643 unsigned char buffer[128];
7645 /** runLen may be equivalent to pos. */
7651 RLE_CHANGE_COST = 4,
7655 /** Flush the buffer of a run length encoder by writing out the run or
7656 data that it currently contains.
7659 _rleCommit(RLECTX *self)
7665 memset(&db, 0, sizeof(db));
7667 emit2(".db %u", self->pos);
7669 for (i = 0; i < self->pos; i++)
7671 _dbEmit(&db, self->buffer[i]);
7680 Can get either a run or a block of random stuff.
7681 Only want to change state if a good run comes in or a run ends.
7682 Detecting run end is easy.
7685 Say initial state is in run, len zero, last zero. Then if you get a
7686 few zeros then something else then a short run will be output.
7687 Seems OK. While in run mode, keep counting. While in random mode,
7688 keep a count of the run. If run hits margin, output all up to run,
7689 restart, enter run mode.
7692 /** Add another byte into the run length encoder, flushing as
7693 required. The run length encoder uses the Amiga IFF style, where
7694 a block is prefixed by its run length. A positive length means
7695 the next n bytes pass straight through. A negative length means
7696 that the next byte is repeated -n times. A zero terminates the
7700 _rleAppend(RLECTX *self, unsigned c)
7704 if (c != self->last)
7706 /* The run has stopped. See if it is worthwhile writing it out
7707 as a run. Note that the random data comes in as runs of
7710 if (self->runLen > RLE_CHANGE_COST)
7712 /* Yes, worthwhile. */
7713 /* Commit whatever was in the buffer. */
7715 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7719 /* Not worthwhile. Append to the end of the random list. */
7720 for (i = 0; i < self->runLen; i++)
7722 if (self->pos >= RLE_MAX_BLOCK)
7727 self->buffer[self->pos++] = self->last;
7735 if (self->runLen >= RLE_MAX_BLOCK)
7737 /* Commit whatever was in the buffer. */
7740 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7748 _rleFlush(RLECTX *self)
7750 _rleAppend(self, -1);
7757 /** genArrayInit - Special code for initialising an array with constant
7761 genArrayInit (iCode * ic)
7765 int elementSize = 0, eIndex, i;
7766 unsigned val, lastVal;
7770 memset(&rle, 0, sizeof(rle));
7772 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7774 _saveRegsForCall(ic, 0);
7776 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7777 emit2 ("call __initrleblock");
7779 type = operandType(IC_LEFT(ic));
7781 if (type && type->next)
7783 if (IS_SPEC(type->next) || IS_PTR(type->next))
7785 elementSize = getSize(type->next);
7787 else if (IS_ARRAY(type->next) && type->next->next)
7789 elementSize = getSize(type->next->next);
7793 printTypeChainRaw (type, NULL);
7794 wassertl (0, "Can't determine element size in genArrayInit.");
7799 wassertl (0, "Can't determine element size in genArrayInit.");
7802 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7804 iLoop = IC_ARRAYILIST(ic);
7805 lastVal = (unsigned)-1;
7807 /* Feed all the bytes into the run length encoder which will handle
7809 This works well for mixed char data, and for random int and long
7816 for (i = 0; i < ix; i++)
7818 for (eIndex = 0; eIndex < elementSize; eIndex++)
7820 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7821 _rleAppend(&rle, val);
7825 iLoop = iLoop->next;
7829 /* Mark the end of the run. */
7832 _restoreRegsAfterCall();
7836 freeAsmop (IC_LEFT(ic), NULL, ic);
7840 _swap (PAIR_ID one, PAIR_ID two)
7842 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7848 emit2 ("ld a,%s", _pairs[one].l);
7849 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7850 emit2 ("ld %s,a", _pairs[two].l);
7851 emit2 ("ld a,%s", _pairs[one].h);
7852 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7853 emit2 ("ld %s,a", _pairs[two].h);
7857 /* The problem is that we may have all three pairs used and they may
7858 be needed in a different order.
7863 hl = hl => unity, fine
7867 hl = hl hl = hl, swap de <=> bc
7875 hl = bc de = de, swap bc <=> hl
7883 hl = de bc = bc, swap hl <=> de
7888 * Any pair = pair are done last
7889 * Any pair = iTemp are done last
7890 * Any swaps can be done any time
7898 So how do we detect the cases?
7899 How about a 3x3 matrix?
7903 x x x x (Fourth for iTemp/other)
7905 First determin which mode to use by counting the number of unity and
7908 Two - Assign the pair first, then the rest
7909 One - Swap the two, then the rest
7913 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7915 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7917 PAIR_BC, PAIR_HL, PAIR_DE
7919 int i, j, nunity = 0;
7920 memset (ids, PAIR_INVALID, sizeof (ids));
7923 wassert (nparams == 3);
7925 /* First save everything that needs to be saved. */
7926 _saveRegsForCall (ic, 0);
7928 /* Loading HL first means that DE is always fine. */
7929 for (i = 0; i < nparams; i++)
7931 aopOp (pparams[i], ic, FALSE, FALSE);
7932 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7935 /* Count the number of unity or iTemp assigns. */
7936 for (i = 0; i < 3; i++)
7938 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7946 /* Any order, fall through. */
7948 else if (nunity == 2)
7950 /* One is assigned. Pull it out and assign. */
7951 for (i = 0; i < 3; i++)
7953 for (j = 0; j < NUM_PAIRS; j++)
7955 if (ids[dest[i]][j] == TRUE)
7957 /* Found it. See if it's the right one. */
7958 if (j == PAIR_INVALID || j == dest[i])
7964 fetchPair(dest[i], AOP (pparams[i]));
7971 else if (nunity == 1)
7973 /* Find the pairs to swap. */
7974 for (i = 0; i < 3; i++)
7976 for (j = 0; j < NUM_PAIRS; j++)
7978 if (ids[dest[i]][j] == TRUE)
7980 if (j == PAIR_INVALID || j == dest[i])
7995 int next = getPairId (AOP (pparams[0]));
7996 emit2 ("push %s", _pairs[next].name);
7998 if (next == dest[1])
8000 fetchPair (dest[1], AOP (pparams[1]));
8001 fetchPair (dest[2], AOP (pparams[2]));
8005 fetchPair (dest[2], AOP (pparams[2]));
8006 fetchPair (dest[1], AOP (pparams[1]));
8008 emit2 ("pop %s", _pairs[dest[0]].name);
8011 /* Finally pull out all of the iTemps */
8012 for (i = 0; i < 3; i++)
8014 if (ids[dest[i]][PAIR_INVALID] == 1)
8016 fetchPair (dest[i], AOP (pparams[i]));
8022 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8028 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8032 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8034 setupForBuiltin3 (ic, nParams, pparams);
8036 label = newiTempLabel(NULL);
8038 emitLabel (label->key);
8039 emit2 ("ld a,(hl)");
8042 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8044 freeAsmop (from, NULL, ic->next);
8045 freeAsmop (to, NULL, ic);
8049 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8051 operand *from, *to, *count;
8054 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8059 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8061 setupForBuiltin3 (ic, nParams, pparams);
8065 freeAsmop (count, NULL, ic->next->next);
8066 freeAsmop (from, NULL, ic);
8068 _restoreRegsAfterCall();
8070 /* if we need assign a result value */
8071 if ((IS_ITEMP (IC_RESULT (ic)) &&
8072 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8073 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8074 IS_TRUE_SYMOP (IC_RESULT (ic)))
8076 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8077 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8078 freeAsmop (IC_RESULT (ic), NULL, ic);
8081 freeAsmop (to, NULL, ic->next);
8084 /*-----------------------------------------------------------------*/
8085 /* genBuiltIn - calls the appropriate function to generating code */
8086 /* for a built in function */
8087 /*-----------------------------------------------------------------*/
8088 static void genBuiltIn (iCode *ic)
8090 operand *bi_parms[MAX_BUILTIN_ARGS];
8095 /* get all the arguments for a built in function */
8096 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8098 /* which function is it */
8099 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8101 if (strcmp(bif->name,"__builtin_strcpy")==0)
8103 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8105 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8107 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8111 wassertl (0, "Unknown builtin function encountered");
8115 /*-----------------------------------------------------------------*/
8116 /* genZ80Code - generate code for Z80 based controllers */
8117 /*-----------------------------------------------------------------*/
8119 genZ80Code (iCode * lic)
8127 _fReturn = _gbz80_return;
8128 _fTmp = _gbz80_return;
8132 _fReturn = _z80_return;
8133 _fTmp = _z80_return;
8136 _G.lines.head = _G.lines.current = NULL;
8138 /* if debug information required */
8139 if (options.debug && currFunc)
8141 debugFile->writeFunction (currFunc, lic);
8144 for (ic = lic; ic; ic = ic->next)
8146 _G.current_iCode = ic;
8148 if (ic->lineno && cln != ic->lineno)
8152 debugFile->writeCLine (ic);
8154 if (!options.noCcodeInAsm)
8156 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8157 printCLine(ic->filename, ic->lineno));
8161 if (options.iCodeInAsm)
8163 const char *iLine = printILine(ic);
8164 emit2 (";ic:%d: %s", ic->key, iLine);
8167 /* if the result is marked as
8168 spilt and rematerializable or code for
8169 this has already been generated then
8171 if (resultRemat (ic) || ic->generated)
8174 /* depending on the operation */
8178 emitDebug ("; genNot");
8183 emitDebug ("; genCpl");
8188 emitDebug ("; genUminus");
8193 emitDebug ("; genIpush");
8198 /* IPOP happens only when trying to restore a
8199 spilt live range, if there is an ifx statement
8200 following this pop then the if statement might
8201 be using some of the registers being popped which
8202 would destroy the contents of the register so
8203 we need to check for this condition and handle it */
8205 ic->next->op == IFX &&
8206 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8208 emitDebug ("; genIfx");
8209 genIfx (ic->next, ic);
8213 emitDebug ("; genIpop");
8219 emitDebug ("; genCall");
8224 emitDebug ("; genPcall");
8229 emitDebug ("; genFunction");
8234 emitDebug ("; genEndFunction");
8235 genEndFunction (ic);
8239 emitDebug ("; genRet");
8244 emitDebug ("; genLabel");
8249 emitDebug ("; genGoto");
8254 emitDebug ("; genPlus");
8259 emitDebug ("; genMinus");
8264 emitDebug ("; genMult");
8269 emitDebug ("; genDiv");
8274 emitDebug ("; genMod");
8279 emitDebug ("; genCmpGt");
8280 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8284 emitDebug ("; genCmpLt");
8285 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8292 /* note these two are xlated by algebraic equivalence
8293 during parsing SDCC.y */
8294 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8295 "got '>=' or '<=' shouldn't have come here");
8299 emitDebug ("; genCmpEq");
8300 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8304 emitDebug ("; genAndOp");
8309 emitDebug ("; genOrOp");
8314 emitDebug ("; genXor");
8315 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8319 emitDebug ("; genOr");
8320 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8324 emitDebug ("; genAnd");
8325 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8329 emitDebug ("; genInline");
8334 emitDebug ("; genRRC");
8339 emitDebug ("; genRLC");
8344 emitDebug ("; genGetHBIT");
8349 emitDebug ("; genLeftShift");
8354 emitDebug ("; genRightShift");
8358 case GET_VALUE_AT_ADDRESS:
8359 emitDebug ("; genPointerGet");
8365 if (POINTER_SET (ic))
8367 emitDebug ("; genAssign (pointer)");
8372 emitDebug ("; genAssign");
8378 emitDebug ("; genIfx");
8383 emitDebug ("; genAddrOf");
8388 emitDebug ("; genJumpTab");
8393 emitDebug ("; genCast");
8398 emitDebug ("; genReceive");
8403 if (ic->builtinSEND)
8405 emitDebug ("; genBuiltIn");
8410 emitDebug ("; addSet");
8411 addSet (&_G.sendSet, ic);
8416 emitDebug ("; genArrayInit");
8420 case DUMMY_READ_VOLATILE:
8421 emitDebug ("; genDummyRead");
8426 emitDebug ("; genCritical");
8431 emitDebug ("; genEndCritical");
8432 genEndCritical (ic);
8441 /* now we are ready to call the
8442 peep hole optimizer */
8443 if (!options.nopeep)
8444 peepHole (&_G.lines.head);
8446 /* This is unfortunate */
8447 /* now do the actual printing */
8449 struct dbuf_s *buf = codeOutBuf;
8450 if (isInHome () && codeOutBuf == &code->oBuf)
8451 codeOutBuf = &home->oBuf;
8452 printLine (_G.lines.head, codeOutBuf);
8453 if (_G.flushStatics)
8456 _G.flushStatics = 0;
8461 freeTrace(&_G.lines.trace);
8462 freeTrace(&_G.trace.aops);
8468 _isPairUsed (iCode * ic, PAIR_ID pairId)
8474 if (bitVectBitValue (ic->rMask, D_IDX))
8476 if (bitVectBitValue (ic->rMask, E_IDX))
8486 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8489 value *val = aop->aopu.aop_lit;
8491 wassert (aop->type == AOP_LIT);
8492 wassert (!IS_FLOAT (val->type));
8494 v = ulFromVal (val);
8502 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8503 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));