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);
2518 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2519 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2522 _emitMove ("a", _fReturn[size-1]);
2523 _emitMove (_fReturn[size-1], _fReturn[size]);
2524 _emitMove (_fReturn[size], "a");
2525 aopPut (AOP (oper), _fReturn[size], size-1);
2530 aopPut (AOP (oper), _fReturn[size], size);
2535 /** Simple restore that doesn't take into account what is used in the
2539 _restoreRegsAfterCall(void)
2541 if (_G.stack.pushedDE)
2544 _G.stack.pushedDE = FALSE;
2546 if (_G.stack.pushedBC)
2549 _G.stack.pushedBC = FALSE;
2551 _G.saves.saved = FALSE;
2555 _saveRegsForCall(iCode *ic, int sendSetSize)
2558 o Stack parameters are pushed before this function enters
2559 o DE and BC may be used in this function.
2560 o HL and DE may be used to return the result.
2561 o HL and DE may be used to send variables.
2562 o DE and BC may be used to store the result value.
2563 o HL may be used in computing the sent value of DE
2564 o The iPushes for other parameters occur before any addSets
2566 Logic: (to be run inside the first iPush or if none, before sending)
2567 o Compute if DE and/or BC are in use over the call
2568 o Compute if DE is used in the send set
2569 o Compute if DE and/or BC are used to hold the result value
2570 o If (DE is used, or in the send set) and is not used in the result, push.
2571 o If BC is used and is not in the result, push
2573 o If DE is used in the send set, fetch
2574 o If HL is used in the send set, fetch
2578 if (_G.saves.saved == FALSE) {
2579 bool deInUse, bcInUse;
2581 bool bcInRet = FALSE, deInRet = FALSE;
2584 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2585 z80_rUmaskForOp (IC_RESULT(ic)));
2587 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2588 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2590 deSending = (sendSetSize > 1);
2592 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2594 if (bcInUse && bcInRet == FALSE) {
2596 _G.stack.pushedBC = TRUE;
2598 if (deInUse && deInRet == FALSE) {
2600 _G.stack.pushedDE = TRUE;
2603 _G.saves.saved = TRUE;
2606 /* Already saved. */
2610 /*-----------------------------------------------------------------*/
2611 /* genIpush - genrate code for pushing this gets a little complex */
2612 /*-----------------------------------------------------------------*/
2614 genIpush (iCode * ic)
2616 int size, offset = 0;
2619 /* if this is not a parm push : ie. it is spill push
2620 and spill push is always done on the local stack */
2623 wassertl(0, "Encountered an unsupported spill push.");
2627 if (_G.saves.saved == FALSE) {
2628 /* Caller saves, and this is the first iPush. */
2629 /* Scan ahead until we find the function that we are pushing parameters to.
2630 Count the number of addSets on the way to figure out what registers
2631 are used in the send set.
2634 iCode *walk = ic->next;
2637 if (walk->op == SEND) {
2640 else if (walk->op == CALL || walk->op == PCALL) {
2649 _saveRegsForCall(walk, nAddSets);
2652 /* Already saved by another iPush. */
2655 /* then do the push */
2656 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2658 size = AOP_SIZE (IC_LEFT (ic));
2660 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2662 _G.stack.pushed += 2;
2663 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2669 fetchHL (AOP (IC_LEFT (ic)));
2671 spillPair (PAIR_HL);
2672 _G.stack.pushed += 2;
2677 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2679 spillPair (PAIR_HL);
2680 _G.stack.pushed += 2;
2681 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2683 spillPair (PAIR_HL);
2684 _G.stack.pushed += 2;
2690 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2692 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2694 emit2 ("ld a,(%s)", l);
2698 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2699 emit2 ("ld a,%s", l);
2707 freeAsmop (IC_LEFT (ic), NULL, ic);
2710 /*-----------------------------------------------------------------*/
2711 /* genIpop - recover the registers: can happen only for spilling */
2712 /*-----------------------------------------------------------------*/
2714 genIpop (iCode * ic)
2719 /* if the temp was not pushed then */
2720 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2723 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2724 size = AOP_SIZE (IC_LEFT (ic));
2725 offset = (size - 1);
2726 if (isPair (AOP (IC_LEFT (ic))))
2728 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2736 spillPair (PAIR_HL);
2737 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2741 freeAsmop (IC_LEFT (ic), NULL, ic);
2744 /* This is quite unfortunate */
2746 setArea (int inHome)
2749 static int lastArea = 0;
2751 if (_G.in_home != inHome) {
2753 const char *sz = port->mem.code_name;
2754 port->mem.code_name = "HOME";
2755 emit2("!area", CODE_NAME);
2756 port->mem.code_name = sz;
2759 emit2("!area", CODE_NAME); */
2760 _G.in_home = inHome;
2771 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2775 symbol *sym = OP_SYMBOL (op);
2777 if (sym->isspilt || sym->nRegs == 0)
2780 aopOp (op, ic, FALSE, FALSE);
2783 if (aop->type == AOP_REG)
2786 for (i = 0; i < aop->size; i++)
2788 if (pairId == PAIR_DE)
2790 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2791 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2793 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2796 else if (pairId == PAIR_BC)
2798 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2799 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2801 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2811 freeAsmop (IC_LEFT (ic), NULL, ic);
2815 /** Emit the code for a call statement
2818 emitCall (iCode * ic, bool ispcall)
2820 bool bInRet, cInRet, dInRet, eInRet;
2821 sym_link *dtype = operandType (IC_LEFT (ic));
2823 /* if caller saves & we have not saved then */
2829 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2831 /* if send set is not empty then assign */
2836 int nSend = elementsInSet(_G.sendSet);
2837 bool swapped = FALSE;
2839 int _z80_sendOrder[] = {
2844 /* Check if the parameters are swapped. If so route through hl instead. */
2845 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2847 sic = setFirstItem(_G.sendSet);
2848 sic = setNextItem(_G.sendSet);
2850 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2851 /* The second send value is loaded from one the one that holds the first
2852 send, i.e. it is overwritten. */
2853 /* Cache the first in HL, and load the second from HL instead. */
2854 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2855 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2861 for (sic = setFirstItem (_G.sendSet); sic;
2862 sic = setNextItem (_G.sendSet))
2865 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2867 size = AOP_SIZE (IC_LEFT (sic));
2868 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2869 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2871 // PENDING: Mild hack
2872 if (swapped == TRUE && send == 1) {
2874 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2877 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2879 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2882 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2886 freeAsmop (IC_LEFT (sic), NULL, sic);
2893 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2895 werror (W_INDIR_BANKED);
2897 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2899 if (isLitWord (AOP (IC_LEFT (ic))))
2901 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2905 symbol *rlbl = newiTempLabel (NULL);
2906 spillPair (PAIR_HL);
2907 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2909 _G.stack.pushed += 2;
2911 fetchHL (AOP (IC_LEFT (ic)));
2913 emit2 ("!tlabeldef", (rlbl->key + 100));
2914 _G.lines.current->isLabel = 1;
2915 _G.stack.pushed -= 2;
2917 freeAsmop (IC_LEFT (ic), NULL, ic);
2921 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2922 OP_SYMBOL (IC_LEFT (ic))->rname :
2923 OP_SYMBOL (IC_LEFT (ic))->name;
2924 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2926 emit2 ("call banked_call");
2927 emit2 ("!dws", name);
2928 emit2 ("!dw !bankimmeds", name);
2933 emit2 ("call %s", name);
2938 /* Mark the registers as restored. */
2939 _G.saves.saved = FALSE;
2941 /* if we need assign a result value */
2942 if ((IS_ITEMP (IC_RESULT (ic)) &&
2943 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2944 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2945 IS_TRUE_SYMOP (IC_RESULT (ic)))
2948 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2950 assignResultValue (IC_RESULT (ic));
2952 freeAsmop (IC_RESULT (ic), NULL, ic);
2955 /* adjust the stack for parameters if required */
2958 int i = ic->parmBytes;
2960 _G.stack.pushed -= i;
2963 emit2 ("!ldaspsp", i);
2970 emit2 ("ld iy,!immedword", i);
2971 emit2 ("add iy,sp");
2992 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2993 bInRet = bitVectBitValue(result, B_IDX);
2994 cInRet = bitVectBitValue(result, C_IDX);
2995 dInRet = bitVectBitValue(result, D_IDX);
2996 eInRet = bitVectBitValue(result, E_IDX);
3006 if (_G.stack.pushedDE)
3008 if (dInRet && eInRet)
3010 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3014 /* Only restore E */
3021 /* Only restore D */
3029 _G.stack.pushedDE = FALSE;
3032 if (_G.stack.pushedBC)
3034 if (bInRet && cInRet)
3036 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3040 /* Only restore C */
3047 /* Only restore B */
3055 _G.stack.pushedBC = FALSE;
3059 /*-----------------------------------------------------------------*/
3060 /* genCall - generates a call statement */
3061 /*-----------------------------------------------------------------*/
3063 genCall (iCode * ic)
3065 emitCall (ic, FALSE);
3068 /*-----------------------------------------------------------------*/
3069 /* genPcall - generates a call by pointer statement */
3070 /*-----------------------------------------------------------------*/
3072 genPcall (iCode * ic)
3074 emitCall (ic, TRUE);
3077 /*-----------------------------------------------------------------*/
3078 /* resultRemat - result is rematerializable */
3079 /*-----------------------------------------------------------------*/
3081 resultRemat (iCode * ic)
3083 if (SKIP_IC (ic) || ic->op == IFX)
3086 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3088 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3089 if (sym->remat && !POINTER_SET (ic))
3096 extern set *publics;
3098 /*-----------------------------------------------------------------*/
3099 /* genFunction - generated code for function entry */
3100 /*-----------------------------------------------------------------*/
3102 genFunction (iCode * ic)
3106 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3109 bool bcInUse = FALSE;
3110 bool deInUse = FALSE;
3112 setArea (IFFUNC_NONBANKED (sym->type));
3114 /* PENDING: Reset the receive offset as it
3115 doesn't seem to get reset anywhere else.
3117 _G.receiveOffset = 0;
3119 /* Record the last function name for debugging. */
3120 _G.lastFunctionName = sym->rname;
3122 /* Create the function header */
3123 emit2 ("!functionheader", sym->name);
3124 if (!IS_STATIC(sym->etype))
3126 sprintf (buffer, "%s_start", sym->rname);
3127 emit2 ("!labeldef", buffer);
3128 _G.lines.current->isLabel = 1;
3130 emit2 ("!functionlabeldef", sym->rname);
3131 _G.lines.current->isLabel = 1;
3133 ftype = operandType (IC_LEFT (ic));
3135 if (IFFUNC_ISNAKED(ftype))
3137 emitDebug("; naked function: no prologue.");
3141 /* if this is an interrupt service routine
3142 then save all potentially used registers. */
3143 if (IFFUNC_ISISR (sym->type))
3145 /* If critical function then turn interrupts off */
3146 /* except when no interrupt number is given then it implies the NMI handler */
3147 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3156 /* This is a non-ISR function.
3157 If critical function then turn interrupts off */
3158 if (IFFUNC_ISCRITICAL (sym->type))
3166 //get interrupt enable flag IFF2 into P/O
3175 if (options.profile)
3177 emit2 ("!profileenter");
3180 /* PENDING: callee-save etc */
3182 _G.stack.param_offset = 0;
3184 if (z80_opts.calleeSavesBC)
3189 /* Detect which registers are used. */
3190 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3193 for (i = 0; i < sym->regsUsed->size; i++)
3195 if (bitVectBitValue (sym->regsUsed, i))
3209 /* Other systems use DE as a temporary. */
3220 _G.stack.param_offset += 2;
3223 _G.calleeSaves.pushedBC = bcInUse;
3228 _G.stack.param_offset += 2;
3231 _G.calleeSaves.pushedDE = deInUse;
3233 /* adjust the stack for the function */
3234 _G.stack.last = sym->stack;
3237 for (sym = setFirstItem (istack->syms); sym;
3238 sym = setNextItem (istack->syms))
3240 if (sym->_isparm && !IS_REGPARM (sym->etype))
3246 sym = OP_SYMBOL (IC_LEFT (ic));
3248 _G.omitFramePtr = options.ommitFramePtr;
3249 if (IS_Z80 && !stackParm && !sym->stack)
3251 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3252 /* the above !sym->stack condition can be removed. -- EEP */
3254 emit2 ("!ldaspsp", -sym->stack);
3255 _G.omitFramePtr = TRUE;
3257 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3258 emit2 ("!enterxl", sym->stack);
3259 else if (sym->stack)
3260 emit2 ("!enterx", sym->stack);
3264 _G.stack.offset = sym->stack;
3267 /*-----------------------------------------------------------------*/
3268 /* genEndFunction - generates epilogue for functions */
3269 /*-----------------------------------------------------------------*/
3271 genEndFunction (iCode * ic)
3273 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3275 if (IFFUNC_ISNAKED(sym->type))
3277 emitDebug("; naked function: no epilogue.");
3281 /* PENDING: calleeSave */
3282 if (IS_Z80 && _G.omitFramePtr)
3284 if (_G.stack.offset)
3285 emit2 ("!ldaspsp", _G.stack.offset);
3287 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3289 emit2 ("!leavexl", _G.stack.offset);
3291 else if (_G.stack.offset)
3293 emit2 ("!leavex", _G.stack.offset);
3300 if (_G.calleeSaves.pushedDE)
3303 _G.calleeSaves.pushedDE = FALSE;
3306 if (_G.calleeSaves.pushedBC)
3309 _G.calleeSaves.pushedBC = FALSE;
3312 if (options.profile)
3314 emit2 ("!profileexit");
3317 /* if this is an interrupt service routine
3318 then save all potentially used registers. */
3319 if (IFFUNC_ISISR (sym->type))
3323 /* If critical function then turn interrupts back on */
3324 /* except when no interrupt number is given then it implies the NMI handler */
3325 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3332 /* This is a non-ISR function.
3333 If critical function then turn interrupts back on */
3334 if (IFFUNC_ISCRITICAL (sym->type))
3342 symbol *tlbl = newiTempLabel (NULL);
3345 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3346 //don't enable interrupts as they were off before
3347 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3349 emit2 ("!tlabeldef", (tlbl->key + 100));
3350 _G.lines.current->isLabel = 1;
3355 if (options.debug && currFunc)
3357 debugFile->writeEndFunction (currFunc, ic, 1);
3360 if (IFFUNC_ISISR (sym->type))
3362 /* "critical interrupt" is used to imply NMI handler */
3363 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3370 /* Both banked and non-banked just ret */
3374 if (!IS_STATIC(sym->etype))
3376 sprintf (buffer, "%s_end", sym->rname);
3377 emit2 ("!labeldef", buffer);
3378 _G.lines.current->isLabel = 1;
3381 _G.flushStatics = 1;
3382 _G.stack.pushed = 0;
3383 _G.stack.offset = 0;
3386 /*-----------------------------------------------------------------*/
3387 /* genRet - generate code for return statement */
3388 /*-----------------------------------------------------------------*/
3393 /* Errk. This is a hack until I can figure out how
3394 to cause dehl to spill on a call */
3395 int size, offset = 0;
3397 /* if we have no return value then
3398 just generate the "ret" */
3402 /* we have something to return then
3403 move the return value into place */
3404 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3405 size = AOP_SIZE (IC_LEFT (ic));
3407 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3410 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3414 emit2 ("ld de,%s", l);
3418 emit2 ("ld hl,%s", l);
3424 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3428 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3430 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3431 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3437 l = aopGet (AOP (IC_LEFT (ic)), offset,
3439 if (strcmp (_fReturn[offset], l))
3440 emit2 ("ld %s,%s", _fReturn[offset], l);
3445 freeAsmop (IC_LEFT (ic), NULL, ic);
3448 /* generate a jump to the return label
3449 if the next is not the return statement */
3450 if (!(ic->next && ic->next->op == LABEL &&
3451 IC_LABEL (ic->next) == returnLabel))
3453 emit2 ("jp !tlabel", returnLabel->key + 100);
3456 /*-----------------------------------------------------------------*/
3457 /* genLabel - generates a label */
3458 /*-----------------------------------------------------------------*/
3460 genLabel (iCode * ic)
3462 /* special case never generate */
3463 if (IC_LABEL (ic) == entryLabel)
3466 emitLabel (IC_LABEL (ic)->key + 100);
3469 /*-----------------------------------------------------------------*/
3470 /* genGoto - generates a ljmp */
3471 /*-----------------------------------------------------------------*/
3473 genGoto (iCode * ic)
3475 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3478 /*-----------------------------------------------------------------*/
3479 /* genPlusIncr :- does addition with increment if possible */
3480 /*-----------------------------------------------------------------*/
3482 genPlusIncr (iCode * ic)
3484 unsigned int icount;
3485 unsigned int size = getDataSize (IC_RESULT (ic));
3486 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3488 /* will try to generate an increment */
3489 /* if the right side is not a literal
3491 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3494 emitDebug ("; genPlusIncr");
3496 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3498 /* If result is a pair */
3499 if (resultId != PAIR_INVALID)
3501 if (isLitWord (AOP (IC_LEFT (ic))))
3503 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3506 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3508 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3510 PAIR_ID freep = getFreePairId (ic);
3511 if (freep != PAIR_INVALID)
3513 fetchPair (freep, AOP (IC_RIGHT (ic)));
3514 emit2 ("add hl,%s", _pairs[freep].name);
3520 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3521 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3528 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3532 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3536 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3541 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3543 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3544 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3548 /* if the literal value of the right hand side
3549 is greater than 4 then it is not worth it */
3553 /* if increment 16 bits in register */
3554 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3560 symbol *tlbl = NULL;
3561 tlbl = newiTempLabel (NULL);
3564 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3567 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3570 emitLabel (tlbl->key + 100);
3574 /* if the sizes are greater than 1 then we cannot */
3575 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3576 AOP_SIZE (IC_LEFT (ic)) > 1)
3579 /* If the result is in a register then we can load then increment.
3581 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3583 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3586 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3591 /* we can if the aops of the left & result match or
3592 if they are in registers and the registers are the
3594 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3598 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3606 /*-----------------------------------------------------------------*/
3607 /* outBitAcc - output a bit in acc */
3608 /*-----------------------------------------------------------------*/
3610 outBitAcc (operand * result)
3612 symbol *tlbl = newiTempLabel (NULL);
3613 /* if the result is a bit */
3614 if (AOP_TYPE (result) == AOP_CRY)
3616 wassertl (0, "Tried to write A into a bit");
3620 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3621 emit2 ("ld a,!one");
3622 emitLabel (tlbl->key + 100);
3628 couldDestroyCarry (asmop *aop)
3632 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3641 shiftIntoPair (int idx, asmop *aop)
3643 PAIR_ID id = PAIR_INVALID;
3645 wassertl (IS_Z80, "Only implemented for the Z80");
3646 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3648 emitDebug ("; Shift into pair idx %u", idx);
3654 setupPair (PAIR_HL, aop, 0);
3659 setupPair (PAIR_IY, aop, 0);
3661 emit2 ("pop %s", _pairs[id].name);
3665 setupPair (PAIR_IY, aop, 0);
3668 wassertl (0, "Internal error - hit default case");
3671 aop->type = AOP_PAIRPTR;
3672 aop->aopu.aop_pairId = id;
3673 _G.pairs[id].offset = 0;
3674 _G.pairs[id].last_type = aop->type;
3678 setupToPreserveCarry (iCode * ic)
3680 asmop *left = AOP (IC_LEFT (ic));
3681 asmop *right = AOP (IC_RIGHT (ic));
3682 asmop *result = AOP (IC_RESULT (ic));
3684 wassert (left && right);
3688 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3690 shiftIntoPair (0, right);
3691 /* check result again, in case right == result */
3692 if (couldDestroyCarry (result))
3694 if (!isPairInUse (PAIR_DE, ic))
3695 shiftIntoPair (1, result);
3697 shiftIntoPair (2, result);
3700 else if (couldDestroyCarry (right))
3702 if (getPairId (result) == PAIR_HL)
3703 _G.preserveCarry = TRUE;
3705 shiftIntoPair (0, right);
3707 else if (couldDestroyCarry (result))
3709 shiftIntoPair (0, result);
3718 /*-----------------------------------------------------------------*/
3719 /* genPlus - generates code for addition */
3720 /*-----------------------------------------------------------------*/
3722 genPlus (iCode * ic)
3724 int size, offset = 0;
3726 /* special cases :- */
3728 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3729 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3730 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3732 /* Swap the left and right operands if:
3734 if literal, literal on the right or
3735 if left requires ACC or right is already
3738 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3739 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3740 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3742 operand *t = IC_RIGHT (ic);
3743 IC_RIGHT (ic) = IC_LEFT (ic);
3747 /* if both left & right are in bit
3749 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3750 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3753 wassertl (0, "Tried to add two bits");
3756 /* if left in bit space & right literal */
3757 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3758 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3760 /* Can happen I guess */
3761 wassertl (0, "Tried to add a bit to a literal");
3764 /* if I can do an increment instead
3765 of add then GOOD for ME */
3766 if (genPlusIncr (ic) == TRUE)
3769 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3771 size = getDataSize (IC_RESULT (ic));
3773 /* Special case when left and right are constant */
3774 if (isPair (AOP (IC_RESULT (ic))))
3777 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3778 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3780 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3786 sprintf (buffer, "#(%s + %s)", left, right);
3787 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3792 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3794 /* Fetch into HL then do the add */
3795 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3796 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3798 spillPair (PAIR_HL);
3800 if (left == PAIR_HL && right != PAIR_INVALID)
3802 emit2 ("add hl,%s", _pairs[right].name);
3805 else if (right == PAIR_HL && left != PAIR_INVALID)
3807 emit2 ("add hl,%s", _pairs[left].name);
3810 else if (right != PAIR_INVALID && right != PAIR_HL)
3812 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3813 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3816 else if (left != PAIR_INVALID && left != PAIR_HL)
3818 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3819 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3828 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3830 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3831 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3833 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3838 ld hl,sp+n trashes C so we can't afford to do it during an
3839 add with stack based variables. Worst case is:
3852 So you can't afford to load up hl if either left, right, or result
3853 is on the stack (*sigh*) The alt is:
3861 Combinations in here are:
3862 * If left or right are in bc then the loss is small - trap later
3863 * If the result is in bc then the loss is also small
3867 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3868 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3869 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3871 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3872 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3873 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3874 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3876 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3878 /* Swap left and right */
3879 operand *t = IC_RIGHT (ic);
3880 IC_RIGHT (ic) = IC_LEFT (ic);
3883 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3885 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3886 emit2 ("add hl,bc");
3890 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3891 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3892 emit2 ("add hl,de");
3894 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3900 /* Be paranoid on the GB with 4 byte variables due to how C
3901 can be trashed by lda hl,n(sp).
3903 _gbz80_emitAddSubLong (ic, TRUE);
3908 setupToPreserveCarry (ic);
3912 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
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));
3924 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3927 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3930 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3932 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3936 _G.preserveCarry = FALSE;
3937 freeAsmop (IC_LEFT (ic), NULL, ic);
3938 freeAsmop (IC_RIGHT (ic), NULL, ic);
3939 freeAsmop (IC_RESULT (ic), NULL, ic);
3942 /*-----------------------------------------------------------------*/
3943 /* genMinusDec :- does subtraction with deccrement if possible */
3944 /*-----------------------------------------------------------------*/
3946 genMinusDec (iCode * ic)
3948 unsigned int icount;
3949 unsigned int size = getDataSize (IC_RESULT (ic));
3951 /* will try to generate an increment */
3952 /* if the right side is not a literal we cannot */
3953 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3956 /* if the literal value of the right hand side
3957 is greater than 4 then it is not worth it */
3958 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3961 size = getDataSize (IC_RESULT (ic));
3963 /* if decrement 16 bits in register */
3964 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3965 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3968 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3972 /* If result is a pair */
3973 if (isPair (AOP (IC_RESULT (ic))))
3975 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3977 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3981 /* if increment 16 bits in register */
3982 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3986 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3989 emit2 ("dec %s", _getTempPairName());
3992 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3998 /* if the sizes are greater than 1 then we cannot */
3999 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4000 AOP_SIZE (IC_LEFT (ic)) > 1)
4003 /* we can if the aops of the left & result match or if they are in
4004 registers and the registers are the same */
4005 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4008 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4015 /*-----------------------------------------------------------------*/
4016 /* genMinus - generates code for subtraction */
4017 /*-----------------------------------------------------------------*/
4019 genMinus (iCode * ic)
4021 int size, offset = 0;
4022 unsigned long lit = 0L;
4024 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4025 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4026 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4028 /* special cases :- */
4029 /* if both left & right are in bit space */
4030 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4031 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4033 wassertl (0, "Tried to subtract two bits");
4037 /* if I can do an decrement instead of subtract then GOOD for ME */
4038 if (genMinusDec (ic) == TRUE)
4041 size = getDataSize (IC_RESULT (ic));
4043 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4048 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4052 /* Same logic as genPlus */
4055 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4056 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4057 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4059 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4060 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4061 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4062 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4064 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4065 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4067 if (left == PAIR_INVALID && right == PAIR_INVALID)
4072 else if (right == PAIR_INVALID)
4074 else if (left == PAIR_INVALID)
4077 fetchPair (left, AOP (IC_LEFT (ic)));
4078 /* Order is important. Right may be HL */
4079 fetchPair (right, AOP (IC_RIGHT (ic)));
4081 emit2 ("ld a,%s", _pairs[left].l);
4082 emit2 ("sub a,%s", _pairs[right].l);
4084 emit2 ("ld a,%s", _pairs[left].h);
4085 emit2 ("sbc a,%s", _pairs[right].h);
4087 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4089 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4091 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4097 /* Be paranoid on the GB with 4 byte variables due to how C
4098 can be trashed by lda hl,n(sp).
4100 _gbz80_emitAddSubLong (ic, FALSE);
4105 setupToPreserveCarry (ic);
4107 /* if literal, add a,#-lit, else normal subb */
4110 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4111 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4115 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4118 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4122 /* first add without previous c */
4124 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4126 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4128 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4131 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4132 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4133 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4135 wassertl (0, "Tried to subtract on a long pointer");
4139 _G.preserveCarry = FALSE;
4140 freeAsmop (IC_LEFT (ic), NULL, ic);
4141 freeAsmop (IC_RIGHT (ic), NULL, ic);
4142 freeAsmop (IC_RESULT (ic), NULL, ic);
4145 /*-----------------------------------------------------------------*/
4146 /* genMult - generates code for multiplication */
4147 /*-----------------------------------------------------------------*/
4149 genMult (iCode * ic)
4153 /* If true then the final operation should be a subtract */
4154 bool active = FALSE;
4157 /* Shouldn't occur - all done through function calls */
4158 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4159 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4160 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4162 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4164 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4165 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4166 AOP_SIZE (IC_RESULT (ic)) > 2)
4168 wassertl (0, "Multiplication is handled through support function calls");
4171 /* Swap left and right such that right is a literal */
4172 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4174 operand *t = IC_RIGHT (ic);
4175 IC_RIGHT (ic) = IC_LEFT (ic);
4179 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4181 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4182 // wassertl (val > 0, "Multiply must be positive");
4183 wassertl (val != 1, "Can't multiply by 1");
4185 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4187 _G.stack.pushedDE = TRUE;
4190 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4192 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4203 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4208 /* Fully unroled version of mul.s. Not the most efficient.
4210 for (count = 0; count < 16; count++)
4212 if (count != 0 && active)
4214 emit2 ("add hl,hl");
4218 if (active == FALSE)
4226 emit2 ("add hl,de");
4235 if (IS_Z80 && _G.stack.pushedDE)
4238 _G.stack.pushedDE = FALSE;
4242 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4244 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4246 freeAsmop (IC_LEFT (ic), NULL, ic);
4247 freeAsmop (IC_RIGHT (ic), NULL, ic);
4248 freeAsmop (IC_RESULT (ic), NULL, ic);
4251 /*-----------------------------------------------------------------*/
4252 /* genDiv - generates code for division */
4253 /*-----------------------------------------------------------------*/
4257 /* Shouldn't occur - all done through function calls */
4258 wassertl (0, "Division is handled through support function calls");
4261 /*-----------------------------------------------------------------*/
4262 /* genMod - generates code for division */
4263 /*-----------------------------------------------------------------*/
4267 /* Shouldn't occur - all done through function calls */
4271 /*-----------------------------------------------------------------*/
4272 /* genIfxJump :- will create a jump depending on the ifx */
4273 /*-----------------------------------------------------------------*/
4275 genIfxJump (iCode * ic, char *jval)
4280 /* if true label then we jump if condition
4284 jlbl = IC_TRUE (ic);
4285 if (!strcmp (jval, "a"))
4289 else if (!strcmp (jval, "c"))
4293 else if (!strcmp (jval, "nc"))
4297 else if (!strcmp (jval, "m"))
4301 else if (!strcmp (jval, "p"))
4307 /* The buffer contains the bit on A that we should test */
4313 /* false label is present */
4314 jlbl = IC_FALSE (ic);
4315 if (!strcmp (jval, "a"))
4319 else if (!strcmp (jval, "c"))
4323 else if (!strcmp (jval, "nc"))
4327 else if (!strcmp (jval, "m"))
4331 else if (!strcmp (jval, "p"))
4337 /* The buffer contains the bit on A that we should test */
4341 /* Z80 can do a conditional long jump */
4342 if (!strcmp (jval, "a"))
4346 else if (!strcmp (jval, "c"))
4349 else if (!strcmp (jval, "nc"))
4352 else if (!strcmp (jval, "m"))
4355 else if (!strcmp (jval, "p"))
4360 emit2 ("bit %s,a", jval);
4362 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4364 /* mark the icode as generated */
4370 _getPairIdName (PAIR_ID id)
4372 return _pairs[id].name;
4377 /* if unsigned char cmp with lit, just compare */
4379 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4381 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4384 emit2 ("xor a,!immedbyte", 0x80);
4385 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4388 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4390 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4392 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4393 // Pull left into DE and right into HL
4394 aopGet (AOP(left), LSB, FALSE);
4397 aopGet (AOP(right), LSB, FALSE);
4401 if (size == 0 && sign)
4403 // Highest byte when signed needs the bits flipped
4406 emit2 ("ld a,(de)");
4407 emit2 ("xor !immedbyte", 0x80);
4409 emit2 ("ld a,(hl)");
4410 emit2 ("xor !immedbyte", 0x80);
4414 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4418 emit2 ("ld a,(de)");
4419 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4429 spillPair (PAIR_HL);
4431 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4433 setupPair (PAIR_HL, AOP (left), 0);
4434 aopGet (AOP(right), LSB, FALSE);
4438 if (size == 0 && sign)
4440 // Highest byte when signed needs the bits flipped
4443 emit2 ("ld a,(hl)");
4444 emit2 ("xor !immedbyte", 0x80);
4446 emit2 ("ld a,%d(iy)", offset);
4447 emit2 ("xor !immedbyte", 0x80);
4451 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4455 emit2 ("ld a,(hl)");
4456 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4465 spillPair (PAIR_HL);
4466 spillPair (PAIR_IY);
4470 if (AOP_TYPE (right) == AOP_LIT)
4472 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4473 /* optimize if(x < 0) or if(x >= 0) */
4478 /* No sign so it's always false */
4483 /* Just load in the top most bit */
4484 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4485 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4487 genIfxJump (ifx, "7");
4499 /* First setup h and l contaning the top most bytes XORed */
4500 bool fDidXor = FALSE;
4501 if (AOP_TYPE (left) == AOP_LIT)
4503 unsigned long lit = (unsigned long)
4504 floatFromVal (AOP (left)->aopu.aop_lit);
4505 emit2 ("ld %s,!immedbyte", _fTmp[0],
4506 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4510 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4511 emit2 ("xor a,!immedbyte", 0x80);
4512 emit2 ("ld %s,a", _fTmp[0]);
4515 if (AOP_TYPE (right) == AOP_LIT)
4517 unsigned long lit = (unsigned long)
4518 floatFromVal (AOP (right)->aopu.aop_lit);
4519 emit2 ("ld %s,!immedbyte", _fTmp[1],
4520 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4524 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4525 emit2 ("xor a,!immedbyte", 0x80);
4526 emit2 ("ld %s,a", _fTmp[1]);
4532 /* Do a long subtract */
4535 _moveA (aopGet (AOP (left), offset, FALSE));
4537 if (sign && size == 0)
4539 emit2 ("ld a,%s", _fTmp[0]);
4540 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4544 /* Subtract through, propagating the carry */
4545 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4553 /** Generic compare for > or <
4556 genCmp (operand * left, operand * right,
4557 operand * result, iCode * ifx, int sign)
4559 int size, offset = 0;
4560 unsigned long lit = 0L;
4561 bool swap_sense = FALSE;
4563 /* if left & right are bit variables */
4564 if (AOP_TYPE (left) == AOP_CRY &&
4565 AOP_TYPE (right) == AOP_CRY)
4567 /* Cant happen on the Z80 */
4568 wassertl (0, "Tried to compare two bits");
4572 /* Do a long subtract of right from left. */
4573 size = max (AOP_SIZE (left), AOP_SIZE (right));
4575 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4577 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4578 // Pull left into DE and right into HL
4579 aopGet (AOP(left), LSB, FALSE);
4582 aopGet (AOP(right), LSB, FALSE);
4586 emit2 ("ld a,(de)");
4587 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4596 spillPair (PAIR_HL);
4600 if (AOP_TYPE (right) == AOP_LIT)
4602 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4603 /* optimize if(x < 0) or if(x >= 0) */
4608 /* No sign so it's always false */
4613 /* Just load in the top most bit */
4614 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4615 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4617 genIfxJump (ifx, "7");
4628 genIfxJump (ifx, swap_sense ? "c" : "nc");
4639 _moveA (aopGet (AOP (left), offset, FALSE));
4640 /* Subtract through, propagating the carry */
4641 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4647 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4651 /* Shift the sign bit up into carry */
4654 outBitCLong (result, swap_sense);
4658 /* if the result is used in the next
4659 ifx conditional branch then generate
4660 code a little differently */
4668 genIfxJump (ifx, swap_sense ? "nc" : "c");
4672 genIfxJump (ifx, swap_sense ? "p" : "m");
4677 genIfxJump (ifx, swap_sense ? "nc" : "c");
4684 /* Shift the sign bit up into carry */
4687 outBitCLong (result, swap_sense);
4689 /* leave the result in acc */
4693 /*-----------------------------------------------------------------*/
4694 /* genCmpGt :- greater than comparison */
4695 /*-----------------------------------------------------------------*/
4697 genCmpGt (iCode * ic, iCode * ifx)
4699 operand *left, *right, *result;
4700 sym_link *letype, *retype;
4703 left = IC_LEFT (ic);
4704 right = IC_RIGHT (ic);
4705 result = IC_RESULT (ic);
4707 letype = getSpec (operandType (left));
4708 retype = getSpec (operandType (right));
4709 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4710 /* assign the amsops */
4711 aopOp (left, ic, FALSE, FALSE);
4712 aopOp (right, ic, FALSE, FALSE);
4713 aopOp (result, ic, TRUE, FALSE);
4715 genCmp (right, left, result, ifx, sign);
4717 freeAsmop (left, NULL, ic);
4718 freeAsmop (right, NULL, ic);
4719 freeAsmop (result, NULL, ic);
4722 /*-----------------------------------------------------------------*/
4723 /* genCmpLt - less than comparisons */
4724 /*-----------------------------------------------------------------*/
4726 genCmpLt (iCode * ic, iCode * ifx)
4728 operand *left, *right, *result;
4729 sym_link *letype, *retype;
4732 left = IC_LEFT (ic);
4733 right = IC_RIGHT (ic);
4734 result = IC_RESULT (ic);
4736 letype = getSpec (operandType (left));
4737 retype = getSpec (operandType (right));
4738 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4740 /* assign the amsops */
4741 aopOp (left, ic, FALSE, FALSE);
4742 aopOp (right, ic, FALSE, FALSE);
4743 aopOp (result, ic, TRUE, FALSE);
4745 genCmp (left, right, result, ifx, sign);
4747 freeAsmop (left, NULL, ic);
4748 freeAsmop (right, NULL, ic);
4749 freeAsmop (result, NULL, ic);
4752 /*-----------------------------------------------------------------*/
4753 /* gencjneshort - compare and jump if not equal */
4754 /*-----------------------------------------------------------------*/
4756 gencjneshort (operand * left, operand * right, symbol * lbl)
4758 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4760 unsigned long lit = 0L;
4762 /* Swap the left and right if it makes the computation easier */
4763 if (AOP_TYPE (left) == AOP_LIT)
4770 if (AOP_TYPE (right) == AOP_LIT)
4772 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4775 /* if the right side is a literal then anything goes */
4776 if (AOP_TYPE (right) == AOP_LIT &&
4777 AOP_TYPE (left) != AOP_DIR)
4781 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4786 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4793 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4799 _moveA (aopGet (AOP (left), offset, FALSE));
4800 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4803 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4804 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4809 /* if the right side is in a register or in direct space or
4810 if the left is a pointer register & right is not */
4811 else if (AOP_TYPE (right) == AOP_REG ||
4812 AOP_TYPE (right) == AOP_DIR ||
4813 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4817 _moveA (aopGet (AOP (left), offset, FALSE));
4818 if (/*AOP_TYPE (left) == AOP_DIR &&*/ AOP_TYPE (right) == AOP_LIT &&
4819 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4822 /* MB: pending what? doesn't this need "or a,a"? */
4823 /* and I don't think AOP_TYPE(left) has anything to do with this */
4825 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4829 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4830 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4837 /* right is a pointer reg need both a & b */
4838 /* PENDING: is this required? */
4841 _moveA (aopGet (AOP (right), offset, FALSE));
4842 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4843 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4849 /*-----------------------------------------------------------------*/
4850 /* gencjne - compare and jump if not equal */
4851 /*-----------------------------------------------------------------*/
4853 gencjne (operand * left, operand * right, symbol * lbl)
4855 symbol *tlbl = newiTempLabel (NULL);
4857 gencjneshort (left, right, lbl);
4860 emit2 ("ld a,!one");
4861 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4862 emitLabel (lbl->key + 100);
4864 emitLabel (tlbl->key + 100);
4867 /*-----------------------------------------------------------------*/
4868 /* genCmpEq - generates code for equal to */
4869 /*-----------------------------------------------------------------*/
4871 genCmpEq (iCode * ic, iCode * ifx)
4873 operand *left, *right, *result;
4875 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4876 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4877 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4879 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4881 /* Swap operands if it makes the operation easier. ie if:
4882 1. Left is a literal.
4884 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4886 operand *t = IC_RIGHT (ic);
4887 IC_RIGHT (ic) = IC_LEFT (ic);
4891 if (ifx && !AOP_SIZE (result))
4894 /* if they are both bit variables */
4895 if (AOP_TYPE (left) == AOP_CRY &&
4896 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4898 wassertl (0, "Tried to compare two bits");
4902 tlbl = newiTempLabel (NULL);
4903 gencjneshort (left, right, tlbl);
4906 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4907 emitLabel (tlbl->key + 100);
4911 /* PENDING: do this better */
4912 symbol *lbl = newiTempLabel (NULL);
4913 emit2 ("!shortjp !tlabel", lbl->key + 100);
4914 emitLabel (tlbl->key + 100);
4915 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4916 emitLabel (lbl->key + 100);
4919 /* mark the icode as generated */
4924 /* if they are both bit variables */
4925 if (AOP_TYPE (left) == AOP_CRY &&
4926 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4928 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4934 gencjne (left, right, newiTempLabel (NULL));
4935 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4942 genIfxJump (ifx, "a");
4945 /* if the result is used in an arithmetic operation
4946 then put the result in place */
4947 if (AOP_TYPE (result) != AOP_CRY)
4952 /* leave the result in acc */
4956 freeAsmop (left, NULL, ic);
4957 freeAsmop (right, NULL, ic);
4958 freeAsmop (result, NULL, ic);
4961 /*-----------------------------------------------------------------*/
4962 /* ifxForOp - returns the icode containing the ifx for operand */
4963 /*-----------------------------------------------------------------*/
4965 ifxForOp (operand * op, iCode * ic)
4967 /* if true symbol then needs to be assigned */
4968 if (IS_TRUE_SYMOP (op))
4971 /* if this has register type condition and
4972 the next instruction is ifx with the same operand
4973 and live to of the operand is upto the ifx only then */
4975 ic->next->op == IFX &&
4976 IC_COND (ic->next)->key == op->key &&
4977 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4983 /*-----------------------------------------------------------------*/
4984 /* genAndOp - for && operation */
4985 /*-----------------------------------------------------------------*/
4987 genAndOp (iCode * ic)
4989 operand *left, *right, *result;
4992 /* note here that && operations that are in an if statement are
4993 taken away by backPatchLabels only those used in arthmetic
4994 operations remain */
4995 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4996 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4997 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4999 /* if both are bit variables */
5000 if (AOP_TYPE (left) == AOP_CRY &&
5001 AOP_TYPE (right) == AOP_CRY)
5003 wassertl (0, "Tried to and two bits");
5007 tlbl = newiTempLabel (NULL);
5009 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5011 emitLabel (tlbl->key + 100);
5015 freeAsmop (left, NULL, ic);
5016 freeAsmop (right, NULL, ic);
5017 freeAsmop (result, NULL, ic);
5020 /*-----------------------------------------------------------------*/
5021 /* genOrOp - for || operation */
5022 /*-----------------------------------------------------------------*/
5024 genOrOp (iCode * ic)
5026 operand *left, *right, *result;
5029 /* note here that || operations that are in an
5030 if statement are taken away by backPatchLabels
5031 only those used in arthmetic operations remain */
5032 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5033 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5034 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5036 /* if both are bit variables */
5037 if (AOP_TYPE (left) == AOP_CRY &&
5038 AOP_TYPE (right) == AOP_CRY)
5040 wassertl (0, "Tried to OR two bits");
5044 tlbl = newiTempLabel (NULL);
5046 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5048 emitLabel (tlbl->key + 100);
5052 freeAsmop (left, NULL, ic);
5053 freeAsmop (right, NULL, ic);
5054 freeAsmop (result, NULL, ic);
5057 /*-----------------------------------------------------------------*/
5058 /* isLiteralBit - test if lit == 2^n */
5059 /*-----------------------------------------------------------------*/
5061 isLiteralBit (unsigned long lit)
5063 unsigned long pw[32] =
5064 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5065 0x100L, 0x200L, 0x400L, 0x800L,
5066 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5067 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5068 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5069 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5070 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5073 for (idx = 0; idx < 32; idx++)
5079 /*-----------------------------------------------------------------*/
5080 /* jmpTrueOrFalse - */
5081 /*-----------------------------------------------------------------*/
5083 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5085 // ugly but optimized by peephole
5088 symbol *nlbl = newiTempLabel (NULL);
5089 emit2 ("jp !tlabel", nlbl->key + 100);
5090 emitLabel (tlbl->key + 100);
5091 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5092 emitLabel (nlbl->key + 100);
5096 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5097 emitLabel (tlbl->key + 100);
5102 /*-----------------------------------------------------------------*/
5103 /* genAnd - code for and */
5104 /*-----------------------------------------------------------------*/
5106 genAnd (iCode * ic, iCode * ifx)
5108 operand *left, *right, *result;
5109 int size, offset = 0;
5110 unsigned long lit = 0L;
5113 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5114 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5115 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5117 /* if left is a literal & right is not then exchange them */
5118 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5119 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5121 operand *tmp = right;
5126 /* if result = right then exchange them */
5127 if (sameRegs (AOP (result), AOP (right)))
5129 operand *tmp = right;
5134 /* if right is bit then exchange them */
5135 if (AOP_TYPE (right) == AOP_CRY &&
5136 AOP_TYPE (left) != AOP_CRY)
5138 operand *tmp = right;
5142 if (AOP_TYPE (right) == AOP_LIT)
5143 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5145 size = AOP_SIZE (result);
5147 if (AOP_TYPE (left) == AOP_CRY)
5149 wassertl (0, "Tried to perform an AND with a bit as an operand");
5153 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5154 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5155 if ((AOP_TYPE (right) == AOP_LIT) &&
5156 (AOP_TYPE (result) == AOP_CRY) &&
5157 (AOP_TYPE (left) != AOP_CRY))
5159 symbol *tlbl = newiTempLabel (NULL);
5160 int sizel = AOP_SIZE (left);
5163 /* PENDING: Test case for this. */
5168 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5170 _moveA (aopGet (AOP (left), offset, FALSE));
5171 if (bytelit != 0x0FFL)
5173 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5180 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5184 // bit = left & literal
5188 emit2 ("!tlabeldef", tlbl->key + 100);
5189 _G.lines.current->isLabel = 1;
5191 // if(left & literal)
5196 jmpTrueOrFalse (ifx, tlbl);
5204 /* if left is same as result */
5205 if (sameRegs (AOP (result), AOP (left)))
5207 for (; size--; offset++)
5209 if (AOP_TYPE (right) == AOP_LIT)
5211 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5216 aopPut (AOP (result), "!zero", offset);
5219 _moveA (aopGet (AOP (left), offset, FALSE));
5221 aopGet (AOP (right), offset, FALSE));
5222 aopPut (AOP (left), "a", offset);
5229 if (AOP_TYPE (left) == AOP_ACC)
5231 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5235 _moveA (aopGet (AOP (left), offset, FALSE));
5237 aopGet (AOP (right), offset, FALSE));
5238 aopPut (AOP (left), "a", offset);
5245 // left & result in different registers
5246 if (AOP_TYPE (result) == AOP_CRY)
5248 wassertl (0, "Tried to AND where the result is in carry");
5252 for (; (size--); offset++)
5255 // result = left & right
5256 if (AOP_TYPE (right) == AOP_LIT)
5258 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5260 aopPut (AOP (result),
5261 aopGet (AOP (left), offset, FALSE),
5265 else if (bytelit == 0)
5267 aopPut (AOP (result), "!zero", offset);
5271 // faster than result <- left, anl result,right
5272 // and better if result is SFR
5273 if (AOP_TYPE (left) == AOP_ACC)
5274 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5277 _moveA (aopGet (AOP (left), offset, FALSE));
5279 aopGet (AOP (right), offset, FALSE));
5281 aopPut (AOP (result), "a", offset);
5288 freeAsmop (left, NULL, ic);
5289 freeAsmop (right, NULL, ic);
5290 freeAsmop (result, NULL, ic);
5293 /*-----------------------------------------------------------------*/
5294 /* genOr - code for or */
5295 /*-----------------------------------------------------------------*/
5297 genOr (iCode * ic, iCode * ifx)
5299 operand *left, *right, *result;
5300 int size, offset = 0;
5301 unsigned long lit = 0L;
5304 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5305 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5306 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5308 /* if left is a literal & right is not then exchange them */
5309 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5310 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5312 operand *tmp = right;
5317 /* if result = right then exchange them */
5318 if (sameRegs (AOP (result), AOP (right)))
5320 operand *tmp = right;
5325 /* if right is bit then exchange them */
5326 if (AOP_TYPE (right) == AOP_CRY &&
5327 AOP_TYPE (left) != AOP_CRY)
5329 operand *tmp = right;
5333 if (AOP_TYPE (right) == AOP_LIT)
5334 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5336 size = AOP_SIZE (result);
5338 if (AOP_TYPE (left) == AOP_CRY)
5340 wassertl (0, "Tried to OR where left is a bit");
5344 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5345 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5346 if ((AOP_TYPE (right) == AOP_LIT) &&
5347 (AOP_TYPE (result) == AOP_CRY) &&
5348 (AOP_TYPE (left) != AOP_CRY))
5350 symbol *tlbl = newiTempLabel (NULL);
5351 int sizel = AOP_SIZE (left);
5355 wassertl (0, "Result is assigned to a bit");
5357 /* PENDING: Modeled after the AND code which is inefficient. */
5360 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5362 _moveA (aopGet (AOP (left), offset, FALSE));
5363 /* OR with any literal is the same as OR with itself. */
5365 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5371 jmpTrueOrFalse (ifx, tlbl);
5376 /* if left is same as result */
5377 if (sameRegs (AOP (result), AOP (left)))
5379 for (; size--; offset++)
5381 if (AOP_TYPE (right) == AOP_LIT)
5383 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5387 _moveA (aopGet (AOP (left), offset, FALSE));
5389 aopGet (AOP (right), offset, FALSE));
5390 aopPut (AOP (result), "a", offset);
5395 if (AOP_TYPE (left) == AOP_ACC)
5396 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5399 _moveA (aopGet (AOP (left), offset, FALSE));
5401 aopGet (AOP (right), offset, FALSE));
5402 aopPut (AOP (result), "a", offset);
5409 // left & result in different registers
5410 if (AOP_TYPE (result) == AOP_CRY)
5412 wassertl (0, "Result of OR is in a bit");
5415 for (; (size--); offset++)
5418 // result = left & right
5419 if (AOP_TYPE (right) == AOP_LIT)
5421 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5423 aopPut (AOP (result),
5424 aopGet (AOP (left), offset, FALSE),
5429 // faster than result <- left, anl result,right
5430 // and better if result is SFR
5431 if (AOP_TYPE (left) == AOP_ACC)
5432 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5435 _moveA (aopGet (AOP (left), offset, FALSE));
5437 aopGet (AOP (right), offset, FALSE));
5439 aopPut (AOP (result), "a", offset);
5440 /* PENDING: something weird is going on here. Add exception. */
5441 if (AOP_TYPE (result) == AOP_ACC)
5447 freeAsmop (left, NULL, ic);
5448 freeAsmop (right, NULL, ic);
5449 freeAsmop (result, NULL, ic);
5452 /*-----------------------------------------------------------------*/
5453 /* genXor - code for xclusive or */
5454 /*-----------------------------------------------------------------*/
5456 genXor (iCode * ic, iCode * ifx)
5458 operand *left, *right, *result;
5459 int size, offset = 0;
5460 unsigned long lit = 0L;
5462 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5463 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5464 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5466 /* if left is a literal & right is not then exchange them */
5467 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5468 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5470 operand *tmp = right;
5475 /* if result = right then exchange them */
5476 if (sameRegs (AOP (result), AOP (right)))
5478 operand *tmp = right;
5483 /* if right is bit then exchange them */
5484 if (AOP_TYPE (right) == AOP_CRY &&
5485 AOP_TYPE (left) != AOP_CRY)
5487 operand *tmp = right;
5491 if (AOP_TYPE (right) == AOP_LIT)
5492 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5494 size = AOP_SIZE (result);
5496 if (AOP_TYPE (left) == AOP_CRY)
5498 wassertl (0, "Tried to XOR a bit");
5502 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5503 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5504 if ((AOP_TYPE (right) == AOP_LIT) &&
5505 (AOP_TYPE (result) == AOP_CRY) &&
5506 (AOP_TYPE (left) != AOP_CRY))
5508 symbol *tlbl = newiTempLabel (NULL);
5509 int sizel = AOP_SIZE (left);
5513 /* PENDING: Test case for this. */
5514 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5518 _moveA (aopGet (AOP (left), offset, FALSE));
5519 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5520 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5525 jmpTrueOrFalse (ifx, tlbl);
5529 wassertl (0, "Result of XOR was destined for a bit");
5534 /* if left is same as result */
5535 if (sameRegs (AOP (result), AOP (left)))
5537 for (; size--; offset++)
5539 if (AOP_TYPE (right) == AOP_LIT)
5541 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5545 _moveA (aopGet (AOP (left), offset, FALSE));
5547 aopGet (AOP (right), offset, FALSE));
5548 aopPut (AOP (result), "a", offset);
5553 if (AOP_TYPE (left) == AOP_ACC)
5555 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5559 _moveA (aopGet (AOP (left), offset, FALSE));
5561 aopGet (AOP (right), offset, FALSE));
5562 aopPut (AOP (result), "a", offset);
5569 // left & result in different registers
5570 if (AOP_TYPE (result) == AOP_CRY)
5572 wassertl (0, "Result of XOR is in a bit");
5575 for (; (size--); offset++)
5578 // result = left & right
5579 if (AOP_TYPE (right) == AOP_LIT)
5581 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5583 aopPut (AOP (result),
5584 aopGet (AOP (left), offset, FALSE),
5589 // faster than result <- left, anl result,right
5590 // and better if result is SFR
5591 if (AOP_TYPE (left) == AOP_ACC)
5593 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5597 _moveA (aopGet (AOP (left), offset, FALSE));
5599 aopGet (AOP (right), offset, FALSE));
5601 aopPut (AOP (result), "a", offset);
5606 freeAsmop (left, NULL, ic);
5607 freeAsmop (right, NULL, ic);
5608 freeAsmop (result, NULL, ic);
5611 /*-----------------------------------------------------------------*/
5612 /* genInline - write the inline code out */
5613 /*-----------------------------------------------------------------*/
5615 genInline (iCode * ic)
5617 char *buffer, *bp, *bp1;
5619 _G.lines.isInline += (!options.asmpeep);
5621 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5622 strcpy (buffer, IC_INLINE (ic));
5624 /* emit each line as a code */
5649 _G.lines.isInline -= (!options.asmpeep);
5653 /*-----------------------------------------------------------------*/
5654 /* genRRC - rotate right with carry */
5655 /*-----------------------------------------------------------------*/
5662 /*-----------------------------------------------------------------*/
5663 /* genRLC - generate code for rotate left with carry */
5664 /*-----------------------------------------------------------------*/
5671 /*-----------------------------------------------------------------*/
5672 /* genGetHbit - generates code get highest order bit */
5673 /*-----------------------------------------------------------------*/
5675 genGetHbit (iCode * ic)
5677 operand *left, *result;
5678 left = IC_LEFT (ic);
5679 result = IC_RESULT (ic);
5681 aopOp (left, ic, FALSE, FALSE);
5682 aopOp (result, ic, FALSE, FALSE);
5684 /* get the highest order byte into a */
5685 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5687 if (AOP_TYPE (result) == AOP_CRY)
5695 emit2 ("and a,!one");
5700 freeAsmop (left, NULL, ic);
5701 freeAsmop (result, NULL, ic);
5705 emitRsh2 (asmop *aop, int size, int is_signed)
5711 const char *l = aopGet (aop, size, FALSE);
5714 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5724 /*-----------------------------------------------------------------*/
5725 /* shiftR2Left2Result - shift right two bytes from left to result */
5726 /*-----------------------------------------------------------------*/
5728 shiftR2Left2Result (operand * left, int offl,
5729 operand * result, int offr,
5730 int shCount, int is_signed)
5733 symbol *tlbl, *tlbl1;
5735 movLeft2Result (left, offl, result, offr, 0);
5736 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5741 /* if (AOP(result)->type == AOP_REG) { */
5743 tlbl = newiTempLabel (NULL);
5744 tlbl1 = newiTempLabel (NULL);
5746 /* Left is already in result - so now do the shift */
5751 emitRsh2 (AOP (result), size, is_signed);
5756 emit2 ("ld a,!immedbyte+1", shCount);
5757 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5758 emitLabel (tlbl->key + 100);
5760 emitRsh2 (AOP (result), size, is_signed);
5762 emitLabel (tlbl1->key + 100);
5764 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5768 /*-----------------------------------------------------------------*/
5769 /* shiftL2Left2Result - shift left two bytes from left to result */
5770 /*-----------------------------------------------------------------*/
5772 shiftL2Left2Result (operand * left, int offl,
5773 operand * result, int offr, int shCount)
5775 if (sameRegs (AOP (result), AOP (left)) &&
5776 ((offl + MSB16) == offr))
5782 /* Copy left into result */
5783 movLeft2Result (left, offl, result, offr, 0);
5784 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5790 if (getPairId (AOP (result)) == PAIR_HL)
5794 emit2 ("add hl,hl");
5801 symbol *tlbl, *tlbl1;
5804 tlbl = newiTempLabel (NULL);
5805 tlbl1 = newiTempLabel (NULL);
5807 if (AOP (result)->type == AOP_REG)
5811 for (offset = 0; offset < size; offset++)
5813 l = aopGet (AOP (result), offset, FALSE);
5817 emit2 ("sla %s", l);
5828 /* Left is already in result - so now do the shift */
5831 emit2 ("ld a,!immedbyte+1", shCount);
5832 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5833 emitLabel (tlbl->key + 100);
5838 l = aopGet (AOP (result), offset, FALSE);
5842 emit2 ("sla %s", l);
5853 emitLabel (tlbl1->key + 100);
5855 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5861 /*-----------------------------------------------------------------*/
5862 /* AccRol - rotate left accumulator by known count */
5863 /*-----------------------------------------------------------------*/
5865 AccRol (int shCount)
5867 shCount &= 0x0007; // shCount : 0..7
5944 /*-----------------------------------------------------------------*/
5945 /* AccLsh - left shift accumulator by known count */
5946 /*-----------------------------------------------------------------*/
5948 AccLsh (int shCount)
5950 static const unsigned char SLMask[] =
5952 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5961 else if (shCount == 2)
5968 /* rotate left accumulator */
5970 /* and kill the lower order bits */
5971 emit2 ("and a,!immedbyte", SLMask[shCount]);
5976 /*-----------------------------------------------------------------*/
5977 /* shiftL1Left2Result - shift left one byte from left to result */
5978 /*-----------------------------------------------------------------*/
5980 shiftL1Left2Result (operand * left, int offl,
5981 operand * result, int offr, int shCount)
5984 l = aopGet (AOP (left), offl, FALSE);
5986 /* shift left accumulator */
5988 aopPut (AOP (result), "a", offr);
5992 /*-----------------------------------------------------------------*/
5993 /* genlshTwo - left shift two bytes by known amount */
5994 /*-----------------------------------------------------------------*/
5996 genlshTwo (operand * result, operand * left, int shCount)
5998 int size = AOP_SIZE (result);
6000 wassert (size == 2);
6002 /* if shCount >= 8 */
6010 movLeft2Result (left, LSB, result, MSB16, 0);
6011 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6012 aopPut (AOP (result), "!zero", LSB);
6016 movLeft2Result (left, LSB, result, MSB16, 0);
6017 aopPut (AOP (result), "!zero", 0);
6022 aopPut (AOP (result), "!zero", LSB);
6025 /* 0 <= shCount <= 7 */
6034 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6039 /*-----------------------------------------------------------------*/
6040 /* genlshOne - left shift a one byte quantity by known count */
6041 /*-----------------------------------------------------------------*/
6043 genlshOne (operand * result, operand * left, int shCount)
6045 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6048 /*-----------------------------------------------------------------*/
6049 /* genLeftShiftLiteral - left shifting by known count */
6050 /*-----------------------------------------------------------------*/
6052 genLeftShiftLiteral (operand * left,
6057 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6060 freeAsmop (right, NULL, ic);
6062 aopOp (left, ic, FALSE, FALSE);
6063 aopOp (result, ic, FALSE, FALSE);
6065 size = getSize (operandType (result));
6067 /* I suppose that the left size >= result size */
6069 if (shCount >= (size * 8))
6073 aopPut (AOP (result), "!zero", size);
6081 genlshOne (result, left, shCount);
6084 genlshTwo (result, left, shCount);
6087 wassertl (0, "Shifting of longs is currently unsupported");
6093 freeAsmop (left, NULL, ic);
6094 freeAsmop (result, NULL, ic);
6097 /*-----------------------------------------------------------------*/
6098 /* genLeftShift - generates code for left shifting */
6099 /*-----------------------------------------------------------------*/
6101 genLeftShift (iCode * ic)
6105 symbol *tlbl, *tlbl1;
6106 operand *left, *right, *result;
6108 right = IC_RIGHT (ic);
6109 left = IC_LEFT (ic);
6110 result = IC_RESULT (ic);
6112 aopOp (right, ic, FALSE, FALSE);
6114 /* if the shift count is known then do it
6115 as efficiently as possible */
6116 if (AOP_TYPE (right) == AOP_LIT)
6118 genLeftShiftLiteral (left, right, result, ic);
6122 /* shift count is unknown then we have to form a loop get the loop
6123 count in B : Note: we take only the lower order byte since
6124 shifting more that 32 bits make no sense anyway, ( the largest
6125 size of an object can be only 32 bits ) */
6126 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6128 freeAsmop (right, NULL, ic);
6129 aopOp (left, ic, FALSE, FALSE);
6130 aopOp (result, ic, FALSE, FALSE);
6132 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6135 /* now move the left to the result if they are not the
6138 if (!sameRegs (AOP (left), AOP (result)))
6141 size = AOP_SIZE (result);
6145 l = aopGet (AOP (left), offset, FALSE);
6146 aopPut (AOP (result), l, offset);
6151 tlbl = newiTempLabel (NULL);
6152 size = AOP_SIZE (result);
6154 tlbl1 = newiTempLabel (NULL);
6156 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6159 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6160 emitLabel (tlbl->key + 100);
6161 l = aopGet (AOP (result), offset, FALSE);
6165 l = aopGet (AOP (result), offset, FALSE);
6169 emit2 ("sla %s", l);
6177 emitLabel (tlbl1->key + 100);
6179 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6181 freeAsmop (left, NULL, ic);
6182 freeAsmop (result, NULL, ic);
6185 /*-----------------------------------------------------------------*/
6186 /* genrshOne - left shift two bytes by known amount != 0 */
6187 /*-----------------------------------------------------------------*/
6189 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6192 int size = AOP_SIZE (result);
6195 wassert (size == 1);
6196 wassert (shCount < 8);
6198 l = aopGet (AOP (left), 0, FALSE);
6200 if (AOP (result)->type == AOP_REG)
6202 aopPut (AOP (result), l, 0);
6203 l = aopGet (AOP (result), 0, FALSE);
6206 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6214 emit2 ("%s a", is_signed ? "sra" : "srl");
6216 aopPut (AOP (result), "a", 0);
6220 /*-----------------------------------------------------------------*/
6221 /* AccRsh - right shift accumulator by known count */
6222 /*-----------------------------------------------------------------*/
6224 AccRsh (int shCount)
6226 static const unsigned char SRMask[] =
6228 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6233 /* rotate right accumulator */
6234 AccRol (8 - shCount);
6235 /* and kill the higher order bits */
6236 emit2 ("and a,!immedbyte", SRMask[shCount]);
6240 /*-----------------------------------------------------------------*/
6241 /* shiftR1Left2Result - shift right one byte from left to result */
6242 /*-----------------------------------------------------------------*/
6244 shiftR1Left2Result (operand * left, int offl,
6245 operand * result, int offr,
6246 int shCount, int sign)
6248 _moveA (aopGet (AOP (left), offl, FALSE));
6253 emit2 ("%s a", sign ? "sra" : "srl");
6260 aopPut (AOP (result), "a", offr);
6263 /*-----------------------------------------------------------------*/
6264 /* genrshTwo - right shift two bytes by known amount */
6265 /*-----------------------------------------------------------------*/
6267 genrshTwo (operand * result, operand * left,
6268 int shCount, int sign)
6270 /* if shCount >= 8 */
6276 shiftR1Left2Result (left, MSB16, result, LSB,
6281 movLeft2Result (left, MSB16, result, LSB, sign);
6285 /* Sign extend the result */
6286 _moveA(aopGet (AOP (result), 0, FALSE));
6290 aopPut (AOP (result), ACC_NAME, MSB16);
6294 aopPut (AOP (result), "!zero", 1);
6297 /* 0 <= shCount <= 7 */
6300 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6304 /*-----------------------------------------------------------------*/
6305 /* genRightShiftLiteral - left shifting by known count */
6306 /*-----------------------------------------------------------------*/
6308 genRightShiftLiteral (operand * left,
6314 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6317 freeAsmop (right, NULL, ic);
6319 aopOp (left, ic, FALSE, FALSE);
6320 aopOp (result, ic, FALSE, FALSE);
6322 size = getSize (operandType (result));
6324 /* I suppose that the left size >= result size */
6326 if (shCount >= (size * 8)) {
6328 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6329 _moveA(aopGet (AOP (left), 0, FALSE));
6337 aopPut (AOP (result), s, size);
6344 genrshOne (result, left, shCount, sign);
6347 genrshTwo (result, left, shCount, sign);
6350 wassertl (0, "Asked to shift right a long which should be a function call");
6353 wassertl (0, "Entered default case in right shift delegate");
6356 freeAsmop (left, NULL, ic);
6357 freeAsmop (result, NULL, ic);
6360 /*-----------------------------------------------------------------*/
6361 /* genRightShift - generate code for right shifting */
6362 /*-----------------------------------------------------------------*/
6364 genRightShift (iCode * ic)
6366 operand *right, *left, *result;
6368 int size, offset, first = 1;
6372 symbol *tlbl, *tlbl1;
6374 /* if signed then we do it the hard way preserve the
6375 sign bit moving it inwards */
6376 retype = getSpec (operandType (IC_RESULT (ic)));
6378 is_signed = !SPEC_USIGN (retype);
6380 /* signed & unsigned types are treated the same : i.e. the
6381 signed is NOT propagated inwards : quoting from the
6382 ANSI - standard : "for E1 >> E2, is equivalent to division
6383 by 2**E2 if unsigned or if it has a non-negative value,
6384 otherwise the result is implementation defined ", MY definition
6385 is that the sign does not get propagated */
6387 right = IC_RIGHT (ic);
6388 left = IC_LEFT (ic);
6389 result = IC_RESULT (ic);
6391 aopOp (right, ic, FALSE, FALSE);
6393 /* if the shift count is known then do it
6394 as efficiently as possible */
6395 if (AOP_TYPE (right) == AOP_LIT)
6397 genRightShiftLiteral (left, right, result, ic, is_signed);
6401 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6403 freeAsmop (right, NULL, ic);
6405 aopOp (left, ic, FALSE, FALSE);
6406 aopOp (result, ic, FALSE, FALSE);
6408 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6411 /* now move the left to the result if they are not the
6413 if (!sameRegs (AOP (left), AOP (result)))
6416 size = AOP_SIZE (result);
6420 l = aopGet (AOP (left), offset, FALSE);
6421 aopPut (AOP (result), l, offset);
6426 tlbl = newiTempLabel (NULL);
6427 tlbl1 = newiTempLabel (NULL);
6428 size = AOP_SIZE (result);
6431 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6434 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6435 emitLabel (tlbl->key + 100);
6438 l = aopGet (AOP (result), offset--, FALSE);
6441 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6449 emitLabel (tlbl1->key + 100);
6451 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6453 freeAsmop (left, NULL, ic);
6454 freeAsmop (result, NULL, ic);
6458 /*-----------------------------------------------------------------*/
6459 /* genUnpackBits - generates code for unpacking bits */
6460 /*-----------------------------------------------------------------*/
6462 genUnpackBits (operand * result, int pair)
6464 int offset = 0; /* result byte offset */
6465 int rsize; /* result size */
6466 int rlen = 0; /* remaining bitfield length */
6467 sym_link *etype; /* bitfield type information */
6468 int blen; /* bitfield length */
6469 int bstr; /* bitfield starting bit within byte */
6471 emitDebug ("; genUnpackBits");
6473 etype = getSpec (operandType (result));
6474 rsize = getSize (operandType (result));
6475 blen = SPEC_BLEN (etype);
6476 bstr = SPEC_BSTR (etype);
6478 /* If the bitfield length is less than a byte */
6481 emit2 ("ld a,!*pair", _pairs[pair].name);
6483 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6484 if (!SPEC_USIGN (etype))
6486 /* signed bitfield */
6487 symbol *tlbl = newiTempLabel (NULL);
6489 emit2 ("bit %d,a", blen - 1);
6490 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6491 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6492 emitLabel (tlbl->key + 100);
6494 aopPut (AOP (result), "a", offset++);
6498 /* TODO: what if pair == PAIR_DE ? */
6499 if (getPairId (AOP (result)) == PAIR_HL)
6501 wassertl (rsize == 2, "HL must be of size 2");
6502 emit2 ("ld a,!*hl");
6504 emit2 ("ld h,!*hl");
6507 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6508 if (!SPEC_USIGN (etype))
6510 /* signed bitfield */
6511 symbol *tlbl = newiTempLabel (NULL);
6513 emit2 ("bit %d,a", blen - 1);
6514 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6515 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6516 emitLabel (tlbl->key + 100);
6519 spillPair (PAIR_HL);
6523 /* Bit field did not fit in a byte. Copy all
6524 but the partial byte at the end. */
6525 for (rlen=blen;rlen>=8;rlen-=8)
6527 emit2 ("ld a,!*pair", _pairs[pair].name);
6528 aopPut (AOP (result), "a", offset++);
6531 emit2 ("inc %s", _pairs[pair].name);
6532 _G.pairs[pair].offset++;
6536 /* Handle the partial byte at the end */
6539 emit2 ("ld a,!*pair", _pairs[pair].name);
6540 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6541 if (!SPEC_USIGN (etype))
6543 /* signed bitfield */
6544 symbol *tlbl = newiTempLabel (NULL);
6546 emit2 ("bit %d,a", rlen - 1);
6547 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6548 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6549 emitLabel (tlbl->key + 100);
6551 aopPut (AOP (result), "a", offset++);
6559 if (SPEC_USIGN (etype))
6563 /* signed bitfield: sign extension with 0x00 or 0xff */
6571 aopPut (AOP (result), source, offset++);
6575 /*-----------------------------------------------------------------*/
6576 /* genGenPointerGet - get value from generic pointer space */
6577 /*-----------------------------------------------------------------*/
6579 genGenPointerGet (operand * left,
6580 operand * result, iCode * ic)
6583 sym_link *retype = getSpec (operandType (result));
6589 aopOp (left, ic, FALSE, FALSE);
6590 aopOp (result, ic, FALSE, FALSE);
6592 size = AOP_SIZE (result);
6594 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6597 if (isPtrPair (AOP (left)))
6599 tsprintf (buffer, sizeof(buffer),
6600 "!*pair", getPairName (AOP (left)));
6601 aopPut (AOP (result), buffer, 0);
6605 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6606 aopPut (AOP (result), "a", 0);
6608 freeAsmop (left, NULL, ic);
6612 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6619 tsprintf (at, sizeof(at), "!*iyx", offset);
6620 aopPut (AOP (result), at, offset);
6624 freeAsmop (left, NULL, ic);
6628 /* For now we always load into IY */
6629 /* if this is remateriazable */
6630 fetchPair (pair, AOP (left));
6632 /* if bit then unpack */
6633 if (IS_BITVAR (retype))
6635 genUnpackBits (result, pair);
6636 freeAsmop (left, NULL, ic);
6640 else if (getPairId (AOP (result)) == PAIR_HL)
6642 wassertl (size == 2, "HL must be of size 2");
6643 emit2 ("ld a,!*hl");
6645 emit2 ("ld h,!*hl");
6647 spillPair (PAIR_HL);
6649 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6651 size = AOP_SIZE (result);
6656 /* PENDING: make this better */
6657 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6659 aopPut (AOP (result), "!*hl", offset++);
6663 emit2 ("ld a,!*pair", _pairs[pair].name);
6664 aopPut (AOP (result), "a", offset++);
6668 emit2 ("inc %s", _pairs[pair].name);
6669 _G.pairs[pair].offset++;
6672 /* Fixup HL back down */
6673 for (size = AOP_SIZE (result)-1; size; size--)
6675 emit2 ("dec %s", _pairs[pair].name);
6680 size = AOP_SIZE (result);
6685 /* PENDING: make this better */
6687 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6689 aopPut (AOP (result), "!*hl", offset++);
6693 emit2 ("ld a,!*pair", _pairs[pair].name);
6694 aopPut (AOP (result), "a", offset++);
6698 emit2 ("inc %s", _pairs[pair].name);
6699 _G.pairs[pair].offset++;
6704 freeAsmop (left, NULL, ic);
6707 freeAsmop (result, NULL, ic);
6710 /*-----------------------------------------------------------------*/
6711 /* genPointerGet - generate code for pointer get */
6712 /*-----------------------------------------------------------------*/
6714 genPointerGet (iCode * ic)
6716 operand *left, *result;
6717 sym_link *type, *etype;
6719 left = IC_LEFT (ic);
6720 result = IC_RESULT (ic);
6722 /* depending on the type of pointer we need to
6723 move it to the correct pointer register */
6724 type = operandType (left);
6725 etype = getSpec (type);
6727 genGenPointerGet (left, result, ic);
6731 isRegOrLit (asmop * aop)
6733 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6739 /*-----------------------------------------------------------------*/
6740 /* genPackBits - generates code for packed bit storage */
6741 /*-----------------------------------------------------------------*/
6743 genPackBits (sym_link * etype,
6748 int offset = 0; /* source byte offset */
6749 int rlen = 0; /* remaining bitfield length */
6750 int blen; /* bitfield length */
6751 int bstr; /* bitfield starting bit within byte */
6752 int litval; /* source literal value (if AOP_LIT) */
6753 unsigned char mask; /* bitmask within current byte */
6754 int extraPair; /* a tempory register */
6755 bool needPopExtra=0; /* need to restore original value of temp reg */
6757 emitDebug ("; genPackBits","");
6759 blen = SPEC_BLEN (etype);
6760 bstr = SPEC_BSTR (etype);
6762 /* If the bitfield length is less than a byte */
6765 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6766 (unsigned char) (0xFF >> (8 - bstr)));
6768 if (AOP_TYPE (right) == AOP_LIT)
6770 /* Case with a bitfield length <8 and literal source
6772 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6774 litval &= (~mask) & 0xff;
6775 emit2 ("ld a,!*pair", _pairs[pair].name);
6776 if ((mask|litval)!=0xff)
6777 emit2 ("and a,!immedbyte", mask);
6779 emit2 ("or a,!immedbyte", litval);
6780 emit2 ("ld !*pair,a", _pairs[pair].name);
6785 /* Case with a bitfield length <8 and arbitrary source
6787 _moveA (aopGet (AOP (right), 0, FALSE));
6788 /* shift and mask source value */
6790 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6792 extraPair = getFreePairId(ic);
6793 if (extraPair == PAIR_INVALID)
6795 extraPair = PAIR_BC;
6796 if (getPairId (AOP (right)) != PAIR_BC
6797 || !isLastUse (ic, right))
6803 emit2 ("ld %s,a", _pairs[extraPair].l);
6804 emit2 ("ld a,!*pair", _pairs[pair].name);
6806 emit2 ("and a,!immedbyte", mask);
6807 emit2 ("or a,%s", _pairs[extraPair].l);
6808 emit2 ("ld !*pair,a", _pairs[pair].name);
6815 /* Bit length is greater than 7 bits. In this case, copy */
6816 /* all except the partial byte at the end */
6817 for (rlen=blen;rlen>=8;rlen-=8)
6819 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6820 emit2 ("ld !*pair,a", _pairs[pair].name);
6823 emit2 ("inc %s", _pairs[pair].name);
6824 _G.pairs[pair].offset++;
6828 /* If there was a partial byte at the end */
6831 mask = (((unsigned char) -1 << rlen) & 0xff);
6833 if (AOP_TYPE (right) == AOP_LIT)
6835 /* Case with partial byte and literal source
6837 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6838 litval >>= (blen-rlen);
6839 litval &= (~mask) & 0xff;
6840 emit2 ("ld a,!*pair", _pairs[pair].name);
6841 if ((mask|litval)!=0xff)
6842 emit2 ("and a,!immedbyte", mask);
6844 emit2 ("or a,!immedbyte", litval);
6848 /* Case with partial byte and arbitrary source
6850 _moveA (aopGet (AOP (right), offset++, FALSE));
6851 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6853 extraPair = getFreePairId(ic);
6854 if (extraPair == PAIR_INVALID)
6856 extraPair = getPairId (AOP (right));
6857 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6858 extraPair = PAIR_BC;
6860 if (getPairId (AOP (right)) != PAIR_BC
6861 || !isLastUse (ic, right))
6867 emit2 ("ld %s,a", _pairs[extraPair].l);
6868 emit2 ("ld a,!*pair", _pairs[pair].name);
6870 emit2 ("and a,!immedbyte", mask);
6871 emit2 ("or a,%s", _pairs[extraPair].l);
6876 emit2 ("ld !*pair,a", _pairs[pair].name);
6881 /*-----------------------------------------------------------------*/
6882 /* genGenPointerSet - stores the value into a pointer location */
6883 /*-----------------------------------------------------------------*/
6885 genGenPointerSet (operand * right,
6886 operand * result, iCode * ic)
6889 sym_link *retype = getSpec (operandType (right));
6890 sym_link *letype = getSpec (operandType (result));
6891 PAIR_ID pairId = PAIR_HL;
6894 aopOp (result, ic, FALSE, FALSE);
6895 aopOp (right, ic, FALSE, FALSE);
6900 size = AOP_SIZE (right);
6902 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6903 emitDebug("; isBitvar = %d", isBitvar);
6905 /* Handle the exceptions first */
6906 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6909 const char *l = aopGet (AOP (right), 0, FALSE);
6910 const char *pair = getPairName (AOP (result));
6911 if (canAssignToPtr (l) && isPtr (pair))
6913 emit2 ("ld !*pair,%s", pair, l);
6918 emit2 ("ld !*pair,a", pair);
6923 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6926 const char *l = aopGet (AOP (right), 0, FALSE);
6931 if (canAssignToPtr (l))
6933 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6937 _moveA (aopGet (AOP (right), offset, FALSE));
6938 emit2 ("ld !*iyx,a", offset);
6944 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6951 const char *l = aopGet (AOP (right), offset, FALSE);
6952 if (isRegOrLit (AOP (right)) && !IS_GB)
6954 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6959 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6963 emit2 ("inc %s", _pairs[PAIR_HL].name);
6964 _G.pairs[PAIR_HL].offset++;
6969 /* Fixup HL back down */
6970 for (size = AOP_SIZE (right)-1; size; size--)
6972 emit2 ("dec %s", _pairs[PAIR_HL].name);
6977 /* if the operand is already in dptr
6978 then we do nothing else we move the value to dptr */
6979 if (AOP_TYPE (result) != AOP_STR)
6981 fetchPair (pairId, AOP (result));
6983 /* so hl now contains the address */
6984 freeAsmop (result, NULL, ic);
6986 /* if bit then unpack */
6989 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6999 const char *l = aopGet (AOP (right), offset, FALSE);
7000 if (isRegOrLit (AOP (right)) && !IS_GB)
7002 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7007 emit2 ("ld !*pair,a", _pairs[pairId].name);
7011 emit2 ("inc %s", _pairs[pairId].name);
7012 _G.pairs[pairId].offset++;
7018 freeAsmop (right, NULL, ic);
7021 /*-----------------------------------------------------------------*/
7022 /* genPointerSet - stores the value into a pointer location */
7023 /*-----------------------------------------------------------------*/
7025 genPointerSet (iCode * ic)
7027 operand *right, *result;
7028 sym_link *type, *etype;
7030 right = IC_RIGHT (ic);
7031 result = IC_RESULT (ic);
7033 /* depending on the type of pointer we need to
7034 move it to the correct pointer register */
7035 type = operandType (result);
7036 etype = getSpec (type);
7038 genGenPointerSet (right, result, ic);
7041 /*-----------------------------------------------------------------*/
7042 /* genIfx - generate code for Ifx statement */
7043 /*-----------------------------------------------------------------*/
7045 genIfx (iCode * ic, iCode * popIc)
7047 operand *cond = IC_COND (ic);
7050 aopOp (cond, ic, FALSE, TRUE);
7052 /* get the value into acc */
7053 if (AOP_TYPE (cond) != AOP_CRY)
7057 /* the result is now in the accumulator */
7058 freeAsmop (cond, NULL, ic);
7060 /* if there was something to be popped then do it */
7064 /* if the condition is a bit variable */
7065 if (isbit && IS_ITEMP (cond) &&
7067 genIfxJump (ic, SPIL_LOC (cond)->rname);
7068 else if (isbit && !IS_ITEMP (cond))
7069 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7071 genIfxJump (ic, "a");
7076 /*-----------------------------------------------------------------*/
7077 /* genAddrOf - generates code for address of */
7078 /*-----------------------------------------------------------------*/
7080 genAddrOf (iCode * ic)
7082 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7084 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7086 /* if the operand is on the stack then we
7087 need to get the stack offset of this
7094 if (sym->stack <= 0)
7096 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7100 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7102 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7106 emit2 ("ld de,!hashedstr", sym->rname);
7107 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7115 /* if it has an offset then we need to compute it */
7117 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7119 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7120 emit2 ("add hl,sp");
7124 emit2 ("ld hl,!hashedstr", sym->rname);
7126 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7128 freeAsmop (IC_RESULT (ic), NULL, ic);
7131 /*-----------------------------------------------------------------*/
7132 /* genAssign - generate code for assignment */
7133 /*-----------------------------------------------------------------*/
7135 genAssign (iCode * ic)
7137 operand *result, *right;
7139 unsigned long lit = 0L;
7141 result = IC_RESULT (ic);
7142 right = IC_RIGHT (ic);
7144 /* Dont bother assigning if they are the same */
7145 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7147 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7151 aopOp (right, ic, FALSE, FALSE);
7152 aopOp (result, ic, TRUE, FALSE);
7154 /* if they are the same registers */
7155 if (sameRegs (AOP (right), AOP (result)))
7157 emitDebug ("; (registers are the same)");
7161 /* if the result is a bit */
7162 if (AOP_TYPE (result) == AOP_CRY)
7164 wassertl (0, "Tried to assign to a bit");
7168 size = AOP_SIZE (result);
7171 if (AOP_TYPE (right) == AOP_LIT)
7173 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7176 if (isPair (AOP (result)))
7178 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7180 else if ((size > 1) &&
7181 (AOP_TYPE (result) != AOP_REG) &&
7182 (AOP_TYPE (right) == AOP_LIT) &&
7183 !IS_FLOAT (operandType (right)) &&
7186 bool fXored = FALSE;
7188 /* Work from the top down.
7189 Done this way so that we can use the cached copy of 0
7190 in A for a fast clear */
7193 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7195 if (!fXored && size > 1)
7202 aopPut (AOP (result), "a", offset);
7206 aopPut (AOP (result), "!zero", offset);
7210 aopPut (AOP (result),
7211 aopGet (AOP (right), offset, FALSE),
7216 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7218 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7219 aopPut (AOP (result), "l", LSB);
7220 aopPut (AOP (result), "h", MSB16);
7222 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7224 /* Special case. Load into a and d, then load out. */
7225 _moveA (aopGet (AOP (right), 0, FALSE));
7226 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7227 aopPut (AOP (result), "a", 0);
7228 aopPut (AOP (result), "e", 1);
7230 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7232 /* Special case - simple memcpy */
7233 aopGet (AOP (right), LSB, FALSE);
7236 aopGet (AOP (result), LSB, FALSE);
7240 emit2 ("ld a,(de)");
7241 /* Peephole will optimise this. */
7242 emit2 ("ld (hl),a");
7250 spillPair (PAIR_HL);
7256 /* PENDING: do this check better */
7257 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7259 _moveA (aopGet (AOP (right), offset, FALSE));
7260 aopPut (AOP (result), "a", offset);
7263 aopPut (AOP (result),
7264 aopGet (AOP (right), offset, FALSE),
7271 freeAsmop (right, NULL, ic);
7272 freeAsmop (result, NULL, ic);
7275 /*-----------------------------------------------------------------*/
7276 /* genJumpTab - genrates code for jump table */
7277 /*-----------------------------------------------------------------*/
7279 genJumpTab (iCode * ic)
7284 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7285 /* get the condition into accumulator */
7286 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7289 emit2 ("ld e,%s", l);
7290 emit2 ("ld d,!zero");
7291 jtab = newiTempLabel (NULL);
7293 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7294 emit2 ("add hl,de");
7295 emit2 ("add hl,de");
7296 emit2 ("add hl,de");
7297 freeAsmop (IC_JTCOND (ic), NULL, ic);
7301 emitLabel (jtab->key + 100);
7302 /* now generate the jump labels */
7303 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7304 jtab = setNextItem (IC_JTLABELS (ic)))
7305 emit2 ("jp !tlabel", jtab->key + 100);
7308 /*-----------------------------------------------------------------*/
7309 /* genCast - gen code for casting */
7310 /*-----------------------------------------------------------------*/
7312 genCast (iCode * ic)
7314 operand *result = IC_RESULT (ic);
7315 sym_link *rtype = operandType (IC_RIGHT (ic));
7316 operand *right = IC_RIGHT (ic);
7319 /* if they are equivalent then do nothing */
7320 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7323 aopOp (right, ic, FALSE, FALSE);
7324 aopOp (result, ic, FALSE, FALSE);
7326 /* if the result is a bit */
7327 if (AOP_TYPE (result) == AOP_CRY)
7329 wassertl (0, "Tried to cast to a bit");
7332 /* if they are the same size : or less */
7333 if (AOP_SIZE (result) <= AOP_SIZE (right))
7336 /* if they are in the same place */
7337 if (sameRegs (AOP (right), AOP (result)))
7340 /* if they in different places then copy */
7341 size = AOP_SIZE (result);
7345 aopPut (AOP (result),
7346 aopGet (AOP (right), offset, FALSE),
7353 /* So we now know that the size of destination is greater
7354 than the size of the source */
7355 /* we move to result for the size of source */
7356 size = AOP_SIZE (right);
7360 aopPut (AOP (result),
7361 aopGet (AOP (right), offset, FALSE),
7366 /* now depending on the sign of the destination */
7367 size = AOP_SIZE (result) - AOP_SIZE (right);
7368 /* Unsigned or not an integral type - right fill with zeros */
7369 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7372 aopPut (AOP (result), "!zero", offset++);
7376 /* we need to extend the sign :{ */
7377 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7383 aopPut (AOP (result), "a", offset++);
7387 freeAsmop (right, NULL, ic);
7388 freeAsmop (result, NULL, ic);
7391 /*-----------------------------------------------------------------*/
7392 /* genReceive - generate code for a receive iCode */
7393 /*-----------------------------------------------------------------*/
7395 genReceive (iCode * ic)
7397 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7398 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7399 IS_TRUE_SYMOP (IC_RESULT (ic))))
7409 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7410 size = AOP_SIZE(IC_RESULT(ic));
7412 for (i = 0; i < size; i++) {
7413 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7417 freeAsmop (IC_RESULT (ic), NULL, ic);
7420 /*-----------------------------------------------------------------*/
7421 /* genDummyRead - generate code for dummy read of volatiles */
7422 /*-----------------------------------------------------------------*/
7424 genDummyRead (iCode * ic)
7430 if (op && IS_SYMOP (op))
7432 aopOp (op, ic, FALSE, FALSE);
7435 size = AOP_SIZE (op);
7440 _moveA (aopGet (AOP (op), offset, FALSE));
7444 freeAsmop (op, NULL, ic);
7448 if (op && IS_SYMOP (op))
7450 aopOp (op, ic, FALSE, FALSE);
7453 size = AOP_SIZE (op);
7458 _moveA (aopGet (AOP (op), offset, FALSE));
7462 freeAsmop (op, NULL, ic);
7466 /*-----------------------------------------------------------------*/
7467 /* genCritical - generate code for start of a critical sequence */
7468 /*-----------------------------------------------------------------*/
7470 genCritical (iCode *ic)
7472 symbol *tlbl = newiTempLabel (NULL);
7478 else if (IC_RESULT (ic))
7480 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7481 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7482 //get interrupt enable flag IFF2 into P/O
7486 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7487 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7488 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7489 emit2 ("!tlabeldef", (tlbl->key + 100));
7490 _G.lines.current->isLabel = 1;
7491 freeAsmop (IC_RESULT (ic), NULL, ic);
7495 //get interrupt enable flag IFF2 into P/O
7504 /*-----------------------------------------------------------------*/
7505 /* genEndCritical - generate code for end of a critical sequence */
7506 /*-----------------------------------------------------------------*/
7508 genEndCritical (iCode *ic)
7510 symbol *tlbl = newiTempLabel (NULL);
7516 else if (IC_RIGHT (ic))
7518 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7519 _toBoolean (IC_RIGHT (ic));
7520 //don't enable interrupts if they were off before
7521 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7523 emitLabel (tlbl->key + 100);
7524 freeAsmop (IC_RIGHT (ic), NULL, ic);
7530 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7531 //don't enable interrupts as they were off before
7532 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7534 emit2 ("!tlabeldef", (tlbl->key + 100));
7535 _G.lines.current->isLabel = 1;
7541 /** Maximum number of bytes to emit per line. */
7545 /** Context for the byte output chunker. */
7548 unsigned char buffer[DBEMIT_MAX_RUN];
7553 /** Flushes a byte chunker by writing out all in the buffer and
7557 _dbFlush(DBEMITCTX *self)
7564 sprintf(line, ".db 0x%02X", self->buffer[0]);
7566 for (i = 1; i < self->pos; i++)
7568 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7575 /** Write out another byte, buffering until a decent line is
7579 _dbEmit(DBEMITCTX *self, int c)
7581 if (self->pos == DBEMIT_MAX_RUN)
7585 self->buffer[self->pos++] = c;
7588 /** Context for a simple run length encoder. */
7592 unsigned char buffer[128];
7594 /** runLen may be equivalent to pos. */
7600 RLE_CHANGE_COST = 4,
7604 /** Flush the buffer of a run length encoder by writing out the run or
7605 data that it currently contains.
7608 _rleCommit(RLECTX *self)
7614 memset(&db, 0, sizeof(db));
7616 emit2(".db %u", self->pos);
7618 for (i = 0; i < self->pos; i++)
7620 _dbEmit(&db, self->buffer[i]);
7629 Can get either a run or a block of random stuff.
7630 Only want to change state if a good run comes in or a run ends.
7631 Detecting run end is easy.
7634 Say initial state is in run, len zero, last zero. Then if you get a
7635 few zeros then something else then a short run will be output.
7636 Seems OK. While in run mode, keep counting. While in random mode,
7637 keep a count of the run. If run hits margin, output all up to run,
7638 restart, enter run mode.
7641 /** Add another byte into the run length encoder, flushing as
7642 required. The run length encoder uses the Amiga IFF style, where
7643 a block is prefixed by its run length. A positive length means
7644 the next n bytes pass straight through. A negative length means
7645 that the next byte is repeated -n times. A zero terminates the
7649 _rleAppend(RLECTX *self, unsigned c)
7653 if (c != self->last)
7655 /* The run has stopped. See if it is worthwhile writing it out
7656 as a run. Note that the random data comes in as runs of
7659 if (self->runLen > RLE_CHANGE_COST)
7661 /* Yes, worthwhile. */
7662 /* Commit whatever was in the buffer. */
7664 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7668 /* Not worthwhile. Append to the end of the random list. */
7669 for (i = 0; i < self->runLen; i++)
7671 if (self->pos >= RLE_MAX_BLOCK)
7676 self->buffer[self->pos++] = self->last;
7684 if (self->runLen >= RLE_MAX_BLOCK)
7686 /* Commit whatever was in the buffer. */
7689 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7697 _rleFlush(RLECTX *self)
7699 _rleAppend(self, -1);
7706 /** genArrayInit - Special code for initialising an array with constant
7710 genArrayInit (iCode * ic)
7714 int elementSize = 0, eIndex, i;
7715 unsigned val, lastVal;
7719 memset(&rle, 0, sizeof(rle));
7721 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7723 _saveRegsForCall(ic, 0);
7725 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7726 emit2 ("call __initrleblock");
7728 type = operandType(IC_LEFT(ic));
7730 if (type && type->next)
7732 if (IS_SPEC(type->next) || IS_PTR(type->next))
7734 elementSize = getSize(type->next);
7736 else if (IS_ARRAY(type->next) && type->next->next)
7738 elementSize = getSize(type->next->next);
7742 printTypeChainRaw (type, NULL);
7743 wassertl (0, "Can't determine element size in genArrayInit.");
7748 wassertl (0, "Can't determine element size in genArrayInit.");
7751 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7753 iLoop = IC_ARRAYILIST(ic);
7754 lastVal = (unsigned)-1;
7756 /* Feed all the bytes into the run length encoder which will handle
7758 This works well for mixed char data, and for random int and long
7765 for (i = 0; i < ix; i++)
7767 for (eIndex = 0; eIndex < elementSize; eIndex++)
7769 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7770 _rleAppend(&rle, val);
7774 iLoop = iLoop->next;
7778 /* Mark the end of the run. */
7781 _restoreRegsAfterCall();
7785 freeAsmop (IC_LEFT(ic), NULL, ic);
7789 _swap (PAIR_ID one, PAIR_ID two)
7791 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7797 emit2 ("ld a,%s", _pairs[one].l);
7798 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7799 emit2 ("ld %s,a", _pairs[two].l);
7800 emit2 ("ld a,%s", _pairs[one].h);
7801 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7802 emit2 ("ld %s,a", _pairs[two].h);
7806 /* The problem is that we may have all three pairs used and they may
7807 be needed in a different order.
7812 hl = hl => unity, fine
7816 hl = hl hl = hl, swap de <=> bc
7824 hl = bc de = de, swap bc <=> hl
7832 hl = de bc = bc, swap hl <=> de
7837 * Any pair = pair are done last
7838 * Any pair = iTemp are done last
7839 * Any swaps can be done any time
7847 So how do we detect the cases?
7848 How about a 3x3 matrix?
7852 x x x x (Fourth for iTemp/other)
7854 First determin which mode to use by counting the number of unity and
7857 Two - Assign the pair first, then the rest
7858 One - Swap the two, then the rest
7862 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7864 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7866 PAIR_BC, PAIR_HL, PAIR_DE
7868 int i, j, nunity = 0;
7869 memset (ids, PAIR_INVALID, sizeof (ids));
7872 wassert (nparams == 3);
7874 /* First save everything that needs to be saved. */
7875 _saveRegsForCall (ic, 0);
7877 /* Loading HL first means that DE is always fine. */
7878 for (i = 0; i < nparams; i++)
7880 aopOp (pparams[i], ic, FALSE, FALSE);
7881 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7884 /* Count the number of unity or iTemp assigns. */
7885 for (i = 0; i < 3; i++)
7887 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7895 /* Any order, fall through. */
7897 else if (nunity == 2)
7899 /* One is assigned. Pull it out and assign. */
7900 for (i = 0; i < 3; i++)
7902 for (j = 0; j < NUM_PAIRS; j++)
7904 if (ids[dest[i]][j] == TRUE)
7906 /* Found it. See if it's the right one. */
7907 if (j == PAIR_INVALID || j == dest[i])
7913 fetchPair(dest[i], AOP (pparams[i]));
7920 else if (nunity == 1)
7922 /* Find the pairs to swap. */
7923 for (i = 0; i < 3; i++)
7925 for (j = 0; j < NUM_PAIRS; j++)
7927 if (ids[dest[i]][j] == TRUE)
7929 if (j == PAIR_INVALID || j == dest[i])
7944 int next = getPairId (AOP (pparams[0]));
7945 emit2 ("push %s", _pairs[next].name);
7947 if (next == dest[1])
7949 fetchPair (dest[1], AOP (pparams[1]));
7950 fetchPair (dest[2], AOP (pparams[2]));
7954 fetchPair (dest[2], AOP (pparams[2]));
7955 fetchPair (dest[1], AOP (pparams[1]));
7957 emit2 ("pop %s", _pairs[dest[0]].name);
7960 /* Finally pull out all of the iTemps */
7961 for (i = 0; i < 3; i++)
7963 if (ids[dest[i]][PAIR_INVALID] == 1)
7965 fetchPair (dest[i], AOP (pparams[i]));
7971 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7977 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7981 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7983 setupForBuiltin3 (ic, nParams, pparams);
7985 label = newiTempLabel(NULL);
7987 emitLabel (label->key);
7988 emit2 ("ld a,(hl)");
7991 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
7993 freeAsmop (from, NULL, ic->next);
7994 freeAsmop (to, NULL, ic);
7998 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8000 operand *from, *to, *count;
8003 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8008 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8010 setupForBuiltin3 (ic, nParams, pparams);
8014 freeAsmop (count, NULL, ic->next->next);
8015 freeAsmop (from, NULL, ic);
8017 _restoreRegsAfterCall();
8019 /* if we need assign a result value */
8020 if ((IS_ITEMP (IC_RESULT (ic)) &&
8021 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8022 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8023 IS_TRUE_SYMOP (IC_RESULT (ic)))
8025 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8026 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8027 freeAsmop (IC_RESULT (ic), NULL, ic);
8030 freeAsmop (to, NULL, ic->next);
8033 /*-----------------------------------------------------------------*/
8034 /* genBuiltIn - calls the appropriate function to generating code */
8035 /* for a built in function */
8036 /*-----------------------------------------------------------------*/
8037 static void genBuiltIn (iCode *ic)
8039 operand *bi_parms[MAX_BUILTIN_ARGS];
8044 /* get all the arguments for a built in function */
8045 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8047 /* which function is it */
8048 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8050 if (strcmp(bif->name,"__builtin_strcpy")==0)
8052 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8054 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8056 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8060 wassertl (0, "Unknown builtin function encountered");
8064 /*-----------------------------------------------------------------*/
8065 /* genZ80Code - generate code for Z80 based controllers */
8066 /*-----------------------------------------------------------------*/
8068 genZ80Code (iCode * lic)
8076 _fReturn = _gbz80_return;
8077 _fTmp = _gbz80_return;
8081 _fReturn = _z80_return;
8082 _fTmp = _z80_return;
8085 _G.lines.head = _G.lines.current = NULL;
8087 /* if debug information required */
8088 if (options.debug && currFunc)
8090 debugFile->writeFunction (currFunc, lic);
8093 for (ic = lic; ic; ic = ic->next)
8095 _G.current_iCode = ic;
8097 if (ic->lineno && cln != ic->lineno)
8101 debugFile->writeCLine (ic);
8103 if (!options.noCcodeInAsm)
8105 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8106 printCLine(ic->filename, ic->lineno));
8110 if (options.iCodeInAsm)
8112 emit2 (";ic:%d: %s", ic->key, printILine(ic));
8114 /* if the result is marked as
8115 spilt and rematerializable or code for
8116 this has already been generated then
8118 if (resultRemat (ic) || ic->generated)
8121 /* depending on the operation */
8125 emitDebug ("; genNot");
8130 emitDebug ("; genCpl");
8135 emitDebug ("; genUminus");
8140 emitDebug ("; genIpush");
8145 /* IPOP happens only when trying to restore a
8146 spilt live range, if there is an ifx statement
8147 following this pop then the if statement might
8148 be using some of the registers being popped which
8149 would destroy the contents of the register so
8150 we need to check for this condition and handle it */
8152 ic->next->op == IFX &&
8153 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8155 emitDebug ("; genIfx");
8156 genIfx (ic->next, ic);
8160 emitDebug ("; genIpop");
8166 emitDebug ("; genCall");
8171 emitDebug ("; genPcall");
8176 emitDebug ("; genFunction");
8181 emitDebug ("; genEndFunction");
8182 genEndFunction (ic);
8186 emitDebug ("; genRet");
8191 emitDebug ("; genLabel");
8196 emitDebug ("; genGoto");
8201 emitDebug ("; genPlus");
8206 emitDebug ("; genMinus");
8211 emitDebug ("; genMult");
8216 emitDebug ("; genDiv");
8221 emitDebug ("; genMod");
8226 emitDebug ("; genCmpGt");
8227 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8231 emitDebug ("; genCmpLt");
8232 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8239 /* note these two are xlated by algebraic equivalence
8240 during parsing SDCC.y */
8241 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8242 "got '>=' or '<=' shouldn't have come here");
8246 emitDebug ("; genCmpEq");
8247 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8251 emitDebug ("; genAndOp");
8256 emitDebug ("; genOrOp");
8261 emitDebug ("; genXor");
8262 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8266 emitDebug ("; genOr");
8267 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8271 emitDebug ("; genAnd");
8272 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8276 emitDebug ("; genInline");
8281 emitDebug ("; genRRC");
8286 emitDebug ("; genRLC");
8291 emitDebug ("; genGetHBIT");
8296 emitDebug ("; genLeftShift");
8301 emitDebug ("; genRightShift");
8305 case GET_VALUE_AT_ADDRESS:
8306 emitDebug ("; genPointerGet");
8312 if (POINTER_SET (ic))
8314 emitDebug ("; genAssign (pointer)");
8319 emitDebug ("; genAssign");
8325 emitDebug ("; genIfx");
8330 emitDebug ("; genAddrOf");
8335 emitDebug ("; genJumpTab");
8340 emitDebug ("; genCast");
8345 emitDebug ("; genReceive");
8350 if (ic->builtinSEND)
8352 emitDebug ("; genBuiltIn");
8357 emitDebug ("; addSet");
8358 addSet (&_G.sendSet, ic);
8363 emitDebug ("; genArrayInit");
8367 case DUMMY_READ_VOLATILE:
8368 emitDebug ("; genDummyRead");
8373 emitDebug ("; genCritical");
8378 emitDebug ("; genEndCritical");
8379 genEndCritical (ic);
8388 /* now we are ready to call the
8389 peep hole optimizer */
8390 if (!options.nopeep)
8391 peepHole (&_G.lines.head);
8393 /* This is unfortunate */
8394 /* now do the actual printing */
8396 FILE *fp = codeOutFile;
8397 if (isInHome () && codeOutFile == code->oFile)
8398 codeOutFile = home->oFile;
8399 printLine (_G.lines.head, codeOutFile);
8400 if (_G.flushStatics)
8403 _G.flushStatics = 0;
8408 freeTrace(&_G.lines.trace);
8409 freeTrace(&_G.trace.aops);
8415 _isPairUsed (iCode * ic, PAIR_ID pairId)
8421 if (bitVectBitValue (ic->rMask, D_IDX))
8423 if (bitVectBitValue (ic->rMask, E_IDX))
8433 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8436 value *val = aop->aopu.aop_lit;
8438 wassert (aop->type == AOP_LIT);
8439 wassert (!IS_FLOAT (val->type));
8441 v = (unsigned long) floatFromVal (val);
8449 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8450 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));