1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
91 #include "SDCCglobl.h"
92 #include "SDCCpeeph.h"
97 /* This is the down and dirty file with all kinds of kludgy & hacky
98 stuff. This is what it is all about CODE GENERATION for a specific MCU.
99 Some of the routines may be reusable, will have to see */
101 /* Z80 calling convention description.
102 Parameters are passed right to left. As the stack grows downwards,
103 the parameters are arranged in left to right in memory.
104 Parameters may be passed in the HL and DE registers with one
106 PENDING: What if the parameter is a long?
107 Everything is caller saves. i.e. the caller must save any registers
108 that it wants to preserve over the call.
109 GB: The return value is returned in DEHL. DE is normally used as a
110 working register pair. Caller saves allows it to be used for a
112 va args functions do not use register parameters. All arguments
113 are passed on the stack.
114 IX is used as an index register to the top of the local variable
115 area. ix-0 is the top most local variable.
120 /* Set to enable debugging trace statements in the output assembly code. */
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129 { "c", "b", "e", "d" };
131 static char **_fReturn;
134 extern struct dbuf_s *codeOutBuf;
142 /** Enum covering all the possible register pairs.
161 } _pairs[NUM_PAIRS] = {
162 { "??1", "?2", "?3" },
167 { "iy", "iyl", "iyh" },
168 { "ix", "ixl", "ixh" }
172 #define ACC_NAME _pairs[PAIR_AF].h
182 /** Code generator persistent data.
186 /** Used to optimised setting up of a pair by remebering what it
187 contains and adjusting instead of reloading where possible.
216 const char *lastFunctionName;
217 iCode *current_iCode;
224 /** TRUE if the registers have already been saved. */
243 static const char *aopGet (asmop * aop, int offset, bool bit16);
245 static const char *aopNames[] = {
266 isLastUse (iCode *ic, operand *op)
268 bitVect *uses = bitVectCopy (OP_USES (op));
270 while (!bitVectIsZero (uses))
272 if (bitVectFirstBit (uses) == ic->key)
274 if (bitVectnBitsOn (uses) == 1)
283 bitVectUnSetBit (uses, bitVectFirstBit (uses));
303 _getTempPairName(void)
305 return _pairs[_getTempPairId()].name;
309 isPairInUse (PAIR_ID id, iCode *ic)
313 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
315 else if (id == PAIR_BC)
317 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
321 wassertl (0, "Only implemented for DE and BC");
327 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
331 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
335 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
339 wassertl (0, "Only implemented for DE");
345 getFreePairId (iCode *ic)
347 if (!isPairInUse (PAIR_BC, ic))
351 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
364 /* Clean up the line so that it is 'prettier' */
365 if (strchr (buf, ':'))
367 /* Is a label - cant do anything */
370 /* Change the first (and probably only) ' ' to a tab so
385 _newLineNode (const char *line)
389 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
390 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
396 _vemit2 (const char *szFormat, va_list ap)
401 dbuf_init(&dbuf, INITIAL_INLINEASM);
403 dbuf_tvprintf (&dbuf, szFormat, ap);
405 buffer = dbuf_c_str(&dbuf);
407 _tidyUp ((char *)buffer);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
413 _G.lines.current->isDebug = _G.lines.isDebug;
414 _G.lines.current->ic = _G.current_iCode;
415 _G.lines.current->isComment = (*buffer == ';');
421 emit2 (const char *szFormat,...)
425 va_start (ap, szFormat);
427 _vemit2 (szFormat, ap);
433 emitDebug (const char *szFormat,...)
439 va_start (ap, szFormat);
441 _vemit2 (szFormat, ap);
447 /*-----------------------------------------------------------------*/
448 /* z80_emitDebuggerSymbol - associate the current code location */
449 /* with a debugger symbol */
450 /*-----------------------------------------------------------------*/
452 z80_emitDebuggerSymbol (char * debugSym)
454 _G.lines.isDebug = 1;
455 emit2 ("%s !equ .", debugSym);
456 emit2 ("!global", debugSym);
457 _G.lines.isDebug = 0;
460 /*-----------------------------------------------------------------*/
461 /* emit2 - writes the code into a file : for now it is simple */
462 /*-----------------------------------------------------------------*/
464 _emit2 (const char *inst, const char *fmt,...)
467 char lb[INITIAL_INLINEASM];
474 sprintf (lb, "%s\t", inst);
475 vsprintf (lb + (strlen (lb)), fmt, ap);
478 vsprintf (lb, fmt, ap);
480 while (isspace (*lbp))
485 _G.lines.current = (_G.lines.current ?
486 connectLine (_G.lines.current, _newLineNode (lb)) :
487 (_G.lines.head = _newLineNode (lb)));
489 _G.lines.current->isInline = _G.lines.isInline;
490 _G.lines.current->ic = _G.current_iCode;
495 _emitMove(const char *to, const char *from)
497 if (STRCASECMP(to, from) != 0)
499 emit2("ld %s,%s", to, from);
504 // Could leave this to the peephole, but sometimes the peephole is inhibited.
509 aopDump(const char *plabel, asmop *aop)
515 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
520 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
523 for (i=aop->size-1;i>=0;i--)
524 *rbp++ = *(aop->aopu.aop_reg[i]->name);
526 emitDebug("; reg = %s", regbuf);
529 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
532 /* No information. */
538 _moveA(const char *moveFrom)
540 // Let the peephole optimiser take care of redundent loads
541 _emitMove(ACC_NAME, moveFrom);
551 getPairName (asmop * aop)
553 if (aop->type == AOP_REG)
555 switch (aop->aopu.aop_reg[0]->rIdx)
568 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
571 for (i = 0; i < NUM_PAIRS; i++)
573 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
575 return _pairs[i].name;
579 wassertl (0, "Tried to get the pair name of something that isn't a pair");
584 getPairId (asmop * aop)
588 if (aop->type == AOP_REG)
590 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
594 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
598 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
603 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
606 for (i = 0; i < NUM_PAIRS; i++)
608 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
618 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
622 return (getPairId (aop) != PAIR_INVALID);
625 /** Returns TRUE if the registers used in aop cannot be split into high
628 isUnsplitable (asmop * aop)
630 switch (getPairId (aop))
642 isPtrPair (asmop * aop)
644 PAIR_ID pairId = getPairId (aop);
657 spillPair (PAIR_ID pairId)
659 _G.pairs[pairId].last_type = AOP_INVALID;
660 _G.pairs[pairId].base = NULL;
663 /* Given a register name, spill the pair (if any) the register is part of */
665 spillPairReg (const char *regname)
667 if (strlen(regname)==1)
687 /** Push a register pair onto the stack */
689 genPairPush (asmop * aop)
691 emit2 ("push %s", getPairName (aop));
695 _push (PAIR_ID pairId)
697 emit2 ("push %s", _pairs[pairId].name);
698 _G.stack.pushed += 2;
702 _pop (PAIR_ID pairId)
704 if (pairId != PAIR_INVALID)
706 emit2 ("pop %s", _pairs[pairId].name);
707 _G.stack.pushed -= 2;
713 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
726 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
733 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
734 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
737 wassertl (0, "Tried to move a nonphysical pair");
739 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
740 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
741 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
745 /*-----------------------------------------------------------------*/
746 /* newAsmop - creates a new asmOp */
747 /*-----------------------------------------------------------------*/
749 newAsmop (short type)
753 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
758 /*-----------------------------------------------------------------*/
759 /* aopForSym - for a true symbol */
760 /*-----------------------------------------------------------------*/
762 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
769 wassert (sym->etype);
771 space = SPEC_OCLS (sym->etype);
773 /* if already has one */
779 /* Assign depending on the storage class */
780 if (sym->onStack || sym->iaccess)
782 /* The pointer that is used depends on how big the offset is.
783 Normally everything is AOP_STK, but for offsets of < -128 or
784 > 127 on the Z80 an extended stack pointer is used.
786 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
788 emitDebug ("; AOP_EXSTK for %s", sym->rname);
789 sym->aop = aop = newAsmop (AOP_EXSTK);
793 emitDebug ("; AOP_STK for %s", sym->rname);
794 sym->aop = aop = newAsmop (AOP_STK);
797 aop->size = getSize (sym->type);
798 aop->aopu.aop_stk = sym->stack;
802 /* special case for a function */
803 if (IS_FUNC (sym->type))
805 sym->aop = aop = newAsmop (AOP_IMMD);
806 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
811 if( IN_REGSP( space ))
812 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
815 /* if it is in direct space */
818 sym->aop = aop = newAsmop (AOP_SFR);
819 aop->aopu.aop_dir = sym->rname;
820 aop->size = getSize (sym->type);
821 emitDebug ("; AOP_SFR for %s", sym->rname);
826 { /*.p.t.20030716 adding SFR support to the Z80 port */
827 aop = newAsmop (AOP_SFR);
829 aop->aopu.aop_dir = sym->rname;
830 aop->size = getSize( sym->type );
831 aop->paged = FUNC_REGBANK(sym->type);
832 aop->bcInUse = isPairInUse( PAIR_BC, ic );
833 aop->deInUse = isPairInUse( PAIR_DE, ic );
834 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
840 /* only remaining is far space */
841 /* in which case DPTR gets the address */
844 emitDebug ("; AOP_HL for %s", sym->rname);
845 sym->aop = aop = newAsmop (AOP_HL);
849 sym->aop = aop = newAsmop (AOP_IY);
851 aop->size = getSize (sym->type);
852 aop->aopu.aop_dir = sym->rname;
854 /* if it is in code space */
855 if (IN_CODESPACE (space))
861 /*-----------------------------------------------------------------*/
862 /* aopForRemat - rematerialzes an object */
863 /*-----------------------------------------------------------------*/
865 aopForRemat (symbol * sym)
868 iCode *ic = sym->rematiCode;
869 asmop *aop = newAsmop (AOP_IMMD);
873 /* if plus or minus print the right hand side */
874 if (ic->op == '+' || ic->op == '-')
876 /* PENDING: for re-target */
877 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
880 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
883 /* we reached the end */
884 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
888 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
892 /*-----------------------------------------------------------------*/
893 /* regsInCommon - two operands have some registers in common */
894 /*-----------------------------------------------------------------*/
896 regsInCommon (operand * op1, operand * op2)
901 /* if they have registers in common */
902 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
905 sym1 = OP_SYMBOL (op1);
906 sym2 = OP_SYMBOL (op2);
908 if (sym1->nRegs == 0 || sym2->nRegs == 0)
911 for (i = 0; i < sym1->nRegs; i++)
917 for (j = 0; j < sym2->nRegs; j++)
922 if (sym2->regs[j] == sym1->regs[i])
930 /*-----------------------------------------------------------------*/
931 /* operandsEqu - equivalent */
932 /*-----------------------------------------------------------------*/
934 operandsEqu (operand * op1, operand * op2)
938 /* if they not symbols */
939 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
942 sym1 = OP_SYMBOL (op1);
943 sym2 = OP_SYMBOL (op2);
945 /* if both are itemps & one is spilt
946 and the other is not then false */
947 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
948 sym1->isspilt != sym2->isspilt)
951 /* if they are the same */
955 if (sym1->rname[0] && sym2->rname[0]
956 && strcmp (sym1->rname, sym2->rname) == 0)
959 /* if left is a tmp & right is not */
960 if (IS_ITEMP (op1) &&
963 (sym1->usl.spillLoc == sym2))
966 if (IS_ITEMP (op2) &&
970 (sym2->usl.spillLoc == sym1))
976 /*-----------------------------------------------------------------*/
977 /* sameRegs - two asmops have the same registers */
978 /*-----------------------------------------------------------------*/
980 sameRegs (asmop * aop1, asmop * aop2)
984 if (aop1->type == AOP_SFR ||
985 aop2->type == AOP_SFR)
991 if (aop1->type != AOP_REG ||
992 aop2->type != AOP_REG)
995 if (aop1->size != aop2->size)
998 for (i = 0; i < aop1->size; i++)
999 if (aop1->aopu.aop_reg[i] !=
1000 aop2->aopu.aop_reg[i])
1006 /*-----------------------------------------------------------------*/
1007 /* aopOp - allocates an asmop for an operand : */
1008 /*-----------------------------------------------------------------*/
1010 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1019 /* if this a literal */
1020 if (IS_OP_LITERAL (op))
1022 op->aop = aop = newAsmop (AOP_LIT);
1023 aop->aopu.aop_lit = op->operand.valOperand;
1024 aop->size = getSize (operandType (op));
1028 /* if already has a asmop then continue */
1031 if (op->aop->type == AOP_SFR)
1033 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1034 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1039 /* if the underlying symbol has a aop */
1040 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1042 op->aop = OP_SYMBOL (op)->aop;
1043 if (op->aop->type == AOP_SFR)
1045 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1046 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1051 /* if this is a true symbol */
1052 if (IS_TRUE_SYMOP (op))
1054 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1058 /* this is a temporary : this has
1064 e) can be a return use only */
1066 sym = OP_SYMBOL (op);
1068 /* if the type is a conditional */
1069 if (sym->regType == REG_CND)
1071 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1076 /* if it is spilt then two situations
1078 b) has a spill location */
1079 if (sym->isspilt || sym->nRegs == 0)
1081 /* rematerialize it NOW */
1084 sym->aop = op->aop = aop =
1086 aop->size = getSize (sym->type);
1093 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1094 aop->size = getSize (sym->type);
1095 for (i = 0; i < 4; i++)
1096 aop->aopu.aop_str[i] = _fReturn[i];
1102 if (sym->accuse == ACCUSE_A)
1104 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1105 aop->size = getSize (sym->type);
1106 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1108 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1110 else if (sym->accuse == ACCUSE_SCRATCH)
1112 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1113 aop->size = getSize (sym->type);
1114 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1115 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1116 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1118 else if (sym->accuse == ACCUSE_IY)
1120 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1121 aop->size = getSize (sym->type);
1122 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1123 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1124 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1128 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1133 if (sym->usl.spillLoc)
1135 asmop *oldAsmOp = NULL;
1137 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1139 /* force a new aop if sizes differ */
1140 oldAsmOp = sym->usl.spillLoc->aop;
1141 sym->usl.spillLoc->aop = NULL;
1143 sym->aop = op->aop = aop =
1144 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1145 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1147 /* Don't reuse the new aop, go with the last one */
1148 sym->usl.spillLoc->aop = oldAsmOp;
1150 aop->size = getSize (sym->type);
1154 /* else must be a dummy iTemp */
1155 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1156 aop->size = getSize (sym->type);
1160 /* must be in a register */
1161 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1162 aop->size = sym->nRegs;
1163 for (i = 0; i < sym->nRegs; i++)
1164 aop->aopu.aop_reg[i] = sym->regs[i];
1167 /*-----------------------------------------------------------------*/
1168 /* freeAsmop - free up the asmop given to an operand */
1169 /*----------------------------------------------------------------*/
1171 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1188 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1190 _pop (aop->aopu.aop_pairId);
1193 if (getPairId (aop) == PAIR_HL)
1195 spillPair (PAIR_HL);
1199 /* all other cases just dealloc */
1205 OP_SYMBOL (op)->aop = NULL;
1206 /* if the symbol has a spill */
1208 SPIL_LOC (op)->aop = NULL;
1215 isLitWord (asmop * aop)
1217 /* if (aop->size != 2)
1230 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1232 /* depending on type */
1238 /* PENDING: for re-target */
1241 tsprintf (buffer, sizeof(buffer),
1242 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1244 else if (offset == 0)
1246 tsprintf (buffer, sizeof(buffer),
1247 "%s", aop->aopu.aop_immd);
1251 tsprintf (buffer, sizeof(buffer),
1252 "%s + %d", aop->aopu.aop_immd, offset);
1254 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1258 value *val = aop->aopu.aop_lit;
1259 /* if it is a float then it gets tricky */
1260 /* otherwise it is fairly simple */
1261 if (!IS_FLOAT (val->type))
1263 unsigned long v = (unsigned long) floatFromVal (val);
1269 else if (offset == 0)
1275 wassertl(0, "Encountered an invalid offset while fetching a literal");
1279 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1281 tsprintf (buffer, sizeof(buffer), "!constword", v);
1283 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1294 /* it is type float */
1295 fl.f = (float) floatFromVal (val);
1297 #ifdef WORDS_BIGENDIAN
1298 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1300 i = fl.c[offset] | (fl.c[offset+1]<<8);
1303 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1305 tsprintf (buffer, sizeof(buffer), "!constword", i);
1307 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1316 aopGetWord (asmop * aop, int offset)
1318 return aopGetLitWordLong (aop, offset, TRUE);
1322 isPtr (const char *s)
1324 if (!strcmp (s, "hl"))
1326 if (!strcmp (s, "ix"))
1328 if (!strcmp (s, "iy"))
1334 adjustPair (const char *pair, int *pold, int new)
1340 emit2 ("inc %s", pair);
1345 emit2 ("dec %s", pair);
1353 spillPair (PAIR_HL);
1354 spillPair (PAIR_IY);
1358 requiresHL (asmop * aop)
1374 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1376 const char *l, *base;
1377 const char *pair = _pairs[pairId].name;
1378 l = aopGetLitWordLong (left, offset, FALSE);
1379 base = aopGetLitWordLong (left, 0, FALSE);
1380 wassert (l && pair && base);
1384 if (pairId == PAIR_HL || pairId == PAIR_IY)
1386 if (_G.pairs[pairId].last_type == left->type)
1388 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1390 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1392 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1395 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1402 _G.pairs[pairId].last_type = left->type;
1403 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1404 _G.pairs[pairId].offset = offset;
1406 /* Both a lit on the right and a true symbol on the left */
1407 emit2 ("ld %s,!hashedstr", pair, l);
1411 makeFreePairId (iCode *ic, bool *pisUsed)
1417 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1421 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1439 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1441 /* if this is remateriazable */
1442 if (isLitWord (aop)) {
1443 fetchLitPair (pairId, aop, offset);
1447 if (getPairId (aop) == pairId)
1451 /* we need to get it byte by byte */
1452 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1453 aopGet (aop, offset, FALSE);
1454 switch (aop->size - offset) {
1456 emit2 ("ld l,!*hl");
1457 emit2 ("ld h,!immedbyte", 0);
1460 // PENDING: Requires that you are only fetching two bytes.
1463 emit2 ("ld h,!*hl");
1467 wassertl (0, "Attempted to fetch too much data into HL");
1471 else if (IS_Z80 && aop->type == AOP_IY) {
1472 /* Instead of fetching relative to IY, just grab directly
1473 from the address IY refers to */
1474 char *l = aopGetLitWordLong (aop, offset, FALSE);
1476 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1478 if (aop->size < 2) {
1479 emit2("ld %s,!zero", _pairs[pairId].h);
1482 else if (pairId == PAIR_IY)
1486 emit2 ("push %s", _pairs[getPairId(aop)].name);
1492 PAIR_ID id = makeFreePairId (ic, &isUsed);
1495 /* Can't load into parts, so load into HL then exchange. */
1496 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1497 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1498 emit2 ("push %s", _pairs[id].name);
1504 else if (isUnsplitable(aop))
1506 emit2("push %s", _pairs[getPairId(aop)].name);
1507 emit2("pop %s", _pairs[pairId].name);
1511 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1512 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1514 /* PENDING: check? */
1515 if (pairId == PAIR_HL)
1516 spillPair (PAIR_HL);
1521 fetchPair (PAIR_ID pairId, asmop * aop)
1523 fetchPairLong (pairId, aop, NULL, 0);
1527 fetchHL (asmop * aop)
1529 fetchPair (PAIR_HL, aop);
1533 setupPairFromSP (PAIR_ID id, int offset)
1535 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1537 if (_G.preserveCarry)
1543 if (offset < INT8MIN || offset > INT8MAX)
1545 emit2 ("ld hl,!immedword", offset);
1546 emit2 ("add hl,sp");
1550 emit2 ("!ldahlsp", offset);
1553 if (_G.preserveCarry)
1561 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1566 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1567 fetchLitPair (pairId, aop, 0);
1571 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1573 fetchLitPair (pairId, aop, offset);
1574 _G.pairs[pairId].offset = offset;
1578 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1579 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1582 int offset = aop->aopu.aop_stk + _G.stack.offset;
1584 if (_G.pairs[pairId].last_type == aop->type &&
1585 _G.pairs[pairId].offset == offset)
1591 /* PENDING: Do this better. */
1592 if (_G.preserveCarry)
1594 sprintf (buffer, "%d", offset + _G.stack.pushed);
1595 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1596 emit2 ("add %s,sp", _pairs[pairId].name);
1597 _G.pairs[pairId].last_type = aop->type;
1598 _G.pairs[pairId].offset = offset;
1599 if (_G.preserveCarry)
1607 /* Doesnt include _G.stack.pushed */
1608 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1610 if (aop->aopu.aop_stk > 0)
1612 abso += _G.stack.param_offset;
1614 assert (pairId == PAIR_HL);
1615 /* In some cases we can still inc or dec hl */
1616 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1618 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1622 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1624 _G.pairs[pairId].offset = abso;
1629 if (pairId != aop->aopu.aop_pairId)
1630 genMovePairPair(aop->aopu.aop_pairId, pairId);
1631 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1637 _G.pairs[pairId].last_type = aop->type;
1643 emit2 ("!tlabeldef", key);
1644 _G.lines.current->isLabel = 1;
1648 /*-----------------------------------------------------------------*/
1649 /* aopGet - for fetching value of the aop */
1650 /*-----------------------------------------------------------------*/
1652 aopGet (asmop * aop, int offset, bool bit16)
1654 // char *s = buffer;
1656 /* offset is greater than size then zero */
1657 /* PENDING: this seems a bit screwed in some pointer cases. */
1658 if (offset > (aop->size - 1) &&
1659 aop->type != AOP_LIT)
1661 tsprintf (buffer, sizeof(buffer), "!zero");
1662 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1665 /* depending on type */
1669 tsprintf (buffer, sizeof(buffer), "!zero");
1670 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1673 /* PENDING: re-target */
1675 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1680 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1683 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1686 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1689 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1692 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1696 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1697 SNPRINTF (buffer, sizeof(buffer), "a");
1699 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1705 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1706 SNPRINTF (buffer, sizeof(buffer), "a");
1708 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1711 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1714 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1715 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1716 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1718 else if( z80_opts.port_mode == 180 )
1719 { /* z180 in0/out0 mode */
1720 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1724 emit2( "in a,(%s)", aop->aopu.aop_dir );
1727 SNPRINTF (buffer, sizeof(buffer), "a");
1729 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1733 return aop->aopu.aop_reg[offset]->name;
1737 setupPair (PAIR_HL, aop, offset);
1738 tsprintf (buffer, sizeof(buffer), "!*hl");
1740 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1744 setupPair (PAIR_IY, aop, offset);
1745 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1747 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1751 setupPair (PAIR_IY, aop, offset);
1752 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1754 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1759 setupPair (PAIR_HL, aop, offset);
1760 tsprintf (buffer, sizeof(buffer), "!*hl");
1764 if (aop->aopu.aop_stk >= 0)
1765 offset += _G.stack.param_offset;
1766 tsprintf (buffer, sizeof(buffer),
1767 "!*ixx", aop->aopu.aop_stk + offset);
1770 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1773 wassertl (0, "Tried to fetch from a bit variable");
1782 tsprintf(buffer, sizeof(buffer), "!zero");
1783 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1787 wassert (offset < 2);
1788 return aop->aopu.aop_str[offset];
1791 return aopLiteral (aop->aopu.aop_lit, offset);
1795 unsigned long v = aop->aopu.aop_simplelit;
1798 tsprintf (buffer, sizeof(buffer),
1799 "!immedbyte", (unsigned int) v & 0xff);
1801 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1805 return aop->aopu.aop_str[offset];
1808 setupPair (aop->aopu.aop_pairId, aop, offset);
1809 if (aop->aopu.aop_pairId==PAIR_IX)
1810 SNPRINTF (buffer, sizeof(buffer),
1812 else if (aop->aopu.aop_pairId==PAIR_IY)
1813 SNPRINTF (buffer, sizeof(buffer),
1816 SNPRINTF (buffer, sizeof(buffer),
1817 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1819 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1824 wassertl (0, "aopget got unsupported aop->type");
1829 isRegString (const char *s)
1831 if (!strcmp (s, "b") ||
1843 isConstant (const char *s)
1845 /* This is a bit of a hack... */
1846 return (*s == '#' || *s == '$');
1850 canAssignToPtr (const char *s)
1852 if (isRegString (s))
1859 /*-----------------------------------------------------------------*/
1860 /* aopPut - puts a string for a aop */
1861 /*-----------------------------------------------------------------*/
1863 aopPut (asmop * aop, const char *s, int offset)
1867 if (aop->size && offset > (aop->size - 1))
1869 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1870 "aopPut got offset > aop->size");
1875 tsprintf(buffer2, sizeof(buffer2), s);
1878 /* will assign value to value */
1879 /* depending on where it is ofcourse */
1883 _moveA (s); /* in case s is volatile */
1889 if (strcmp (s, "a"))
1890 emit2 ("ld a,%s", s);
1891 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1898 if (strcmp (s, "a"))
1899 emit2 ("ld a,%s", s);
1900 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1903 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1910 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1911 && s[0] != 'h' && s[0] != 'l'))
1913 emit2( "ld a,%s", s );
1917 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1918 emit2( "out (c),%s", s );
1923 spillPair (PAIR_BC);
1925 else if( z80_opts.port_mode == 180 )
1926 { /* z180 in0/out0 mode */
1927 emit2( "ld a,%s", s );
1928 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1932 emit2( "ld a,%s", s );
1933 emit2( "out (%s),a", aop->aopu.aop_dir );
1939 if (!strcmp (s, "!*hl"))
1940 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1943 aop->aopu.aop_reg[offset]->name, s);
1944 spillPairReg(aop->aopu.aop_reg[offset]->name);
1949 if (!canAssignToPtr (s))
1951 emit2 ("ld a,%s", s);
1952 setupPair (PAIR_IY, aop, offset);
1953 emit2 ("ld !*iyx,a", offset);
1957 setupPair (PAIR_IY, aop, offset);
1958 emit2 ("ld !*iyx,%s", offset, s);
1964 /* PENDING: for re-target */
1965 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1967 emit2 ("ld a,!*hl");
1970 setupPair (PAIR_HL, aop, offset);
1972 emit2 ("ld !*hl,%s", s);
1977 if (!canAssignToPtr (s))
1979 emit2 ("ld a,%s", s);
1980 setupPair (PAIR_IY, aop, offset);
1981 emit2 ("ld !*iyx,a", offset);
1985 setupPair (PAIR_IY, aop, offset);
1986 emit2 ("ld !*iyx,%s", offset, s);
1993 /* PENDING: re-target */
1994 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1996 emit2 ("ld a,!*hl");
1999 setupPair (PAIR_HL, aop, offset);
2000 if (!canAssignToPtr (s))
2002 emit2 ("ld a,%s", s);
2003 emit2 ("ld !*hl,a");
2006 emit2 ("ld !*hl,%s", s);
2010 if (aop->aopu.aop_stk >= 0)
2011 offset += _G.stack.param_offset;
2012 if (!canAssignToPtr (s))
2014 emit2 ("ld a,%s", s);
2015 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2019 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2025 /* if bit variable */
2026 if (!aop->aopu.aop_dir)
2028 emit2 ("ld a,!zero");
2033 /* In bit space but not in C - cant happen */
2034 wassertl (0, "Tried to write into a bit variable");
2040 if (strcmp (aop->aopu.aop_str[offset], s))
2042 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2044 spillPairReg(aop->aopu.aop_str[offset]);
2049 if (!offset && (strcmp (s, "acc") == 0))
2053 wassertl (0, "Tried to access past the end of A");
2057 if (strcmp (aop->aopu.aop_str[offset], s))
2059 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2060 spillPairReg(aop->aopu.aop_str[offset]);
2066 wassert (offset < 2);
2067 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2068 spillPairReg(aop->aopu.aop_str[offset]);
2072 setupPair (aop->aopu.aop_pairId, aop, offset);
2073 if (aop->aopu.aop_pairId==PAIR_IX)
2074 emit2 ("ld !*ixx,%s", 0, s);
2075 else if (aop->aopu.aop_pairId==PAIR_IY)
2076 emit2 ("ld !*iyx,%s", 0, s);
2078 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2082 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2083 "aopPut got unsupported aop->type");
2088 #define AOP(op) op->aop
2089 #define AOP_TYPE(op) AOP(op)->type
2090 #define AOP_SIZE(op) AOP(op)->size
2091 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2092 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2095 commitPair (asmop * aop, PAIR_ID id)
2097 /* PENDING: Verify this. */
2098 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2102 aopPut (aop, "a", 0);
2103 aopPut (aop, "d", 1);
2108 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2110 char *l = aopGetLitWordLong (aop, 0, FALSE);
2113 emit2 ("ld (%s),%s", l, _pairs[id].name);
2117 aopPut (aop, _pairs[id].l, 0);
2118 aopPut (aop, _pairs[id].h, 1);
2123 /*-----------------------------------------------------------------*/
2124 /* getDataSize - get the operand data size */
2125 /*-----------------------------------------------------------------*/
2127 getDataSize (operand * op)
2130 size = AOP_SIZE (op);
2134 wassertl (0, "Somehow got a three byte data pointer");
2139 /*-----------------------------------------------------------------*/
2140 /* movLeft2Result - move byte from left to result */
2141 /*-----------------------------------------------------------------*/
2143 movLeft2Result (operand * left, int offl,
2144 operand * result, int offr, int sign)
2148 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2150 l = aopGet (AOP (left), offl, FALSE);
2154 aopPut (AOP (result), l, offr);
2158 if (getDataSize (left) == offl + 1)
2160 emit2 ("ld a,%s", l);
2161 aopPut (AOP (result), "a", offr);
2168 movLeft2ResultLong (operand * left, int offl,
2169 operand * result, int offr, int sign,
2174 movLeft2Result (left, offl, result, offr, sign);
2178 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2179 wassertl (size == 2, "Only implemented for two bytes or one");
2181 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2183 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2184 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2186 spillPair (PAIR_HL);
2188 else if ( getPairId ( AOP (result)) == PAIR_IY)
2190 PAIR_ID id = getPairId (AOP (left));
2191 if (id != PAIR_INVALID)
2193 emit2("push %s", _pairs[id].name);
2204 movLeft2Result (left, offl, result, offr, sign);
2205 movLeft2Result (left, offl+1, result, offr+1, sign);
2210 /** Put Acc into a register set
2213 outAcc (operand * result)
2216 size = getDataSize (result);
2219 aopPut (AOP (result), "a", 0);
2222 /* unsigned or positive */
2225 aopPut (AOP (result), "!zero", offset++);
2230 /** Take the value in carry and put it into a register
2233 outBitC (operand * result)
2235 /* if the result is bit */
2236 if (AOP_TYPE (result) == AOP_CRY)
2238 if (!IS_OP_RUONLY (result))
2239 aopPut (AOP (result), "c", 0);
2243 emit2 ("ld a,!zero");
2249 /*-----------------------------------------------------------------*/
2250 /* toBoolean - emit code for orl a,operator(sizeop) */
2251 /*-----------------------------------------------------------------*/
2253 _toBoolean (operand * oper)
2255 int size = AOP_SIZE (oper);
2259 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2262 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2266 if (AOP (oper)->type != AOP_ACC)
2269 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2275 /*-----------------------------------------------------------------*/
2276 /* genNot - generate code for ! operation */
2277 /*-----------------------------------------------------------------*/
2282 /* assign asmOps to operand & result */
2283 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2284 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2286 /* if in bit space then a special case */
2287 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2289 wassertl (0, "Tried to negate a bit");
2292 _toBoolean (IC_LEFT (ic));
2297 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2298 emit2 ("sub a,!one");
2299 outBitC (IC_RESULT (ic));
2301 /* release the aops */
2302 freeAsmop (IC_LEFT (ic), NULL, ic);
2303 freeAsmop (IC_RESULT (ic), NULL, ic);
2306 /*-----------------------------------------------------------------*/
2307 /* genCpl - generate code for complement */
2308 /*-----------------------------------------------------------------*/
2316 /* assign asmOps to operand & result */
2317 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2318 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2320 /* if both are in bit space then
2322 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2323 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2325 wassertl (0, "Left and the result are in bit space");
2328 size = AOP_SIZE (IC_RESULT (ic));
2331 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2334 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2337 /* release the aops */
2338 freeAsmop (IC_LEFT (ic), NULL, ic);
2339 freeAsmop (IC_RESULT (ic), NULL, ic);
2343 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2350 store de into result
2355 store de into result
2357 const char *first = isAdd ? "add" : "sub";
2358 const char *later = isAdd ? "adc" : "sbc";
2360 wassertl (IS_GB, "Code is only relevent to the gbz80");
2361 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2363 fetchPair (PAIR_DE, left);
2366 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2369 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2372 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2373 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2375 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2376 aopGet (right, MSB24, FALSE);
2380 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2383 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2385 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2386 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2390 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2392 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2395 /*-----------------------------------------------------------------*/
2396 /* genUminusFloat - unary minus for floating points */
2397 /*-----------------------------------------------------------------*/
2399 genUminusFloat (operand * op, operand * result)
2401 int size, offset = 0;
2403 emitDebug("; genUminusFloat");
2405 /* for this we just need to flip the
2406 first bit then copy the rest in place */
2407 size = AOP_SIZE (op) - 1;
2409 _moveA(aopGet (AOP (op), MSB32, FALSE));
2411 emit2("xor a,!immedbyte", 0x80);
2412 aopPut (AOP (result), "a", MSB32);
2416 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2421 /*-----------------------------------------------------------------*/
2422 /* genUminus - unary minus code generation */
2423 /*-----------------------------------------------------------------*/
2425 genUminus (iCode * ic)
2428 sym_link *optype, *rtype;
2431 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2432 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2434 /* if both in bit space then special
2436 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2437 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2439 wassertl (0, "Left and right are in bit space");
2443 optype = operandType (IC_LEFT (ic));
2444 rtype = operandType (IC_RESULT (ic));
2446 /* if float then do float stuff */
2447 if (IS_FLOAT (optype))
2449 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2453 /* otherwise subtract from zero */
2454 size = AOP_SIZE (IC_LEFT (ic));
2456 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2458 /* Create a new asmop with value zero */
2459 asmop *azero = newAsmop (AOP_SIMPLELIT);
2460 azero->aopu.aop_simplelit = 0;
2462 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2470 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2471 emit2 ("ld a,!zero");
2472 emit2 ("sbc a,%s", l);
2473 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2476 /* if any remaining bytes in the result */
2477 /* we just need to propagate the sign */
2478 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2483 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2487 /* release the aops */
2488 freeAsmop (IC_LEFT (ic), NULL, ic);
2489 freeAsmop (IC_RESULT (ic), NULL, ic);
2492 /*-----------------------------------------------------------------*/
2493 /* assignResultValue - */
2494 /*-----------------------------------------------------------------*/
2496 assignResultValue (operand * oper)
2498 int size = AOP_SIZE (oper);
2501 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2502 topInA = requiresHL (AOP (oper));
2504 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2506 /* We do it the hard way here. */
2508 aopPut (AOP (oper), _fReturn[0], 0);
2509 aopPut (AOP (oper), _fReturn[1], 1);
2511 aopPut (AOP (oper), _fReturn[0], 2);
2512 aopPut (AOP (oper), _fReturn[1], 3);
2516 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2517 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2520 _emitMove ("a", _fReturn[size-1]);
2521 _emitMove (_fReturn[size-1], _fReturn[size]);
2522 _emitMove (_fReturn[size], "a");
2523 aopPut (AOP (oper), _fReturn[size], size-1);
2528 aopPut (AOP (oper), _fReturn[size], size);
2533 /** Simple restore that doesn't take into account what is used in the
2537 _restoreRegsAfterCall(void)
2539 if (_G.stack.pushedDE)
2542 _G.stack.pushedDE = FALSE;
2544 if (_G.stack.pushedBC)
2547 _G.stack.pushedBC = FALSE;
2549 _G.saves.saved = FALSE;
2553 _saveRegsForCall(iCode *ic, int sendSetSize)
2556 o Stack parameters are pushed before this function enters
2557 o DE and BC may be used in this function.
2558 o HL and DE may be used to return the result.
2559 o HL and DE may be used to send variables.
2560 o DE and BC may be used to store the result value.
2561 o HL may be used in computing the sent value of DE
2562 o The iPushes for other parameters occur before any addSets
2564 Logic: (to be run inside the first iPush or if none, before sending)
2565 o Compute if DE and/or BC are in use over the call
2566 o Compute if DE is used in the send set
2567 o Compute if DE and/or BC are used to hold the result value
2568 o If (DE is used, or in the send set) and is not used in the result, push.
2569 o If BC is used and is not in the result, push
2571 o If DE is used in the send set, fetch
2572 o If HL is used in the send set, fetch
2576 if (_G.saves.saved == FALSE) {
2577 bool deInUse, bcInUse;
2579 bool bcInRet = FALSE, deInRet = FALSE;
2582 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2583 z80_rUmaskForOp (IC_RESULT(ic)));
2585 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2586 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2588 deSending = (sendSetSize > 1);
2590 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2592 if (bcInUse && bcInRet == FALSE) {
2594 _G.stack.pushedBC = TRUE;
2596 if (deInUse && deInRet == FALSE) {
2598 _G.stack.pushedDE = TRUE;
2601 _G.saves.saved = TRUE;
2604 /* Already saved. */
2608 /*-----------------------------------------------------------------*/
2609 /* genIpush - genrate code for pushing this gets a little complex */
2610 /*-----------------------------------------------------------------*/
2612 genIpush (iCode * ic)
2614 int size, offset = 0;
2617 /* if this is not a parm push : ie. it is spill push
2618 and spill push is always done on the local stack */
2621 wassertl(0, "Encountered an unsupported spill push.");
2625 if (_G.saves.saved == FALSE) {
2626 /* Caller saves, and this is the first iPush. */
2627 /* Scan ahead until we find the function that we are pushing parameters to.
2628 Count the number of addSets on the way to figure out what registers
2629 are used in the send set.
2632 iCode *walk = ic->next;
2635 if (walk->op == SEND) {
2638 else if (walk->op == CALL || walk->op == PCALL) {
2647 _saveRegsForCall(walk, nAddSets);
2650 /* Already saved by another iPush. */
2653 /* then do the push */
2654 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2656 size = AOP_SIZE (IC_LEFT (ic));
2658 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2660 _G.stack.pushed += 2;
2661 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2667 fetchHL (AOP (IC_LEFT (ic)));
2669 spillPair (PAIR_HL);
2670 _G.stack.pushed += 2;
2675 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2677 spillPair (PAIR_HL);
2678 _G.stack.pushed += 2;
2679 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2681 spillPair (PAIR_HL);
2682 _G.stack.pushed += 2;
2688 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2690 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2692 emit2 ("ld a,(%s)", l);
2697 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2698 if (!strcmp(l, "b"))
2700 else if (!strcmp(l, "d"))
2702 else if (!strcmp(l, "h"))
2706 emit2 ("ld a,%s", l);
2715 freeAsmop (IC_LEFT (ic), NULL, ic);
2718 /*-----------------------------------------------------------------*/
2719 /* genIpop - recover the registers: can happen only for spilling */
2720 /*-----------------------------------------------------------------*/
2722 genIpop (iCode * ic)
2727 /* if the temp was not pushed then */
2728 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2731 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2732 size = AOP_SIZE (IC_LEFT (ic));
2733 offset = (size - 1);
2734 if (isPair (AOP (IC_LEFT (ic))))
2736 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2744 spillPair (PAIR_HL);
2745 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2749 freeAsmop (IC_LEFT (ic), NULL, ic);
2752 /* This is quite unfortunate */
2754 setArea (int inHome)
2757 static int lastArea = 0;
2759 if (_G.in_home != inHome) {
2761 const char *sz = port->mem.code_name;
2762 port->mem.code_name = "HOME";
2763 emit2("!area", CODE_NAME);
2764 port->mem.code_name = sz;
2767 emit2("!area", CODE_NAME); */
2768 _G.in_home = inHome;
2779 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2783 symbol *sym = OP_SYMBOL (op);
2785 if (sym->isspilt || sym->nRegs == 0)
2788 aopOp (op, ic, FALSE, FALSE);
2791 if (aop->type == AOP_REG)
2794 for (i = 0; i < aop->size; i++)
2796 if (pairId == PAIR_DE)
2798 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2799 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2801 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2804 else if (pairId == PAIR_BC)
2806 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2807 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2809 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2819 freeAsmop (IC_LEFT (ic), NULL, ic);
2823 /** Emit the code for a call statement
2826 emitCall (iCode * ic, bool ispcall)
2828 bool bInRet, cInRet, dInRet, eInRet;
2829 sym_link *dtype = operandType (IC_LEFT (ic));
2831 /* if caller saves & we have not saved then */
2837 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2839 /* if send set is not empty then assign */
2844 int nSend = elementsInSet(_G.sendSet);
2845 bool swapped = FALSE;
2847 int _z80_sendOrder[] = {
2852 /* Check if the parameters are swapped. If so route through hl instead. */
2853 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2855 sic = setFirstItem(_G.sendSet);
2856 sic = setNextItem(_G.sendSet);
2858 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2859 /* The second send value is loaded from one the one that holds the first
2860 send, i.e. it is overwritten. */
2861 /* Cache the first in HL, and load the second from HL instead. */
2862 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2863 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2869 for (sic = setFirstItem (_G.sendSet); sic;
2870 sic = setNextItem (_G.sendSet))
2873 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2875 size = AOP_SIZE (IC_LEFT (sic));
2876 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2877 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2879 // PENDING: Mild hack
2880 if (swapped == TRUE && send == 1) {
2882 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2885 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2887 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2890 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2894 freeAsmop (IC_LEFT (sic), NULL, sic);
2901 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2903 werror (W_INDIR_BANKED);
2905 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2907 if (isLitWord (AOP (IC_LEFT (ic))))
2909 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2913 symbol *rlbl = newiTempLabel (NULL);
2914 spillPair (PAIR_HL);
2915 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2917 _G.stack.pushed += 2;
2919 fetchHL (AOP (IC_LEFT (ic)));
2921 emit2 ("!tlabeldef", (rlbl->key + 100));
2922 _G.lines.current->isLabel = 1;
2923 _G.stack.pushed -= 2;
2925 freeAsmop (IC_LEFT (ic), NULL, ic);
2929 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2930 OP_SYMBOL (IC_LEFT (ic))->rname :
2931 OP_SYMBOL (IC_LEFT (ic))->name;
2932 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2934 emit2 ("call banked_call");
2935 emit2 ("!dws", name);
2936 emit2 ("!dw !bankimmeds", name);
2941 emit2 ("call %s", name);
2946 /* Mark the registers as restored. */
2947 _G.saves.saved = FALSE;
2949 /* if we need assign a result value */
2950 if ((IS_ITEMP (IC_RESULT (ic)) &&
2951 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2952 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2953 IS_TRUE_SYMOP (IC_RESULT (ic)))
2955 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2957 assignResultValue (IC_RESULT (ic));
2959 freeAsmop (IC_RESULT (ic), NULL, ic);
2962 /* adjust the stack for parameters if required */
2965 int i = ic->parmBytes;
2967 _G.stack.pushed -= i;
2970 emit2 ("!ldaspsp", i);
2977 emit2 ("ld iy,!immedword", i);
2978 emit2 ("add iy,sp");
2999 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3000 bInRet = bitVectBitValue(result, B_IDX);
3001 cInRet = bitVectBitValue(result, C_IDX);
3002 dInRet = bitVectBitValue(result, D_IDX);
3003 eInRet = bitVectBitValue(result, E_IDX);
3013 if (_G.stack.pushedDE)
3015 if (dInRet && eInRet)
3017 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3021 /* Only restore E */
3028 /* Only restore D */
3036 _G.stack.pushedDE = FALSE;
3039 if (_G.stack.pushedBC)
3041 if (bInRet && cInRet)
3043 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3047 /* Only restore C */
3054 /* Only restore B */
3062 _G.stack.pushedBC = FALSE;
3066 /*-----------------------------------------------------------------*/
3067 /* genCall - generates a call statement */
3068 /*-----------------------------------------------------------------*/
3070 genCall (iCode * ic)
3072 emitCall (ic, FALSE);
3075 /*-----------------------------------------------------------------*/
3076 /* genPcall - generates a call by pointer statement */
3077 /*-----------------------------------------------------------------*/
3079 genPcall (iCode * ic)
3081 emitCall (ic, TRUE);
3084 /*-----------------------------------------------------------------*/
3085 /* resultRemat - result is rematerializable */
3086 /*-----------------------------------------------------------------*/
3088 resultRemat (iCode * ic)
3090 if (SKIP_IC (ic) || ic->op == IFX)
3093 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3095 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3096 if (sym->remat && !POINTER_SET (ic))
3103 extern set *publics;
3105 /*-----------------------------------------------------------------*/
3106 /* genFunction - generated code for function entry */
3107 /*-----------------------------------------------------------------*/
3109 genFunction (iCode * ic)
3113 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3116 bool bcInUse = FALSE;
3117 bool deInUse = FALSE;
3119 setArea (IFFUNC_NONBANKED (sym->type));
3121 /* PENDING: Reset the receive offset as it
3122 doesn't seem to get reset anywhere else.
3124 _G.receiveOffset = 0;
3126 /* Record the last function name for debugging. */
3127 _G.lastFunctionName = sym->rname;
3129 /* Create the function header */
3130 emit2 ("!functionheader", sym->name);
3131 if (!IS_STATIC(sym->etype))
3133 sprintf (buffer, "%s_start", sym->rname);
3134 emit2 ("!labeldef", buffer);
3135 _G.lines.current->isLabel = 1;
3137 emit2 ("!functionlabeldef", sym->rname);
3138 _G.lines.current->isLabel = 1;
3140 ftype = operandType (IC_LEFT (ic));
3142 if (IFFUNC_ISNAKED(ftype))
3144 emitDebug("; naked function: no prologue.");
3148 /* if this is an interrupt service routine
3149 then save all potentially used registers. */
3150 if (IFFUNC_ISISR (sym->type))
3152 /* If critical function then turn interrupts off */
3153 /* except when no interrupt number is given then it implies the NMI handler */
3154 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3163 /* This is a non-ISR function.
3164 If critical function then turn interrupts off */
3165 if (IFFUNC_ISCRITICAL (sym->type))
3173 //get interrupt enable flag IFF2 into P/O
3182 if (options.profile)
3184 emit2 ("!profileenter");
3187 /* PENDING: callee-save etc */
3189 _G.stack.param_offset = 0;
3191 if (z80_opts.calleeSavesBC)
3196 /* Detect which registers are used. */
3197 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3200 for (i = 0; i < sym->regsUsed->size; i++)
3202 if (bitVectBitValue (sym->regsUsed, i))
3216 /* Other systems use DE as a temporary. */
3227 _G.stack.param_offset += 2;
3230 _G.calleeSaves.pushedBC = bcInUse;
3235 _G.stack.param_offset += 2;
3238 _G.calleeSaves.pushedDE = deInUse;
3240 /* adjust the stack for the function */
3241 _G.stack.last = sym->stack;
3244 for (sym = setFirstItem (istack->syms); sym;
3245 sym = setNextItem (istack->syms))
3247 if (sym->_isparm && !IS_REGPARM (sym->etype))
3253 sym = OP_SYMBOL (IC_LEFT (ic));
3255 _G.omitFramePtr = options.ommitFramePtr;
3256 if (IS_Z80 && !stackParm && !sym->stack)
3258 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3259 /* the above !sym->stack condition can be removed. -- EEP */
3261 emit2 ("!ldaspsp", -sym->stack);
3262 _G.omitFramePtr = TRUE;
3264 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3265 emit2 ("!enterxl", sym->stack);
3266 else if (sym->stack)
3267 emit2 ("!enterx", sym->stack);
3271 _G.stack.offset = sym->stack;
3274 /*-----------------------------------------------------------------*/
3275 /* genEndFunction - generates epilogue for functions */
3276 /*-----------------------------------------------------------------*/
3278 genEndFunction (iCode * ic)
3280 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3282 if (IFFUNC_ISNAKED(sym->type))
3284 emitDebug("; naked function: no epilogue.");
3288 /* PENDING: calleeSave */
3289 if (IS_Z80 && _G.omitFramePtr)
3291 if (_G.stack.offset)
3292 emit2 ("!ldaspsp", _G.stack.offset);
3294 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3296 emit2 ("!leavexl", _G.stack.offset);
3298 else if (_G.stack.offset)
3300 emit2 ("!leavex", _G.stack.offset);
3307 if (_G.calleeSaves.pushedDE)
3310 _G.calleeSaves.pushedDE = FALSE;
3313 if (_G.calleeSaves.pushedBC)
3316 _G.calleeSaves.pushedBC = FALSE;
3319 if (options.profile)
3321 emit2 ("!profileexit");
3324 /* if this is an interrupt service routine
3325 then save all potentially used registers. */
3326 if (IFFUNC_ISISR (sym->type))
3330 /* If critical function then turn interrupts back on */
3331 /* except when no interrupt number is given then it implies the NMI handler */
3332 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3339 /* This is a non-ISR function.
3340 If critical function then turn interrupts back on */
3341 if (IFFUNC_ISCRITICAL (sym->type))
3349 symbol *tlbl = newiTempLabel (NULL);
3352 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3353 //don't enable interrupts as they were off before
3354 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3356 emit2 ("!tlabeldef", (tlbl->key + 100));
3357 _G.lines.current->isLabel = 1;
3362 if (options.debug && currFunc)
3364 debugFile->writeEndFunction (currFunc, ic, 1);
3367 if (IFFUNC_ISISR (sym->type))
3369 /* "critical interrupt" is used to imply NMI handler */
3370 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3377 /* Both banked and non-banked just ret */
3381 if (!IS_STATIC(sym->etype))
3383 sprintf (buffer, "%s_end", sym->rname);
3384 emit2 ("!labeldef", buffer);
3385 _G.lines.current->isLabel = 1;
3388 _G.flushStatics = 1;
3389 _G.stack.pushed = 0;
3390 _G.stack.offset = 0;
3393 /*-----------------------------------------------------------------*/
3394 /* genRet - generate code for return statement */
3395 /*-----------------------------------------------------------------*/
3400 /* Errk. This is a hack until I can figure out how
3401 to cause dehl to spill on a call */
3402 int size, offset = 0;
3404 /* if we have no return value then
3405 just generate the "ret" */
3409 /* we have something to return then
3410 move the return value into place */
3411 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3412 size = AOP_SIZE (IC_LEFT (ic));
3414 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3417 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3421 emit2 ("ld de,%s", l);
3425 emit2 ("ld hl,%s", l);
3431 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3435 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3437 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3438 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3444 l = aopGet (AOP (IC_LEFT (ic)), offset,
3446 if (strcmp (_fReturn[offset], l))
3447 emit2 ("ld %s,%s", _fReturn[offset], l);
3452 freeAsmop (IC_LEFT (ic), NULL, ic);
3455 /* generate a jump to the return label
3456 if the next is not the return statement */
3457 if (!(ic->next && ic->next->op == LABEL &&
3458 IC_LABEL (ic->next) == returnLabel))
3460 emit2 ("jp !tlabel", returnLabel->key + 100);
3463 /*-----------------------------------------------------------------*/
3464 /* genLabel - generates a label */
3465 /*-----------------------------------------------------------------*/
3467 genLabel (iCode * ic)
3469 /* special case never generate */
3470 if (IC_LABEL (ic) == entryLabel)
3473 emitLabel (IC_LABEL (ic)->key + 100);
3476 /*-----------------------------------------------------------------*/
3477 /* genGoto - generates a ljmp */
3478 /*-----------------------------------------------------------------*/
3480 genGoto (iCode * ic)
3482 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3485 /*-----------------------------------------------------------------*/
3486 /* genPlusIncr :- does addition with increment if possible */
3487 /*-----------------------------------------------------------------*/
3489 genPlusIncr (iCode * ic)
3491 unsigned int icount;
3492 unsigned int size = getDataSize (IC_RESULT (ic));
3493 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3495 /* will try to generate an increment */
3496 /* if the right side is not a literal
3498 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3501 emitDebug ("; genPlusIncr");
3503 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3505 /* If result is a pair */
3506 if (resultId != PAIR_INVALID)
3508 if (isLitWord (AOP (IC_LEFT (ic))))
3510 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3513 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3515 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3517 PAIR_ID freep = getFreePairId (ic);
3518 if (freep != PAIR_INVALID)
3520 fetchPair (freep, AOP (IC_RIGHT (ic)));
3521 emit2 ("add hl,%s", _pairs[freep].name);
3527 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3528 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3535 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3539 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3543 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3548 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3550 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3551 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3555 /* if the literal value of the right hand side
3556 is greater than 4 then it is not worth it */
3560 /* if increment 16 bits in register */
3561 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3567 symbol *tlbl = NULL;
3568 tlbl = newiTempLabel (NULL);
3571 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3574 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3577 emitLabel (tlbl->key + 100);
3581 /* if the sizes are greater than 1 then we cannot */
3582 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3583 AOP_SIZE (IC_LEFT (ic)) > 1)
3586 /* If the result is in a register then we can load then increment.
3588 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3590 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3593 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3598 /* we can if the aops of the left & result match or
3599 if they are in registers and the registers are the
3601 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3605 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3613 /*-----------------------------------------------------------------*/
3614 /* outBitAcc - output a bit in acc */
3615 /*-----------------------------------------------------------------*/
3617 outBitAcc (operand * result)
3619 symbol *tlbl = newiTempLabel (NULL);
3620 /* if the result is a bit */
3621 if (AOP_TYPE (result) == AOP_CRY)
3623 wassertl (0, "Tried to write A into a bit");
3627 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3628 emit2 ("ld a,!one");
3629 emitLabel (tlbl->key + 100);
3635 couldDestroyCarry (asmop *aop)
3639 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3648 shiftIntoPair (int idx, asmop *aop)
3650 PAIR_ID id = PAIR_INVALID;
3652 wassertl (IS_Z80, "Only implemented for the Z80");
3653 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3655 emitDebug ("; Shift into pair idx %u", idx);
3661 setupPair (PAIR_HL, aop, 0);
3666 setupPair (PAIR_IY, aop, 0);
3668 emit2 ("pop %s", _pairs[id].name);
3672 setupPair (PAIR_IY, aop, 0);
3675 wassertl (0, "Internal error - hit default case");
3678 aop->type = AOP_PAIRPTR;
3679 aop->aopu.aop_pairId = id;
3680 _G.pairs[id].offset = 0;
3681 _G.pairs[id].last_type = aop->type;
3685 setupToPreserveCarry (iCode * ic)
3687 asmop *left = AOP (IC_LEFT (ic));
3688 asmop *right = AOP (IC_RIGHT (ic));
3689 asmop *result = AOP (IC_RESULT (ic));
3691 wassert (left && right);
3695 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3697 shiftIntoPair (0, right);
3698 /* check result again, in case right == result */
3699 if (couldDestroyCarry (result))
3701 if (!isPairInUse (PAIR_DE, ic))
3702 shiftIntoPair (1, result);
3704 shiftIntoPair (2, result);
3707 else if (couldDestroyCarry (right))
3709 if (getPairId (result) == PAIR_HL)
3710 _G.preserveCarry = TRUE;
3712 shiftIntoPair (0, right);
3714 else if (couldDestroyCarry (result))
3716 shiftIntoPair (0, result);
3725 /*-----------------------------------------------------------------*/
3726 /* genPlus - generates code for addition */
3727 /*-----------------------------------------------------------------*/
3729 genPlus (iCode * ic)
3731 int size, offset = 0;
3733 /* special cases :- */
3735 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3736 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3737 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3739 /* Swap the left and right operands if:
3741 if literal, literal on the right or
3742 if left requires ACC or right is already
3745 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3746 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3747 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3749 operand *t = IC_RIGHT (ic);
3750 IC_RIGHT (ic) = IC_LEFT (ic);
3754 /* if both left & right are in bit
3756 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3757 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3760 wassertl (0, "Tried to add two bits");
3763 /* if left in bit space & right literal */
3764 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3765 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3767 /* Can happen I guess */
3768 wassertl (0, "Tried to add a bit to a literal");
3771 /* if I can do an increment instead
3772 of add then GOOD for ME */
3773 if (genPlusIncr (ic) == TRUE)
3776 size = getDataSize (IC_RESULT (ic));
3778 /* Special case when left and right are constant */
3779 if (isPair (AOP (IC_RESULT (ic))))
3782 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3783 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3785 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3791 sprintf (buffer, "#(%s + %s)", left, right);
3792 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3797 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3799 /* Fetch into HL then do the add */
3800 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3801 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3803 spillPair (PAIR_HL);
3805 if (left == PAIR_HL && right != PAIR_INVALID)
3807 emit2 ("add hl,%s", _pairs[right].name);
3810 else if (right == PAIR_HL && left != PAIR_INVALID)
3812 emit2 ("add hl,%s", _pairs[left].name);
3815 else if (right != PAIR_INVALID && right != PAIR_HL)
3817 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3818 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3821 else if (left != PAIR_INVALID && left != PAIR_HL)
3823 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3824 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3833 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3835 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3836 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3838 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3843 ld hl,sp+n trashes C so we can't afford to do it during an
3844 add with stack based variables. Worst case is:
3857 So you can't afford to load up hl if either left, right, or result
3858 is on the stack (*sigh*) The alt is:
3866 Combinations in here are:
3867 * If left or right are in bc then the loss is small - trap later
3868 * If the result is in bc then the loss is also small
3872 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3873 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3874 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3876 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3877 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3878 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3879 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3881 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3883 /* Swap left and right */
3884 operand *t = IC_RIGHT (ic);
3885 IC_RIGHT (ic) = IC_LEFT (ic);
3888 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3890 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3891 emit2 ("add hl,bc");
3895 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3896 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3897 emit2 ("add hl,de");
3899 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3905 /* Be paranoid on the GB with 4 byte variables due to how C
3906 can be trashed by lda hl,n(sp).
3908 _gbz80_emitAddSubLong (ic, TRUE);
3913 setupToPreserveCarry (ic);
3917 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3919 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3922 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3925 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3929 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3932 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3935 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3937 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3941 _G.preserveCarry = FALSE;
3942 freeAsmop (IC_LEFT (ic), NULL, ic);
3943 freeAsmop (IC_RIGHT (ic), NULL, ic);
3944 freeAsmop (IC_RESULT (ic), NULL, ic);
3947 /*-----------------------------------------------------------------*/
3948 /* genMinusDec :- does subtraction with deccrement if possible */
3949 /*-----------------------------------------------------------------*/
3951 genMinusDec (iCode * ic)
3953 unsigned int icount;
3954 unsigned int size = getDataSize (IC_RESULT (ic));
3956 /* will try to generate an increment */
3957 /* if the right side is not a literal we cannot */
3958 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3961 /* if the literal value of the right hand side
3962 is greater than 4 then it is not worth it */
3963 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3966 size = getDataSize (IC_RESULT (ic));
3968 /* if decrement 16 bits in register */
3969 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3970 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3973 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3977 /* If result is a pair */
3978 if (isPair (AOP (IC_RESULT (ic))))
3980 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3982 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3986 /* if increment 16 bits in register */
3987 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3991 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3994 emit2 ("dec %s", _getTempPairName());
3997 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4003 /* if the sizes are greater than 1 then we cannot */
4004 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4005 AOP_SIZE (IC_LEFT (ic)) > 1)
4008 /* we can if the aops of the left & result match or if they are in
4009 registers and the registers are the same */
4010 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4013 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4020 /*-----------------------------------------------------------------*/
4021 /* genMinus - generates code for subtraction */
4022 /*-----------------------------------------------------------------*/
4024 genMinus (iCode * ic)
4026 int size, offset = 0;
4027 unsigned long lit = 0L;
4029 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4030 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4031 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4033 /* special cases :- */
4034 /* if both left & right are in bit space */
4035 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4036 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4038 wassertl (0, "Tried to subtract two bits");
4042 /* if I can do an decrement instead of subtract then GOOD for ME */
4043 if (genMinusDec (ic) == TRUE)
4046 size = getDataSize (IC_RESULT (ic));
4048 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4053 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4057 /* Same logic as genPlus */
4060 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4061 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4062 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4064 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4065 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4066 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4067 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4069 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4070 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4072 if (left == PAIR_INVALID && right == PAIR_INVALID)
4077 else if (right == PAIR_INVALID)
4079 else if (left == PAIR_INVALID)
4082 fetchPair (left, AOP (IC_LEFT (ic)));
4083 /* Order is important. Right may be HL */
4084 fetchPair (right, AOP (IC_RIGHT (ic)));
4086 emit2 ("ld a,%s", _pairs[left].l);
4087 emit2 ("sub a,%s", _pairs[right].l);
4089 emit2 ("ld a,%s", _pairs[left].h);
4090 emit2 ("sbc a,%s", _pairs[right].h);
4092 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4094 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4096 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4102 /* Be paranoid on the GB with 4 byte variables due to how C
4103 can be trashed by lda hl,n(sp).
4105 _gbz80_emitAddSubLong (ic, FALSE);
4110 setupToPreserveCarry (ic);
4112 /* if literal, add a,#-lit, else normal subb */
4115 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4116 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4120 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4123 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4127 /* first add without previous c */
4129 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4131 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4133 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4136 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4137 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4138 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4140 wassertl (0, "Tried to subtract on a long pointer");
4144 _G.preserveCarry = FALSE;
4145 freeAsmop (IC_LEFT (ic), NULL, ic);
4146 freeAsmop (IC_RIGHT (ic), NULL, ic);
4147 freeAsmop (IC_RESULT (ic), NULL, ic);
4150 /*-----------------------------------------------------------------*/
4151 /* genMult - generates code for multiplication */
4152 /*-----------------------------------------------------------------*/
4154 genMult (iCode * ic)
4158 /* If true then the final operation should be a subtract */
4159 bool active = FALSE;
4162 /* Shouldn't occur - all done through function calls */
4163 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4164 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4165 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4167 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4169 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4170 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4171 AOP_SIZE (IC_RESULT (ic)) > 2)
4173 wassertl (0, "Multiplication is handled through support function calls");
4176 /* Swap left and right such that right is a literal */
4177 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4179 operand *t = IC_RIGHT (ic);
4180 IC_RIGHT (ic) = IC_LEFT (ic);
4184 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4186 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4187 // wassertl (val > 0, "Multiply must be positive");
4188 wassertl (val != 1, "Can't multiply by 1");
4190 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4192 _G.stack.pushedDE = TRUE;
4195 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4197 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4208 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4213 /* Fully unroled version of mul.s. Not the most efficient.
4215 for (count = 0; count < 16; count++)
4217 if (count != 0 && active)
4219 emit2 ("add hl,hl");
4223 if (active == FALSE)
4231 emit2 ("add hl,de");
4240 if (IS_Z80 && _G.stack.pushedDE)
4243 _G.stack.pushedDE = FALSE;
4247 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4249 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4251 freeAsmop (IC_LEFT (ic), NULL, ic);
4252 freeAsmop (IC_RIGHT (ic), NULL, ic);
4253 freeAsmop (IC_RESULT (ic), NULL, ic);
4256 /*-----------------------------------------------------------------*/
4257 /* genDiv - generates code for division */
4258 /*-----------------------------------------------------------------*/
4262 /* Shouldn't occur - all done through function calls */
4263 wassertl (0, "Division is handled through support function calls");
4266 /*-----------------------------------------------------------------*/
4267 /* genMod - generates code for division */
4268 /*-----------------------------------------------------------------*/
4272 /* Shouldn't occur - all done through function calls */
4276 /*-----------------------------------------------------------------*/
4277 /* genIfxJump :- will create a jump depending on the ifx */
4278 /*-----------------------------------------------------------------*/
4280 genIfxJump (iCode * ic, char *jval)
4285 /* if true label then we jump if condition
4289 jlbl = IC_TRUE (ic);
4290 if (!strcmp (jval, "a"))
4294 else if (!strcmp (jval, "c"))
4298 else if (!strcmp (jval, "nc"))
4302 else if (!strcmp (jval, "m"))
4306 else if (!strcmp (jval, "p"))
4312 /* The buffer contains the bit on A that we should test */
4318 /* false label is present */
4319 jlbl = IC_FALSE (ic);
4320 if (!strcmp (jval, "a"))
4324 else if (!strcmp (jval, "c"))
4328 else if (!strcmp (jval, "nc"))
4332 else if (!strcmp (jval, "m"))
4336 else if (!strcmp (jval, "p"))
4342 /* The buffer contains the bit on A that we should test */
4346 /* Z80 can do a conditional long jump */
4347 if (!strcmp (jval, "a"))
4351 else if (!strcmp (jval, "c"))
4354 else if (!strcmp (jval, "nc"))
4357 else if (!strcmp (jval, "m"))
4360 else if (!strcmp (jval, "p"))
4365 emit2 ("bit %s,a", jval);
4367 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4369 /* mark the icode as generated */
4375 _getPairIdName (PAIR_ID id)
4377 return _pairs[id].name;
4382 /* if unsigned char cmp with lit, just compare */
4384 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4386 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4389 emit2 ("xor a,!immedbyte", 0x80);
4390 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4393 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4395 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4397 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4398 // Pull left into DE and right into HL
4399 aopGet (AOP(left), LSB, FALSE);
4402 aopGet (AOP(right), LSB, FALSE);
4406 if (size == 0 && sign)
4408 // Highest byte when signed needs the bits flipped
4411 emit2 ("ld a,(de)");
4412 emit2 ("xor !immedbyte", 0x80);
4414 emit2 ("ld a,(hl)");
4415 emit2 ("xor !immedbyte", 0x80);
4419 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4423 emit2 ("ld a,(de)");
4424 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4434 spillPair (PAIR_HL);
4436 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4438 setupPair (PAIR_HL, AOP (left), 0);
4439 aopGet (AOP(right), LSB, FALSE);
4443 if (size == 0 && sign)
4445 // Highest byte when signed needs the bits flipped
4448 emit2 ("ld a,(hl)");
4449 emit2 ("xor !immedbyte", 0x80);
4451 emit2 ("ld a,%d(iy)", offset);
4452 emit2 ("xor !immedbyte", 0x80);
4456 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4460 emit2 ("ld a,(hl)");
4461 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4470 spillPair (PAIR_HL);
4471 spillPair (PAIR_IY);
4475 if (AOP_TYPE (right) == AOP_LIT)
4477 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4478 /* optimize if(x < 0) or if(x >= 0) */
4483 /* No sign so it's always false */
4488 /* Just load in the top most bit */
4489 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4490 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4492 genIfxJump (ifx, "7");
4504 /* First setup h and l contaning the top most bytes XORed */
4505 bool fDidXor = FALSE;
4506 if (AOP_TYPE (left) == AOP_LIT)
4508 unsigned long lit = (unsigned long)
4509 floatFromVal (AOP (left)->aopu.aop_lit);
4510 emit2 ("ld %s,!immedbyte", _fTmp[0],
4511 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4515 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4516 emit2 ("xor a,!immedbyte", 0x80);
4517 emit2 ("ld %s,a", _fTmp[0]);
4520 if (AOP_TYPE (right) == AOP_LIT)
4522 unsigned long lit = (unsigned long)
4523 floatFromVal (AOP (right)->aopu.aop_lit);
4524 emit2 ("ld %s,!immedbyte", _fTmp[1],
4525 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4529 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4530 emit2 ("xor a,!immedbyte", 0x80);
4531 emit2 ("ld %s,a", _fTmp[1]);
4537 /* Do a long subtract */
4540 _moveA (aopGet (AOP (left), offset, FALSE));
4542 if (sign && size == 0)
4544 emit2 ("ld a,%s", _fTmp[0]);
4545 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4549 /* Subtract through, propagating the carry */
4550 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4558 /** Generic compare for > or <
4561 genCmp (operand * left, operand * right,
4562 operand * result, iCode * ifx, int sign)
4564 int size, offset = 0;
4565 unsigned long lit = 0L;
4567 /* if left & right are bit variables */
4568 if (AOP_TYPE (left) == AOP_CRY &&
4569 AOP_TYPE (right) == AOP_CRY)
4571 /* Cant happen on the Z80 */
4572 wassertl (0, "Tried to compare two bits");
4576 /* Do a long subtract of right from left. */
4577 size = max (AOP_SIZE (left), AOP_SIZE (right));
4579 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4581 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4582 // Pull left into DE and right into HL
4583 aopGet (AOP(left), LSB, FALSE);
4586 aopGet (AOP(right), LSB, FALSE);
4590 emit2 ("ld a,(de)");
4591 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4600 spillPair (PAIR_HL);
4604 if (AOP_TYPE (right) == AOP_LIT)
4606 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4607 /* optimize if(x < 0) or if(x >= 0) */
4612 /* No sign so it's always false */
4617 /* Just load in the top most bit */
4618 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4619 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4621 genIfxJump (ifx, "7");
4632 genIfxJump (ifx, "nc");
4643 _moveA (aopGet (AOP (left), offset, FALSE));
4644 /* Subtract through, propagating the carry */
4645 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4651 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4655 /* Shift the sign bit up into carry */
4662 /* if the result is used in the next
4663 ifx conditional branch then generate
4664 code a little differently */
4672 genIfxJump (ifx, "c");
4676 genIfxJump (ifx, "m");
4681 genIfxJump (ifx, "c");
4688 /* Shift the sign bit up into carry */
4693 /* leave the result in acc */
4697 /*-----------------------------------------------------------------*/
4698 /* genCmpGt :- greater than comparison */
4699 /*-----------------------------------------------------------------*/
4701 genCmpGt (iCode * ic, iCode * ifx)
4703 operand *left, *right, *result;
4704 sym_link *letype, *retype;
4707 left = IC_LEFT (ic);
4708 right = IC_RIGHT (ic);
4709 result = IC_RESULT (ic);
4711 letype = getSpec (operandType (left));
4712 retype = getSpec (operandType (right));
4713 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4714 /* assign the amsops */
4715 aopOp (left, ic, FALSE, FALSE);
4716 aopOp (right, ic, FALSE, FALSE);
4717 aopOp (result, ic, TRUE, FALSE);
4719 genCmp (right, left, result, ifx, sign);
4721 freeAsmop (left, NULL, ic);
4722 freeAsmop (right, NULL, ic);
4723 freeAsmop (result, NULL, ic);
4726 /*-----------------------------------------------------------------*/
4727 /* genCmpLt - less than comparisons */
4728 /*-----------------------------------------------------------------*/
4730 genCmpLt (iCode * ic, iCode * ifx)
4732 operand *left, *right, *result;
4733 sym_link *letype, *retype;
4736 left = IC_LEFT (ic);
4737 right = IC_RIGHT (ic);
4738 result = IC_RESULT (ic);
4740 letype = getSpec (operandType (left));
4741 retype = getSpec (operandType (right));
4742 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4744 /* assign the amsops */
4745 aopOp (left, ic, FALSE, FALSE);
4746 aopOp (right, ic, FALSE, FALSE);
4747 aopOp (result, ic, TRUE, FALSE);
4749 genCmp (left, right, result, ifx, sign);
4751 freeAsmop (left, NULL, ic);
4752 freeAsmop (right, NULL, ic);
4753 freeAsmop (result, NULL, ic);
4756 /*-----------------------------------------------------------------*/
4757 /* gencjneshort - compare and jump if not equal */
4758 /* returns pair that still needs to be popped */
4759 /*-----------------------------------------------------------------*/
4761 gencjneshort (operand * left, operand * right, symbol * lbl)
4763 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4765 unsigned long lit = 0L;
4767 /* Swap the left and right if it makes the computation easier */
4768 if (AOP_TYPE (left) == AOP_LIT)
4775 /* if the right side is a literal then anything goes */
4776 if (AOP_TYPE (right) == AOP_LIT)
4778 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4781 _moveA (aopGet (AOP (left), offset, FALSE));
4786 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4793 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4799 _moveA (aopGet (AOP (left), offset, FALSE));
4800 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4803 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4804 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4809 /* if the right side is in a register or
4810 pointed to by HL, IX or IY */
4811 else if (AOP_TYPE (right) == AOP_REG ||
4812 AOP_TYPE (right) == AOP_HL ||
4813 AOP_TYPE (right) == AOP_IY ||
4814 AOP_TYPE (right) == AOP_STK ||
4815 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4816 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4817 AOP_IS_PAIRPTR (right, PAIR_IY))
4821 _moveA (aopGet (AOP (left), offset, FALSE));
4822 if (AOP_TYPE (right) == AOP_LIT &&
4823 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4826 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4830 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4831 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4836 /* right is in direct space or a pointer reg, need both a & b */
4840 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4842 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4843 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4851 emit2 ("; direct compare");
4852 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4853 _moveA (aopGet (AOP (right), offset, FALSE));
4854 emit2 ("sub %s", _pairs[pair].l);
4855 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4860 return PAIR_INVALID;
4863 /*-----------------------------------------------------------------*/
4864 /* gencjne - compare and jump if not equal */
4865 /*-----------------------------------------------------------------*/
4867 gencjne (operand * left, operand * right, symbol * lbl)
4869 symbol *tlbl = newiTempLabel (NULL);
4871 PAIR_ID pop = gencjneshort (left, right, lbl);
4874 emit2 ("ld a,!one");
4875 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4876 emitLabel (lbl->key + 100);
4878 emitLabel (tlbl->key + 100);
4882 /*-----------------------------------------------------------------*/
4883 /* genCmpEq - generates code for equal to */
4884 /*-----------------------------------------------------------------*/
4886 genCmpEq (iCode * ic, iCode * ifx)
4888 operand *left, *right, *result;
4890 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4891 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4892 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4894 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4896 /* Swap operands if it makes the operation easier. ie if:
4897 1. Left is a literal.
4899 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4901 operand *t = IC_RIGHT (ic);
4902 IC_RIGHT (ic) = IC_LEFT (ic);
4906 if (ifx && !AOP_SIZE (result))
4909 /* if they are both bit variables */
4910 if (AOP_TYPE (left) == AOP_CRY &&
4911 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4913 wassertl (0, "Tried to compare two bits");
4918 tlbl = newiTempLabel (NULL);
4919 pop = gencjneshort (left, right, tlbl);
4923 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4924 emitLabel (tlbl->key + 100);
4929 /* PENDING: do this better */
4930 symbol *lbl = newiTempLabel (NULL);
4932 emit2 ("!shortjp !tlabel", lbl->key + 100);
4933 emitLabel (tlbl->key + 100);
4935 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4936 emitLabel (lbl->key + 100);
4939 /* mark the icode as generated */
4944 /* if they are both bit variables */
4945 if (AOP_TYPE (left) == AOP_CRY &&
4946 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4948 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4954 gencjne (left, right, newiTempLabel (NULL));
4955 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4962 genIfxJump (ifx, "a");
4965 /* if the result is used in an arithmetic operation
4966 then put the result in place */
4967 if (AOP_TYPE (result) != AOP_CRY)
4972 /* leave the result in acc */
4976 freeAsmop (left, NULL, ic);
4977 freeAsmop (right, NULL, ic);
4978 freeAsmop (result, NULL, ic);
4981 /*-----------------------------------------------------------------*/
4982 /* ifxForOp - returns the icode containing the ifx for operand */
4983 /*-----------------------------------------------------------------*/
4985 ifxForOp (operand * op, iCode * ic)
4987 /* if true symbol then needs to be assigned */
4988 if (IS_TRUE_SYMOP (op))
4991 /* if this has register type condition and
4992 the next instruction is ifx with the same operand
4993 and live to of the operand is upto the ifx only then */
4995 ic->next->op == IFX &&
4996 IC_COND (ic->next)->key == op->key &&
4997 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5003 /*-----------------------------------------------------------------*/
5004 /* genAndOp - for && operation */
5005 /*-----------------------------------------------------------------*/
5007 genAndOp (iCode * ic)
5009 operand *left, *right, *result;
5012 /* note here that && operations that are in an if statement are
5013 taken away by backPatchLabels only those used in arthmetic
5014 operations remain */
5015 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5016 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5017 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5019 /* if both are bit variables */
5020 if (AOP_TYPE (left) == AOP_CRY &&
5021 AOP_TYPE (right) == AOP_CRY)
5023 wassertl (0, "Tried to and two bits");
5027 tlbl = newiTempLabel (NULL);
5029 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5031 emitLabel (tlbl->key + 100);
5035 freeAsmop (left, NULL, ic);
5036 freeAsmop (right, NULL, ic);
5037 freeAsmop (result, NULL, ic);
5040 /*-----------------------------------------------------------------*/
5041 /* genOrOp - for || operation */
5042 /*-----------------------------------------------------------------*/
5044 genOrOp (iCode * ic)
5046 operand *left, *right, *result;
5049 /* note here that || operations that are in an
5050 if statement are taken away by backPatchLabels
5051 only those used in arthmetic operations remain */
5052 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5053 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5054 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5056 /* if both are bit variables */
5057 if (AOP_TYPE (left) == AOP_CRY &&
5058 AOP_TYPE (right) == AOP_CRY)
5060 wassertl (0, "Tried to OR two bits");
5064 tlbl = newiTempLabel (NULL);
5066 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5068 emitLabel (tlbl->key + 100);
5072 freeAsmop (left, NULL, ic);
5073 freeAsmop (right, NULL, ic);
5074 freeAsmop (result, NULL, ic);
5077 /*-----------------------------------------------------------------*/
5078 /* isLiteralBit - test if lit == 2^n */
5079 /*-----------------------------------------------------------------*/
5081 isLiteralBit (unsigned long lit)
5083 unsigned long pw[32] =
5084 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5085 0x100L, 0x200L, 0x400L, 0x800L,
5086 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5087 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5088 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5089 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5090 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5093 for (idx = 0; idx < 32; idx++)
5099 /*-----------------------------------------------------------------*/
5100 /* jmpTrueOrFalse - */
5101 /*-----------------------------------------------------------------*/
5103 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5105 // ugly but optimized by peephole
5108 symbol *nlbl = newiTempLabel (NULL);
5109 emit2 ("jp !tlabel", nlbl->key + 100);
5110 emitLabel (tlbl->key + 100);
5111 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5112 emitLabel (nlbl->key + 100);
5116 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5117 emitLabel (tlbl->key + 100);
5122 /*-----------------------------------------------------------------*/
5123 /* genAnd - code for and */
5124 /*-----------------------------------------------------------------*/
5126 genAnd (iCode * ic, iCode * ifx)
5128 operand *left, *right, *result;
5129 int size, offset = 0;
5130 unsigned long lit = 0L;
5133 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5134 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5135 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5137 /* if left is a literal & right is not then exchange them */
5138 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5139 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5141 operand *tmp = right;
5146 /* if result = right then exchange them */
5147 if (sameRegs (AOP (result), AOP (right)))
5149 operand *tmp = right;
5154 /* if right is bit then exchange them */
5155 if (AOP_TYPE (right) == AOP_CRY &&
5156 AOP_TYPE (left) != AOP_CRY)
5158 operand *tmp = right;
5162 if (AOP_TYPE (right) == AOP_LIT)
5163 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5165 size = AOP_SIZE (result);
5167 if (AOP_TYPE (left) == AOP_CRY)
5169 wassertl (0, "Tried to perform an AND with a bit as an operand");
5173 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5174 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5175 if ((AOP_TYPE (right) == AOP_LIT) &&
5176 (AOP_TYPE (result) == AOP_CRY) &&
5177 (AOP_TYPE (left) != AOP_CRY))
5179 symbol *tlbl = newiTempLabel (NULL);
5180 int sizel = AOP_SIZE (left);
5183 /* PENDING: Test case for this. */
5188 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5190 _moveA (aopGet (AOP (left), offset, FALSE));
5191 if (bytelit != 0x0FFL)
5193 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5200 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5204 // bit = left & literal
5208 emit2 ("!tlabeldef", tlbl->key + 100);
5209 _G.lines.current->isLabel = 1;
5211 // if(left & literal)
5216 jmpTrueOrFalse (ifx, tlbl);
5224 /* if left is same as result */
5225 if (sameRegs (AOP (result), AOP (left)))
5227 for (; size--; offset++)
5229 if (AOP_TYPE (right) == AOP_LIT)
5231 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5236 aopPut (AOP (result), "!zero", offset);
5239 _moveA (aopGet (AOP (left), offset, FALSE));
5241 aopGet (AOP (right), offset, FALSE));
5242 aopPut (AOP (left), "a", offset);
5249 if (AOP_TYPE (left) == AOP_ACC)
5251 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5255 _moveA (aopGet (AOP (left), offset, FALSE));
5257 aopGet (AOP (right), offset, FALSE));
5258 aopPut (AOP (left), "a", offset);
5265 // left & result in different registers
5266 if (AOP_TYPE (result) == AOP_CRY)
5268 wassertl (0, "Tried to AND where the result is in carry");
5272 for (; (size--); offset++)
5275 // result = left & right
5276 if (AOP_TYPE (right) == AOP_LIT)
5278 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5280 aopPut (AOP (result),
5281 aopGet (AOP (left), offset, FALSE),
5285 else if (bytelit == 0)
5287 aopPut (AOP (result), "!zero", offset);
5291 // faster than result <- left, anl result,right
5292 // and better if result is SFR
5293 if (AOP_TYPE (left) == AOP_ACC)
5294 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5297 _moveA (aopGet (AOP (left), offset, FALSE));
5299 aopGet (AOP (right), offset, FALSE));
5301 aopPut (AOP (result), "a", offset);
5308 freeAsmop (left, NULL, ic);
5309 freeAsmop (right, NULL, ic);
5310 freeAsmop (result, NULL, ic);
5313 /*-----------------------------------------------------------------*/
5314 /* genOr - code for or */
5315 /*-----------------------------------------------------------------*/
5317 genOr (iCode * ic, iCode * ifx)
5319 operand *left, *right, *result;
5320 int size, offset = 0;
5321 unsigned long lit = 0L;
5324 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5325 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5326 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5328 /* if left is a literal & right is not then exchange them */
5329 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5330 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5332 operand *tmp = right;
5337 /* if result = right then exchange them */
5338 if (sameRegs (AOP (result), AOP (right)))
5340 operand *tmp = right;
5345 /* if right is bit then exchange them */
5346 if (AOP_TYPE (right) == AOP_CRY &&
5347 AOP_TYPE (left) != AOP_CRY)
5349 operand *tmp = right;
5353 if (AOP_TYPE (right) == AOP_LIT)
5354 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5356 size = AOP_SIZE (result);
5358 if (AOP_TYPE (left) == AOP_CRY)
5360 wassertl (0, "Tried to OR where left is a bit");
5364 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5365 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5366 if ((AOP_TYPE (right) == AOP_LIT) &&
5367 (AOP_TYPE (result) == AOP_CRY) &&
5368 (AOP_TYPE (left) != AOP_CRY))
5370 symbol *tlbl = newiTempLabel (NULL);
5371 int sizel = AOP_SIZE (left);
5375 wassertl (0, "Result is assigned to a bit");
5377 /* PENDING: Modeled after the AND code which is inefficient. */
5380 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5382 _moveA (aopGet (AOP (left), offset, FALSE));
5383 /* OR with any literal is the same as OR with itself. */
5385 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5391 jmpTrueOrFalse (ifx, tlbl);
5396 /* if left is same as result */
5397 if (sameRegs (AOP (result), AOP (left)))
5399 for (; size--; offset++)
5401 if (AOP_TYPE (right) == AOP_LIT)
5403 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5407 _moveA (aopGet (AOP (left), offset, FALSE));
5409 aopGet (AOP (right), offset, FALSE));
5410 aopPut (AOP (result), "a", offset);
5415 if (AOP_TYPE (left) == AOP_ACC)
5416 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5419 _moveA (aopGet (AOP (left), offset, FALSE));
5421 aopGet (AOP (right), offset, FALSE));
5422 aopPut (AOP (result), "a", offset);
5429 // left & result in different registers
5430 if (AOP_TYPE (result) == AOP_CRY)
5432 wassertl (0, "Result of OR is in a bit");
5435 for (; (size--); offset++)
5438 // result = left & right
5439 if (AOP_TYPE (right) == AOP_LIT)
5441 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5443 aopPut (AOP (result),
5444 aopGet (AOP (left), offset, FALSE),
5449 // faster than result <- left, anl result,right
5450 // and better if result is SFR
5451 if (AOP_TYPE (left) == AOP_ACC)
5452 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5455 _moveA (aopGet (AOP (left), offset, FALSE));
5457 aopGet (AOP (right), offset, FALSE));
5459 aopPut (AOP (result), "a", offset);
5460 /* PENDING: something weird is going on here. Add exception. */
5461 if (AOP_TYPE (result) == AOP_ACC)
5467 freeAsmop (left, NULL, ic);
5468 freeAsmop (right, NULL, ic);
5469 freeAsmop (result, NULL, ic);
5472 /*-----------------------------------------------------------------*/
5473 /* genXor - code for xclusive or */
5474 /*-----------------------------------------------------------------*/
5476 genXor (iCode * ic, iCode * ifx)
5478 operand *left, *right, *result;
5479 int size, offset = 0;
5480 unsigned long lit = 0L;
5482 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5483 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5484 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5486 /* if left is a literal & right is not then exchange them */
5487 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5488 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5490 operand *tmp = right;
5495 /* if result = right then exchange them */
5496 if (sameRegs (AOP (result), AOP (right)))
5498 operand *tmp = right;
5503 /* if right is bit then exchange them */
5504 if (AOP_TYPE (right) == AOP_CRY &&
5505 AOP_TYPE (left) != AOP_CRY)
5507 operand *tmp = right;
5511 if (AOP_TYPE (right) == AOP_LIT)
5512 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5514 size = AOP_SIZE (result);
5516 if (AOP_TYPE (left) == AOP_CRY)
5518 wassertl (0, "Tried to XOR a bit");
5522 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5523 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5524 if ((AOP_TYPE (right) == AOP_LIT) &&
5525 (AOP_TYPE (result) == AOP_CRY) &&
5526 (AOP_TYPE (left) != AOP_CRY))
5528 symbol *tlbl = newiTempLabel (NULL);
5529 int sizel = AOP_SIZE (left);
5533 /* PENDING: Test case for this. */
5534 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5538 _moveA (aopGet (AOP (left), offset, FALSE));
5539 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5540 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5545 jmpTrueOrFalse (ifx, tlbl);
5549 wassertl (0, "Result of XOR was destined for a bit");
5554 /* if left is same as result */
5555 if (sameRegs (AOP (result), AOP (left)))
5557 for (; size--; offset++)
5559 if (AOP_TYPE (right) == AOP_LIT)
5561 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5565 _moveA (aopGet (AOP (left), offset, FALSE));
5567 aopGet (AOP (right), offset, FALSE));
5568 aopPut (AOP (result), "a", offset);
5573 if (AOP_TYPE (left) == AOP_ACC)
5575 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5579 _moveA (aopGet (AOP (left), offset, FALSE));
5581 aopGet (AOP (right), offset, FALSE));
5582 aopPut (AOP (result), "a", offset);
5589 // left & result in different registers
5590 if (AOP_TYPE (result) == AOP_CRY)
5592 wassertl (0, "Result of XOR is in a bit");
5595 for (; (size--); offset++)
5598 // result = left & right
5599 if (AOP_TYPE (right) == AOP_LIT)
5601 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5603 aopPut (AOP (result),
5604 aopGet (AOP (left), offset, FALSE),
5609 // faster than result <- left, anl result,right
5610 // and better if result is SFR
5611 if (AOP_TYPE (left) == AOP_ACC)
5613 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5617 _moveA (aopGet (AOP (left), offset, FALSE));
5619 aopGet (AOP (right), offset, FALSE));
5621 aopPut (AOP (result), "a", offset);
5626 freeAsmop (left, NULL, ic);
5627 freeAsmop (right, NULL, ic);
5628 freeAsmop (result, NULL, ic);
5631 /*-----------------------------------------------------------------*/
5632 /* genInline - write the inline code out */
5633 /*-----------------------------------------------------------------*/
5635 genInline (iCode * ic)
5637 char *buffer, *bp, *bp1;
5638 bool inComment = FALSE;
5640 _G.lines.isInline += (!options.asmpeep);
5642 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5644 /* emit each line as a code */
5662 /* Add \n for labels, not dirs such as c:\mydir */
5663 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5681 _G.lines.isInline -= (!options.asmpeep);
5685 /*-----------------------------------------------------------------*/
5686 /* genRRC - rotate right with carry */
5687 /*-----------------------------------------------------------------*/
5694 /*-----------------------------------------------------------------*/
5695 /* genRLC - generate code for rotate left with carry */
5696 /*-----------------------------------------------------------------*/
5703 /*-----------------------------------------------------------------*/
5704 /* genGetHbit - generates code get highest order bit */
5705 /*-----------------------------------------------------------------*/
5707 genGetHbit (iCode * ic)
5709 operand *left, *result;
5710 left = IC_LEFT (ic);
5711 result = IC_RESULT (ic);
5713 aopOp (left, ic, FALSE, FALSE);
5714 aopOp (result, ic, FALSE, FALSE);
5716 /* get the highest order byte into a */
5717 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5719 if (AOP_TYPE (result) == AOP_CRY)
5727 emit2 ("and a,!one");
5732 freeAsmop (left, NULL, ic);
5733 freeAsmop (result, NULL, ic);
5737 emitRsh2 (asmop *aop, int size, int is_signed)
5743 const char *l = aopGet (aop, size, FALSE);
5746 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5756 /*-----------------------------------------------------------------*/
5757 /* shiftR2Left2Result - shift right two bytes from left to result */
5758 /*-----------------------------------------------------------------*/
5760 shiftR2Left2Result (operand * left, int offl,
5761 operand * result, int offr,
5762 int shCount, int is_signed)
5767 movLeft2Result (left, offl, result, offr, 0);
5768 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5773 /* if (AOP(result)->type == AOP_REG) { */
5775 tlbl = newiTempLabel (NULL);
5777 /* Left is already in result - so now do the shift */
5778 /* Optimizing for speed by default. */
5779 if (!optimize.codeSize || shCount <= 2)
5783 emitRsh2 (AOP (result), size, is_signed);
5788 emit2 ("ld a,!immedbyte", shCount);
5790 emitLabel (tlbl->key + 100);
5792 emitRsh2 (AOP (result), size, is_signed);
5795 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5799 /*-----------------------------------------------------------------*/
5800 /* shiftL2Left2Result - shift left two bytes from left to result */
5801 /*-----------------------------------------------------------------*/
5803 shiftL2Left2Result (operand * left, int offl,
5804 operand * result, int offr, int shCount)
5806 if (sameRegs (AOP (result), AOP (left)) &&
5807 ((offl + MSB16) == offr))
5813 /* Copy left into result */
5814 movLeft2Result (left, offl, result, offr, 0);
5815 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5821 if (getPairId (AOP (result)) == PAIR_HL)
5825 emit2 ("add hl,hl");
5832 symbol *tlbl, *tlbl1;
5835 tlbl = newiTempLabel (NULL);
5836 tlbl1 = newiTempLabel (NULL);
5838 if (AOP (result)->type == AOP_REG)
5842 for (offset = 0; offset < size; offset++)
5844 l = aopGet (AOP (result), offset, FALSE);
5848 emit2 ("sla %s", l);
5859 /* Left is already in result - so now do the shift */
5862 emit2 ("ld a,!immedbyte+1", shCount);
5863 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5864 emitLabel (tlbl->key + 100);
5869 l = aopGet (AOP (result), offset, FALSE);
5873 emit2 ("sla %s", l);
5884 emitLabel (tlbl1->key + 100);
5886 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5892 /*-----------------------------------------------------------------*/
5893 /* AccRol - rotate left accumulator by known count */
5894 /*-----------------------------------------------------------------*/
5896 AccRol (int shCount)
5898 shCount &= 0x0007; // shCount : 0..7
5975 /*-----------------------------------------------------------------*/
5976 /* AccLsh - left shift accumulator by known count */
5977 /*-----------------------------------------------------------------*/
5979 AccLsh (int shCount)
5981 static const unsigned char SLMask[] =
5983 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5992 else if (shCount == 2)
5999 /* rotate left accumulator */
6001 /* and kill the lower order bits */
6002 emit2 ("and a,!immedbyte", SLMask[shCount]);
6007 /*-----------------------------------------------------------------*/
6008 /* shiftL1Left2Result - shift left one byte from left to result */
6009 /*-----------------------------------------------------------------*/
6011 shiftL1Left2Result (operand * left, int offl,
6012 operand * result, int offr, int shCount)
6015 l = aopGet (AOP (left), offl, FALSE);
6017 /* shift left accumulator */
6019 aopPut (AOP (result), "a", offr);
6023 /*-----------------------------------------------------------------*/
6024 /* genlshTwo - left shift two bytes by known amount */
6025 /*-----------------------------------------------------------------*/
6027 genlshTwo (operand * result, operand * left, int shCount)
6029 int size = AOP_SIZE (result);
6031 wassert (size == 2);
6033 /* if shCount >= 8 */
6041 movLeft2Result (left, LSB, result, MSB16, 0);
6042 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6043 aopPut (AOP (result), "!zero", LSB);
6047 movLeft2Result (left, LSB, result, MSB16, 0);
6048 aopPut (AOP (result), "!zero", 0);
6053 aopPut (AOP (result), "!zero", LSB);
6056 /* 0 <= shCount <= 7 */
6065 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6070 /*-----------------------------------------------------------------*/
6071 /* genlshOne - left shift a one byte quantity by known count */
6072 /*-----------------------------------------------------------------*/
6074 genlshOne (operand * result, operand * left, int shCount)
6076 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6079 /*-----------------------------------------------------------------*/
6080 /* genLeftShiftLiteral - left shifting by known count */
6081 /*-----------------------------------------------------------------*/
6083 genLeftShiftLiteral (operand * left,
6088 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6091 freeAsmop (right, NULL, ic);
6093 aopOp (left, ic, FALSE, FALSE);
6094 aopOp (result, ic, FALSE, FALSE);
6096 size = getSize (operandType (result));
6098 /* I suppose that the left size >= result size */
6100 if (shCount >= (size * 8))
6104 aopPut (AOP (result), "!zero", size);
6112 genlshOne (result, left, shCount);
6115 genlshTwo (result, left, shCount);
6118 wassertl (0, "Shifting of longs is currently unsupported");
6124 freeAsmop (left, NULL, ic);
6125 freeAsmop (result, NULL, ic);
6128 /*-----------------------------------------------------------------*/
6129 /* genLeftShift - generates code for left shifting */
6130 /*-----------------------------------------------------------------*/
6132 genLeftShift (iCode * ic)
6136 symbol *tlbl, *tlbl1;
6137 operand *left, *right, *result;
6139 right = IC_RIGHT (ic);
6140 left = IC_LEFT (ic);
6141 result = IC_RESULT (ic);
6143 aopOp (right, ic, FALSE, FALSE);
6145 /* if the shift count is known then do it
6146 as efficiently as possible */
6147 if (AOP_TYPE (right) == AOP_LIT)
6149 genLeftShiftLiteral (left, right, result, ic);
6153 /* shift count is unknown then we have to form a loop get the loop
6154 count in B : Note: we take only the lower order byte since
6155 shifting more that 32 bits make no sense anyway, ( the largest
6156 size of an object can be only 32 bits ) */
6157 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6159 freeAsmop (right, NULL, ic);
6160 aopOp (left, ic, FALSE, FALSE);
6161 aopOp (result, ic, FALSE, FALSE);
6163 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6166 /* now move the left to the result if they are not the
6169 if (!sameRegs (AOP (left), AOP (result)))
6172 size = AOP_SIZE (result);
6176 l = aopGet (AOP (left), offset, FALSE);
6177 aopPut (AOP (result), l, offset);
6182 tlbl = newiTempLabel (NULL);
6183 size = AOP_SIZE (result);
6185 tlbl1 = newiTempLabel (NULL);
6187 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6190 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6191 emitLabel (tlbl->key + 100);
6192 l = aopGet (AOP (result), offset, FALSE);
6196 l = aopGet (AOP (result), offset, FALSE);
6200 emit2 ("sla %s", l);
6208 emitLabel (tlbl1->key + 100);
6210 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6212 freeAsmop (left, NULL, ic);
6213 freeAsmop (result, NULL, ic);
6216 /*-----------------------------------------------------------------*/
6217 /* genrshOne - left shift two bytes by known amount != 0 */
6218 /*-----------------------------------------------------------------*/
6220 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6223 int size = AOP_SIZE (result);
6226 wassert (size == 1);
6227 wassert (shCount < 8);
6229 l = aopGet (AOP (left), 0, FALSE);
6231 if (AOP (result)->type == AOP_REG)
6233 aopPut (AOP (result), l, 0);
6234 l = aopGet (AOP (result), 0, FALSE);
6237 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6245 emit2 ("%s a", is_signed ? "sra" : "srl");
6247 aopPut (AOP (result), "a", 0);
6251 /*-----------------------------------------------------------------*/
6252 /* AccRsh - right shift accumulator by known count */
6253 /*-----------------------------------------------------------------*/
6255 AccRsh (int shCount)
6257 static const unsigned char SRMask[] =
6259 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6264 /* rotate right accumulator */
6265 AccRol (8 - shCount);
6266 /* and kill the higher order bits */
6267 emit2 ("and a,!immedbyte", SRMask[shCount]);
6271 /*-----------------------------------------------------------------*/
6272 /* shiftR1Left2Result - shift right one byte from left to result */
6273 /*-----------------------------------------------------------------*/
6275 shiftR1Left2Result (operand * left, int offl,
6276 operand * result, int offr,
6277 int shCount, int sign)
6279 _moveA (aopGet (AOP (left), offl, FALSE));
6284 emit2 ("%s a", sign ? "sra" : "srl");
6291 aopPut (AOP (result), "a", offr);
6294 /*-----------------------------------------------------------------*/
6295 /* genrshTwo - right shift two bytes by known amount */
6296 /*-----------------------------------------------------------------*/
6298 genrshTwo (operand * result, operand * left,
6299 int shCount, int sign)
6301 /* if shCount >= 8 */
6307 shiftR1Left2Result (left, MSB16, result, LSB,
6312 movLeft2Result (left, MSB16, result, LSB, sign);
6316 /* Sign extend the result */
6317 _moveA(aopGet (AOP (result), 0, FALSE));
6321 aopPut (AOP (result), ACC_NAME, MSB16);
6325 aopPut (AOP (result), "!zero", 1);
6328 /* 0 <= shCount <= 7 */
6331 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6335 /*-----------------------------------------------------------------*/
6336 /* genRightShiftLiteral - left shifting by known count */
6337 /*-----------------------------------------------------------------*/
6339 genRightShiftLiteral (operand * left,
6345 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6348 freeAsmop (right, NULL, ic);
6350 aopOp (left, ic, FALSE, FALSE);
6351 aopOp (result, ic, FALSE, FALSE);
6353 size = getSize (operandType (result));
6355 /* I suppose that the left size >= result size */
6357 if (shCount >= (size * 8)) {
6359 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6360 _moveA(aopGet (AOP (left), 0, FALSE));
6368 aopPut (AOP (result), s, size);
6375 genrshOne (result, left, shCount, sign);
6378 genrshTwo (result, left, shCount, sign);
6381 wassertl (0, "Asked to shift right a long which should be a function call");
6384 wassertl (0, "Entered default case in right shift delegate");
6387 freeAsmop (left, NULL, ic);
6388 freeAsmop (result, NULL, ic);
6391 /*-----------------------------------------------------------------*/
6392 /* genRightShift - generate code for right shifting */
6393 /*-----------------------------------------------------------------*/
6395 genRightShift (iCode * ic)
6397 operand *right, *left, *result;
6399 int size, offset, first = 1;
6403 symbol *tlbl, *tlbl1;
6405 /* if signed then we do it the hard way preserve the
6406 sign bit moving it inwards */
6407 retype = getSpec (operandType (IC_RESULT (ic)));
6409 is_signed = !SPEC_USIGN (retype);
6411 /* signed & unsigned types are treated the same : i.e. the
6412 signed is NOT propagated inwards : quoting from the
6413 ANSI - standard : "for E1 >> E2, is equivalent to division
6414 by 2**E2 if unsigned or if it has a non-negative value,
6415 otherwise the result is implementation defined ", MY definition
6416 is that the sign does not get propagated */
6418 right = IC_RIGHT (ic);
6419 left = IC_LEFT (ic);
6420 result = IC_RESULT (ic);
6422 aopOp (right, ic, FALSE, FALSE);
6424 /* if the shift count is known then do it
6425 as efficiently as possible */
6426 if (AOP_TYPE (right) == AOP_LIT)
6428 genRightShiftLiteral (left, right, result, ic, is_signed);
6432 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6434 freeAsmop (right, NULL, ic);
6436 aopOp (left, ic, FALSE, FALSE);
6437 aopOp (result, ic, FALSE, FALSE);
6439 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6442 /* now move the left to the result if they are not the
6444 if (!sameRegs (AOP (left), AOP (result)))
6447 size = AOP_SIZE (result);
6451 l = aopGet (AOP (left), offset, FALSE);
6452 aopPut (AOP (result), l, offset);
6457 tlbl = newiTempLabel (NULL);
6458 tlbl1 = newiTempLabel (NULL);
6459 size = AOP_SIZE (result);
6462 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6465 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6466 emitLabel (tlbl->key + 100);
6469 l = aopGet (AOP (result), offset--, FALSE);
6472 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6480 emitLabel (tlbl1->key + 100);
6482 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6484 freeAsmop (left, NULL, ic);
6485 freeAsmop (result, NULL, ic);
6489 /*-----------------------------------------------------------------*/
6490 /* genUnpackBits - generates code for unpacking bits */
6491 /*-----------------------------------------------------------------*/
6493 genUnpackBits (operand * result, int pair)
6495 int offset = 0; /* result byte offset */
6496 int rsize; /* result size */
6497 int rlen = 0; /* remaining bitfield length */
6498 sym_link *etype; /* bitfield type information */
6499 int blen; /* bitfield length */
6500 int bstr; /* bitfield starting bit within byte */
6502 emitDebug ("; genUnpackBits");
6504 etype = getSpec (operandType (result));
6505 rsize = getSize (operandType (result));
6506 blen = SPEC_BLEN (etype);
6507 bstr = SPEC_BSTR (etype);
6509 /* If the bitfield length is less than a byte */
6512 emit2 ("ld a,!*pair", _pairs[pair].name);
6514 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6515 if (!SPEC_USIGN (etype))
6517 /* signed bitfield */
6518 symbol *tlbl = newiTempLabel (NULL);
6520 emit2 ("bit %d,a", blen - 1);
6521 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6522 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6523 emitLabel (tlbl->key + 100);
6525 aopPut (AOP (result), "a", offset++);
6529 /* TODO: what if pair == PAIR_DE ? */
6530 if (getPairId (AOP (result)) == PAIR_HL)
6532 wassertl (rsize == 2, "HL must be of size 2");
6533 emit2 ("ld a,!*hl");
6535 emit2 ("ld h,!*hl");
6538 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6539 if (!SPEC_USIGN (etype))
6541 /* signed bitfield */
6542 symbol *tlbl = newiTempLabel (NULL);
6544 emit2 ("bit %d,a", blen - 1);
6545 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6546 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6547 emitLabel (tlbl->key + 100);
6550 spillPair (PAIR_HL);
6554 /* Bit field did not fit in a byte. Copy all
6555 but the partial byte at the end. */
6556 for (rlen=blen;rlen>=8;rlen-=8)
6558 emit2 ("ld a,!*pair", _pairs[pair].name);
6559 aopPut (AOP (result), "a", offset++);
6562 emit2 ("inc %s", _pairs[pair].name);
6563 _G.pairs[pair].offset++;
6567 /* Handle the partial byte at the end */
6570 emit2 ("ld a,!*pair", _pairs[pair].name);
6571 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6572 if (!SPEC_USIGN (etype))
6574 /* signed bitfield */
6575 symbol *tlbl = newiTempLabel (NULL);
6577 emit2 ("bit %d,a", rlen - 1);
6578 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6579 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6580 emitLabel (tlbl->key + 100);
6582 aopPut (AOP (result), "a", offset++);
6590 if (SPEC_USIGN (etype))
6594 /* signed bitfield: sign extension with 0x00 or 0xff */
6602 aopPut (AOP (result), source, offset++);
6606 /*-----------------------------------------------------------------*/
6607 /* genGenPointerGet - get value from generic pointer space */
6608 /*-----------------------------------------------------------------*/
6610 genGenPointerGet (operand * left,
6611 operand * result, iCode * ic)
6614 sym_link *retype = getSpec (operandType (result));
6620 aopOp (left, ic, FALSE, FALSE);
6621 aopOp (result, ic, FALSE, FALSE);
6623 size = AOP_SIZE (result);
6625 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6628 if (isPtrPair (AOP (left)))
6630 tsprintf (buffer, sizeof(buffer),
6631 "!*pair", getPairName (AOP (left)));
6632 aopPut (AOP (result), buffer, 0);
6636 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6637 aopPut (AOP (result), "a", 0);
6639 freeAsmop (left, NULL, ic);
6643 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6650 tsprintf (at, sizeof(at), "!*iyx", offset);
6651 aopPut (AOP (result), at, offset);
6655 freeAsmop (left, NULL, ic);
6659 /* For now we always load into IY */
6660 /* if this is remateriazable */
6661 fetchPair (pair, AOP (left));
6663 /* if bit then unpack */
6664 if (IS_BITVAR (retype))
6666 genUnpackBits (result, pair);
6667 freeAsmop (left, NULL, ic);
6671 else if (getPairId (AOP (result)) == PAIR_HL)
6673 wassertl (size == 2, "HL must be of size 2");
6674 emit2 ("ld a,!*hl");
6676 emit2 ("ld h,!*hl");
6678 spillPair (PAIR_HL);
6680 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6682 size = AOP_SIZE (result);
6687 /* PENDING: make this better */
6688 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6690 aopPut (AOP (result), "!*hl", offset++);
6694 emit2 ("ld a,!*pair", _pairs[pair].name);
6695 aopPut (AOP (result), "a", offset++);
6699 emit2 ("inc %s", _pairs[pair].name);
6700 _G.pairs[pair].offset++;
6703 /* Fixup HL back down */
6704 for (size = AOP_SIZE (result)-1; size; size--)
6706 emit2 ("dec %s", _pairs[pair].name);
6711 size = AOP_SIZE (result);
6716 /* PENDING: make this better */
6718 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6720 aopPut (AOP (result), "!*hl", offset++);
6724 emit2 ("ld a,!*pair", _pairs[pair].name);
6725 aopPut (AOP (result), "a", offset++);
6729 emit2 ("inc %s", _pairs[pair].name);
6730 _G.pairs[pair].offset++;
6735 freeAsmop (left, NULL, ic);
6738 freeAsmop (result, NULL, ic);
6741 /*-----------------------------------------------------------------*/
6742 /* genPointerGet - generate code for pointer get */
6743 /*-----------------------------------------------------------------*/
6745 genPointerGet (iCode * ic)
6747 operand *left, *result;
6748 sym_link *type, *etype;
6750 left = IC_LEFT (ic);
6751 result = IC_RESULT (ic);
6753 /* depending on the type of pointer we need to
6754 move it to the correct pointer register */
6755 type = operandType (left);
6756 etype = getSpec (type);
6758 genGenPointerGet (left, result, ic);
6762 isRegOrLit (asmop * aop)
6764 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6770 /*-----------------------------------------------------------------*/
6771 /* genPackBits - generates code for packed bit storage */
6772 /*-----------------------------------------------------------------*/
6774 genPackBits (sym_link * etype,
6779 int offset = 0; /* source byte offset */
6780 int rlen = 0; /* remaining bitfield length */
6781 int blen; /* bitfield length */
6782 int bstr; /* bitfield starting bit within byte */
6783 int litval; /* source literal value (if AOP_LIT) */
6784 unsigned char mask; /* bitmask within current byte */
6785 int extraPair; /* a tempory register */
6786 bool needPopExtra=0; /* need to restore original value of temp reg */
6788 emitDebug ("; genPackBits","");
6790 blen = SPEC_BLEN (etype);
6791 bstr = SPEC_BSTR (etype);
6793 /* If the bitfield length is less than a byte */
6796 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6797 (unsigned char) (0xFF >> (8 - bstr)));
6799 if (AOP_TYPE (right) == AOP_LIT)
6801 /* Case with a bitfield length <8 and literal source
6803 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6805 litval &= (~mask) & 0xff;
6806 emit2 ("ld a,!*pair", _pairs[pair].name);
6807 if ((mask|litval)!=0xff)
6808 emit2 ("and a,!immedbyte", mask);
6810 emit2 ("or a,!immedbyte", litval);
6811 emit2 ("ld !*pair,a", _pairs[pair].name);
6816 /* Case with a bitfield length <8 and arbitrary source
6818 _moveA (aopGet (AOP (right), 0, FALSE));
6819 /* shift and mask source value */
6821 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6823 extraPair = getFreePairId(ic);
6824 if (extraPair == PAIR_INVALID)
6826 extraPair = PAIR_BC;
6827 if (getPairId (AOP (right)) != PAIR_BC
6828 || !isLastUse (ic, right))
6834 emit2 ("ld %s,a", _pairs[extraPair].l);
6835 emit2 ("ld a,!*pair", _pairs[pair].name);
6837 emit2 ("and a,!immedbyte", mask);
6838 emit2 ("or a,%s", _pairs[extraPair].l);
6839 emit2 ("ld !*pair,a", _pairs[pair].name);
6846 /* Bit length is greater than 7 bits. In this case, copy */
6847 /* all except the partial byte at the end */
6848 for (rlen=blen;rlen>=8;rlen-=8)
6850 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6851 emit2 ("ld !*pair,a", _pairs[pair].name);
6854 emit2 ("inc %s", _pairs[pair].name);
6855 _G.pairs[pair].offset++;
6859 /* If there was a partial byte at the end */
6862 mask = (((unsigned char) -1 << rlen) & 0xff);
6864 if (AOP_TYPE (right) == AOP_LIT)
6866 /* Case with partial byte and literal source
6868 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6869 litval >>= (blen-rlen);
6870 litval &= (~mask) & 0xff;
6871 emit2 ("ld a,!*pair", _pairs[pair].name);
6872 if ((mask|litval)!=0xff)
6873 emit2 ("and a,!immedbyte", mask);
6875 emit2 ("or a,!immedbyte", litval);
6879 /* Case with partial byte and arbitrary source
6881 _moveA (aopGet (AOP (right), offset++, FALSE));
6882 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6884 extraPair = getFreePairId(ic);
6885 if (extraPair == PAIR_INVALID)
6887 extraPair = getPairId (AOP (right));
6888 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6889 extraPair = PAIR_BC;
6891 if (getPairId (AOP (right)) != PAIR_BC
6892 || !isLastUse (ic, right))
6898 emit2 ("ld %s,a", _pairs[extraPair].l);
6899 emit2 ("ld a,!*pair", _pairs[pair].name);
6901 emit2 ("and a,!immedbyte", mask);
6902 emit2 ("or a,%s", _pairs[extraPair].l);
6907 emit2 ("ld !*pair,a", _pairs[pair].name);
6912 /*-----------------------------------------------------------------*/
6913 /* genGenPointerSet - stores the value into a pointer location */
6914 /*-----------------------------------------------------------------*/
6916 genGenPointerSet (operand * right,
6917 operand * result, iCode * ic)
6920 sym_link *retype = getSpec (operandType (right));
6921 sym_link *letype = getSpec (operandType (result));
6922 PAIR_ID pairId = PAIR_HL;
6925 aopOp (result, ic, FALSE, FALSE);
6926 aopOp (right, ic, FALSE, FALSE);
6931 size = AOP_SIZE (right);
6933 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6934 emitDebug("; isBitvar = %d", isBitvar);
6936 /* Handle the exceptions first */
6937 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6940 const char *l = aopGet (AOP (right), 0, FALSE);
6941 const char *pair = getPairName (AOP (result));
6942 if (canAssignToPtr (l) && isPtr (pair))
6944 emit2 ("ld !*pair,%s", pair, l);
6949 emit2 ("ld !*pair,a", pair);
6954 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6957 const char *l = aopGet (AOP (right), 0, FALSE);
6962 if (canAssignToPtr (l))
6964 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6968 _moveA (aopGet (AOP (right), offset, FALSE));
6969 emit2 ("ld !*iyx,a", offset);
6975 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6982 const char *l = aopGet (AOP (right), offset, FALSE);
6983 if (isRegOrLit (AOP (right)) && !IS_GB)
6985 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6990 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6994 emit2 ("inc %s", _pairs[PAIR_HL].name);
6995 _G.pairs[PAIR_HL].offset++;
7000 /* Fixup HL back down */
7001 for (size = AOP_SIZE (right)-1; size; size--)
7003 emit2 ("dec %s", _pairs[PAIR_HL].name);
7008 /* if the operand is already in dptr
7009 then we do nothing else we move the value to dptr */
7010 if (AOP_TYPE (result) != AOP_STR)
7012 fetchPair (pairId, AOP (result));
7014 /* so hl now contains the address */
7015 freeAsmop (result, NULL, ic);
7017 /* if bit then unpack */
7020 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7030 const char *l = aopGet (AOP (right), offset, FALSE);
7031 if (isRegOrLit (AOP (right)) && !IS_GB)
7033 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7038 emit2 ("ld !*pair,a", _pairs[pairId].name);
7042 emit2 ("inc %s", _pairs[pairId].name);
7043 _G.pairs[pairId].offset++;
7049 freeAsmop (right, NULL, ic);
7052 /*-----------------------------------------------------------------*/
7053 /* genPointerSet - stores the value into a pointer location */
7054 /*-----------------------------------------------------------------*/
7056 genPointerSet (iCode * ic)
7058 operand *right, *result;
7059 sym_link *type, *etype;
7061 right = IC_RIGHT (ic);
7062 result = IC_RESULT (ic);
7064 /* depending on the type of pointer we need to
7065 move it to the correct pointer register */
7066 type = operandType (result);
7067 etype = getSpec (type);
7069 genGenPointerSet (right, result, ic);
7072 /*-----------------------------------------------------------------*/
7073 /* genIfx - generate code for Ifx statement */
7074 /*-----------------------------------------------------------------*/
7076 genIfx (iCode * ic, iCode * popIc)
7078 operand *cond = IC_COND (ic);
7081 aopOp (cond, ic, FALSE, TRUE);
7083 /* get the value into acc */
7084 if (AOP_TYPE (cond) != AOP_CRY)
7088 /* the result is now in the accumulator */
7089 freeAsmop (cond, NULL, ic);
7091 /* if there was something to be popped then do it */
7095 /* if the condition is a bit variable */
7096 if (isbit && IS_ITEMP (cond) &&
7098 genIfxJump (ic, SPIL_LOC (cond)->rname);
7099 else if (isbit && !IS_ITEMP (cond))
7100 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7102 genIfxJump (ic, "a");
7107 /*-----------------------------------------------------------------*/
7108 /* genAddrOf - generates code for address of */
7109 /*-----------------------------------------------------------------*/
7111 genAddrOf (iCode * ic)
7113 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7115 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7117 /* if the operand is on the stack then we
7118 need to get the stack offset of this
7125 if (sym->stack <= 0)
7127 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7131 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7133 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7137 emit2 ("ld de,!hashedstr", sym->rname);
7138 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7146 /* if it has an offset then we need to compute it */
7148 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7150 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7151 emit2 ("add hl,sp");
7155 emit2 ("ld hl,!hashedstr", sym->rname);
7157 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7159 freeAsmop (IC_RESULT (ic), NULL, ic);
7162 /*-----------------------------------------------------------------*/
7163 /* genAssign - generate code for assignment */
7164 /*-----------------------------------------------------------------*/
7166 genAssign (iCode * ic)
7168 operand *result, *right;
7170 unsigned long lit = 0L;
7172 result = IC_RESULT (ic);
7173 right = IC_RIGHT (ic);
7175 /* Dont bother assigning if they are the same */
7176 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7178 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7182 aopOp (right, ic, FALSE, FALSE);
7183 aopOp (result, ic, TRUE, FALSE);
7185 /* if they are the same registers */
7186 if (sameRegs (AOP (right), AOP (result)))
7188 emitDebug ("; (registers are the same)");
7192 /* if the result is a bit */
7193 if (AOP_TYPE (result) == AOP_CRY)
7195 wassertl (0, "Tried to assign to a bit");
7199 size = AOP_SIZE (result);
7202 if (AOP_TYPE (right) == AOP_LIT)
7204 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7207 if (isPair (AOP (result)))
7209 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7211 else if ((size > 1) &&
7212 (AOP_TYPE (result) != AOP_REG) &&
7213 (AOP_TYPE (right) == AOP_LIT) &&
7214 !IS_FLOAT (operandType (right)) &&
7217 bool fXored = FALSE;
7219 /* Work from the top down.
7220 Done this way so that we can use the cached copy of 0
7221 in A for a fast clear */
7224 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7226 if (!fXored && size > 1)
7233 aopPut (AOP (result), "a", offset);
7237 aopPut (AOP (result), "!zero", offset);
7241 aopPut (AOP (result),
7242 aopGet (AOP (right), offset, FALSE),
7247 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7249 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7250 aopPut (AOP (result), "l", LSB);
7251 aopPut (AOP (result), "h", MSB16);
7253 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7255 /* Special case. Load into a and d, then load out. */
7256 _moveA (aopGet (AOP (right), 0, FALSE));
7257 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7258 aopPut (AOP (result), "a", 0);
7259 aopPut (AOP (result), "e", 1);
7261 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7263 /* Special case - simple memcpy */
7264 aopGet (AOP (right), LSB, FALSE);
7267 aopGet (AOP (result), LSB, FALSE);
7271 emit2 ("ld a,(de)");
7272 /* Peephole will optimise this. */
7273 emit2 ("ld (hl),a");
7281 spillPair (PAIR_HL);
7287 /* PENDING: do this check better */
7288 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7290 _moveA (aopGet (AOP (right), offset, FALSE));
7291 aopPut (AOP (result), "a", offset);
7294 aopPut (AOP (result),
7295 aopGet (AOP (right), offset, FALSE),
7302 freeAsmop (right, NULL, ic);
7303 freeAsmop (result, NULL, ic);
7306 /*-----------------------------------------------------------------*/
7307 /* genJumpTab - genrates code for jump table */
7308 /*-----------------------------------------------------------------*/
7310 genJumpTab (iCode * ic)
7315 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7316 /* get the condition into accumulator */
7317 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7320 emit2 ("ld e,%s", l);
7321 emit2 ("ld d,!zero");
7322 jtab = newiTempLabel (NULL);
7324 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7325 emit2 ("add hl,de");
7326 emit2 ("add hl,de");
7327 emit2 ("add hl,de");
7328 freeAsmop (IC_JTCOND (ic), NULL, ic);
7332 emitLabel (jtab->key + 100);
7333 /* now generate the jump labels */
7334 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7335 jtab = setNextItem (IC_JTLABELS (ic)))
7336 emit2 ("jp !tlabel", jtab->key + 100);
7339 /*-----------------------------------------------------------------*/
7340 /* genCast - gen code for casting */
7341 /*-----------------------------------------------------------------*/
7343 genCast (iCode * ic)
7345 operand *result = IC_RESULT (ic);
7346 sym_link *rtype = operandType (IC_RIGHT (ic));
7347 operand *right = IC_RIGHT (ic);
7350 /* if they are equivalent then do nothing */
7351 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7354 aopOp (right, ic, FALSE, FALSE);
7355 aopOp (result, ic, FALSE, FALSE);
7357 /* if the result is a bit */
7358 if (AOP_TYPE (result) == AOP_CRY)
7360 wassertl (0, "Tried to cast to a bit");
7363 /* if they are the same size : or less */
7364 if (AOP_SIZE (result) <= AOP_SIZE (right))
7367 /* if they are in the same place */
7368 if (sameRegs (AOP (right), AOP (result)))
7371 /* if they in different places then copy */
7372 size = AOP_SIZE (result);
7376 aopPut (AOP (result),
7377 aopGet (AOP (right), offset, FALSE),
7384 /* So we now know that the size of destination is greater
7385 than the size of the source */
7386 /* we move to result for the size of source */
7387 size = AOP_SIZE (right);
7391 aopPut (AOP (result),
7392 aopGet (AOP (right), offset, FALSE),
7397 /* now depending on the sign of the destination */
7398 size = AOP_SIZE (result) - AOP_SIZE (right);
7399 /* Unsigned or not an integral type - right fill with zeros */
7400 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7403 aopPut (AOP (result), "!zero", offset++);
7407 /* we need to extend the sign :{ */
7408 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7414 aopPut (AOP (result), "a", offset++);
7418 freeAsmop (right, NULL, ic);
7419 freeAsmop (result, NULL, ic);
7422 /*-----------------------------------------------------------------*/
7423 /* genReceive - generate code for a receive iCode */
7424 /*-----------------------------------------------------------------*/
7426 genReceive (iCode * ic)
7428 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7429 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7430 IS_TRUE_SYMOP (IC_RESULT (ic))))
7440 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7441 size = AOP_SIZE(IC_RESULT(ic));
7443 for (i = 0; i < size; i++) {
7444 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7448 freeAsmop (IC_RESULT (ic), NULL, ic);
7451 /*-----------------------------------------------------------------*/
7452 /* genDummyRead - generate code for dummy read of volatiles */
7453 /*-----------------------------------------------------------------*/
7455 genDummyRead (iCode * ic)
7461 if (op && IS_SYMOP (op))
7463 aopOp (op, ic, FALSE, FALSE);
7466 size = AOP_SIZE (op);
7471 _moveA (aopGet (AOP (op), offset, FALSE));
7475 freeAsmop (op, NULL, ic);
7479 if (op && IS_SYMOP (op))
7481 aopOp (op, ic, FALSE, FALSE);
7484 size = AOP_SIZE (op);
7489 _moveA (aopGet (AOP (op), offset, FALSE));
7493 freeAsmop (op, NULL, ic);
7497 /*-----------------------------------------------------------------*/
7498 /* genCritical - generate code for start of a critical sequence */
7499 /*-----------------------------------------------------------------*/
7501 genCritical (iCode *ic)
7503 symbol *tlbl = newiTempLabel (NULL);
7509 else if (IC_RESULT (ic))
7511 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7512 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7513 //get interrupt enable flag IFF2 into P/O
7517 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7518 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7519 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7520 emit2 ("!tlabeldef", (tlbl->key + 100));
7521 _G.lines.current->isLabel = 1;
7522 freeAsmop (IC_RESULT (ic), NULL, ic);
7526 //get interrupt enable flag IFF2 into P/O
7535 /*-----------------------------------------------------------------*/
7536 /* genEndCritical - generate code for end of a critical sequence */
7537 /*-----------------------------------------------------------------*/
7539 genEndCritical (iCode *ic)
7541 symbol *tlbl = newiTempLabel (NULL);
7547 else if (IC_RIGHT (ic))
7549 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7550 _toBoolean (IC_RIGHT (ic));
7551 //don't enable interrupts if they were off before
7552 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7554 emitLabel (tlbl->key + 100);
7555 freeAsmop (IC_RIGHT (ic), NULL, ic);
7561 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7562 //don't enable interrupts as they were off before
7563 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7565 emit2 ("!tlabeldef", (tlbl->key + 100));
7566 _G.lines.current->isLabel = 1;
7572 /** Maximum number of bytes to emit per line. */
7576 /** Context for the byte output chunker. */
7579 unsigned char buffer[DBEMIT_MAX_RUN];
7584 /** Flushes a byte chunker by writing out all in the buffer and
7588 _dbFlush(DBEMITCTX *self)
7595 sprintf(line, ".db 0x%02X", self->buffer[0]);
7597 for (i = 1; i < self->pos; i++)
7599 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7606 /** Write out another byte, buffering until a decent line is
7610 _dbEmit(DBEMITCTX *self, int c)
7612 if (self->pos == DBEMIT_MAX_RUN)
7616 self->buffer[self->pos++] = c;
7619 /** Context for a simple run length encoder. */
7623 unsigned char buffer[128];
7625 /** runLen may be equivalent to pos. */
7631 RLE_CHANGE_COST = 4,
7635 /** Flush the buffer of a run length encoder by writing out the run or
7636 data that it currently contains.
7639 _rleCommit(RLECTX *self)
7645 memset(&db, 0, sizeof(db));
7647 emit2(".db %u", self->pos);
7649 for (i = 0; i < self->pos; i++)
7651 _dbEmit(&db, self->buffer[i]);
7660 Can get either a run or a block of random stuff.
7661 Only want to change state if a good run comes in or a run ends.
7662 Detecting run end is easy.
7665 Say initial state is in run, len zero, last zero. Then if you get a
7666 few zeros then something else then a short run will be output.
7667 Seems OK. While in run mode, keep counting. While in random mode,
7668 keep a count of the run. If run hits margin, output all up to run,
7669 restart, enter run mode.
7672 /** Add another byte into the run length encoder, flushing as
7673 required. The run length encoder uses the Amiga IFF style, where
7674 a block is prefixed by its run length. A positive length means
7675 the next n bytes pass straight through. A negative length means
7676 that the next byte is repeated -n times. A zero terminates the
7680 _rleAppend(RLECTX *self, unsigned c)
7684 if (c != self->last)
7686 /* The run has stopped. See if it is worthwhile writing it out
7687 as a run. Note that the random data comes in as runs of
7690 if (self->runLen > RLE_CHANGE_COST)
7692 /* Yes, worthwhile. */
7693 /* Commit whatever was in the buffer. */
7695 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7699 /* Not worthwhile. Append to the end of the random list. */
7700 for (i = 0; i < self->runLen; i++)
7702 if (self->pos >= RLE_MAX_BLOCK)
7707 self->buffer[self->pos++] = self->last;
7715 if (self->runLen >= RLE_MAX_BLOCK)
7717 /* Commit whatever was in the buffer. */
7720 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7728 _rleFlush(RLECTX *self)
7730 _rleAppend(self, -1);
7737 /** genArrayInit - Special code for initialising an array with constant
7741 genArrayInit (iCode * ic)
7745 int elementSize = 0, eIndex, i;
7746 unsigned val, lastVal;
7750 memset(&rle, 0, sizeof(rle));
7752 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7754 _saveRegsForCall(ic, 0);
7756 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7757 emit2 ("call __initrleblock");
7759 type = operandType(IC_LEFT(ic));
7761 if (type && type->next)
7763 if (IS_SPEC(type->next) || IS_PTR(type->next))
7765 elementSize = getSize(type->next);
7767 else if (IS_ARRAY(type->next) && type->next->next)
7769 elementSize = getSize(type->next->next);
7773 printTypeChainRaw (type, NULL);
7774 wassertl (0, "Can't determine element size in genArrayInit.");
7779 wassertl (0, "Can't determine element size in genArrayInit.");
7782 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7784 iLoop = IC_ARRAYILIST(ic);
7785 lastVal = (unsigned)-1;
7787 /* Feed all the bytes into the run length encoder which will handle
7789 This works well for mixed char data, and for random int and long
7796 for (i = 0; i < ix; i++)
7798 for (eIndex = 0; eIndex < elementSize; eIndex++)
7800 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7801 _rleAppend(&rle, val);
7805 iLoop = iLoop->next;
7809 /* Mark the end of the run. */
7812 _restoreRegsAfterCall();
7816 freeAsmop (IC_LEFT(ic), NULL, ic);
7820 _swap (PAIR_ID one, PAIR_ID two)
7822 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7828 emit2 ("ld a,%s", _pairs[one].l);
7829 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7830 emit2 ("ld %s,a", _pairs[two].l);
7831 emit2 ("ld a,%s", _pairs[one].h);
7832 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7833 emit2 ("ld %s,a", _pairs[two].h);
7837 /* The problem is that we may have all three pairs used and they may
7838 be needed in a different order.
7843 hl = hl => unity, fine
7847 hl = hl hl = hl, swap de <=> bc
7855 hl = bc de = de, swap bc <=> hl
7863 hl = de bc = bc, swap hl <=> de
7868 * Any pair = pair are done last
7869 * Any pair = iTemp are done last
7870 * Any swaps can be done any time
7878 So how do we detect the cases?
7879 How about a 3x3 matrix?
7883 x x x x (Fourth for iTemp/other)
7885 First determin which mode to use by counting the number of unity and
7888 Two - Assign the pair first, then the rest
7889 One - Swap the two, then the rest
7893 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7895 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7897 PAIR_BC, PAIR_HL, PAIR_DE
7899 int i, j, nunity = 0;
7900 memset (ids, PAIR_INVALID, sizeof (ids));
7903 wassert (nparams == 3);
7905 /* First save everything that needs to be saved. */
7906 _saveRegsForCall (ic, 0);
7908 /* Loading HL first means that DE is always fine. */
7909 for (i = 0; i < nparams; i++)
7911 aopOp (pparams[i], ic, FALSE, FALSE);
7912 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7915 /* Count the number of unity or iTemp assigns. */
7916 for (i = 0; i < 3; i++)
7918 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7926 /* Any order, fall through. */
7928 else if (nunity == 2)
7930 /* One is assigned. Pull it out and assign. */
7931 for (i = 0; i < 3; i++)
7933 for (j = 0; j < NUM_PAIRS; j++)
7935 if (ids[dest[i]][j] == TRUE)
7937 /* Found it. See if it's the right one. */
7938 if (j == PAIR_INVALID || j == dest[i])
7944 fetchPair(dest[i], AOP (pparams[i]));
7951 else if (nunity == 1)
7953 /* Find the pairs to swap. */
7954 for (i = 0; i < 3; i++)
7956 for (j = 0; j < NUM_PAIRS; j++)
7958 if (ids[dest[i]][j] == TRUE)
7960 if (j == PAIR_INVALID || j == dest[i])
7975 int next = getPairId (AOP (pparams[0]));
7976 emit2 ("push %s", _pairs[next].name);
7978 if (next == dest[1])
7980 fetchPair (dest[1], AOP (pparams[1]));
7981 fetchPair (dest[2], AOP (pparams[2]));
7985 fetchPair (dest[2], AOP (pparams[2]));
7986 fetchPair (dest[1], AOP (pparams[1]));
7988 emit2 ("pop %s", _pairs[dest[0]].name);
7991 /* Finally pull out all of the iTemps */
7992 for (i = 0; i < 3; i++)
7994 if (ids[dest[i]][PAIR_INVALID] == 1)
7996 fetchPair (dest[i], AOP (pparams[i]));
8002 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8008 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8012 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8014 setupForBuiltin3 (ic, nParams, pparams);
8016 label = newiTempLabel(NULL);
8018 emitLabel (label->key);
8019 emit2 ("ld a,(hl)");
8022 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8024 freeAsmop (from, NULL, ic->next);
8025 freeAsmop (to, NULL, ic);
8029 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8031 operand *from, *to, *count;
8034 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8039 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8041 setupForBuiltin3 (ic, nParams, pparams);
8045 freeAsmop (count, NULL, ic->next->next);
8046 freeAsmop (from, NULL, ic);
8048 _restoreRegsAfterCall();
8050 /* if we need assign a result value */
8051 if ((IS_ITEMP (IC_RESULT (ic)) &&
8052 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8053 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8054 IS_TRUE_SYMOP (IC_RESULT (ic)))
8056 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8057 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8058 freeAsmop (IC_RESULT (ic), NULL, ic);
8061 freeAsmop (to, NULL, ic->next);
8064 /*-----------------------------------------------------------------*/
8065 /* genBuiltIn - calls the appropriate function to generating code */
8066 /* for a built in function */
8067 /*-----------------------------------------------------------------*/
8068 static void genBuiltIn (iCode *ic)
8070 operand *bi_parms[MAX_BUILTIN_ARGS];
8075 /* get all the arguments for a built in function */
8076 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8078 /* which function is it */
8079 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8081 if (strcmp(bif->name,"__builtin_strcpy")==0)
8083 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8085 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8087 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8091 wassertl (0, "Unknown builtin function encountered");
8095 /*-----------------------------------------------------------------*/
8096 /* genZ80Code - generate code for Z80 based controllers */
8097 /*-----------------------------------------------------------------*/
8099 genZ80Code (iCode * lic)
8107 _fReturn = _gbz80_return;
8108 _fTmp = _gbz80_return;
8112 _fReturn = _z80_return;
8113 _fTmp = _z80_return;
8116 _G.lines.head = _G.lines.current = NULL;
8118 /* if debug information required */
8119 if (options.debug && currFunc)
8121 debugFile->writeFunction (currFunc, lic);
8124 for (ic = lic; ic; ic = ic->next)
8126 _G.current_iCode = ic;
8128 if (ic->lineno && cln != ic->lineno)
8132 debugFile->writeCLine (ic);
8134 if (!options.noCcodeInAsm)
8136 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8137 printCLine(ic->filename, ic->lineno));
8141 if (options.iCodeInAsm)
8143 char *iLine = printILine(ic);
8144 emit2 (";ic:%d: %s", ic->key, iLine);
8147 /* if the result is marked as
8148 spilt and rematerializable or code for
8149 this has already been generated then
8151 if (resultRemat (ic) || ic->generated)
8154 /* depending on the operation */
8158 emitDebug ("; genNot");
8163 emitDebug ("; genCpl");
8168 emitDebug ("; genUminus");
8173 emitDebug ("; genIpush");
8178 /* IPOP happens only when trying to restore a
8179 spilt live range, if there is an ifx statement
8180 following this pop then the if statement might
8181 be using some of the registers being popped which
8182 would destroy the contents of the register so
8183 we need to check for this condition and handle it */
8185 ic->next->op == IFX &&
8186 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8188 emitDebug ("; genIfx");
8189 genIfx (ic->next, ic);
8193 emitDebug ("; genIpop");
8199 emitDebug ("; genCall");
8204 emitDebug ("; genPcall");
8209 emitDebug ("; genFunction");
8214 emitDebug ("; genEndFunction");
8215 genEndFunction (ic);
8219 emitDebug ("; genRet");
8224 emitDebug ("; genLabel");
8229 emitDebug ("; genGoto");
8234 emitDebug ("; genPlus");
8239 emitDebug ("; genMinus");
8244 emitDebug ("; genMult");
8249 emitDebug ("; genDiv");
8254 emitDebug ("; genMod");
8259 emitDebug ("; genCmpGt");
8260 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8264 emitDebug ("; genCmpLt");
8265 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8272 /* note these two are xlated by algebraic equivalence
8273 during parsing SDCC.y */
8274 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8275 "got '>=' or '<=' shouldn't have come here");
8279 emitDebug ("; genCmpEq");
8280 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8284 emitDebug ("; genAndOp");
8289 emitDebug ("; genOrOp");
8294 emitDebug ("; genXor");
8295 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8299 emitDebug ("; genOr");
8300 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8304 emitDebug ("; genAnd");
8305 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8309 emitDebug ("; genInline");
8314 emitDebug ("; genRRC");
8319 emitDebug ("; genRLC");
8324 emitDebug ("; genGetHBIT");
8329 emitDebug ("; genLeftShift");
8334 emitDebug ("; genRightShift");
8338 case GET_VALUE_AT_ADDRESS:
8339 emitDebug ("; genPointerGet");
8345 if (POINTER_SET (ic))
8347 emitDebug ("; genAssign (pointer)");
8352 emitDebug ("; genAssign");
8358 emitDebug ("; genIfx");
8363 emitDebug ("; genAddrOf");
8368 emitDebug ("; genJumpTab");
8373 emitDebug ("; genCast");
8378 emitDebug ("; genReceive");
8383 if (ic->builtinSEND)
8385 emitDebug ("; genBuiltIn");
8390 emitDebug ("; addSet");
8391 addSet (&_G.sendSet, ic);
8396 emitDebug ("; genArrayInit");
8400 case DUMMY_READ_VOLATILE:
8401 emitDebug ("; genDummyRead");
8406 emitDebug ("; genCritical");
8411 emitDebug ("; genEndCritical");
8412 genEndCritical (ic);
8421 /* now we are ready to call the
8422 peep hole optimizer */
8423 if (!options.nopeep)
8424 peepHole (&_G.lines.head);
8426 /* This is unfortunate */
8427 /* now do the actual printing */
8429 struct dbuf_s *buf = codeOutBuf;
8430 if (isInHome () && codeOutBuf == &code->oBuf)
8431 codeOutBuf = &home->oBuf;
8432 printLine (_G.lines.head, codeOutBuf);
8433 if (_G.flushStatics)
8436 _G.flushStatics = 0;
8441 freeTrace(&_G.lines.trace);
8442 freeTrace(&_G.trace.aops);
8448 _isPairUsed (iCode * ic, PAIR_ID pairId)
8454 if (bitVectBitValue (ic->rMask, D_IDX))
8456 if (bitVectBitValue (ic->rMask, E_IDX))
8466 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8469 value *val = aop->aopu.aop_lit;
8471 wassert (aop->type == AOP_LIT);
8472 wassert (!IS_FLOAT (val->type));
8474 v = (unsigned long) floatFromVal (val);
8482 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8483 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));