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.
90 #if defined(__BORLANDC__) || defined(_MSC_VER)
91 #define STRCASECMP stricmp
93 #define STRCASECMP strcasecmp
97 #include "SDCCglobl.h"
98 #include "SDCCpeeph.h"
100 #include "SDCCglue.h"
101 #include "newalloc.h"
103 /* This is the down and dirty file with all kinds of kludgy & hacky
104 stuff. This is what it is all about CODE GENERATION for a specific MCU.
105 Some of the routines may be reusable, will have to see */
107 /* Z80 calling convention description.
108 Parameters are passed right to left. As the stack grows downwards,
109 the parameters are arranged in left to right in memory.
110 Parameters may be passed in the HL and DE registers with one
112 PENDING: What if the parameter is a long?
113 Everything is caller saves. i.e. the caller must save any registers
114 that it wants to preserve over the call.
115 GB: The return value is returned in DEHL. DE is normally used as a
116 working register pair. Caller saves allows it to be used for a
118 va args functions do not use register parameters. All arguments
119 are passed on the stack.
120 IX is used as an index register to the top of the local variable
121 area. ix-0 is the top most local variable.
126 /* Set to enable debugging trace statements in the output assembly code. */
130 static char *_z80_return[] =
131 {"l", "h", "e", "d"};
132 static char *_gbz80_return[] =
133 {"e", "d", "l", "h"};
134 static char *_fReceive[] =
135 { "c", "b", "e", "d" };
137 static char **_fReturn;
140 extern FILE *codeOutFile;
148 /** Enum covering all the possible register pairs.
167 } _pairs[NUM_PAIRS] = {
168 { "??1", "?2", "?3" },
173 { "iy", "iyl", "iyh" },
174 { "ix", "ixl", "ixh" }
178 #define ACC_NAME _pairs[PAIR_AF].h
188 /** Code generator persistent data.
192 /** Used to optimised setting up of a pair by remebering what it
193 contains and adjusting instead of reloading where possible.
222 const char *lastFunctionName;
223 iCode *current_iCode;
230 /** TRUE if the registers have already been saved. */
249 static const char *aopGet (asmop * aop, int offset, bool bit16);
251 static const char *aopNames[] = {
272 isLastUse (iCode *ic, operand *op)
274 bitVect *uses = bitVectCopy (OP_USES (op));
276 while (!bitVectIsZero (uses))
278 if (bitVectFirstBit (uses) == ic->key)
280 if (bitVectnBitsOn (uses) == 1)
289 bitVectUnSetBit (uses, bitVectFirstBit (uses));
309 _getTempPairName(void)
311 return _pairs[_getTempPairId()].name;
315 isPairInUse (PAIR_ID id, iCode *ic)
319 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
321 else if (id == PAIR_BC)
323 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
327 wassertl (0, "Only implemented for DE and BC");
333 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
337 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
341 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
345 wassertl (0, "Only implemented for DE");
351 getFreePairId (iCode *ic)
353 if (!isPairInUse (PAIR_BC, ic))
357 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
370 /* Clean up the line so that it is 'prettier' */
371 if (strchr (buf, ':'))
373 /* Is a label - cant do anything */
376 /* Change the first (and probably only) ' ' to a tab so
391 _newLineNode (char *line)
395 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
396 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
402 _vemit2 (const char *szFormat, va_list ap)
404 char buffer[INITIAL_INLINEASM];
406 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
409 _G.lines.current = (_G.lines.current ?
410 connectLine (_G.lines.current, _newLineNode (buffer)) :
411 (_G.lines.head = _newLineNode (buffer)));
413 _G.lines.current->isInline = _G.lines.isInline;
414 _G.lines.current->isDebug = _G.lines.isDebug;
415 _G.lines.current->ic = _G.current_iCode;
416 _G.lines.current->isComment = (*buffer == ';');
420 emit2 (const char *szFormat,...)
424 va_start (ap, szFormat);
426 _vemit2 (szFormat, ap);
432 emitDebug (const char *szFormat,...)
438 va_start (ap, szFormat);
440 _vemit2 (szFormat, ap);
446 /*-----------------------------------------------------------------*/
447 /* z80_emitDebuggerSymbol - associate the current code location */
448 /* with a debugger symbol */
449 /*-----------------------------------------------------------------*/
451 z80_emitDebuggerSymbol (char * debugSym)
453 _G.lines.isDebug = 1;
454 emit2 ("%s !equ .", debugSym);
455 emit2 ("!global", debugSym);
456 _G.lines.isDebug = 0;
459 /*-----------------------------------------------------------------*/
460 /* emit2 - writes the code into a file : for now it is simple */
461 /*-----------------------------------------------------------------*/
463 _emit2 (const char *inst, const char *fmt,...)
466 char lb[INITIAL_INLINEASM];
473 sprintf (lb, "%s\t", inst);
474 vsprintf (lb + (strlen (lb)), fmt, ap);
477 vsprintf (lb, fmt, ap);
479 while (isspace (*lbp))
484 _G.lines.current = (_G.lines.current ?
485 connectLine (_G.lines.current, _newLineNode (lb)) :
486 (_G.lines.head = _newLineNode (lb)));
488 _G.lines.current->isInline = _G.lines.isInline;
489 _G.lines.current->ic = _G.current_iCode;
494 _emitMove(const char *to, const char *from)
496 if (STRCASECMP(to, from) != 0)
498 emit2("ld %s,%s", to, from);
503 // Could leave this to the peephole, but sometimes the peephole is inhibited.
508 aopDump(const char *plabel, asmop *aop)
514 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
519 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
522 for (i=aop->size-1;i>=0;i--)
523 *rbp++ = *(aop->aopu.aop_reg[i]->name);
525 emitDebug("; reg = %s", regbuf);
528 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
531 /* No information. */
537 _moveA(const char *moveFrom)
539 // Let the peephole optimiser take care of redundent loads
540 _emitMove(ACC_NAME, moveFrom);
550 getPairName (asmop * aop)
552 if (aop->type == AOP_REG)
554 switch (aop->aopu.aop_reg[0]->rIdx)
567 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
570 for (i = 0; i < NUM_PAIRS; i++)
572 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
574 return _pairs[i].name;
578 wassertl (0, "Tried to get the pair name of something that isn't a pair");
583 getPairId (asmop * aop)
587 if (aop->type == AOP_REG)
589 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
593 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
597 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
602 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
605 for (i = 0; i < NUM_PAIRS; i++)
607 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
617 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
621 return (getPairId (aop) != PAIR_INVALID);
624 /** Returns TRUE if the registers used in aop cannot be split into high
627 isUnsplitable (asmop * aop)
629 switch (getPairId (aop))
641 isPtrPair (asmop * aop)
643 PAIR_ID pairId = getPairId (aop);
656 spillPair (PAIR_ID pairId)
658 _G.pairs[pairId].last_type = AOP_INVALID;
659 _G.pairs[pairId].base = NULL;
662 /* Given a register name, spill the pair (if any) the register is part of */
664 spillPairReg (const char *regname)
666 if (strlen(regname)==1)
686 /** Push a register pair onto the stack */
688 genPairPush (asmop * aop)
690 emit2 ("push %s", getPairName (aop));
694 _push (PAIR_ID pairId)
696 emit2 ("push %s", _pairs[pairId].name);
697 _G.stack.pushed += 2;
701 _pop (PAIR_ID pairId)
703 emit2 ("pop %s", _pairs[pairId].name);
704 _G.stack.pushed -= 2;
709 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
722 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
729 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
730 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
733 wassertl (0, "Tried to move a nonphysical pair");
735 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
736 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
737 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
741 /*-----------------------------------------------------------------*/
742 /* newAsmop - creates a new asmOp */
743 /*-----------------------------------------------------------------*/
745 newAsmop (short type)
749 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
754 /*-----------------------------------------------------------------*/
755 /* aopForSym - for a true symbol */
756 /*-----------------------------------------------------------------*/
758 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
765 wassert (sym->etype);
767 space = SPEC_OCLS (sym->etype);
769 /* if already has one */
775 /* Assign depending on the storage class */
776 if (sym->onStack || sym->iaccess)
778 /* The pointer that is used depends on how big the offset is.
779 Normally everything is AOP_STK, but for offsets of < -128 or
780 > 127 on the Z80 an extended stack pointer is used.
782 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
784 emitDebug ("; AOP_EXSTK for %s", sym->rname);
785 sym->aop = aop = newAsmop (AOP_EXSTK);
789 emitDebug ("; AOP_STK for %s", sym->rname);
790 sym->aop = aop = newAsmop (AOP_STK);
793 aop->size = getSize (sym->type);
794 aop->aopu.aop_stk = sym->stack;
798 /* special case for a function */
799 if (IS_FUNC (sym->type))
801 sym->aop = aop = newAsmop (AOP_IMMD);
802 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
807 if( IN_REGSP( space ))
808 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
811 /* if it is in direct space */
814 sym->aop = aop = newAsmop (AOP_SFR);
815 aop->aopu.aop_dir = sym->rname;
816 aop->size = getSize (sym->type);
817 emitDebug ("; AOP_SFR for %s", sym->rname);
822 { /*.p.t.20030716 adding SFR support to the Z80 port */
823 aop = newAsmop (AOP_SFR);
825 aop->aopu.aop_dir = sym->rname;
826 aop->size = getSize( sym->type );
827 aop->paged = FUNC_REGBANK(sym->type);
828 aop->bcInUse = isPairInUse( PAIR_BC, ic );
829 aop->deInUse = isPairInUse( PAIR_DE, ic );
830 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
836 /* only remaining is far space */
837 /* in which case DPTR gets the address */
840 emitDebug ("; AOP_HL for %s", sym->rname);
841 sym->aop = aop = newAsmop (AOP_HL);
845 sym->aop = aop = newAsmop (AOP_IY);
847 aop->size = getSize (sym->type);
848 aop->aopu.aop_dir = sym->rname;
850 /* if it is in code space */
851 if (IN_CODESPACE (space))
857 /*-----------------------------------------------------------------*/
858 /* aopForRemat - rematerialzes an object */
859 /*-----------------------------------------------------------------*/
861 aopForRemat (symbol * sym)
864 iCode *ic = sym->rematiCode;
865 asmop *aop = newAsmop (AOP_IMMD);
869 /* if plus or minus print the right hand side */
870 if (ic->op == '+' || ic->op == '-')
872 /* PENDING: for re-target */
873 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
876 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
879 /* we reached the end */
880 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
884 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
888 /*-----------------------------------------------------------------*/
889 /* regsInCommon - two operands have some registers in common */
890 /*-----------------------------------------------------------------*/
892 regsInCommon (operand * op1, operand * op2)
897 /* if they have registers in common */
898 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
901 sym1 = OP_SYMBOL (op1);
902 sym2 = OP_SYMBOL (op2);
904 if (sym1->nRegs == 0 || sym2->nRegs == 0)
907 for (i = 0; i < sym1->nRegs; i++)
913 for (j = 0; j < sym2->nRegs; j++)
918 if (sym2->regs[j] == sym1->regs[i])
926 /*-----------------------------------------------------------------*/
927 /* operandsEqu - equivalent */
928 /*-----------------------------------------------------------------*/
930 operandsEqu (operand * op1, operand * op2)
934 /* if they not symbols */
935 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
938 sym1 = OP_SYMBOL (op1);
939 sym2 = OP_SYMBOL (op2);
941 /* if both are itemps & one is spilt
942 and the other is not then false */
943 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
944 sym1->isspilt != sym2->isspilt)
947 /* if they are the same */
951 if (sym1->rname[0] && sym2->rname[0]
952 && strcmp (sym1->rname, sym2->rname) == 0)
955 /* if left is a tmp & right is not */
956 if (IS_ITEMP (op1) &&
959 (sym1->usl.spillLoc == sym2))
962 if (IS_ITEMP (op2) &&
966 (sym2->usl.spillLoc == sym1))
972 /*-----------------------------------------------------------------*/
973 /* sameRegs - two asmops have the same registers */
974 /*-----------------------------------------------------------------*/
976 sameRegs (asmop * aop1, asmop * aop2)
980 if (aop1->type == AOP_SFR ||
981 aop2->type == AOP_SFR)
987 if (aop1->type != AOP_REG ||
988 aop2->type != AOP_REG)
991 if (aop1->size != aop2->size)
994 for (i = 0; i < aop1->size; i++)
995 if (aop1->aopu.aop_reg[i] !=
996 aop2->aopu.aop_reg[i])
1002 /*-----------------------------------------------------------------*/
1003 /* aopOp - allocates an asmop for an operand : */
1004 /*-----------------------------------------------------------------*/
1006 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1015 /* if this a literal */
1016 if (IS_OP_LITERAL (op))
1018 op->aop = aop = newAsmop (AOP_LIT);
1019 aop->aopu.aop_lit = op->operand.valOperand;
1020 aop->size = getSize (operandType (op));
1024 /* if already has a asmop then continue */
1027 if (op->aop->type == AOP_SFR)
1029 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1030 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1035 /* if the underlying symbol has a aop */
1036 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1038 op->aop = OP_SYMBOL (op)->aop;
1039 if (op->aop->type == AOP_SFR)
1041 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1042 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1047 /* if this is a true symbol */
1048 if (IS_TRUE_SYMOP (op))
1050 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1054 /* this is a temporary : this has
1060 e) can be a return use only */
1062 sym = OP_SYMBOL (op);
1064 /* if the type is a conditional */
1065 if (sym->regType == REG_CND)
1067 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1072 /* if it is spilt then two situations
1074 b) has a spill location */
1075 if (sym->isspilt || sym->nRegs == 0)
1077 /* rematerialize it NOW */
1080 sym->aop = op->aop = aop =
1082 aop->size = getSize (sym->type);
1089 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1090 aop->size = getSize (sym->type);
1091 for (i = 0; i < 4; i++)
1092 aop->aopu.aop_str[i] = _fReturn[i];
1098 if (sym->accuse == ACCUSE_A)
1100 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1101 aop->size = getSize (sym->type);
1102 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1104 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1106 else if (sym->accuse == ACCUSE_SCRATCH)
1108 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1109 aop->size = getSize (sym->type);
1110 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1111 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1112 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1114 else if (sym->accuse == ACCUSE_IY)
1116 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1117 aop->size = getSize (sym->type);
1118 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1119 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1120 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1124 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1129 if (sym->usl.spillLoc)
1131 asmop *oldAsmOp = NULL;
1133 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1135 /* force a new aop if sizes differ */
1136 oldAsmOp = sym->usl.spillLoc->aop;
1137 sym->usl.spillLoc->aop = NULL;
1139 sym->aop = op->aop = aop =
1140 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1141 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1143 /* Don't reuse the new aop, go with the last one */
1144 sym->usl.spillLoc->aop = oldAsmOp;
1146 aop->size = getSize (sym->type);
1150 /* else must be a dummy iTemp */
1151 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1152 aop->size = getSize (sym->type);
1156 /* must be in a register */
1157 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1158 aop->size = sym->nRegs;
1159 for (i = 0; i < sym->nRegs; i++)
1160 aop->aopu.aop_reg[i] = sym->regs[i];
1163 /*-----------------------------------------------------------------*/
1164 /* freeAsmop - free up the asmop given to an operand */
1165 /*----------------------------------------------------------------*/
1167 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1184 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1186 _pop (aop->aopu.aop_pairId);
1189 if (getPairId (aop) == PAIR_HL)
1191 spillPair (PAIR_HL);
1195 /* all other cases just dealloc */
1201 OP_SYMBOL (op)->aop = NULL;
1202 /* if the symbol has a spill */
1204 SPIL_LOC (op)->aop = NULL;
1211 isLitWord (asmop * aop)
1213 /* if (aop->size != 2)
1226 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1228 /* depending on type */
1234 /* PENDING: for re-target */
1237 tsprintf (buffer, sizeof(buffer),
1238 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1240 else if (offset == 0)
1242 tsprintf (buffer, sizeof(buffer),
1243 "%s", aop->aopu.aop_immd);
1247 tsprintf (buffer, sizeof(buffer),
1248 "%s + %d", aop->aopu.aop_immd, offset);
1250 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1254 value *val = aop->aopu.aop_lit;
1255 /* if it is a float then it gets tricky */
1256 /* otherwise it is fairly simple */
1257 if (!IS_FLOAT (val->type))
1259 unsigned long v = (unsigned long) floatFromVal (val);
1265 else if (offset == 0)
1271 wassertl(0, "Encountered an invalid offset while fetching a literal");
1275 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1277 tsprintf (buffer, sizeof(buffer), "!constword", v);
1279 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1290 /* it is type float */
1291 fl.f = (float) floatFromVal (val);
1293 #ifdef WORDS_BIGENDIAN
1294 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1296 i = fl.c[offset] | (fl.c[offset+1]<<8);
1299 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1301 tsprintf (buffer, sizeof(buffer), "!constword", i);
1303 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1312 aopGetWord (asmop * aop, int offset)
1314 return aopGetLitWordLong (aop, offset, TRUE);
1318 isPtr (const char *s)
1320 if (!strcmp (s, "hl"))
1322 if (!strcmp (s, "ix"))
1324 if (!strcmp (s, "iy"))
1330 adjustPair (const char *pair, int *pold, int new)
1336 emit2 ("inc %s", pair);
1341 emit2 ("dec %s", pair);
1349 spillPair (PAIR_HL);
1350 spillPair (PAIR_IY);
1354 requiresHL (asmop * aop)
1370 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1372 const char *l, *base;
1373 const char *pair = _pairs[pairId].name;
1374 l = aopGetLitWordLong (left, offset, FALSE);
1375 base = aopGetLitWordLong (left, 0, FALSE);
1376 wassert (l && pair && base);
1380 if (pairId == PAIR_HL || pairId == PAIR_IY)
1382 if (_G.pairs[pairId].last_type == left->type)
1384 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1386 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1388 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1391 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1398 _G.pairs[pairId].last_type = left->type;
1399 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1400 _G.pairs[pairId].offset = offset;
1402 /* Both a lit on the right and a true symbol on the left */
1403 emit2 ("ld %s,!hashedstr", pair, l);
1407 makeFreePairId (iCode *ic, bool *pisUsed)
1413 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1417 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1435 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1437 /* if this is remateriazable */
1438 if (isLitWord (aop)) {
1439 fetchLitPair (pairId, aop, offset);
1443 if (getPairId (aop) == pairId)
1447 /* we need to get it byte by byte */
1448 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1449 aopGet (aop, offset, FALSE);
1450 switch (aop->size - offset) {
1452 emit2 ("ld l,!*hl");
1453 emit2 ("ld h,!immedbyte", 0);
1456 // PENDING: Requires that you are only fetching two bytes.
1459 emit2 ("ld h,!*hl");
1463 wassertl (0, "Attempted to fetch too much data into HL");
1467 else if (IS_Z80 && aop->type == AOP_IY) {
1468 /* Instead of fetching relative to IY, just grab directly
1469 from the address IY refers to */
1470 char *l = aopGetLitWordLong (aop, offset, FALSE);
1472 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1474 if (aop->size < 2) {
1475 emit2("ld %s,!zero", _pairs[pairId].h);
1478 else if (pairId == PAIR_IY)
1482 emit2 ("push %s", _pairs[getPairId(aop)].name);
1488 PAIR_ID id = makeFreePairId (ic, &isUsed);
1491 /* Can't load into parts, so load into HL then exchange. */
1492 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1493 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1494 emit2 ("push %s", _pairs[id].name);
1500 else if (isUnsplitable(aop))
1502 emit2("push %s", _pairs[getPairId(aop)].name);
1503 emit2("pop %s", _pairs[pairId].name);
1507 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1508 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1510 /* PENDING: check? */
1511 if (pairId == PAIR_HL)
1512 spillPair (PAIR_HL);
1517 fetchPair (PAIR_ID pairId, asmop * aop)
1519 fetchPairLong (pairId, aop, NULL, 0);
1523 fetchHL (asmop * aop)
1525 fetchPair (PAIR_HL, aop);
1529 setupPairFromSP (PAIR_ID id, int offset)
1531 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1533 if (_G.preserveCarry)
1539 if (offset < INT8MIN || offset > INT8MAX)
1541 emit2 ("ld hl,!immedword", offset);
1542 emit2 ("add hl,sp");
1546 emit2 ("!ldahlsp", offset);
1549 if (_G.preserveCarry)
1557 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1562 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1563 fetchLitPair (pairId, aop, 0);
1567 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1569 fetchLitPair (pairId, aop, offset);
1570 _G.pairs[pairId].offset = offset;
1574 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1575 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1578 int offset = aop->aopu.aop_stk + _G.stack.offset;
1580 if (_G.pairs[pairId].last_type == aop->type &&
1581 _G.pairs[pairId].offset == offset)
1587 /* PENDING: Do this better. */
1588 if (_G.preserveCarry)
1590 sprintf (buffer, "%d", offset + _G.stack.pushed);
1591 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1592 emit2 ("add %s,sp", _pairs[pairId].name);
1593 _G.pairs[pairId].last_type = aop->type;
1594 _G.pairs[pairId].offset = offset;
1595 if (_G.preserveCarry)
1603 /* Doesnt include _G.stack.pushed */
1604 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1606 if (aop->aopu.aop_stk > 0)
1608 abso += _G.stack.param_offset;
1610 assert (pairId == PAIR_HL);
1611 /* In some cases we can still inc or dec hl */
1612 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1614 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1618 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1620 _G.pairs[pairId].offset = abso;
1625 if (pairId != aop->aopu.aop_pairId)
1626 genMovePairPair(aop->aopu.aop_pairId, pairId);
1627 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1633 _G.pairs[pairId].last_type = aop->type;
1639 emit2 ("!tlabeldef", key);
1640 _G.lines.current->isLabel = 1;
1644 /*-----------------------------------------------------------------*/
1645 /* aopGet - for fetching value of the aop */
1646 /*-----------------------------------------------------------------*/
1648 aopGet (asmop * aop, int offset, bool bit16)
1650 // char *s = buffer;
1652 /* offset is greater than size then zero */
1653 /* PENDING: this seems a bit screwed in some pointer cases. */
1654 if (offset > (aop->size - 1) &&
1655 aop->type != AOP_LIT)
1657 tsprintf (buffer, sizeof(buffer), "!zero");
1658 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1661 /* depending on type */
1665 tsprintf (buffer, sizeof(buffer), "!zero");
1666 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1669 /* PENDING: re-target */
1671 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1676 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1679 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1682 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1685 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1688 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1692 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1693 SNPRINTF (buffer, sizeof(buffer), "a");
1695 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1701 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1702 SNPRINTF (buffer, sizeof(buffer), "a");
1704 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1707 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1710 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1711 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1712 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1714 else if( z80_opts.port_mode == 180 )
1715 { /* z180 in0/out0 mode */
1716 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1720 emit2( "in a,(%s)", aop->aopu.aop_dir );
1723 SNPRINTF (buffer, sizeof(buffer), "a");
1725 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1729 return aop->aopu.aop_reg[offset]->name;
1733 setupPair (PAIR_HL, aop, offset);
1734 tsprintf (buffer, sizeof(buffer), "!*hl");
1736 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1740 setupPair (PAIR_IY, aop, offset);
1741 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1743 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1747 setupPair (PAIR_IY, aop, offset);
1748 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1750 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1755 setupPair (PAIR_HL, aop, offset);
1756 tsprintf (buffer, sizeof(buffer), "!*hl");
1760 if (aop->aopu.aop_stk >= 0)
1761 offset += _G.stack.param_offset;
1762 tsprintf (buffer, sizeof(buffer),
1763 "!*ixx", aop->aopu.aop_stk + offset);
1766 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1769 wassertl (0, "Tried to fetch from a bit variable");
1778 tsprintf(buffer, sizeof(buffer), "!zero");
1779 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1783 wassert (offset < 2);
1784 return aop->aopu.aop_str[offset];
1787 return aopLiteral (aop->aopu.aop_lit, offset);
1791 unsigned long v = aop->aopu.aop_simplelit;
1794 tsprintf (buffer, sizeof(buffer),
1795 "!immedbyte", (unsigned int) v & 0xff);
1797 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1801 return aop->aopu.aop_str[offset];
1804 setupPair (aop->aopu.aop_pairId, aop, offset);
1805 if (aop->aopu.aop_pairId==PAIR_IX)
1806 SNPRINTF (buffer, sizeof(buffer),
1808 else if (aop->aopu.aop_pairId==PAIR_IY)
1809 SNPRINTF (buffer, sizeof(buffer),
1812 SNPRINTF (buffer, sizeof(buffer),
1813 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1815 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1820 wassertl (0, "aopget got unsupported aop->type");
1825 isRegString (const char *s)
1827 if (!strcmp (s, "b") ||
1839 isConstant (const char *s)
1841 /* This is a bit of a hack... */
1842 return (*s == '#' || *s == '$');
1846 canAssignToPtr (const char *s)
1848 if (isRegString (s))
1855 /*-----------------------------------------------------------------*/
1856 /* aopPut - puts a string for a aop */
1857 /*-----------------------------------------------------------------*/
1859 aopPut (asmop * aop, const char *s, int offset)
1863 if (aop->size && offset > (aop->size - 1))
1865 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1866 "aopPut got offset > aop->size");
1871 tsprintf(buffer2, sizeof(buffer2), s);
1874 /* will assign value to value */
1875 /* depending on where it is ofcourse */
1879 _moveA (s); /* in case s is volatile */
1885 if (strcmp (s, "a"))
1886 emit2 ("ld a,%s", s);
1887 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1894 if (strcmp (s, "a"))
1895 emit2 ("ld a,%s", s);
1896 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1899 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1906 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1907 && s[0] != 'h' && s[0] != 'l'))
1909 emit2( "ld a,%s", s );
1913 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1914 emit2( "out (c),%s", s );
1919 spillPair (PAIR_BC);
1921 else if( z80_opts.port_mode == 180 )
1922 { /* z180 in0/out0 mode */
1923 emit2( "ld a,%s", s );
1924 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1928 emit2( "ld a,%s", s );
1929 emit2( "out (%s),a", aop->aopu.aop_dir );
1935 if (!strcmp (s, "!*hl"))
1936 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1939 aop->aopu.aop_reg[offset]->name, s);
1940 spillPairReg(aop->aopu.aop_reg[offset]->name);
1945 if (!canAssignToPtr (s))
1947 emit2 ("ld a,%s", s);
1948 setupPair (PAIR_IY, aop, offset);
1949 emit2 ("ld !*iyx,a", offset);
1953 setupPair (PAIR_IY, aop, offset);
1954 emit2 ("ld !*iyx,%s", offset, s);
1960 /* PENDING: for re-target */
1961 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1963 emit2 ("ld a,!*hl");
1966 setupPair (PAIR_HL, aop, offset);
1968 emit2 ("ld !*hl,%s", s);
1973 if (!canAssignToPtr (s))
1975 emit2 ("ld a,%s", s);
1976 setupPair (PAIR_IY, aop, offset);
1977 emit2 ("ld !*iyx,a", offset);
1981 setupPair (PAIR_IY, aop, offset);
1982 emit2 ("ld !*iyx,%s", offset, s);
1989 /* PENDING: re-target */
1990 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1992 emit2 ("ld a,!*hl");
1995 setupPair (PAIR_HL, aop, offset);
1996 if (!canAssignToPtr (s))
1998 emit2 ("ld a,%s", s);
1999 emit2 ("ld !*hl,a");
2002 emit2 ("ld !*hl,%s", s);
2006 if (aop->aopu.aop_stk >= 0)
2007 offset += _G.stack.param_offset;
2008 if (!canAssignToPtr (s))
2010 emit2 ("ld a,%s", s);
2011 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2015 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2021 /* if bit variable */
2022 if (!aop->aopu.aop_dir)
2024 emit2 ("ld a,!zero");
2029 /* In bit space but not in C - cant happen */
2030 wassertl (0, "Tried to write into a bit variable");
2036 if (strcmp (aop->aopu.aop_str[offset], s))
2038 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2040 spillPairReg(aop->aopu.aop_str[offset]);
2045 if (!offset && (strcmp (s, "acc") == 0))
2049 wassertl (0, "Tried to access past the end of A");
2053 if (strcmp (aop->aopu.aop_str[offset], s))
2055 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2056 spillPairReg(aop->aopu.aop_str[offset]);
2062 wassert (offset < 2);
2063 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2064 spillPairReg(aop->aopu.aop_str[offset]);
2068 setupPair (aop->aopu.aop_pairId, aop, offset);
2069 if (aop->aopu.aop_pairId==PAIR_IX)
2070 emit2 ("ld !*ixx,%s", 0, s);
2071 else if (aop->aopu.aop_pairId==PAIR_IY)
2072 emit2 ("ld !*iyx,%s", 0, s);
2074 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2078 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2079 "aopPut got unsupported aop->type");
2084 #define AOP(op) op->aop
2085 #define AOP_TYPE(op) AOP(op)->type
2086 #define AOP_SIZE(op) AOP(op)->size
2087 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2090 commitPair (asmop * aop, PAIR_ID id)
2092 /* PENDING: Verify this. */
2093 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2097 aopPut (aop, "a", 0);
2098 aopPut (aop, "d", 1);
2103 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2105 char *l = aopGetLitWordLong (aop, 0, FALSE);
2108 emit2 ("ld (%s),%s", l, _pairs[id].name);
2112 aopPut (aop, _pairs[id].l, 0);
2113 aopPut (aop, _pairs[id].h, 1);
2118 /*-----------------------------------------------------------------*/
2119 /* getDataSize - get the operand data size */
2120 /*-----------------------------------------------------------------*/
2122 getDataSize (operand * op)
2125 size = AOP_SIZE (op);
2129 wassertl (0, "Somehow got a three byte data pointer");
2134 /*-----------------------------------------------------------------*/
2135 /* movLeft2Result - move byte from left to result */
2136 /*-----------------------------------------------------------------*/
2138 movLeft2Result (operand * left, int offl,
2139 operand * result, int offr, int sign)
2143 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2145 l = aopGet (AOP (left), offl, FALSE);
2149 aopPut (AOP (result), l, offr);
2153 if (getDataSize (left) == offl + 1)
2155 emit2 ("ld a,%s", l);
2156 aopPut (AOP (result), "a", offr);
2163 movLeft2ResultLong (operand * left, int offl,
2164 operand * result, int offr, int sign,
2169 movLeft2Result (left, offl, result, offr, sign);
2173 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2174 wassertl (size == 2, "Only implemented for two bytes or one");
2176 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2178 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2179 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2181 spillPair (PAIR_HL);
2183 else if ( getPairId ( AOP (result)) == PAIR_IY)
2185 PAIR_ID id = getPairId (AOP (left));
2186 if (id != PAIR_INVALID)
2188 emit2("push %s", _pairs[id].name);
2199 movLeft2Result (left, offl, result, offr, sign);
2200 movLeft2Result (left, offl+1, result, offr+1, sign);
2205 /** Put Acc into a register set
2208 outAcc (operand * result)
2211 size = getDataSize (result);
2214 aopPut (AOP (result), "a", 0);
2217 /* unsigned or positive */
2220 aopPut (AOP (result), "!zero", offset++);
2225 /** Take the value in carry and put it into a register
2228 outBitCLong (operand * result, bool swap_sense)
2230 /* if the result is bit */
2231 if (AOP_TYPE (result) == AOP_CRY)
2233 wassertl (0, "Tried to write carry to a bit");
2237 emit2 ("ld a,!zero");
2240 emit2 ("xor a,!immedbyte", 1);
2246 outBitC (operand * result)
2248 outBitCLong (result, FALSE);
2251 /*-----------------------------------------------------------------*/
2252 /* toBoolean - emit code for orl a,operator(sizeop) */
2253 /*-----------------------------------------------------------------*/
2255 _toBoolean (operand * oper)
2257 int size = AOP_SIZE (oper);
2261 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2264 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2268 if (AOP (oper)->type != AOP_ACC)
2271 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2277 /*-----------------------------------------------------------------*/
2278 /* genNot - generate code for ! operation */
2279 /*-----------------------------------------------------------------*/
2284 /* assign asmOps to operand & result */
2285 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2286 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2288 /* if in bit space then a special case */
2289 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2291 wassertl (0, "Tried to negate a bit");
2294 _toBoolean (IC_LEFT (ic));
2299 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2300 emit2 ("sub a,!one");
2301 outBitC (IC_RESULT (ic));
2303 /* release the aops */
2304 freeAsmop (IC_LEFT (ic), NULL, ic);
2305 freeAsmop (IC_RESULT (ic), NULL, ic);
2308 /*-----------------------------------------------------------------*/
2309 /* genCpl - generate code for complement */
2310 /*-----------------------------------------------------------------*/
2318 /* assign asmOps to operand & result */
2319 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2320 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2322 /* if both are in bit space then
2324 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2325 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2327 wassertl (0, "Left and the result are in bit space");
2330 size = AOP_SIZE (IC_RESULT (ic));
2333 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2336 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2339 /* release the aops */
2340 freeAsmop (IC_LEFT (ic), NULL, ic);
2341 freeAsmop (IC_RESULT (ic), NULL, ic);
2345 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2352 store de into result
2357 store de into result
2359 const char *first = isAdd ? "add" : "sub";
2360 const char *later = isAdd ? "adc" : "sbc";
2362 wassertl (IS_GB, "Code is only relevent to the gbz80");
2363 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2365 fetchPair (PAIR_DE, left);
2368 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2371 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2374 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2375 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2377 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2378 aopGet (right, MSB24, FALSE);
2382 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2385 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2387 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2388 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2392 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2394 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2397 /*-----------------------------------------------------------------*/
2398 /* genUminusFloat - unary minus for floating points */
2399 /*-----------------------------------------------------------------*/
2401 genUminusFloat (operand * op, operand * result)
2403 int size, offset = 0;
2405 emitDebug("; genUminusFloat");
2407 /* for this we just need to flip the
2408 first bit then copy the rest in place */
2409 size = AOP_SIZE (op) - 1;
2411 _moveA(aopGet (AOP (op), MSB32, FALSE));
2413 emit2("xor a,!immedbyte", 0x80);
2414 aopPut (AOP (result), "a", MSB32);
2418 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2423 /*-----------------------------------------------------------------*/
2424 /* genUminus - unary minus code generation */
2425 /*-----------------------------------------------------------------*/
2427 genUminus (iCode * ic)
2430 sym_link *optype, *rtype;
2433 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2434 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2436 /* if both in bit space then special
2438 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2439 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2441 wassertl (0, "Left and right are in bit space");
2445 optype = operandType (IC_LEFT (ic));
2446 rtype = operandType (IC_RESULT (ic));
2448 /* if float then do float stuff */
2449 if (IS_FLOAT (optype))
2451 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2455 /* otherwise subtract from zero */
2456 size = AOP_SIZE (IC_LEFT (ic));
2458 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2460 /* Create a new asmop with value zero */
2461 asmop *azero = newAsmop (AOP_SIMPLELIT);
2462 azero->aopu.aop_simplelit = 0;
2464 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2472 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2473 emit2 ("ld a,!zero");
2474 emit2 ("sbc a,%s", l);
2475 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2478 /* if any remaining bytes in the result */
2479 /* we just need to propagate the sign */
2480 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2485 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2489 /* release the aops */
2490 freeAsmop (IC_LEFT (ic), NULL, ic);
2491 freeAsmop (IC_RESULT (ic), NULL, ic);
2494 /*-----------------------------------------------------------------*/
2495 /* assignResultValue - */
2496 /*-----------------------------------------------------------------*/
2498 assignResultValue (operand * oper)
2500 int size = AOP_SIZE (oper);
2503 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2504 topInA = requiresHL (AOP (oper));
2506 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2508 /* We do it the hard way here. */
2510 aopPut (AOP (oper), _fReturn[0], 0);
2511 aopPut (AOP (oper), _fReturn[1], 1);
2513 aopPut (AOP (oper), _fReturn[0], 2);
2514 aopPut (AOP (oper), _fReturn[1], 3);
2520 aopPut (AOP (oper), _fReturn[size], size);
2525 /** Simple restore that doesn't take into account what is used in the
2529 _restoreRegsAfterCall(void)
2531 if (_G.stack.pushedDE)
2534 _G.stack.pushedDE = FALSE;
2536 if (_G.stack.pushedBC)
2539 _G.stack.pushedBC = FALSE;
2541 _G.saves.saved = FALSE;
2545 _saveRegsForCall(iCode *ic, int sendSetSize)
2548 o Stack parameters are pushed before this function enters
2549 o DE and BC may be used in this function.
2550 o HL and DE may be used to return the result.
2551 o HL and DE may be used to send variables.
2552 o DE and BC may be used to store the result value.
2553 o HL may be used in computing the sent value of DE
2554 o The iPushes for other parameters occur before any addSets
2556 Logic: (to be run inside the first iPush or if none, before sending)
2557 o Compute if DE and/or BC are in use over the call
2558 o Compute if DE is used in the send set
2559 o Compute if DE and/or BC are used to hold the result value
2560 o If (DE is used, or in the send set) and is not used in the result, push.
2561 o If BC is used and is not in the result, push
2563 o If DE is used in the send set, fetch
2564 o If HL is used in the send set, fetch
2568 if (_G.saves.saved == FALSE) {
2569 bool deInUse, bcInUse;
2571 bool bcInRet = FALSE, deInRet = FALSE;
2574 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2575 z80_rUmaskForOp (IC_RESULT(ic)));
2577 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2578 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2580 deSending = (sendSetSize > 1);
2582 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2584 if (bcInUse && bcInRet == FALSE) {
2586 _G.stack.pushedBC = TRUE;
2588 if (deInUse && deInRet == FALSE) {
2590 _G.stack.pushedDE = TRUE;
2593 _G.saves.saved = TRUE;
2596 /* Already saved. */
2600 /*-----------------------------------------------------------------*/
2601 /* genIpush - genrate code for pushing this gets a little complex */
2602 /*-----------------------------------------------------------------*/
2604 genIpush (iCode * ic)
2606 int size, offset = 0;
2609 /* if this is not a parm push : ie. it is spill push
2610 and spill push is always done on the local stack */
2613 wassertl(0, "Encountered an unsupported spill push.");
2617 if (_G.saves.saved == FALSE) {
2618 /* Caller saves, and this is the first iPush. */
2619 /* Scan ahead until we find the function that we are pushing parameters to.
2620 Count the number of addSets on the way to figure out what registers
2621 are used in the send set.
2624 iCode *walk = ic->next;
2627 if (walk->op == SEND) {
2630 else if (walk->op == CALL || walk->op == PCALL) {
2639 _saveRegsForCall(walk, nAddSets);
2642 /* Already saved by another iPush. */
2645 /* then do the push */
2646 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2648 size = AOP_SIZE (IC_LEFT (ic));
2650 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2652 _G.stack.pushed += 2;
2653 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2659 fetchHL (AOP (IC_LEFT (ic)));
2661 spillPair (PAIR_HL);
2662 _G.stack.pushed += 2;
2667 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2669 spillPair (PAIR_HL);
2670 _G.stack.pushed += 2;
2671 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2673 spillPair (PAIR_HL);
2674 _G.stack.pushed += 2;
2680 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2682 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2684 emit2 ("ld a,(%s)", l);
2688 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2689 emit2 ("ld a,%s", l);
2697 freeAsmop (IC_LEFT (ic), NULL, ic);
2700 /*-----------------------------------------------------------------*/
2701 /* genIpop - recover the registers: can happen only for spilling */
2702 /*-----------------------------------------------------------------*/
2704 genIpop (iCode * ic)
2709 /* if the temp was not pushed then */
2710 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2713 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2714 size = AOP_SIZE (IC_LEFT (ic));
2715 offset = (size - 1);
2716 if (isPair (AOP (IC_LEFT (ic))))
2718 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2726 spillPair (PAIR_HL);
2727 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2731 freeAsmop (IC_LEFT (ic), NULL, ic);
2734 /* This is quite unfortunate */
2736 setArea (int inHome)
2739 static int lastArea = 0;
2741 if (_G.in_home != inHome) {
2743 const char *sz = port->mem.code_name;
2744 port->mem.code_name = "HOME";
2745 emit2("!area", CODE_NAME);
2746 port->mem.code_name = sz;
2749 emit2("!area", CODE_NAME); */
2750 _G.in_home = inHome;
2761 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2765 symbol *sym = OP_SYMBOL (op);
2767 if (sym->isspilt || sym->nRegs == 0)
2770 aopOp (op, ic, FALSE, FALSE);
2773 if (aop->type == AOP_REG)
2776 for (i = 0; i < aop->size; i++)
2778 if (pairId == PAIR_DE)
2780 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2781 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2783 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2786 else if (pairId == PAIR_BC)
2788 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2789 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2791 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2801 freeAsmop (IC_LEFT (ic), NULL, ic);
2805 /** Emit the code for a call statement
2808 emitCall (iCode * ic, bool ispcall)
2810 bool bInRet, cInRet, dInRet, eInRet;
2811 sym_link *dtype = operandType (IC_LEFT (ic));
2813 /* if caller saves & we have not saved then */
2819 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2821 /* if send set is not empty then assign */
2826 int nSend = elementsInSet(_G.sendSet);
2827 bool swapped = FALSE;
2829 int _z80_sendOrder[] = {
2834 /* Check if the parameters are swapped. If so route through hl instead. */
2835 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2837 sic = setFirstItem(_G.sendSet);
2838 sic = setNextItem(_G.sendSet);
2840 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2841 /* The second send value is loaded from one the one that holds the first
2842 send, i.e. it is overwritten. */
2843 /* Cache the first in HL, and load the second from HL instead. */
2844 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2845 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2851 for (sic = setFirstItem (_G.sendSet); sic;
2852 sic = setNextItem (_G.sendSet))
2855 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2857 size = AOP_SIZE (IC_LEFT (sic));
2858 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2859 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2861 // PENDING: Mild hack
2862 if (swapped == TRUE && send == 1) {
2864 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2867 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2869 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2872 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2876 freeAsmop (IC_LEFT (sic), NULL, sic);
2883 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2885 werror (W_INDIR_BANKED);
2887 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2889 if (isLitWord (AOP (IC_LEFT (ic))))
2891 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2895 symbol *rlbl = newiTempLabel (NULL);
2896 spillPair (PAIR_HL);
2897 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2899 _G.stack.pushed += 2;
2901 fetchHL (AOP (IC_LEFT (ic)));
2903 emit2 ("!tlabeldef", (rlbl->key + 100));
2904 _G.lines.current->isLabel = 1;
2905 _G.stack.pushed -= 2;
2907 freeAsmop (IC_LEFT (ic), NULL, ic);
2911 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2912 OP_SYMBOL (IC_LEFT (ic))->rname :
2913 OP_SYMBOL (IC_LEFT (ic))->name;
2914 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2916 emit2 ("call banked_call");
2917 emit2 ("!dws", name);
2918 emit2 ("!dw !bankimmeds", name);
2923 emit2 ("call %s", name);
2928 /* Mark the registers as restored. */
2929 _G.saves.saved = FALSE;
2931 /* if we need assign a result value */
2932 if ((IS_ITEMP (IC_RESULT (ic)) &&
2933 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2934 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2935 IS_TRUE_SYMOP (IC_RESULT (ic)))
2938 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2940 assignResultValue (IC_RESULT (ic));
2942 freeAsmop (IC_RESULT (ic), NULL, ic);
2945 /* adjust the stack for parameters if required */
2948 int i = ic->parmBytes;
2950 _G.stack.pushed -= i;
2953 emit2 ("!ldaspsp", i);
2960 emit2 ("ld iy,!immedword", i);
2961 emit2 ("add iy,sp");
2982 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2983 bInRet = bitVectBitValue(result, B_IDX);
2984 cInRet = bitVectBitValue(result, C_IDX);
2985 dInRet = bitVectBitValue(result, D_IDX);
2986 eInRet = bitVectBitValue(result, E_IDX);
2996 if (_G.stack.pushedDE)
2998 if (dInRet && eInRet)
3000 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3004 /* Only restore E */
3011 /* Only restore D */
3019 _G.stack.pushedDE = FALSE;
3022 if (_G.stack.pushedBC)
3024 if (bInRet && cInRet)
3026 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3030 /* Only restore C */
3037 /* Only restore B */
3045 _G.stack.pushedBC = FALSE;
3049 /*-----------------------------------------------------------------*/
3050 /* genCall - generates a call statement */
3051 /*-----------------------------------------------------------------*/
3053 genCall (iCode * ic)
3055 emitCall (ic, FALSE);
3058 /*-----------------------------------------------------------------*/
3059 /* genPcall - generates a call by pointer statement */
3060 /*-----------------------------------------------------------------*/
3062 genPcall (iCode * ic)
3064 emitCall (ic, TRUE);
3067 /*-----------------------------------------------------------------*/
3068 /* resultRemat - result is rematerializable */
3069 /*-----------------------------------------------------------------*/
3071 resultRemat (iCode * ic)
3073 if (SKIP_IC (ic) || ic->op == IFX)
3076 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3078 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3079 if (sym->remat && !POINTER_SET (ic))
3086 extern set *publics;
3088 /*-----------------------------------------------------------------*/
3089 /* genFunction - generated code for function entry */
3090 /*-----------------------------------------------------------------*/
3092 genFunction (iCode * ic)
3096 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3099 bool bcInUse = FALSE;
3100 bool deInUse = FALSE;
3102 setArea (IFFUNC_NONBANKED (sym->type));
3104 /* PENDING: Reset the receive offset as it
3105 doesn't seem to get reset anywhere else.
3107 _G.receiveOffset = 0;
3109 /* Record the last function name for debugging. */
3110 _G.lastFunctionName = sym->rname;
3112 /* Create the function header */
3113 emit2 ("!functionheader", sym->name);
3114 if (!IS_STATIC(sym->etype))
3116 sprintf (buffer, "%s_start", sym->rname);
3117 emit2 ("!labeldef", buffer);
3118 _G.lines.current->isLabel = 1;
3120 emit2 ("!functionlabeldef", sym->rname);
3121 _G.lines.current->isLabel = 1;
3123 ftype = operandType (IC_LEFT (ic));
3125 if (IFFUNC_ISNAKED(ftype))
3127 emitDebug("; naked function: no prologue.");
3131 /* if this is an interrupt service routine
3132 then save all potentially used registers. */
3133 if (IFFUNC_ISISR (sym->type))
3135 /* If critical function then turn interrupts off */
3136 /* except when no interrupt number is given then it implies the NMI handler */
3137 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3146 /* This is a non-ISR function.
3147 If critical function then turn interrupts off */
3148 if (IFFUNC_ISCRITICAL (sym->type))
3156 //get interrupt enable flag IFF2 into P/O
3165 if (options.profile)
3167 emit2 ("!profileenter");
3170 /* PENDING: callee-save etc */
3172 _G.stack.param_offset = 0;
3174 if (z80_opts.calleeSavesBC)
3179 /* Detect which registers are used. */
3180 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3183 for (i = 0; i < sym->regsUsed->size; i++)
3185 if (bitVectBitValue (sym->regsUsed, i))
3199 /* Other systems use DE as a temporary. */
3210 _G.stack.param_offset += 2;
3213 _G.calleeSaves.pushedBC = bcInUse;
3218 _G.stack.param_offset += 2;
3221 _G.calleeSaves.pushedDE = deInUse;
3223 /* adjust the stack for the function */
3224 _G.stack.last = sym->stack;
3227 for (sym = setFirstItem (istack->syms); sym;
3228 sym = setNextItem (istack->syms))
3230 if (sym->_isparm && !IS_REGPARM (sym->etype))
3236 sym = OP_SYMBOL (IC_LEFT (ic));
3238 _G.omitFramePtr = options.ommitFramePtr;
3239 if (IS_Z80 && !stackParm && !sym->stack)
3241 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3242 /* the above !sym->stack condition can be removed. -- EEP */
3244 emit2 ("!ldaspsp", -sym->stack);
3245 _G.omitFramePtr = TRUE;
3247 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3248 emit2 ("!enterxl", sym->stack);
3249 else if (sym->stack)
3250 emit2 ("!enterx", sym->stack);
3254 _G.stack.offset = sym->stack;
3257 /*-----------------------------------------------------------------*/
3258 /* genEndFunction - generates epilogue for functions */
3259 /*-----------------------------------------------------------------*/
3261 genEndFunction (iCode * ic)
3263 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3265 if (IFFUNC_ISNAKED(sym->type))
3267 emitDebug("; naked function: no epilogue.");
3271 /* PENDING: calleeSave */
3272 if (IS_Z80 && _G.omitFramePtr)
3274 if (_G.stack.offset)
3275 emit2 ("!ldaspsp", _G.stack.offset);
3277 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3279 emit2 ("!leavexl", _G.stack.offset);
3281 else if (_G.stack.offset)
3283 emit2 ("!leavex", _G.stack.offset);
3290 if (_G.calleeSaves.pushedDE)
3293 _G.calleeSaves.pushedDE = FALSE;
3296 if (_G.calleeSaves.pushedBC)
3299 _G.calleeSaves.pushedBC = FALSE;
3302 if (options.profile)
3304 emit2 ("!profileexit");
3307 /* if this is an interrupt service routine
3308 then save all potentially used registers. */
3309 if (IFFUNC_ISISR (sym->type))
3313 /* If critical function then turn interrupts back on */
3314 /* except when no interrupt number is given then it implies the NMI handler */
3315 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3322 /* This is a non-ISR function.
3323 If critical function then turn interrupts back on */
3324 if (IFFUNC_ISCRITICAL (sym->type))
3332 symbol *tlbl = newiTempLabel (NULL);
3335 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3336 //don't enable interrupts as they were off before
3337 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3339 emit2 ("!tlabeldef", (tlbl->key + 100));
3340 _G.lines.current->isLabel = 1;
3345 if (options.debug && currFunc)
3347 debugFile->writeEndFunction (currFunc, ic, 1);
3350 if (IFFUNC_ISISR (sym->type))
3352 /* "critical interrupt" is used to imply NMI handler */
3353 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3360 /* Both banked and non-banked just ret */
3364 if (!IS_STATIC(sym->etype))
3366 sprintf (buffer, "%s_end", sym->rname);
3367 emit2 ("!labeldef", buffer);
3368 _G.lines.current->isLabel = 1;
3371 _G.flushStatics = 1;
3372 _G.stack.pushed = 0;
3373 _G.stack.offset = 0;
3376 /*-----------------------------------------------------------------*/
3377 /* genRet - generate code for return statement */
3378 /*-----------------------------------------------------------------*/
3383 /* Errk. This is a hack until I can figure out how
3384 to cause dehl to spill on a call */
3385 int size, offset = 0;
3387 /* if we have no return value then
3388 just generate the "ret" */
3392 /* we have something to return then
3393 move the return value into place */
3394 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3395 size = AOP_SIZE (IC_LEFT (ic));
3397 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3400 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3404 emit2 ("ld de,%s", l);
3408 emit2 ("ld hl,%s", l);
3414 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3418 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3420 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3421 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3427 l = aopGet (AOP (IC_LEFT (ic)), offset,
3429 if (strcmp (_fReturn[offset], l))
3430 emit2 ("ld %s,%s", _fReturn[offset], l);
3435 freeAsmop (IC_LEFT (ic), NULL, ic);
3438 /* generate a jump to the return label
3439 if the next is not the return statement */
3440 if (!(ic->next && ic->next->op == LABEL &&
3441 IC_LABEL (ic->next) == returnLabel))
3443 emit2 ("jp !tlabel", returnLabel->key + 100);
3446 /*-----------------------------------------------------------------*/
3447 /* genLabel - generates a label */
3448 /*-----------------------------------------------------------------*/
3450 genLabel (iCode * ic)
3452 /* special case never generate */
3453 if (IC_LABEL (ic) == entryLabel)
3456 emitLabel (IC_LABEL (ic)->key + 100);
3459 /*-----------------------------------------------------------------*/
3460 /* genGoto - generates a ljmp */
3461 /*-----------------------------------------------------------------*/
3463 genGoto (iCode * ic)
3465 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3468 /*-----------------------------------------------------------------*/
3469 /* genPlusIncr :- does addition with increment if possible */
3470 /*-----------------------------------------------------------------*/
3472 genPlusIncr (iCode * ic)
3474 unsigned int icount;
3475 unsigned int size = getDataSize (IC_RESULT (ic));
3476 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3478 /* will try to generate an increment */
3479 /* if the right side is not a literal
3481 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3484 emitDebug ("; genPlusIncr");
3486 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3488 /* If result is a pair */
3489 if (resultId != PAIR_INVALID)
3491 if (isLitWord (AOP (IC_LEFT (ic))))
3493 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3496 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3498 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3500 PAIR_ID freep = getFreePairId (ic);
3501 if (freep != PAIR_INVALID)
3503 fetchPair (freep, AOP (IC_RIGHT (ic)));
3504 emit2 ("add hl,%s", _pairs[freep].name);
3510 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3511 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3518 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3522 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3526 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3531 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3533 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3534 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3538 /* if the literal value of the right hand side
3539 is greater than 4 then it is not worth it */
3543 /* if increment 16 bits in register */
3544 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3550 symbol *tlbl = NULL;
3551 tlbl = newiTempLabel (NULL);
3554 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3557 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3560 emitLabel (tlbl->key + 100);
3564 /* if the sizes are greater than 1 then we cannot */
3565 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3566 AOP_SIZE (IC_LEFT (ic)) > 1)
3569 /* If the result is in a register then we can load then increment.
3571 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3573 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3576 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3581 /* we can if the aops of the left & result match or
3582 if they are in registers and the registers are the
3584 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3588 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3596 /*-----------------------------------------------------------------*/
3597 /* outBitAcc - output a bit in acc */
3598 /*-----------------------------------------------------------------*/
3600 outBitAcc (operand * result)
3602 symbol *tlbl = newiTempLabel (NULL);
3603 /* if the result is a bit */
3604 if (AOP_TYPE (result) == AOP_CRY)
3606 wassertl (0, "Tried to write A into a bit");
3610 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3611 emit2 ("ld a,!one");
3612 emitLabel (tlbl->key + 100);
3618 couldDestroyCarry (asmop *aop)
3622 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3631 shiftIntoPair (int idx, asmop *aop)
3633 PAIR_ID id = PAIR_INVALID;
3635 wassertl (IS_Z80, "Only implemented for the Z80");
3636 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3638 emitDebug ("; Shift into pair idx %u", idx);
3644 setupPair (PAIR_HL, aop, 0);
3649 setupPair (PAIR_IY, aop, 0);
3651 emit2 ("pop %s", _pairs[id].name);
3655 setupPair (PAIR_IY, aop, 0);
3658 wassertl (0, "Internal error - hit default case");
3661 aop->type = AOP_PAIRPTR;
3662 aop->aopu.aop_pairId = id;
3663 _G.pairs[id].offset = 0;
3664 _G.pairs[id].last_type = aop->type;
3668 setupToPreserveCarry (iCode * ic)
3670 asmop *left = AOP (IC_LEFT (ic));
3671 asmop *right = AOP (IC_RIGHT (ic));
3672 asmop *result = AOP (IC_RESULT (ic));
3674 wassert (left && right);
3678 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3680 shiftIntoPair (0, right);
3681 /* check result again, in case right == result */
3682 if (couldDestroyCarry (result))
3684 if (!isPairInUse (PAIR_DE, ic))
3685 shiftIntoPair (1, result);
3687 shiftIntoPair (2, result);
3690 else if (couldDestroyCarry (right))
3692 if (getPairId (result) == PAIR_HL)
3693 _G.preserveCarry = TRUE;
3695 shiftIntoPair (0, right);
3697 else if (couldDestroyCarry (result))
3699 shiftIntoPair (0, result);
3708 /*-----------------------------------------------------------------*/
3709 /* genPlus - generates code for addition */
3710 /*-----------------------------------------------------------------*/
3712 genPlus (iCode * ic)
3714 int size, offset = 0;
3716 /* special cases :- */
3718 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3719 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3720 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3722 /* Swap the left and right operands if:
3724 if literal, literal on the right or
3725 if left requires ACC or right is already
3728 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3729 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3730 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3732 operand *t = IC_RIGHT (ic);
3733 IC_RIGHT (ic) = IC_LEFT (ic);
3737 /* if both left & right are in bit
3739 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3740 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3743 wassertl (0, "Tried to add two bits");
3746 /* if left in bit space & right literal */
3747 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3748 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3750 /* Can happen I guess */
3751 wassertl (0, "Tried to add a bit to a literal");
3754 /* if I can do an increment instead
3755 of add then GOOD for ME */
3756 if (genPlusIncr (ic) == TRUE)
3759 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3761 size = getDataSize (IC_RESULT (ic));
3763 /* Special case when left and right are constant */
3764 if (isPair (AOP (IC_RESULT (ic))))
3767 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3768 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3770 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3776 sprintf (buffer, "#(%s + %s)", left, right);
3777 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3782 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3784 /* Fetch into HL then do the add */
3785 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3786 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3788 spillPair (PAIR_HL);
3790 if (left == PAIR_HL && right != PAIR_INVALID)
3792 emit2 ("add hl,%s", _pairs[right].name);
3795 else if (right == PAIR_HL && left != PAIR_INVALID)
3797 emit2 ("add hl,%s", _pairs[left].name);
3800 else if (right != PAIR_INVALID && right != PAIR_HL)
3802 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3803 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3806 else if (left != PAIR_INVALID && left != PAIR_HL)
3808 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3809 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3818 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3820 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3821 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3823 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3828 ld hl,sp+n trashes C so we can't afford to do it during an
3829 add with stack based variables. Worst case is:
3842 So you can't afford to load up hl if either left, right, or result
3843 is on the stack (*sigh*) The alt is:
3851 Combinations in here are:
3852 * If left or right are in bc then the loss is small - trap later
3853 * If the result is in bc then the loss is also small
3857 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3858 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3859 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3861 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3862 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3863 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3864 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3866 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3868 /* Swap left and right */
3869 operand *t = IC_RIGHT (ic);
3870 IC_RIGHT (ic) = IC_LEFT (ic);
3873 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3875 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3876 emit2 ("add hl,bc");
3880 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3881 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3882 emit2 ("add hl,de");
3884 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3890 /* Be paranoid on the GB with 4 byte variables due to how C
3891 can be trashed by lda hl,n(sp).
3893 _gbz80_emitAddSubLong (ic, TRUE);
3898 setupToPreserveCarry (ic);
3902 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3904 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3907 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3910 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3914 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3917 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3920 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3922 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3926 _G.preserveCarry = FALSE;
3927 freeAsmop (IC_LEFT (ic), NULL, ic);
3928 freeAsmop (IC_RIGHT (ic), NULL, ic);
3929 freeAsmop (IC_RESULT (ic), NULL, ic);
3932 /*-----------------------------------------------------------------*/
3933 /* genMinusDec :- does subtraction with deccrement if possible */
3934 /*-----------------------------------------------------------------*/
3936 genMinusDec (iCode * ic)
3938 unsigned int icount;
3939 unsigned int size = getDataSize (IC_RESULT (ic));
3941 /* will try to generate an increment */
3942 /* if the right side is not a literal we cannot */
3943 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3946 /* if the literal value of the right hand side
3947 is greater than 4 then it is not worth it */
3948 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3951 size = getDataSize (IC_RESULT (ic));
3953 /* if decrement 16 bits in register */
3954 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3955 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3958 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3962 /* If result is a pair */
3963 if (isPair (AOP (IC_RESULT (ic))))
3965 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3967 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3971 /* if increment 16 bits in register */
3972 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3976 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3979 emit2 ("dec %s", _getTempPairName());
3982 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3988 /* if the sizes are greater than 1 then we cannot */
3989 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3990 AOP_SIZE (IC_LEFT (ic)) > 1)
3993 /* we can if the aops of the left & result match or if they are in
3994 registers and the registers are the same */
3995 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3998 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4005 /*-----------------------------------------------------------------*/
4006 /* genMinus - generates code for subtraction */
4007 /*-----------------------------------------------------------------*/
4009 genMinus (iCode * ic)
4011 int size, offset = 0;
4012 unsigned long lit = 0L;
4014 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4015 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4016 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4018 /* special cases :- */
4019 /* if both left & right are in bit space */
4020 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4021 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4023 wassertl (0, "Tried to subtract two bits");
4027 /* if I can do an decrement instead of subtract then GOOD for ME */
4028 if (genMinusDec (ic) == TRUE)
4031 size = getDataSize (IC_RESULT (ic));
4033 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4038 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4042 /* Same logic as genPlus */
4045 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4046 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4047 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4049 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4050 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4051 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4052 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4054 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4055 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4057 if (left == PAIR_INVALID && right == PAIR_INVALID)
4062 else if (right == PAIR_INVALID)
4064 else if (left == PAIR_INVALID)
4067 fetchPair (left, AOP (IC_LEFT (ic)));
4068 /* Order is important. Right may be HL */
4069 fetchPair (right, AOP (IC_RIGHT (ic)));
4071 emit2 ("ld a,%s", _pairs[left].l);
4072 emit2 ("sub a,%s", _pairs[right].l);
4074 emit2 ("ld a,%s", _pairs[left].h);
4075 emit2 ("sbc a,%s", _pairs[right].h);
4077 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4079 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4081 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4087 /* Be paranoid on the GB with 4 byte variables due to how C
4088 can be trashed by lda hl,n(sp).
4090 _gbz80_emitAddSubLong (ic, FALSE);
4095 setupToPreserveCarry (ic);
4097 /* if literal, add a,#-lit, else normal subb */
4100 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4101 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4105 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4108 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4112 /* first add without previous c */
4114 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4116 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4118 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4121 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4122 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4123 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4125 wassertl (0, "Tried to subtract on a long pointer");
4129 _G.preserveCarry = FALSE;
4130 freeAsmop (IC_LEFT (ic), NULL, ic);
4131 freeAsmop (IC_RIGHT (ic), NULL, ic);
4132 freeAsmop (IC_RESULT (ic), NULL, ic);
4135 /*-----------------------------------------------------------------*/
4136 /* genMult - generates code for multiplication */
4137 /*-----------------------------------------------------------------*/
4139 genMult (iCode * ic)
4143 /* If true then the final operation should be a subtract */
4144 bool active = FALSE;
4147 /* Shouldn't occur - all done through function calls */
4148 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4149 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4150 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4152 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4154 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4155 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4156 AOP_SIZE (IC_RESULT (ic)) > 2)
4158 wassertl (0, "Multiplication is handled through support function calls");
4161 /* Swap left and right such that right is a literal */
4162 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4164 operand *t = IC_RIGHT (ic);
4165 IC_RIGHT (ic) = IC_LEFT (ic);
4169 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4171 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4172 // wassertl (val > 0, "Multiply must be positive");
4173 wassertl (val != 1, "Can't multiply by 1");
4175 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4177 _G.stack.pushedDE = TRUE;
4180 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4182 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4193 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4198 /* Fully unroled version of mul.s. Not the most efficient.
4200 for (count = 0; count < 16; count++)
4202 if (count != 0 && active)
4204 emit2 ("add hl,hl");
4208 if (active == FALSE)
4216 emit2 ("add hl,de");
4225 if (IS_Z80 && _G.stack.pushedDE)
4228 _G.stack.pushedDE = FALSE;
4232 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4234 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4236 freeAsmop (IC_LEFT (ic), NULL, ic);
4237 freeAsmop (IC_RIGHT (ic), NULL, ic);
4238 freeAsmop (IC_RESULT (ic), NULL, ic);
4241 /*-----------------------------------------------------------------*/
4242 /* genDiv - generates code for division */
4243 /*-----------------------------------------------------------------*/
4247 /* Shouldn't occur - all done through function calls */
4248 wassertl (0, "Division is handled through support function calls");
4251 /*-----------------------------------------------------------------*/
4252 /* genMod - generates code for division */
4253 /*-----------------------------------------------------------------*/
4257 /* Shouldn't occur - all done through function calls */
4261 /*-----------------------------------------------------------------*/
4262 /* genIfxJump :- will create a jump depending on the ifx */
4263 /*-----------------------------------------------------------------*/
4265 genIfxJump (iCode * ic, char *jval)
4270 /* if true label then we jump if condition
4274 jlbl = IC_TRUE (ic);
4275 if (!strcmp (jval, "a"))
4279 else if (!strcmp (jval, "c"))
4283 else if (!strcmp (jval, "nc"))
4287 else if (!strcmp (jval, "m"))
4291 else if (!strcmp (jval, "p"))
4297 /* The buffer contains the bit on A that we should test */
4303 /* false label is present */
4304 jlbl = IC_FALSE (ic);
4305 if (!strcmp (jval, "a"))
4309 else if (!strcmp (jval, "c"))
4313 else if (!strcmp (jval, "nc"))
4317 else if (!strcmp (jval, "m"))
4321 else if (!strcmp (jval, "p"))
4327 /* The buffer contains the bit on A that we should test */
4331 /* Z80 can do a conditional long jump */
4332 if (!strcmp (jval, "a"))
4336 else if (!strcmp (jval, "c"))
4339 else if (!strcmp (jval, "nc"))
4342 else if (!strcmp (jval, "m"))
4345 else if (!strcmp (jval, "p"))
4350 emit2 ("bit %s,a", jval);
4352 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4354 /* mark the icode as generated */
4360 _getPairIdName (PAIR_ID id)
4362 return _pairs[id].name;
4367 /* if unsigned char cmp with lit, just compare */
4369 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4371 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4374 emit2 ("xor a,!immedbyte", 0x80);
4375 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4378 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4380 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4382 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4383 // Pull left into DE and right into HL
4384 aopGet (AOP(left), LSB, FALSE);
4387 aopGet (AOP(right), LSB, FALSE);
4391 if (size == 0 && sign)
4393 // Highest byte when signed needs the bits flipped
4396 emit2 ("ld a,(de)");
4397 emit2 ("xor !immedbyte", 0x80);
4399 emit2 ("ld a,(hl)");
4400 emit2 ("xor !immedbyte", 0x80);
4404 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4408 emit2 ("ld a,(de)");
4409 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4419 spillPair (PAIR_HL);
4421 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4423 setupPair (PAIR_HL, AOP (left), 0);
4424 aopGet (AOP(right), LSB, FALSE);
4428 if (size == 0 && sign)
4430 // Highest byte when signed needs the bits flipped
4433 emit2 ("ld a,(hl)");
4434 emit2 ("xor !immedbyte", 0x80);
4436 emit2 ("ld a,%d(iy)", offset);
4437 emit2 ("xor !immedbyte", 0x80);
4441 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4445 emit2 ("ld a,(hl)");
4446 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4455 spillPair (PAIR_HL);
4456 spillPair (PAIR_IY);
4460 if (AOP_TYPE (right) == AOP_LIT)
4462 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4463 /* optimize if(x < 0) or if(x >= 0) */
4468 /* No sign so it's always false */
4473 /* Just load in the top most bit */
4474 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4475 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4477 genIfxJump (ifx, "7");
4489 /* First setup h and l contaning the top most bytes XORed */
4490 bool fDidXor = FALSE;
4491 if (AOP_TYPE (left) == AOP_LIT)
4493 unsigned long lit = (unsigned long)
4494 floatFromVal (AOP (left)->aopu.aop_lit);
4495 emit2 ("ld %s,!immedbyte", _fTmp[0],
4496 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4500 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4501 emit2 ("xor a,!immedbyte", 0x80);
4502 emit2 ("ld %s,a", _fTmp[0]);
4505 if (AOP_TYPE (right) == AOP_LIT)
4507 unsigned long lit = (unsigned long)
4508 floatFromVal (AOP (right)->aopu.aop_lit);
4509 emit2 ("ld %s,!immedbyte", _fTmp[1],
4510 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4514 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4515 emit2 ("xor a,!immedbyte", 0x80);
4516 emit2 ("ld %s,a", _fTmp[1]);
4522 /* Do a long subtract */
4525 _moveA (aopGet (AOP (left), offset, FALSE));
4527 if (sign && size == 0)
4529 emit2 ("ld a,%s", _fTmp[0]);
4530 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4534 /* Subtract through, propagating the carry */
4535 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4543 /** Generic compare for > or <
4546 genCmp (operand * left, operand * right,
4547 operand * result, iCode * ifx, int sign)
4549 int size, offset = 0;
4550 unsigned long lit = 0L;
4551 bool swap_sense = FALSE;
4553 /* if left & right are bit variables */
4554 if (AOP_TYPE (left) == AOP_CRY &&
4555 AOP_TYPE (right) == AOP_CRY)
4557 /* Cant happen on the Z80 */
4558 wassertl (0, "Tried to compare two bits");
4562 /* Do a long subtract of right from left. */
4563 size = max (AOP_SIZE (left), AOP_SIZE (right));
4565 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4567 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4568 // Pull left into DE and right into HL
4569 aopGet (AOP(left), LSB, FALSE);
4572 aopGet (AOP(right), LSB, FALSE);
4576 emit2 ("ld a,(de)");
4577 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4586 spillPair (PAIR_HL);
4590 if (AOP_TYPE (right) == AOP_LIT)
4592 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4593 /* optimize if(x < 0) or if(x >= 0) */
4598 /* No sign so it's always false */
4603 /* Just load in the top most bit */
4604 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4605 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4607 genIfxJump (ifx, "7");
4618 genIfxJump (ifx, swap_sense ? "c" : "nc");
4629 _moveA (aopGet (AOP (left), offset, FALSE));
4630 /* Subtract through, propagating the carry */
4631 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4637 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4641 /* Shift the sign bit up into carry */
4644 outBitCLong (result, swap_sense);
4648 /* if the result is used in the next
4649 ifx conditional branch then generate
4650 code a little differently */
4658 genIfxJump (ifx, swap_sense ? "nc" : "c");
4662 genIfxJump (ifx, swap_sense ? "p" : "m");
4667 genIfxJump (ifx, swap_sense ? "nc" : "c");
4674 /* Shift the sign bit up into carry */
4677 outBitCLong (result, swap_sense);
4679 /* leave the result in acc */
4683 /*-----------------------------------------------------------------*/
4684 /* genCmpGt :- greater than comparison */
4685 /*-----------------------------------------------------------------*/
4687 genCmpGt (iCode * ic, iCode * ifx)
4689 operand *left, *right, *result;
4690 sym_link *letype, *retype;
4693 left = IC_LEFT (ic);
4694 right = IC_RIGHT (ic);
4695 result = IC_RESULT (ic);
4697 letype = getSpec (operandType (left));
4698 retype = getSpec (operandType (right));
4699 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4700 /* assign the amsops */
4701 aopOp (left, ic, FALSE, FALSE);
4702 aopOp (right, ic, FALSE, FALSE);
4703 aopOp (result, ic, TRUE, FALSE);
4705 genCmp (right, left, result, ifx, sign);
4707 freeAsmop (left, NULL, ic);
4708 freeAsmop (right, NULL, ic);
4709 freeAsmop (result, NULL, ic);
4712 /*-----------------------------------------------------------------*/
4713 /* genCmpLt - less than comparisons */
4714 /*-----------------------------------------------------------------*/
4716 genCmpLt (iCode * ic, iCode * ifx)
4718 operand *left, *right, *result;
4719 sym_link *letype, *retype;
4722 left = IC_LEFT (ic);
4723 right = IC_RIGHT (ic);
4724 result = IC_RESULT (ic);
4726 letype = getSpec (operandType (left));
4727 retype = getSpec (operandType (right));
4728 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4730 /* assign the amsops */
4731 aopOp (left, ic, FALSE, FALSE);
4732 aopOp (right, ic, FALSE, FALSE);
4733 aopOp (result, ic, TRUE, FALSE);
4735 genCmp (left, right, result, ifx, sign);
4737 freeAsmop (left, NULL, ic);
4738 freeAsmop (right, NULL, ic);
4739 freeAsmop (result, NULL, ic);
4742 /*-----------------------------------------------------------------*/
4743 /* gencjneshort - compare and jump if not equal */
4744 /*-----------------------------------------------------------------*/
4746 gencjneshort (operand * left, operand * right, symbol * lbl)
4748 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4750 unsigned long lit = 0L;
4752 /* Swap the left and right if it makes the computation easier */
4753 if (AOP_TYPE (left) == AOP_LIT)
4760 if (AOP_TYPE (right) == AOP_LIT)
4762 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4765 /* if the right side is a literal then anything goes */
4766 if (AOP_TYPE (right) == AOP_LIT &&
4767 AOP_TYPE (left) != AOP_DIR)
4771 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4776 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4783 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4789 _moveA (aopGet (AOP (left), offset, FALSE));
4790 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4793 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4794 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4799 /* if the right side is in a register or in direct space or
4800 if the left is a pointer register & right is not */
4801 else if (AOP_TYPE (right) == AOP_REG ||
4802 AOP_TYPE (right) == AOP_DIR ||
4803 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4807 _moveA (aopGet (AOP (left), offset, FALSE));
4808 if (/*AOP_TYPE (left) == AOP_DIR &&*/ AOP_TYPE (right) == AOP_LIT &&
4809 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4812 /* MB: pending what? doesn't this need "or a,a"? */
4813 /* and I don't think AOP_TYPE(left) has anything to do with this */
4815 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4819 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4820 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4827 /* right is a pointer reg need both a & b */
4828 /* PENDING: is this required? */
4831 _moveA (aopGet (AOP (right), offset, FALSE));
4832 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4833 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4839 /*-----------------------------------------------------------------*/
4840 /* gencjne - compare and jump if not equal */
4841 /*-----------------------------------------------------------------*/
4843 gencjne (operand * left, operand * right, symbol * lbl)
4845 symbol *tlbl = newiTempLabel (NULL);
4847 gencjneshort (left, right, lbl);
4850 emit2 ("ld a,!one");
4851 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4852 emitLabel (lbl->key + 100);
4854 emitLabel (tlbl->key + 100);
4857 /*-----------------------------------------------------------------*/
4858 /* genCmpEq - generates code for equal to */
4859 /*-----------------------------------------------------------------*/
4861 genCmpEq (iCode * ic, iCode * ifx)
4863 operand *left, *right, *result;
4865 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4866 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4867 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4869 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4871 /* Swap operands if it makes the operation easier. ie if:
4872 1. Left is a literal.
4874 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4876 operand *t = IC_RIGHT (ic);
4877 IC_RIGHT (ic) = IC_LEFT (ic);
4881 if (ifx && !AOP_SIZE (result))
4884 /* if they are both bit variables */
4885 if (AOP_TYPE (left) == AOP_CRY &&
4886 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4888 wassertl (0, "Tried to compare two bits");
4892 tlbl = newiTempLabel (NULL);
4893 gencjneshort (left, right, tlbl);
4896 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4897 emitLabel (tlbl->key + 100);
4901 /* PENDING: do this better */
4902 symbol *lbl = newiTempLabel (NULL);
4903 emit2 ("!shortjp !tlabel", lbl->key + 100);
4904 emitLabel (tlbl->key + 100);
4905 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4906 emitLabel (lbl->key + 100);
4909 /* mark the icode as generated */
4914 /* if they are both bit variables */
4915 if (AOP_TYPE (left) == AOP_CRY &&
4916 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4918 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4924 gencjne (left, right, newiTempLabel (NULL));
4925 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4932 genIfxJump (ifx, "a");
4935 /* if the result is used in an arithmetic operation
4936 then put the result in place */
4937 if (AOP_TYPE (result) != AOP_CRY)
4942 /* leave the result in acc */
4946 freeAsmop (left, NULL, ic);
4947 freeAsmop (right, NULL, ic);
4948 freeAsmop (result, NULL, ic);
4951 /*-----------------------------------------------------------------*/
4952 /* ifxForOp - returns the icode containing the ifx for operand */
4953 /*-----------------------------------------------------------------*/
4955 ifxForOp (operand * op, iCode * ic)
4957 /* if true symbol then needs to be assigned */
4958 if (IS_TRUE_SYMOP (op))
4961 /* if this has register type condition and
4962 the next instruction is ifx with the same operand
4963 and live to of the operand is upto the ifx only then */
4965 ic->next->op == IFX &&
4966 IC_COND (ic->next)->key == op->key &&
4967 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4973 /*-----------------------------------------------------------------*/
4974 /* genAndOp - for && operation */
4975 /*-----------------------------------------------------------------*/
4977 genAndOp (iCode * ic)
4979 operand *left, *right, *result;
4982 /* note here that && operations that are in an if statement are
4983 taken away by backPatchLabels only those used in arthmetic
4984 operations remain */
4985 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4986 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4987 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4989 /* if both are bit variables */
4990 if (AOP_TYPE (left) == AOP_CRY &&
4991 AOP_TYPE (right) == AOP_CRY)
4993 wassertl (0, "Tried to and two bits");
4997 tlbl = newiTempLabel (NULL);
4999 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5001 emitLabel (tlbl->key + 100);
5005 freeAsmop (left, NULL, ic);
5006 freeAsmop (right, NULL, ic);
5007 freeAsmop (result, NULL, ic);
5010 /*-----------------------------------------------------------------*/
5011 /* genOrOp - for || operation */
5012 /*-----------------------------------------------------------------*/
5014 genOrOp (iCode * ic)
5016 operand *left, *right, *result;
5019 /* note here that || operations that are in an
5020 if statement are taken away by backPatchLabels
5021 only those used in arthmetic operations remain */
5022 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5023 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5024 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5026 /* if both are bit variables */
5027 if (AOP_TYPE (left) == AOP_CRY &&
5028 AOP_TYPE (right) == AOP_CRY)
5030 wassertl (0, "Tried to OR two bits");
5034 tlbl = newiTempLabel (NULL);
5036 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5038 emitLabel (tlbl->key + 100);
5042 freeAsmop (left, NULL, ic);
5043 freeAsmop (right, NULL, ic);
5044 freeAsmop (result, NULL, ic);
5047 /*-----------------------------------------------------------------*/
5048 /* isLiteralBit - test if lit == 2^n */
5049 /*-----------------------------------------------------------------*/
5051 isLiteralBit (unsigned long lit)
5053 unsigned long pw[32] =
5054 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5055 0x100L, 0x200L, 0x400L, 0x800L,
5056 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5057 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5058 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5059 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5060 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5063 for (idx = 0; idx < 32; idx++)
5069 /*-----------------------------------------------------------------*/
5070 /* jmpTrueOrFalse - */
5071 /*-----------------------------------------------------------------*/
5073 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5075 // ugly but optimized by peephole
5078 symbol *nlbl = newiTempLabel (NULL);
5079 emit2 ("jp !tlabel", nlbl->key + 100);
5080 emitLabel (tlbl->key + 100);
5081 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5082 emitLabel (nlbl->key + 100);
5086 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5087 emitLabel (tlbl->key + 100);
5092 /*-----------------------------------------------------------------*/
5093 /* genAnd - code for and */
5094 /*-----------------------------------------------------------------*/
5096 genAnd (iCode * ic, iCode * ifx)
5098 operand *left, *right, *result;
5099 int size, offset = 0;
5100 unsigned long lit = 0L;
5103 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5104 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5105 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5107 /* if left is a literal & right is not then exchange them */
5108 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5109 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5111 operand *tmp = right;
5116 /* if result = right then exchange them */
5117 if (sameRegs (AOP (result), AOP (right)))
5119 operand *tmp = right;
5124 /* if right is bit then exchange them */
5125 if (AOP_TYPE (right) == AOP_CRY &&
5126 AOP_TYPE (left) != AOP_CRY)
5128 operand *tmp = right;
5132 if (AOP_TYPE (right) == AOP_LIT)
5133 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5135 size = AOP_SIZE (result);
5137 if (AOP_TYPE (left) == AOP_CRY)
5139 wassertl (0, "Tried to perform an AND with a bit as an operand");
5143 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5144 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5145 if ((AOP_TYPE (right) == AOP_LIT) &&
5146 (AOP_TYPE (result) == AOP_CRY) &&
5147 (AOP_TYPE (left) != AOP_CRY))
5149 symbol *tlbl = newiTempLabel (NULL);
5150 int sizel = AOP_SIZE (left);
5153 /* PENDING: Test case for this. */
5158 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5160 _moveA (aopGet (AOP (left), offset, FALSE));
5161 if (bytelit != 0x0FFL)
5163 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5170 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5174 // bit = left & literal
5178 emit2 ("!tlabeldef", tlbl->key + 100);
5179 _G.lines.current->isLabel = 1;
5181 // if(left & literal)
5186 jmpTrueOrFalse (ifx, tlbl);
5194 /* if left is same as result */
5195 if (sameRegs (AOP (result), AOP (left)))
5197 for (; size--; offset++)
5199 if (AOP_TYPE (right) == AOP_LIT)
5201 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5206 aopPut (AOP (result), "!zero", offset);
5209 _moveA (aopGet (AOP (left), offset, FALSE));
5211 aopGet (AOP (right), offset, FALSE));
5212 aopPut (AOP (left), "a", offset);
5219 if (AOP_TYPE (left) == AOP_ACC)
5221 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5225 _moveA (aopGet (AOP (left), offset, FALSE));
5227 aopGet (AOP (right), offset, FALSE));
5228 aopPut (AOP (left), "a", offset);
5235 // left & result in different registers
5236 if (AOP_TYPE (result) == AOP_CRY)
5238 wassertl (0, "Tried to AND where the result is in carry");
5242 for (; (size--); offset++)
5245 // result = left & right
5246 if (AOP_TYPE (right) == AOP_LIT)
5248 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5250 aopPut (AOP (result),
5251 aopGet (AOP (left), offset, FALSE),
5255 else if (bytelit == 0)
5257 aopPut (AOP (result), "!zero", offset);
5261 // faster than result <- left, anl result,right
5262 // and better if result is SFR
5263 if (AOP_TYPE (left) == AOP_ACC)
5264 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5267 _moveA (aopGet (AOP (left), offset, FALSE));
5269 aopGet (AOP (right), offset, FALSE));
5271 aopPut (AOP (result), "a", offset);
5278 freeAsmop (left, NULL, ic);
5279 freeAsmop (right, NULL, ic);
5280 freeAsmop (result, NULL, ic);
5283 /*-----------------------------------------------------------------*/
5284 /* genOr - code for or */
5285 /*-----------------------------------------------------------------*/
5287 genOr (iCode * ic, iCode * ifx)
5289 operand *left, *right, *result;
5290 int size, offset = 0;
5291 unsigned long lit = 0L;
5294 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5295 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5296 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5298 /* if left is a literal & right is not then exchange them */
5299 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5300 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5302 operand *tmp = right;
5307 /* if result = right then exchange them */
5308 if (sameRegs (AOP (result), AOP (right)))
5310 operand *tmp = right;
5315 /* if right is bit then exchange them */
5316 if (AOP_TYPE (right) == AOP_CRY &&
5317 AOP_TYPE (left) != AOP_CRY)
5319 operand *tmp = right;
5323 if (AOP_TYPE (right) == AOP_LIT)
5324 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5326 size = AOP_SIZE (result);
5328 if (AOP_TYPE (left) == AOP_CRY)
5330 wassertl (0, "Tried to OR where left is a bit");
5334 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5335 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5336 if ((AOP_TYPE (right) == AOP_LIT) &&
5337 (AOP_TYPE (result) == AOP_CRY) &&
5338 (AOP_TYPE (left) != AOP_CRY))
5340 symbol *tlbl = newiTempLabel (NULL);
5341 int sizel = AOP_SIZE (left);
5345 wassertl (0, "Result is assigned to a bit");
5347 /* PENDING: Modeled after the AND code which is inefficient. */
5350 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5352 _moveA (aopGet (AOP (left), offset, FALSE));
5353 /* OR with any literal is the same as OR with itself. */
5355 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5361 jmpTrueOrFalse (ifx, tlbl);
5366 /* if left is same as result */
5367 if (sameRegs (AOP (result), AOP (left)))
5369 for (; size--; offset++)
5371 if (AOP_TYPE (right) == AOP_LIT)
5373 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5377 _moveA (aopGet (AOP (left), offset, FALSE));
5379 aopGet (AOP (right), offset, FALSE));
5380 aopPut (AOP (result), "a", offset);
5385 if (AOP_TYPE (left) == AOP_ACC)
5386 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5389 _moveA (aopGet (AOP (left), offset, FALSE));
5391 aopGet (AOP (right), offset, FALSE));
5392 aopPut (AOP (result), "a", offset);
5399 // left & result in different registers
5400 if (AOP_TYPE (result) == AOP_CRY)
5402 wassertl (0, "Result of OR is in a bit");
5405 for (; (size--); offset++)
5408 // result = left & right
5409 if (AOP_TYPE (right) == AOP_LIT)
5411 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5413 aopPut (AOP (result),
5414 aopGet (AOP (left), offset, FALSE),
5419 // faster than result <- left, anl result,right
5420 // and better if result is SFR
5421 if (AOP_TYPE (left) == AOP_ACC)
5422 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5425 _moveA (aopGet (AOP (left), offset, FALSE));
5427 aopGet (AOP (right), offset, FALSE));
5429 aopPut (AOP (result), "a", offset);
5430 /* PENDING: something weird is going on here. Add exception. */
5431 if (AOP_TYPE (result) == AOP_ACC)
5437 freeAsmop (left, NULL, ic);
5438 freeAsmop (right, NULL, ic);
5439 freeAsmop (result, NULL, ic);
5442 /*-----------------------------------------------------------------*/
5443 /* genXor - code for xclusive or */
5444 /*-----------------------------------------------------------------*/
5446 genXor (iCode * ic, iCode * ifx)
5448 operand *left, *right, *result;
5449 int size, offset = 0;
5450 unsigned long lit = 0L;
5452 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5453 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5454 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5456 /* if left is a literal & right is not then exchange them */
5457 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5458 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5460 operand *tmp = right;
5465 /* if result = right then exchange them */
5466 if (sameRegs (AOP (result), AOP (right)))
5468 operand *tmp = right;
5473 /* if right is bit then exchange them */
5474 if (AOP_TYPE (right) == AOP_CRY &&
5475 AOP_TYPE (left) != AOP_CRY)
5477 operand *tmp = right;
5481 if (AOP_TYPE (right) == AOP_LIT)
5482 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5484 size = AOP_SIZE (result);
5486 if (AOP_TYPE (left) == AOP_CRY)
5488 wassertl (0, "Tried to XOR a bit");
5492 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5493 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5494 if ((AOP_TYPE (right) == AOP_LIT) &&
5495 (AOP_TYPE (result) == AOP_CRY) &&
5496 (AOP_TYPE (left) != AOP_CRY))
5498 symbol *tlbl = newiTempLabel (NULL);
5499 int sizel = AOP_SIZE (left);
5503 /* PENDING: Test case for this. */
5504 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5508 _moveA (aopGet (AOP (left), offset, FALSE));
5509 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5510 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5515 jmpTrueOrFalse (ifx, tlbl);
5519 wassertl (0, "Result of XOR was destined for a bit");
5524 /* if left is same as result */
5525 if (sameRegs (AOP (result), AOP (left)))
5527 for (; size--; offset++)
5529 if (AOP_TYPE (right) == AOP_LIT)
5531 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5535 _moveA (aopGet (AOP (left), offset, FALSE));
5537 aopGet (AOP (right), offset, FALSE));
5538 aopPut (AOP (result), "a", offset);
5543 if (AOP_TYPE (left) == AOP_ACC)
5545 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5549 _moveA (aopGet (AOP (left), offset, FALSE));
5551 aopGet (AOP (right), offset, FALSE));
5552 aopPut (AOP (result), "a", offset);
5559 // left & result in different registers
5560 if (AOP_TYPE (result) == AOP_CRY)
5562 wassertl (0, "Result of XOR is in a bit");
5565 for (; (size--); offset++)
5568 // result = left & right
5569 if (AOP_TYPE (right) == AOP_LIT)
5571 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5573 aopPut (AOP (result),
5574 aopGet (AOP (left), offset, FALSE),
5579 // faster than result <- left, anl result,right
5580 // and better if result is SFR
5581 if (AOP_TYPE (left) == AOP_ACC)
5583 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5587 _moveA (aopGet (AOP (left), offset, FALSE));
5589 aopGet (AOP (right), offset, FALSE));
5591 aopPut (AOP (result), "a", offset);
5596 freeAsmop (left, NULL, ic);
5597 freeAsmop (right, NULL, ic);
5598 freeAsmop (result, NULL, ic);
5601 /*-----------------------------------------------------------------*/
5602 /* genInline - write the inline code out */
5603 /*-----------------------------------------------------------------*/
5605 genInline (iCode * ic)
5607 char *buffer, *bp, *bp1;
5609 _G.lines.isInline += (!options.asmpeep);
5611 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5612 strcpy (buffer, IC_INLINE (ic));
5614 /* emit each line as a code */
5639 _G.lines.isInline -= (!options.asmpeep);
5643 /*-----------------------------------------------------------------*/
5644 /* genRRC - rotate right with carry */
5645 /*-----------------------------------------------------------------*/
5652 /*-----------------------------------------------------------------*/
5653 /* genRLC - generate code for rotate left with carry */
5654 /*-----------------------------------------------------------------*/
5661 /*-----------------------------------------------------------------*/
5662 /* genGetHbit - generates code get highest order bit */
5663 /*-----------------------------------------------------------------*/
5665 genGetHbit (iCode * ic)
5667 operand *left, *result;
5668 left = IC_LEFT (ic);
5669 result = IC_RESULT (ic);
5671 aopOp (left, ic, FALSE, FALSE);
5672 aopOp (result, ic, FALSE, FALSE);
5674 /* get the highest order byte into a */
5675 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5677 if (AOP_TYPE (result) == AOP_CRY)
5685 emit2 ("and a,!one");
5690 freeAsmop (left, NULL, ic);
5691 freeAsmop (result, NULL, ic);
5695 emitRsh2 (asmop *aop, int size, int is_signed)
5701 const char *l = aopGet (aop, size, FALSE);
5704 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5714 /*-----------------------------------------------------------------*/
5715 /* shiftR2Left2Result - shift right two bytes from left to result */
5716 /*-----------------------------------------------------------------*/
5718 shiftR2Left2Result (operand * left, int offl,
5719 operand * result, int offr,
5720 int shCount, int is_signed)
5723 symbol *tlbl, *tlbl1;
5725 movLeft2Result (left, offl, result, offr, 0);
5726 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5731 /* if (AOP(result)->type == AOP_REG) { */
5733 tlbl = newiTempLabel (NULL);
5734 tlbl1 = newiTempLabel (NULL);
5736 /* Left is already in result - so now do the shift */
5741 emitRsh2 (AOP (result), size, is_signed);
5746 emit2 ("ld a,!immedbyte+1", shCount);
5747 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5748 emitLabel (tlbl->key + 100);
5750 emitRsh2 (AOP (result), size, is_signed);
5752 emitLabel (tlbl1->key + 100);
5754 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5758 /*-----------------------------------------------------------------*/
5759 /* shiftL2Left2Result - shift left two bytes from left to result */
5760 /*-----------------------------------------------------------------*/
5762 shiftL2Left2Result (operand * left, int offl,
5763 operand * result, int offr, int shCount)
5765 if (sameRegs (AOP (result), AOP (left)) &&
5766 ((offl + MSB16) == offr))
5772 /* Copy left into result */
5773 movLeft2Result (left, offl, result, offr, 0);
5774 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5780 if (getPairId (AOP (result)) == PAIR_HL)
5784 emit2 ("add hl,hl");
5791 symbol *tlbl, *tlbl1;
5794 tlbl = newiTempLabel (NULL);
5795 tlbl1 = newiTempLabel (NULL);
5797 if (AOP (result)->type == AOP_REG)
5801 for (offset = 0; offset < size; offset++)
5803 l = aopGet (AOP (result), offset, FALSE);
5807 emit2 ("sla %s", l);
5818 /* Left is already in result - so now do the shift */
5821 emit2 ("ld a,!immedbyte+1", shCount);
5822 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5823 emitLabel (tlbl->key + 100);
5828 l = aopGet (AOP (result), offset, FALSE);
5832 emit2 ("sla %s", l);
5843 emitLabel (tlbl1->key + 100);
5845 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5851 /*-----------------------------------------------------------------*/
5852 /* AccRol - rotate left accumulator by known count */
5853 /*-----------------------------------------------------------------*/
5855 AccRol (int shCount)
5857 shCount &= 0x0007; // shCount : 0..7
5934 /*-----------------------------------------------------------------*/
5935 /* AccLsh - left shift accumulator by known count */
5936 /*-----------------------------------------------------------------*/
5938 AccLsh (int shCount)
5940 static const unsigned char SLMask[] =
5942 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5951 else if (shCount == 2)
5958 /* rotate left accumulator */
5960 /* and kill the lower order bits */
5961 emit2 ("and a,!immedbyte", SLMask[shCount]);
5966 /*-----------------------------------------------------------------*/
5967 /* shiftL1Left2Result - shift left one byte from left to result */
5968 /*-----------------------------------------------------------------*/
5970 shiftL1Left2Result (operand * left, int offl,
5971 operand * result, int offr, int shCount)
5974 l = aopGet (AOP (left), offl, FALSE);
5976 /* shift left accumulator */
5978 aopPut (AOP (result), "a", offr);
5982 /*-----------------------------------------------------------------*/
5983 /* genlshTwo - left shift two bytes by known amount */
5984 /*-----------------------------------------------------------------*/
5986 genlshTwo (operand * result, operand * left, int shCount)
5988 int size = AOP_SIZE (result);
5990 wassert (size == 2);
5992 /* if shCount >= 8 */
6000 movLeft2Result (left, LSB, result, MSB16, 0);
6001 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6002 aopPut (AOP (result), "!zero", LSB);
6006 movLeft2Result (left, LSB, result, MSB16, 0);
6007 aopPut (AOP (result), "!zero", 0);
6012 aopPut (AOP (result), "!zero", LSB);
6015 /* 0 <= shCount <= 7 */
6024 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6029 /*-----------------------------------------------------------------*/
6030 /* genlshOne - left shift a one byte quantity by known count */
6031 /*-----------------------------------------------------------------*/
6033 genlshOne (operand * result, operand * left, int shCount)
6035 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6038 /*-----------------------------------------------------------------*/
6039 /* genLeftShiftLiteral - left shifting by known count */
6040 /*-----------------------------------------------------------------*/
6042 genLeftShiftLiteral (operand * left,
6047 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6050 freeAsmop (right, NULL, ic);
6052 aopOp (left, ic, FALSE, FALSE);
6053 aopOp (result, ic, FALSE, FALSE);
6055 size = getSize (operandType (result));
6057 /* I suppose that the left size >= result size */
6059 if (shCount >= (size * 8))
6063 aopPut (AOP (result), "!zero", size);
6071 genlshOne (result, left, shCount);
6074 genlshTwo (result, left, shCount);
6077 wassertl (0, "Shifting of longs is currently unsupported");
6083 freeAsmop (left, NULL, ic);
6084 freeAsmop (result, NULL, ic);
6087 /*-----------------------------------------------------------------*/
6088 /* genLeftShift - generates code for left shifting */
6089 /*-----------------------------------------------------------------*/
6091 genLeftShift (iCode * ic)
6095 symbol *tlbl, *tlbl1;
6096 operand *left, *right, *result;
6098 right = IC_RIGHT (ic);
6099 left = IC_LEFT (ic);
6100 result = IC_RESULT (ic);
6102 aopOp (right, ic, FALSE, FALSE);
6104 /* if the shift count is known then do it
6105 as efficiently as possible */
6106 if (AOP_TYPE (right) == AOP_LIT)
6108 genLeftShiftLiteral (left, right, result, ic);
6112 /* shift count is unknown then we have to form a loop get the loop
6113 count in B : Note: we take only the lower order byte since
6114 shifting more that 32 bits make no sense anyway, ( the largest
6115 size of an object can be only 32 bits ) */
6116 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6118 freeAsmop (right, NULL, ic);
6119 aopOp (left, ic, FALSE, FALSE);
6120 aopOp (result, ic, FALSE, FALSE);
6122 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6125 /* now move the left to the result if they are not the
6128 if (!sameRegs (AOP (left), AOP (result)))
6131 size = AOP_SIZE (result);
6135 l = aopGet (AOP (left), offset, FALSE);
6136 aopPut (AOP (result), l, offset);
6141 tlbl = newiTempLabel (NULL);
6142 size = AOP_SIZE (result);
6144 tlbl1 = newiTempLabel (NULL);
6146 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6149 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6150 emitLabel (tlbl->key + 100);
6151 l = aopGet (AOP (result), offset, FALSE);
6155 l = aopGet (AOP (result), offset, FALSE);
6159 emit2 ("sla %s", l);
6167 emitLabel (tlbl1->key + 100);
6169 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6171 freeAsmop (left, NULL, ic);
6172 freeAsmop (result, NULL, ic);
6175 /*-----------------------------------------------------------------*/
6176 /* genrshOne - left shift two bytes by known amount != 0 */
6177 /*-----------------------------------------------------------------*/
6179 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6182 int size = AOP_SIZE (result);
6185 wassert (size == 1);
6186 wassert (shCount < 8);
6188 l = aopGet (AOP (left), 0, FALSE);
6190 if (AOP (result)->type == AOP_REG)
6192 aopPut (AOP (result), l, 0);
6193 l = aopGet (AOP (result), 0, FALSE);
6196 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6204 emit2 ("%s a", is_signed ? "sra" : "srl");
6206 aopPut (AOP (result), "a", 0);
6210 /*-----------------------------------------------------------------*/
6211 /* AccRsh - right shift accumulator by known count */
6212 /*-----------------------------------------------------------------*/
6214 AccRsh (int shCount)
6216 static const unsigned char SRMask[] =
6218 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6223 /* rotate right accumulator */
6224 AccRol (8 - shCount);
6225 /* and kill the higher order bits */
6226 emit2 ("and a,!immedbyte", SRMask[shCount]);
6230 /*-----------------------------------------------------------------*/
6231 /* shiftR1Left2Result - shift right one byte from left to result */
6232 /*-----------------------------------------------------------------*/
6234 shiftR1Left2Result (operand * left, int offl,
6235 operand * result, int offr,
6236 int shCount, int sign)
6238 _moveA (aopGet (AOP (left), offl, FALSE));
6243 emit2 ("%s a", sign ? "sra" : "srl");
6250 aopPut (AOP (result), "a", offr);
6253 /*-----------------------------------------------------------------*/
6254 /* genrshTwo - right shift two bytes by known amount */
6255 /*-----------------------------------------------------------------*/
6257 genrshTwo (operand * result, operand * left,
6258 int shCount, int sign)
6260 /* if shCount >= 8 */
6266 shiftR1Left2Result (left, MSB16, result, LSB,
6271 movLeft2Result (left, MSB16, result, LSB, sign);
6275 /* Sign extend the result */
6276 _moveA(aopGet (AOP (result), 0, FALSE));
6280 aopPut (AOP (result), ACC_NAME, MSB16);
6284 aopPut (AOP (result), "!zero", 1);
6287 /* 0 <= shCount <= 7 */
6290 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6294 /*-----------------------------------------------------------------*/
6295 /* genRightShiftLiteral - left shifting by known count */
6296 /*-----------------------------------------------------------------*/
6298 genRightShiftLiteral (operand * left,
6304 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6307 freeAsmop (right, NULL, ic);
6309 aopOp (left, ic, FALSE, FALSE);
6310 aopOp (result, ic, FALSE, FALSE);
6312 size = getSize (operandType (result));
6314 /* I suppose that the left size >= result size */
6316 if (shCount >= (size * 8)) {
6318 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6319 _moveA(aopGet (AOP (left), 0, FALSE));
6327 aopPut (AOP (result), s, size);
6334 genrshOne (result, left, shCount, sign);
6337 genrshTwo (result, left, shCount, sign);
6340 wassertl (0, "Asked to shift right a long which should be a function call");
6343 wassertl (0, "Entered default case in right shift delegate");
6346 freeAsmop (left, NULL, ic);
6347 freeAsmop (result, NULL, ic);
6350 /*-----------------------------------------------------------------*/
6351 /* genRightShift - generate code for right shifting */
6352 /*-----------------------------------------------------------------*/
6354 genRightShift (iCode * ic)
6356 operand *right, *left, *result;
6358 int size, offset, first = 1;
6362 symbol *tlbl, *tlbl1;
6364 /* if signed then we do it the hard way preserve the
6365 sign bit moving it inwards */
6366 retype = getSpec (operandType (IC_RESULT (ic)));
6368 is_signed = !SPEC_USIGN (retype);
6370 /* signed & unsigned types are treated the same : i.e. the
6371 signed is NOT propagated inwards : quoting from the
6372 ANSI - standard : "for E1 >> E2, is equivalent to division
6373 by 2**E2 if unsigned or if it has a non-negative value,
6374 otherwise the result is implementation defined ", MY definition
6375 is that the sign does not get propagated */
6377 right = IC_RIGHT (ic);
6378 left = IC_LEFT (ic);
6379 result = IC_RESULT (ic);
6381 aopOp (right, ic, FALSE, FALSE);
6383 /* if the shift count is known then do it
6384 as efficiently as possible */
6385 if (AOP_TYPE (right) == AOP_LIT)
6387 genRightShiftLiteral (left, right, result, ic, is_signed);
6391 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6393 freeAsmop (right, NULL, ic);
6395 aopOp (left, ic, FALSE, FALSE);
6396 aopOp (result, ic, FALSE, FALSE);
6398 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6401 /* now move the left to the result if they are not the
6403 if (!sameRegs (AOP (left), AOP (result)))
6406 size = AOP_SIZE (result);
6410 l = aopGet (AOP (left), offset, FALSE);
6411 aopPut (AOP (result), l, offset);
6416 tlbl = newiTempLabel (NULL);
6417 tlbl1 = newiTempLabel (NULL);
6418 size = AOP_SIZE (result);
6421 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6424 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6425 emitLabel (tlbl->key + 100);
6428 l = aopGet (AOP (result), offset--, FALSE);
6431 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6439 emitLabel (tlbl1->key + 100);
6441 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6443 freeAsmop (left, NULL, ic);
6444 freeAsmop (result, NULL, ic);
6448 /*-----------------------------------------------------------------*/
6449 /* genUnpackBits - generates code for unpacking bits */
6450 /*-----------------------------------------------------------------*/
6452 genUnpackBits (operand * result, int pair)
6454 int offset = 0; /* result byte offset */
6455 int rsize; /* result size */
6456 int rlen = 0; /* remaining bitfield length */
6457 sym_link *etype; /* bitfield type information */
6458 int blen; /* bitfield length */
6459 int bstr; /* bitfield starting bit within byte */
6461 emitDebug ("; genUnpackBits");
6463 etype = getSpec (operandType (result));
6464 rsize = getSize (operandType (result));
6465 blen = SPEC_BLEN (etype);
6466 bstr = SPEC_BSTR (etype);
6468 /* If the bitfield length is less than a byte */
6471 emit2 ("ld a,!*pair", _pairs[pair].name);
6473 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6474 if (!SPEC_USIGN (etype))
6476 /* signed bitfield */
6477 symbol *tlbl = newiTempLabel (NULL);
6479 emit2 ("bit %d,a", blen - 1);
6480 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6481 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6482 emitLabel (tlbl->key + 100);
6484 aopPut (AOP (result), "a", offset++);
6488 /* TODO: what if pair == PAIR_DE ? */
6489 if (getPairId (AOP (result)) == PAIR_HL)
6491 wassertl (rsize == 2, "HL must be of size 2");
6492 emit2 ("ld a,!*hl");
6494 emit2 ("ld h,!*hl");
6497 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6498 if (!SPEC_USIGN (etype))
6500 /* signed bitfield */
6501 symbol *tlbl = newiTempLabel (NULL);
6503 emit2 ("bit %d,a", blen - 1);
6504 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6505 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6506 emitLabel (tlbl->key + 100);
6509 spillPair (PAIR_HL);
6513 /* Bit field did not fit in a byte. Copy all
6514 but the partial byte at the end. */
6515 for (rlen=blen;rlen>=8;rlen-=8)
6517 emit2 ("ld a,!*pair", _pairs[pair].name);
6518 aopPut (AOP (result), "a", offset++);
6521 emit2 ("inc %s", _pairs[pair].name);
6522 _G.pairs[pair].offset++;
6526 /* Handle the partial byte at the end */
6529 emit2 ("ld a,!*pair", _pairs[pair].name);
6530 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6531 if (!SPEC_USIGN (etype))
6533 /* signed bitfield */
6534 symbol *tlbl = newiTempLabel (NULL);
6536 emit2 ("bit %d,a", rlen - 1);
6537 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6538 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6539 emitLabel (tlbl->key + 100);
6541 aopPut (AOP (result), "a", offset++);
6549 if (SPEC_USIGN (etype))
6553 /* signed bitfield: sign extension with 0x00 or 0xff */
6561 aopPut (AOP (result), source, offset++);
6565 /*-----------------------------------------------------------------*/
6566 /* genGenPointerGet - get value from generic pointer space */
6567 /*-----------------------------------------------------------------*/
6569 genGenPointerGet (operand * left,
6570 operand * result, iCode * ic)
6573 sym_link *retype = getSpec (operandType (result));
6579 aopOp (left, ic, FALSE, FALSE);
6580 aopOp (result, ic, FALSE, FALSE);
6582 size = AOP_SIZE (result);
6584 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6587 if (isPtrPair (AOP (left)))
6589 tsprintf (buffer, sizeof(buffer),
6590 "!*pair", getPairName (AOP (left)));
6591 aopPut (AOP (result), buffer, 0);
6595 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6596 aopPut (AOP (result), "a", 0);
6598 freeAsmop (left, NULL, ic);
6602 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6609 tsprintf (at, sizeof(at), "!*iyx", offset);
6610 aopPut (AOP (result), at, offset);
6614 freeAsmop (left, NULL, ic);
6618 /* For now we always load into IY */
6619 /* if this is remateriazable */
6620 fetchPair (pair, AOP (left));
6622 /* if bit then unpack */
6623 if (IS_BITVAR (retype))
6625 genUnpackBits (result, pair);
6626 freeAsmop (left, NULL, ic);
6630 else if (getPairId (AOP (result)) == PAIR_HL)
6632 wassertl (size == 2, "HL must be of size 2");
6633 emit2 ("ld a,!*hl");
6635 emit2 ("ld h,!*hl");
6637 spillPair (PAIR_HL);
6639 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6641 size = AOP_SIZE (result);
6646 /* PENDING: make this better */
6647 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6649 aopPut (AOP (result), "!*hl", offset++);
6653 emit2 ("ld a,!*pair", _pairs[pair].name);
6654 aopPut (AOP (result), "a", offset++);
6658 emit2 ("inc %s", _pairs[pair].name);
6659 _G.pairs[pair].offset++;
6662 /* Fixup HL back down */
6663 for (size = AOP_SIZE (result)-1; size; size--)
6665 emit2 ("dec %s", _pairs[pair].name);
6670 size = AOP_SIZE (result);
6675 /* PENDING: make this better */
6677 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6679 aopPut (AOP (result), "!*hl", offset++);
6683 emit2 ("ld a,!*pair", _pairs[pair].name);
6684 aopPut (AOP (result), "a", offset++);
6688 emit2 ("inc %s", _pairs[pair].name);
6689 _G.pairs[pair].offset++;
6694 freeAsmop (left, NULL, ic);
6697 freeAsmop (result, NULL, ic);
6700 /*-----------------------------------------------------------------*/
6701 /* genPointerGet - generate code for pointer get */
6702 /*-----------------------------------------------------------------*/
6704 genPointerGet (iCode * ic)
6706 operand *left, *result;
6707 sym_link *type, *etype;
6709 left = IC_LEFT (ic);
6710 result = IC_RESULT (ic);
6712 /* depending on the type of pointer we need to
6713 move it to the correct pointer register */
6714 type = operandType (left);
6715 etype = getSpec (type);
6717 genGenPointerGet (left, result, ic);
6721 isRegOrLit (asmop * aop)
6723 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6729 /*-----------------------------------------------------------------*/
6730 /* genPackBits - generates code for packed bit storage */
6731 /*-----------------------------------------------------------------*/
6733 genPackBits (sym_link * etype,
6738 int offset = 0; /* source byte offset */
6739 int rlen = 0; /* remaining bitfield length */
6740 int blen; /* bitfield length */
6741 int bstr; /* bitfield starting bit within byte */
6742 int litval; /* source literal value (if AOP_LIT) */
6743 unsigned char mask; /* bitmask within current byte */
6744 int extraPair; /* a tempory register */
6745 bool needPopExtra=0; /* need to restore original value of temp reg */
6747 emitDebug ("; genPackBits","");
6749 blen = SPEC_BLEN (etype);
6750 bstr = SPEC_BSTR (etype);
6752 /* If the bitfield length is less than a byte */
6755 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6756 (unsigned char) (0xFF >> (8 - bstr)));
6758 if (AOP_TYPE (right) == AOP_LIT)
6760 /* Case with a bitfield length <8 and literal source
6762 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6764 litval &= (~mask) & 0xff;
6765 emit2 ("ld a,!*pair", _pairs[pair].name);
6766 if ((mask|litval)!=0xff)
6767 emit2 ("and a,!immedbyte", mask);
6769 emit2 ("or a,!immedbyte", litval);
6770 emit2 ("ld !*pair,a", _pairs[pair].name);
6775 /* Case with a bitfield length <8 and arbitrary source
6777 _moveA (aopGet (AOP (right), 0, FALSE));
6778 /* shift and mask source value */
6780 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6782 extraPair = getFreePairId(ic);
6783 if (extraPair == PAIR_INVALID)
6785 extraPair = PAIR_BC;
6786 if (getPairId (AOP (right)) != PAIR_BC
6787 || !isLastUse (ic, right))
6793 emit2 ("ld %s,a", _pairs[extraPair].l);
6794 emit2 ("ld a,!*pair", _pairs[pair].name);
6796 emit2 ("and a,!immedbyte", mask);
6797 emit2 ("or a,%s", _pairs[extraPair].l);
6798 emit2 ("ld !*pair,a", _pairs[pair].name);
6805 /* Bit length is greater than 7 bits. In this case, copy */
6806 /* all except the partial byte at the end */
6807 for (rlen=blen;rlen>=8;rlen-=8)
6809 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6810 emit2 ("ld !*pair,a", _pairs[pair].name);
6813 emit2 ("inc %s", _pairs[pair].name);
6814 _G.pairs[pair].offset++;
6818 /* If there was a partial byte at the end */
6821 mask = (((unsigned char) -1 << rlen) & 0xff);
6823 if (AOP_TYPE (right) == AOP_LIT)
6825 /* Case with partial byte and literal source
6827 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6828 litval >>= (blen-rlen);
6829 litval &= (~mask) & 0xff;
6830 emit2 ("ld a,!*pair", _pairs[pair].name);
6831 if ((mask|litval)!=0xff)
6832 emit2 ("and a,!immedbyte", mask);
6834 emit2 ("or a,!immedbyte", litval);
6838 /* Case with partial byte and arbitrary source
6840 _moveA (aopGet (AOP (right), offset++, FALSE));
6841 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6843 extraPair = getFreePairId(ic);
6844 if (extraPair == PAIR_INVALID)
6846 extraPair = getPairId (AOP (right));
6847 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6848 extraPair = PAIR_BC;
6850 if (getPairId (AOP (right)) != PAIR_BC
6851 || !isLastUse (ic, right))
6857 emit2 ("ld %s,a", _pairs[extraPair].l);
6858 emit2 ("ld a,!*pair", _pairs[pair].name);
6860 emit2 ("and a,!immedbyte", mask);
6861 emit2 ("or a,%s", _pairs[extraPair].l);
6866 emit2 ("ld !*pair,a", _pairs[pair].name);
6871 /*-----------------------------------------------------------------*/
6872 /* genGenPointerSet - stores the value into a pointer location */
6873 /*-----------------------------------------------------------------*/
6875 genGenPointerSet (operand * right,
6876 operand * result, iCode * ic)
6879 sym_link *retype = getSpec (operandType (right));
6880 sym_link *letype = getSpec (operandType (result));
6881 PAIR_ID pairId = PAIR_HL;
6884 aopOp (result, ic, FALSE, FALSE);
6885 aopOp (right, ic, FALSE, FALSE);
6890 size = AOP_SIZE (right);
6892 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6893 emitDebug("; isBitvar = %d", isBitvar);
6895 /* Handle the exceptions first */
6896 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6899 const char *l = aopGet (AOP (right), 0, FALSE);
6900 const char *pair = getPairName (AOP (result));
6901 if (canAssignToPtr (l) && isPtr (pair))
6903 emit2 ("ld !*pair,%s", pair, l);
6908 emit2 ("ld !*pair,a", pair);
6913 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6916 const char *l = aopGet (AOP (right), 0, FALSE);
6921 if (canAssignToPtr (l))
6923 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6927 _moveA (aopGet (AOP (right), offset, FALSE));
6928 emit2 ("ld !*iyx,a", offset);
6934 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6941 const char *l = aopGet (AOP (right), offset, FALSE);
6942 if (isRegOrLit (AOP (right)) && !IS_GB)
6944 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6949 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6953 emit2 ("inc %s", _pairs[PAIR_HL].name);
6954 _G.pairs[PAIR_HL].offset++;
6959 /* Fixup HL back down */
6960 for (size = AOP_SIZE (right)-1; size; size--)
6962 emit2 ("dec %s", _pairs[PAIR_HL].name);
6967 /* if the operand is already in dptr
6968 then we do nothing else we move the value to dptr */
6969 if (AOP_TYPE (result) != AOP_STR)
6971 fetchPair (pairId, AOP (result));
6973 /* so hl now contains the address */
6974 freeAsmop (result, NULL, ic);
6976 /* if bit then unpack */
6979 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6989 const char *l = aopGet (AOP (right), offset, FALSE);
6990 if (isRegOrLit (AOP (right)) && !IS_GB)
6992 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6997 emit2 ("ld !*pair,a", _pairs[pairId].name);
7001 emit2 ("inc %s", _pairs[pairId].name);
7002 _G.pairs[pairId].offset++;
7008 freeAsmop (right, NULL, ic);
7011 /*-----------------------------------------------------------------*/
7012 /* genPointerSet - stores the value into a pointer location */
7013 /*-----------------------------------------------------------------*/
7015 genPointerSet (iCode * ic)
7017 operand *right, *result;
7018 sym_link *type, *etype;
7020 right = IC_RIGHT (ic);
7021 result = IC_RESULT (ic);
7023 /* depending on the type of pointer we need to
7024 move it to the correct pointer register */
7025 type = operandType (result);
7026 etype = getSpec (type);
7028 genGenPointerSet (right, result, ic);
7031 /*-----------------------------------------------------------------*/
7032 /* genIfx - generate code for Ifx statement */
7033 /*-----------------------------------------------------------------*/
7035 genIfx (iCode * ic, iCode * popIc)
7037 operand *cond = IC_COND (ic);
7040 aopOp (cond, ic, FALSE, TRUE);
7042 /* get the value into acc */
7043 if (AOP_TYPE (cond) != AOP_CRY)
7047 /* the result is now in the accumulator */
7048 freeAsmop (cond, NULL, ic);
7050 /* if there was something to be popped then do it */
7054 /* if the condition is a bit variable */
7055 if (isbit && IS_ITEMP (cond) &&
7057 genIfxJump (ic, SPIL_LOC (cond)->rname);
7058 else if (isbit && !IS_ITEMP (cond))
7059 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7061 genIfxJump (ic, "a");
7066 /*-----------------------------------------------------------------*/
7067 /* genAddrOf - generates code for address of */
7068 /*-----------------------------------------------------------------*/
7070 genAddrOf (iCode * ic)
7072 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7074 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7076 /* if the operand is on the stack then we
7077 need to get the stack offset of this
7084 if (sym->stack <= 0)
7086 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7090 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7092 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7096 emit2 ("ld de,!hashedstr", sym->rname);
7097 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7105 /* if it has an offset then we need to compute it */
7107 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7109 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7110 emit2 ("add hl,sp");
7114 emit2 ("ld hl,!hashedstr", sym->rname);
7116 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7118 freeAsmop (IC_RESULT (ic), NULL, ic);
7121 /*-----------------------------------------------------------------*/
7122 /* genAssign - generate code for assignment */
7123 /*-----------------------------------------------------------------*/
7125 genAssign (iCode * ic)
7127 operand *result, *right;
7129 unsigned long lit = 0L;
7131 result = IC_RESULT (ic);
7132 right = IC_RIGHT (ic);
7134 /* Dont bother assigning if they are the same */
7135 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7137 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7141 aopOp (right, ic, FALSE, FALSE);
7142 aopOp (result, ic, TRUE, FALSE);
7144 /* if they are the same registers */
7145 if (sameRegs (AOP (right), AOP (result)))
7147 emitDebug ("; (registers are the same)");
7151 /* if the result is a bit */
7152 if (AOP_TYPE (result) == AOP_CRY)
7154 wassertl (0, "Tried to assign to a bit");
7158 size = AOP_SIZE (result);
7161 if (AOP_TYPE (right) == AOP_LIT)
7163 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7166 if (isPair (AOP (result)))
7168 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7170 else if ((size > 1) &&
7171 (AOP_TYPE (result) != AOP_REG) &&
7172 (AOP_TYPE (right) == AOP_LIT) &&
7173 !IS_FLOAT (operandType (right)) &&
7176 bool fXored = FALSE;
7178 /* Work from the top down.
7179 Done this way so that we can use the cached copy of 0
7180 in A for a fast clear */
7183 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7185 if (!fXored && size > 1)
7192 aopPut (AOP (result), "a", offset);
7196 aopPut (AOP (result), "!zero", offset);
7200 aopPut (AOP (result),
7201 aopGet (AOP (right), offset, FALSE),
7206 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7208 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7209 aopPut (AOP (result), "l", LSB);
7210 aopPut (AOP (result), "h", MSB16);
7212 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7214 /* Special case. Load into a and d, then load out. */
7215 _moveA (aopGet (AOP (right), 0, FALSE));
7216 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7217 aopPut (AOP (result), "a", 0);
7218 aopPut (AOP (result), "e", 1);
7220 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7222 /* Special case - simple memcpy */
7223 aopGet (AOP (right), LSB, FALSE);
7226 aopGet (AOP (result), LSB, FALSE);
7230 emit2 ("ld a,(de)");
7231 /* Peephole will optimise this. */
7232 emit2 ("ld (hl),a");
7240 spillPair (PAIR_HL);
7246 /* PENDING: do this check better */
7247 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7249 _moveA (aopGet (AOP (right), offset, FALSE));
7250 aopPut (AOP (result), "a", offset);
7253 aopPut (AOP (result),
7254 aopGet (AOP (right), offset, FALSE),
7261 freeAsmop (right, NULL, ic);
7262 freeAsmop (result, NULL, ic);
7265 /*-----------------------------------------------------------------*/
7266 /* genJumpTab - genrates code for jump table */
7267 /*-----------------------------------------------------------------*/
7269 genJumpTab (iCode * ic)
7274 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7275 /* get the condition into accumulator */
7276 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7279 emit2 ("ld e,%s", l);
7280 emit2 ("ld d,!zero");
7281 jtab = newiTempLabel (NULL);
7283 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7284 emit2 ("add hl,de");
7285 emit2 ("add hl,de");
7286 emit2 ("add hl,de");
7287 freeAsmop (IC_JTCOND (ic), NULL, ic);
7291 emitLabel (jtab->key + 100);
7292 /* now generate the jump labels */
7293 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7294 jtab = setNextItem (IC_JTLABELS (ic)))
7295 emit2 ("jp !tlabel", jtab->key + 100);
7298 /*-----------------------------------------------------------------*/
7299 /* genCast - gen code for casting */
7300 /*-----------------------------------------------------------------*/
7302 genCast (iCode * ic)
7304 operand *result = IC_RESULT (ic);
7305 sym_link *rtype = operandType (IC_RIGHT (ic));
7306 operand *right = IC_RIGHT (ic);
7309 /* if they are equivalent then do nothing */
7310 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7313 aopOp (right, ic, FALSE, FALSE);
7314 aopOp (result, ic, FALSE, FALSE);
7316 /* if the result is a bit */
7317 if (AOP_TYPE (result) == AOP_CRY)
7319 wassertl (0, "Tried to cast to a bit");
7322 /* if they are the same size : or less */
7323 if (AOP_SIZE (result) <= AOP_SIZE (right))
7326 /* if they are in the same place */
7327 if (sameRegs (AOP (right), AOP (result)))
7330 /* if they in different places then copy */
7331 size = AOP_SIZE (result);
7335 aopPut (AOP (result),
7336 aopGet (AOP (right), offset, FALSE),
7343 /* So we now know that the size of destination is greater
7344 than the size of the source */
7345 /* we move to result for the size of source */
7346 size = AOP_SIZE (right);
7350 aopPut (AOP (result),
7351 aopGet (AOP (right), offset, FALSE),
7356 /* now depending on the sign of the destination */
7357 size = AOP_SIZE (result) - AOP_SIZE (right);
7358 /* Unsigned or not an integral type - right fill with zeros */
7359 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7362 aopPut (AOP (result), "!zero", offset++);
7366 /* we need to extend the sign :{ */
7367 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7373 aopPut (AOP (result), "a", offset++);
7377 freeAsmop (right, NULL, ic);
7378 freeAsmop (result, NULL, ic);
7381 /*-----------------------------------------------------------------*/
7382 /* genReceive - generate code for a receive iCode */
7383 /*-----------------------------------------------------------------*/
7385 genReceive (iCode * ic)
7387 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7388 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7389 IS_TRUE_SYMOP (IC_RESULT (ic))))
7399 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7400 size = AOP_SIZE(IC_RESULT(ic));
7402 for (i = 0; i < size; i++) {
7403 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7407 freeAsmop (IC_RESULT (ic), NULL, ic);
7410 /*-----------------------------------------------------------------*/
7411 /* genDummyRead - generate code for dummy read of volatiles */
7412 /*-----------------------------------------------------------------*/
7414 genDummyRead (iCode * ic)
7420 if (op && IS_SYMOP (op))
7422 aopOp (op, ic, FALSE, FALSE);
7425 size = AOP_SIZE (op);
7430 _moveA (aopGet (AOP (op), offset, FALSE));
7434 freeAsmop (op, NULL, ic);
7438 if (op && IS_SYMOP (op))
7440 aopOp (op, ic, FALSE, FALSE);
7443 size = AOP_SIZE (op);
7448 _moveA (aopGet (AOP (op), offset, FALSE));
7452 freeAsmop (op, NULL, ic);
7456 /*-----------------------------------------------------------------*/
7457 /* genCritical - generate code for start of a critical sequence */
7458 /*-----------------------------------------------------------------*/
7460 genCritical (iCode *ic)
7462 symbol *tlbl = newiTempLabel (NULL);
7468 else if (IC_RESULT (ic))
7470 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7471 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7472 //get interrupt enable flag IFF2 into P/O
7476 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7477 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7478 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7479 emit2 ("!tlabeldef", (tlbl->key + 100));
7480 _G.lines.current->isLabel = 1;
7481 freeAsmop (IC_RESULT (ic), NULL, ic);
7485 //get interrupt enable flag IFF2 into P/O
7494 /*-----------------------------------------------------------------*/
7495 /* genEndCritical - generate code for end of a critical sequence */
7496 /*-----------------------------------------------------------------*/
7498 genEndCritical (iCode *ic)
7500 symbol *tlbl = newiTempLabel (NULL);
7506 else if (IC_RIGHT (ic))
7508 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7509 _toBoolean (IC_RIGHT (ic));
7510 //don't enable interrupts if they were off before
7511 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7513 emitLabel (tlbl->key + 100);
7514 freeAsmop (IC_RIGHT (ic), NULL, ic);
7520 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7521 //don't enable interrupts as they were off before
7522 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7524 emit2 ("!tlabeldef", (tlbl->key + 100));
7525 _G.lines.current->isLabel = 1;
7531 /** Maximum number of bytes to emit per line. */
7535 /** Context for the byte output chunker. */
7538 unsigned char buffer[DBEMIT_MAX_RUN];
7543 /** Flushes a byte chunker by writing out all in the buffer and
7547 _dbFlush(DBEMITCTX *self)
7554 sprintf(line, ".db 0x%02X", self->buffer[0]);
7556 for (i = 1; i < self->pos; i++)
7558 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7565 /** Write out another byte, buffering until a decent line is
7569 _dbEmit(DBEMITCTX *self, int c)
7571 if (self->pos == DBEMIT_MAX_RUN)
7575 self->buffer[self->pos++] = c;
7578 /** Context for a simple run length encoder. */
7582 unsigned char buffer[128];
7584 /** runLen may be equivalent to pos. */
7590 RLE_CHANGE_COST = 4,
7594 /** Flush the buffer of a run length encoder by writing out the run or
7595 data that it currently contains.
7598 _rleCommit(RLECTX *self)
7604 memset(&db, 0, sizeof(db));
7606 emit2(".db %u", self->pos);
7608 for (i = 0; i < self->pos; i++)
7610 _dbEmit(&db, self->buffer[i]);
7619 Can get either a run or a block of random stuff.
7620 Only want to change state if a good run comes in or a run ends.
7621 Detecting run end is easy.
7624 Say initial state is in run, len zero, last zero. Then if you get a
7625 few zeros then something else then a short run will be output.
7626 Seems OK. While in run mode, keep counting. While in random mode,
7627 keep a count of the run. If run hits margin, output all up to run,
7628 restart, enter run mode.
7631 /** Add another byte into the run length encoder, flushing as
7632 required. The run length encoder uses the Amiga IFF style, where
7633 a block is prefixed by its run length. A positive length means
7634 the next n bytes pass straight through. A negative length means
7635 that the next byte is repeated -n times. A zero terminates the
7639 _rleAppend(RLECTX *self, unsigned c)
7643 if (c != self->last)
7645 /* The run has stopped. See if it is worthwhile writing it out
7646 as a run. Note that the random data comes in as runs of
7649 if (self->runLen > RLE_CHANGE_COST)
7651 /* Yes, worthwhile. */
7652 /* Commit whatever was in the buffer. */
7654 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7658 /* Not worthwhile. Append to the end of the random list. */
7659 for (i = 0; i < self->runLen; i++)
7661 if (self->pos >= RLE_MAX_BLOCK)
7666 self->buffer[self->pos++] = self->last;
7674 if (self->runLen >= RLE_MAX_BLOCK)
7676 /* Commit whatever was in the buffer. */
7679 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7687 _rleFlush(RLECTX *self)
7689 _rleAppend(self, -1);
7696 /** genArrayInit - Special code for initialising an array with constant
7700 genArrayInit (iCode * ic)
7704 int elementSize = 0, eIndex, i;
7705 unsigned val, lastVal;
7709 memset(&rle, 0, sizeof(rle));
7711 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7713 _saveRegsForCall(ic, 0);
7715 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7716 emit2 ("call __initrleblock");
7718 type = operandType(IC_LEFT(ic));
7720 if (type && type->next)
7722 if (IS_SPEC(type->next) || IS_PTR(type->next))
7724 elementSize = getSize(type->next);
7726 else if (IS_ARRAY(type->next) && type->next->next)
7728 elementSize = getSize(type->next->next);
7732 printTypeChainRaw (type, NULL);
7733 wassertl (0, "Can't determine element size in genArrayInit.");
7738 wassertl (0, "Can't determine element size in genArrayInit.");
7741 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7743 iLoop = IC_ARRAYILIST(ic);
7744 lastVal = (unsigned)-1;
7746 /* Feed all the bytes into the run length encoder which will handle
7748 This works well for mixed char data, and for random int and long
7755 for (i = 0; i < ix; i++)
7757 for (eIndex = 0; eIndex < elementSize; eIndex++)
7759 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7760 _rleAppend(&rle, val);
7764 iLoop = iLoop->next;
7768 /* Mark the end of the run. */
7771 _restoreRegsAfterCall();
7775 freeAsmop (IC_LEFT(ic), NULL, ic);
7779 _swap (PAIR_ID one, PAIR_ID two)
7781 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7787 emit2 ("ld a,%s", _pairs[one].l);
7788 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7789 emit2 ("ld %s,a", _pairs[two].l);
7790 emit2 ("ld a,%s", _pairs[one].h);
7791 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7792 emit2 ("ld %s,a", _pairs[two].h);
7796 /* The problem is that we may have all three pairs used and they may
7797 be needed in a different order.
7802 hl = hl => unity, fine
7806 hl = hl hl = hl, swap de <=> bc
7814 hl = bc de = de, swap bc <=> hl
7822 hl = de bc = bc, swap hl <=> de
7827 * Any pair = pair are done last
7828 * Any pair = iTemp are done last
7829 * Any swaps can be done any time
7837 So how do we detect the cases?
7838 How about a 3x3 matrix?
7842 x x x x (Fourth for iTemp/other)
7844 First determin which mode to use by counting the number of unity and
7847 Two - Assign the pair first, then the rest
7848 One - Swap the two, then the rest
7852 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7854 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7856 PAIR_BC, PAIR_HL, PAIR_DE
7858 int i, j, nunity = 0;
7859 memset (ids, PAIR_INVALID, sizeof (ids));
7862 wassert (nparams == 3);
7864 /* First save everything that needs to be saved. */
7865 _saveRegsForCall (ic, 0);
7867 /* Loading HL first means that DE is always fine. */
7868 for (i = 0; i < nparams; i++)
7870 aopOp (pparams[i], ic, FALSE, FALSE);
7871 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7874 /* Count the number of unity or iTemp assigns. */
7875 for (i = 0; i < 3; i++)
7877 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7885 /* Any order, fall through. */
7887 else if (nunity == 2)
7889 /* One is assigned. Pull it out and assign. */
7890 for (i = 0; i < 3; i++)
7892 for (j = 0; j < NUM_PAIRS; j++)
7894 if (ids[dest[i]][j] == TRUE)
7896 /* Found it. See if it's the right one. */
7897 if (j == PAIR_INVALID || j == dest[i])
7903 fetchPair(dest[i], AOP (pparams[i]));
7910 else if (nunity == 1)
7912 /* Find the pairs to swap. */
7913 for (i = 0; i < 3; i++)
7915 for (j = 0; j < NUM_PAIRS; j++)
7917 if (ids[dest[i]][j] == TRUE)
7919 if (j == PAIR_INVALID || j == dest[i])
7934 int next = getPairId (AOP (pparams[0]));
7935 emit2 ("push %s", _pairs[next].name);
7937 if (next == dest[1])
7939 fetchPair (dest[1], AOP (pparams[1]));
7940 fetchPair (dest[2], AOP (pparams[2]));
7944 fetchPair (dest[2], AOP (pparams[2]));
7945 fetchPair (dest[1], AOP (pparams[1]));
7947 emit2 ("pop %s", _pairs[dest[0]].name);
7950 /* Finally pull out all of the iTemps */
7951 for (i = 0; i < 3; i++)
7953 if (ids[dest[i]][PAIR_INVALID] == 1)
7955 fetchPair (dest[i], AOP (pparams[i]));
7961 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7967 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7971 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7973 setupForBuiltin3 (ic, nParams, pparams);
7975 label = newiTempLabel(NULL);
7977 emitLabel (label->key);
7978 emit2 ("ld a,(hl)");
7981 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
7983 freeAsmop (from, NULL, ic->next);
7984 freeAsmop (to, NULL, ic);
7988 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7990 operand *from, *to, *count;
7993 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7998 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8000 setupForBuiltin3 (ic, nParams, pparams);
8004 freeAsmop (count, NULL, ic->next->next);
8005 freeAsmop (from, NULL, ic);
8007 _restoreRegsAfterCall();
8009 /* if we need assign a result value */
8010 if ((IS_ITEMP (IC_RESULT (ic)) &&
8011 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8012 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8013 IS_TRUE_SYMOP (IC_RESULT (ic)))
8015 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8016 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8017 freeAsmop (IC_RESULT (ic), NULL, ic);
8020 freeAsmop (to, NULL, ic->next);
8023 /*-----------------------------------------------------------------*/
8024 /* genBuiltIn - calls the appropriate function to generating code */
8025 /* for a built in function */
8026 /*-----------------------------------------------------------------*/
8027 static void genBuiltIn (iCode *ic)
8029 operand *bi_parms[MAX_BUILTIN_ARGS];
8034 /* get all the arguments for a built in function */
8035 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8037 /* which function is it */
8038 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8040 if (strcmp(bif->name,"__builtin_strcpy")==0)
8042 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8044 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8046 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8050 wassertl (0, "Unknown builtin function encountered");
8054 /*-----------------------------------------------------------------*/
8055 /* genZ80Code - generate code for Z80 based controllers */
8056 /*-----------------------------------------------------------------*/
8058 genZ80Code (iCode * lic)
8066 _fReturn = _gbz80_return;
8067 _fTmp = _gbz80_return;
8071 _fReturn = _z80_return;
8072 _fTmp = _z80_return;
8075 _G.lines.head = _G.lines.current = NULL;
8077 /* if debug information required */
8078 if (options.debug && currFunc)
8080 debugFile->writeFunction (currFunc, lic);
8083 for (ic = lic; ic; ic = ic->next)
8085 _G.current_iCode = ic;
8087 if (ic->lineno && cln != ic->lineno)
8091 debugFile->writeCLine (ic);
8093 if (!options.noCcodeInAsm)
8095 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8096 printCLine(ic->filename, ic->lineno));
8100 if (options.iCodeInAsm)
8102 emit2 (";ic:%d: %s", ic->key, printILine(ic));
8104 /* if the result is marked as
8105 spilt and rematerializable or code for
8106 this has already been generated then
8108 if (resultRemat (ic) || ic->generated)
8111 /* depending on the operation */
8115 emitDebug ("; genNot");
8120 emitDebug ("; genCpl");
8125 emitDebug ("; genUminus");
8130 emitDebug ("; genIpush");
8135 /* IPOP happens only when trying to restore a
8136 spilt live range, if there is an ifx statement
8137 following this pop then the if statement might
8138 be using some of the registers being popped which
8139 would destory the contents of the register so
8140 we need to check for this condition and handle it */
8142 ic->next->op == IFX &&
8143 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8145 emitDebug ("; genIfx");
8146 genIfx (ic->next, ic);
8150 emitDebug ("; genIpop");
8156 emitDebug ("; genCall");
8161 emitDebug ("; genPcall");
8166 emitDebug ("; genFunction");
8171 emitDebug ("; genEndFunction");
8172 genEndFunction (ic);
8176 emitDebug ("; genRet");
8181 emitDebug ("; genLabel");
8186 emitDebug ("; genGoto");
8191 emitDebug ("; genPlus");
8196 emitDebug ("; genMinus");
8201 emitDebug ("; genMult");
8206 emitDebug ("; genDiv");
8211 emitDebug ("; genMod");
8216 emitDebug ("; genCmpGt");
8217 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8221 emitDebug ("; genCmpLt");
8222 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8229 /* note these two are xlated by algebraic equivalence
8230 during parsing SDCC.y */
8231 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8232 "got '>=' or '<=' shouldn't have come here");
8236 emitDebug ("; genCmpEq");
8237 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8241 emitDebug ("; genAndOp");
8246 emitDebug ("; genOrOp");
8251 emitDebug ("; genXor");
8252 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8256 emitDebug ("; genOr");
8257 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8261 emitDebug ("; genAnd");
8262 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8266 emitDebug ("; genInline");
8271 emitDebug ("; genRRC");
8276 emitDebug ("; genRLC");
8281 emitDebug ("; genGetHBIT");
8286 emitDebug ("; genLeftShift");
8291 emitDebug ("; genRightShift");
8295 case GET_VALUE_AT_ADDRESS:
8296 emitDebug ("; genPointerGet");
8302 if (POINTER_SET (ic))
8304 emitDebug ("; genAssign (pointer)");
8309 emitDebug ("; genAssign");
8315 emitDebug ("; genIfx");
8320 emitDebug ("; genAddrOf");
8325 emitDebug ("; genJumpTab");
8330 emitDebug ("; genCast");
8335 emitDebug ("; genReceive");
8340 if (ic->builtinSEND)
8342 emitDebug ("; genBuiltIn");
8347 emitDebug ("; addSet");
8348 addSet (&_G.sendSet, ic);
8353 emitDebug ("; genArrayInit");
8357 case DUMMY_READ_VOLATILE:
8358 emitDebug ("; genDummyRead");
8363 emitDebug ("; genCritical");
8368 emitDebug ("; genEndCritical");
8369 genEndCritical (ic);
8378 /* now we are ready to call the
8379 peep hole optimizer */
8380 if (!options.nopeep)
8381 peepHole (&_G.lines.head);
8383 /* This is unfortunate */
8384 /* now do the actual printing */
8386 FILE *fp = codeOutFile;
8387 if (isInHome () && codeOutFile == code->oFile)
8388 codeOutFile = home->oFile;
8389 printLine (_G.lines.head, codeOutFile);
8390 if (_G.flushStatics)
8393 _G.flushStatics = 0;
8398 freeTrace(&_G.lines.trace);
8399 freeTrace(&_G.trace.aops);
8405 _isPairUsed (iCode * ic, PAIR_ID pairId)
8411 if (bitVectBitValue (ic->rMask, D_IDX))
8413 if (bitVectBitValue (ic->rMask, E_IDX))
8423 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8426 value *val = aop->aopu.aop_lit;
8428 wassert (aop->type == AOP_LIT);
8429 wassert (!IS_FLOAT (val->type));
8431 v = (unsigned long) floatFromVal (val);
8439 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8440 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));