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;
419 emit2 (const char *szFormat,...)
423 va_start (ap, szFormat);
425 _vemit2 (szFormat, ap);
431 emitDebug (const char *szFormat,...)
437 va_start (ap, szFormat);
439 _vemit2 (szFormat, ap);
445 /*-----------------------------------------------------------------*/
446 /* z80_emitDebuggerSymbol - associate the current code location */
447 /* with a debugger symbol */
448 /*-----------------------------------------------------------------*/
450 z80_emitDebuggerSymbol (char * debugSym)
452 _G.lines.isDebug = 1;
453 emit2 ("%s !equ .", debugSym);
454 emit2 ("!global", debugSym);
455 _G.lines.isDebug = 0;
458 /*-----------------------------------------------------------------*/
459 /* emit2 - writes the code into a file : for now it is simple */
460 /*-----------------------------------------------------------------*/
462 _emit2 (const char *inst, const char *fmt,...)
465 char lb[INITIAL_INLINEASM];
472 sprintf (lb, "%s\t", inst);
473 vsprintf (lb + (strlen (lb)), fmt, ap);
476 vsprintf (lb, fmt, ap);
478 while (isspace (*lbp))
483 _G.lines.current = (_G.lines.current ?
484 connectLine (_G.lines.current, _newLineNode (lb)) :
485 (_G.lines.head = _newLineNode (lb)));
487 _G.lines.current->isInline = _G.lines.isInline;
488 _G.lines.current->ic = _G.current_iCode;
493 _emitMove(const char *to, const char *from)
495 if (STRCASECMP(to, from) != 0)
497 emit2("ld %s,%s", to, from);
502 // Could leave this to the peephole, but sometimes the peephole is inhibited.
507 aopDump(const char *plabel, asmop *aop)
513 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
518 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
521 for (i=aop->size-1;i>=0;i--)
522 *rbp++ = *(aop->aopu.aop_reg[i]->name);
524 emitDebug("; reg = %s", regbuf);
527 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
530 /* No information. */
536 _moveA(const char *moveFrom)
538 // Let the peephole optimiser take care of redundent loads
539 _emitMove(ACC_NAME, moveFrom);
549 getPairName (asmop * aop)
551 if (aop->type == AOP_REG)
553 switch (aop->aopu.aop_reg[0]->rIdx)
566 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
569 for (i = 0; i < NUM_PAIRS; i++)
571 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
573 return _pairs[i].name;
577 wassertl (0, "Tried to get the pair name of something that isn't a pair");
582 getPairId (asmop * aop)
586 if (aop->type == AOP_REG)
588 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
592 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
596 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
601 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
604 for (i = 0; i < NUM_PAIRS; i++)
606 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
616 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
620 return (getPairId (aop) != PAIR_INVALID);
623 /** Returns TRUE if the registers used in aop cannot be split into high
626 isUnsplitable (asmop * aop)
628 switch (getPairId (aop))
640 isPtrPair (asmop * aop)
642 PAIR_ID pairId = getPairId (aop);
655 spillPair (PAIR_ID pairId)
657 _G.pairs[pairId].last_type = AOP_INVALID;
658 _G.pairs[pairId].base = NULL;
661 /* Given a register name, spill the pair (if any) the register is part of */
663 spillPairReg (const char *regname)
665 if (strlen(regname)==1)
685 /** Push a register pair onto the stack */
687 genPairPush (asmop * aop)
689 emit2 ("push %s", getPairName (aop));
693 _push (PAIR_ID pairId)
695 emit2 ("push %s", _pairs[pairId].name);
696 _G.stack.pushed += 2;
700 _pop (PAIR_ID pairId)
702 emit2 ("pop %s", _pairs[pairId].name);
703 _G.stack.pushed -= 2;
708 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
721 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
728 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
729 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
732 wassertl (0, "Tried to move a nonphysical pair");
734 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
735 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
736 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
740 /*-----------------------------------------------------------------*/
741 /* newAsmop - creates a new asmOp */
742 /*-----------------------------------------------------------------*/
744 newAsmop (short type)
748 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
753 /*-----------------------------------------------------------------*/
754 /* aopForSym - for a true symbol */
755 /*-----------------------------------------------------------------*/
757 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
764 wassert (sym->etype);
766 space = SPEC_OCLS (sym->etype);
768 /* if already has one */
774 /* Assign depending on the storage class */
775 if (sym->onStack || sym->iaccess)
777 /* The pointer that is used depends on how big the offset is.
778 Normally everything is AOP_STK, but for offsets of < -128 or
779 > 127 on the Z80 an extended stack pointer is used.
781 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
783 emitDebug ("; AOP_EXSTK for %s", sym->rname);
784 sym->aop = aop = newAsmop (AOP_EXSTK);
788 emitDebug ("; AOP_STK for %s", sym->rname);
789 sym->aop = aop = newAsmop (AOP_STK);
792 aop->size = getSize (sym->type);
793 aop->aopu.aop_stk = sym->stack;
797 /* special case for a function */
798 if (IS_FUNC (sym->type))
800 sym->aop = aop = newAsmop (AOP_IMMD);
801 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
806 if( IN_REGSP( space ))
807 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
810 /* if it is in direct space */
813 sym->aop = aop = newAsmop (AOP_SFR);
814 aop->aopu.aop_dir = sym->rname;
815 aop->size = getSize (sym->type);
816 emitDebug ("; AOP_SFR for %s", sym->rname);
821 { /*.p.t.20030716 adding SFR support to the Z80 port */
822 aop = newAsmop (AOP_SFR);
824 aop->aopu.aop_dir = sym->rname;
825 aop->size = getSize( sym->type );
826 aop->paged = FUNC_REGBANK(sym->type);
827 aop->bcInUse = isPairInUse( PAIR_BC, ic );
828 aop->deInUse = isPairInUse( PAIR_DE, ic );
829 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
835 /* only remaining is far space */
836 /* in which case DPTR gets the address */
839 emitDebug ("; AOP_HL for %s", sym->rname);
840 sym->aop = aop = newAsmop (AOP_HL);
844 sym->aop = aop = newAsmop (AOP_IY);
846 aop->size = getSize (sym->type);
847 aop->aopu.aop_dir = sym->rname;
849 /* if it is in code space */
850 if (IN_CODESPACE (space))
856 /*-----------------------------------------------------------------*/
857 /* aopForRemat - rematerialzes an object */
858 /*-----------------------------------------------------------------*/
860 aopForRemat (symbol * sym)
863 iCode *ic = sym->rematiCode;
864 asmop *aop = newAsmop (AOP_IMMD);
868 /* if plus or minus print the right hand side */
869 if (ic->op == '+' || ic->op == '-')
871 /* PENDING: for re-target */
872 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
875 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
878 /* we reached the end */
879 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
883 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
887 /*-----------------------------------------------------------------*/
888 /* regsInCommon - two operands have some registers in common */
889 /*-----------------------------------------------------------------*/
891 regsInCommon (operand * op1, operand * op2)
896 /* if they have registers in common */
897 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
900 sym1 = OP_SYMBOL (op1);
901 sym2 = OP_SYMBOL (op2);
903 if (sym1->nRegs == 0 || sym2->nRegs == 0)
906 for (i = 0; i < sym1->nRegs; i++)
912 for (j = 0; j < sym2->nRegs; j++)
917 if (sym2->regs[j] == sym1->regs[i])
925 /*-----------------------------------------------------------------*/
926 /* operandsEqu - equivalent */
927 /*-----------------------------------------------------------------*/
929 operandsEqu (operand * op1, operand * op2)
933 /* if they not symbols */
934 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
937 sym1 = OP_SYMBOL (op1);
938 sym2 = OP_SYMBOL (op2);
940 /* if both are itemps & one is spilt
941 and the other is not then false */
942 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
943 sym1->isspilt != sym2->isspilt)
946 /* if they are the same */
950 if (sym1->rname[0] && sym2->rname[0]
951 && strcmp (sym1->rname, sym2->rname) == 0)
954 /* if left is a tmp & right is not */
955 if (IS_ITEMP (op1) &&
958 (sym1->usl.spillLoc == sym2))
961 if (IS_ITEMP (op2) &&
965 (sym2->usl.spillLoc == sym1))
971 /*-----------------------------------------------------------------*/
972 /* sameRegs - two asmops have the same registers */
973 /*-----------------------------------------------------------------*/
975 sameRegs (asmop * aop1, asmop * aop2)
979 if (aop1->type == AOP_SFR ||
980 aop2->type == AOP_SFR)
986 if (aop1->type != AOP_REG ||
987 aop2->type != AOP_REG)
990 if (aop1->size != aop2->size)
993 for (i = 0; i < aop1->size; i++)
994 if (aop1->aopu.aop_reg[i] !=
995 aop2->aopu.aop_reg[i])
1001 /*-----------------------------------------------------------------*/
1002 /* aopOp - allocates an asmop for an operand : */
1003 /*-----------------------------------------------------------------*/
1005 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1014 /* if this a literal */
1015 if (IS_OP_LITERAL (op))
1017 op->aop = aop = newAsmop (AOP_LIT);
1018 aop->aopu.aop_lit = op->operand.valOperand;
1019 aop->size = getSize (operandType (op));
1023 /* if already has a asmop then continue */
1026 if (op->aop->type == AOP_SFR)
1028 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1029 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1034 /* if the underlying symbol has a aop */
1035 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1037 op->aop = OP_SYMBOL (op)->aop;
1038 if (op->aop->type == AOP_SFR)
1040 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1041 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1046 /* if this is a true symbol */
1047 if (IS_TRUE_SYMOP (op))
1049 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1053 /* this is a temporary : this has
1059 e) can be a return use only */
1061 sym = OP_SYMBOL (op);
1063 /* if the type is a conditional */
1064 if (sym->regType == REG_CND)
1066 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1071 /* if it is spilt then two situations
1073 b) has a spill location */
1074 if (sym->isspilt || sym->nRegs == 0)
1076 /* rematerialize it NOW */
1079 sym->aop = op->aop = aop =
1081 aop->size = getSize (sym->type);
1088 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1089 aop->size = getSize (sym->type);
1090 for (i = 0; i < 4; i++)
1091 aop->aopu.aop_str[i] = _fReturn[i];
1097 if (sym->accuse == ACCUSE_A)
1099 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1100 aop->size = getSize (sym->type);
1101 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1103 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1105 else if (sym->accuse == ACCUSE_SCRATCH)
1107 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1108 aop->size = getSize (sym->type);
1109 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1110 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1111 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1113 else if (sym->accuse == ACCUSE_IY)
1115 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1116 aop->size = getSize (sym->type);
1117 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1118 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1119 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1123 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1128 if (sym->usl.spillLoc)
1130 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1132 /* force a new aop if sizes differ */
1133 sym->usl.spillLoc->aop = NULL;
1135 sym->aop = op->aop = aop =
1136 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1137 aop->size = getSize (sym->type);
1141 /* else must be a dummy iTemp */
1142 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1143 aop->size = getSize (sym->type);
1147 /* must be in a register */
1148 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1149 aop->size = sym->nRegs;
1150 for (i = 0; i < sym->nRegs; i++)
1151 aop->aopu.aop_reg[i] = sym->regs[i];
1154 /*-----------------------------------------------------------------*/
1155 /* freeAsmop - free up the asmop given to an operand */
1156 /*----------------------------------------------------------------*/
1158 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1175 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1177 _pop (aop->aopu.aop_pairId);
1180 if (getPairId (aop) == PAIR_HL)
1182 spillPair (PAIR_HL);
1186 /* all other cases just dealloc */
1192 OP_SYMBOL (op)->aop = NULL;
1193 /* if the symbol has a spill */
1195 SPIL_LOC (op)->aop = NULL;
1202 isLitWord (asmop * aop)
1204 /* if (aop->size != 2)
1217 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1219 /* depending on type */
1225 /* PENDING: for re-target */
1228 tsprintf (buffer, sizeof(buffer),
1229 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1231 else if (offset == 0)
1233 tsprintf (buffer, sizeof(buffer),
1234 "%s", aop->aopu.aop_immd);
1238 tsprintf (buffer, sizeof(buffer),
1239 "%s + %d", aop->aopu.aop_immd, offset);
1241 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1245 value *val = aop->aopu.aop_lit;
1246 /* if it is a float then it gets tricky */
1247 /* otherwise it is fairly simple */
1248 if (!IS_FLOAT (val->type))
1250 unsigned long v = (unsigned long) floatFromVal (val);
1256 else if (offset == 0)
1262 wassertl(0, "Encountered an invalid offset while fetching a literal");
1266 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1268 tsprintf (buffer, sizeof(buffer), "!constword", v);
1270 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1281 /* it is type float */
1282 fl.f = (float) floatFromVal (val);
1284 #ifdef WORDS_BIGENDIAN
1285 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1287 i = fl.c[offset] | (fl.c[offset+1]<<8);
1290 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1292 tsprintf (buffer, sizeof(buffer), "!constword", i);
1294 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1303 aopGetWord (asmop * aop, int offset)
1305 return aopGetLitWordLong (aop, offset, TRUE);
1309 isPtr (const char *s)
1311 if (!strcmp (s, "hl"))
1313 if (!strcmp (s, "ix"))
1315 if (!strcmp (s, "iy"))
1321 adjustPair (const char *pair, int *pold, int new)
1327 emit2 ("inc %s", pair);
1332 emit2 ("dec %s", pair);
1340 spillPair (PAIR_HL);
1341 spillPair (PAIR_IY);
1345 requiresHL (asmop * aop)
1361 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1363 const char *l, *base;
1364 const char *pair = _pairs[pairId].name;
1365 l = aopGetLitWordLong (left, offset, FALSE);
1366 base = aopGetLitWordLong (left, 0, FALSE);
1367 wassert (l && pair && base);
1371 if (pairId == PAIR_HL || pairId == PAIR_IY)
1373 if (_G.pairs[pairId].last_type == left->type)
1375 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1377 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1379 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1382 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1389 _G.pairs[pairId].last_type = left->type;
1390 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1391 _G.pairs[pairId].offset = offset;
1393 /* Both a lit on the right and a true symbol on the left */
1394 emit2 ("ld %s,!hashedstr", pair, l);
1398 makeFreePairId (iCode *ic, bool *pisUsed)
1404 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1408 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1426 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1428 /* if this is remateriazable */
1429 if (isLitWord (aop)) {
1430 fetchLitPair (pairId, aop, offset);
1434 if (getPairId (aop) == pairId)
1438 /* we need to get it byte by byte */
1439 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1440 aopGet (aop, offset, FALSE);
1441 switch (aop->size - offset) {
1443 emit2 ("ld l,!*hl");
1444 emit2 ("ld h,!immedbyte", 0);
1447 // PENDING: Requires that you are only fetching two bytes.
1450 emit2 ("ld h,!*hl");
1454 wassertl (0, "Attempted to fetch too much data into HL");
1458 else if (IS_Z80 && aop->type == AOP_IY) {
1459 /* Instead of fetching relative to IY, just grab directly
1460 from the address IY refers to */
1461 char *l = aopGetLitWordLong (aop, offset, FALSE);
1463 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1465 if (aop->size < 2) {
1466 emit2("ld %s,!zero", _pairs[pairId].h);
1469 else if (pairId == PAIR_IY)
1473 emit2 ("push %s", _pairs[getPairId(aop)].name);
1479 PAIR_ID id = makeFreePairId (ic, &isUsed);
1482 /* Can't load into parts, so load into HL then exchange. */
1483 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1484 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1485 emit2 ("push %s", _pairs[id].name);
1491 else if (isUnsplitable(aop))
1493 emit2("push %s", _pairs[getPairId(aop)].name);
1494 emit2("pop %s", _pairs[pairId].name);
1498 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1499 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1501 /* PENDING: check? */
1502 if (pairId == PAIR_HL)
1503 spillPair (PAIR_HL);
1508 fetchPair (PAIR_ID pairId, asmop * aop)
1510 fetchPairLong (pairId, aop, NULL, 0);
1514 fetchHL (asmop * aop)
1516 fetchPair (PAIR_HL, aop);
1520 setupPairFromSP (PAIR_ID id, int offset)
1522 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1524 if (_G.preserveCarry)
1530 if (offset < INT8MIN || offset > INT8MAX)
1532 emit2 ("ld hl,!immedword", offset);
1533 emit2 ("add hl,sp");
1537 emit2 ("!ldahlsp", offset);
1540 if (_G.preserveCarry)
1548 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1553 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1554 fetchLitPair (pairId, aop, 0);
1558 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1560 fetchLitPair (pairId, aop, offset);
1561 _G.pairs[pairId].offset = offset;
1565 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1566 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1569 int offset = aop->aopu.aop_stk + _G.stack.offset;
1571 if (_G.pairs[pairId].last_type == aop->type &&
1572 _G.pairs[pairId].offset == offset)
1578 /* PENDING: Do this better. */
1579 if (_G.preserveCarry)
1581 sprintf (buffer, "%d", offset + _G.stack.pushed);
1582 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1583 emit2 ("add %s,sp", _pairs[pairId].name);
1584 _G.pairs[pairId].last_type = aop->type;
1585 _G.pairs[pairId].offset = offset;
1586 if (_G.preserveCarry)
1594 /* Doesnt include _G.stack.pushed */
1595 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1597 if (aop->aopu.aop_stk > 0)
1599 abso += _G.stack.param_offset;
1601 assert (pairId == PAIR_HL);
1602 /* In some cases we can still inc or dec hl */
1603 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1605 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1609 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1611 _G.pairs[pairId].offset = abso;
1616 if (pairId != aop->aopu.aop_pairId)
1617 genMovePairPair(aop->aopu.aop_pairId, pairId);
1618 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1624 _G.pairs[pairId].last_type = aop->type;
1630 emit2 ("!tlabeldef", key);
1634 /*-----------------------------------------------------------------*/
1635 /* aopGet - for fetching value of the aop */
1636 /*-----------------------------------------------------------------*/
1638 aopGet (asmop * aop, int offset, bool bit16)
1640 // char *s = buffer;
1642 /* offset is greater than size then zero */
1643 /* PENDING: this seems a bit screwed in some pointer cases. */
1644 if (offset > (aop->size - 1) &&
1645 aop->type != AOP_LIT)
1647 tsprintf (buffer, sizeof(buffer), "!zero");
1648 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1651 /* depending on type */
1655 tsprintf (buffer, sizeof(buffer), "!zero");
1656 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1659 /* PENDING: re-target */
1661 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1666 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1669 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1672 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1675 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1678 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1682 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1683 SNPRINTF (buffer, sizeof(buffer), "a");
1685 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1691 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1692 SNPRINTF (buffer, sizeof(buffer), "a");
1694 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1697 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1700 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1701 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1702 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1704 else if( z80_opts.port_mode == 180 )
1705 { /* z180 in0/out0 mode */
1706 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1710 emit2( "in a,(%s)", aop->aopu.aop_dir );
1713 SNPRINTF (buffer, sizeof(buffer), "a");
1715 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1719 return aop->aopu.aop_reg[offset]->name;
1723 setupPair (PAIR_HL, aop, offset);
1724 tsprintf (buffer, sizeof(buffer), "!*hl");
1726 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1730 setupPair (PAIR_IY, aop, offset);
1731 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1733 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1737 setupPair (PAIR_IY, aop, offset);
1738 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1740 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1745 setupPair (PAIR_HL, aop, offset);
1746 tsprintf (buffer, sizeof(buffer), "!*hl");
1750 if (aop->aopu.aop_stk >= 0)
1751 offset += _G.stack.param_offset;
1752 tsprintf (buffer, sizeof(buffer),
1753 "!*ixx", aop->aopu.aop_stk + offset);
1756 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1759 wassertl (0, "Tried to fetch from a bit variable");
1768 tsprintf(buffer, sizeof(buffer), "!zero");
1769 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1773 wassert (offset < 2);
1774 return aop->aopu.aop_str[offset];
1777 return aopLiteral (aop->aopu.aop_lit, offset);
1781 unsigned long v = aop->aopu.aop_simplelit;
1784 tsprintf (buffer, sizeof(buffer),
1785 "!immedbyte", (unsigned int) v & 0xff);
1787 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1791 return aop->aopu.aop_str[offset];
1794 setupPair (aop->aopu.aop_pairId, aop, offset);
1795 if (aop->aopu.aop_pairId==PAIR_IX)
1796 SNPRINTF (buffer, sizeof(buffer),
1798 else if (aop->aopu.aop_pairId==PAIR_IY)
1799 SNPRINTF (buffer, sizeof(buffer),
1802 SNPRINTF (buffer, sizeof(buffer),
1803 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1805 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1810 wassertl (0, "aopget got unsupported aop->type");
1815 isRegString (const char *s)
1817 if (!strcmp (s, "b") ||
1829 isConstant (const char *s)
1831 /* This is a bit of a hack... */
1832 return (*s == '#' || *s == '$');
1836 canAssignToPtr (const char *s)
1838 if (isRegString (s))
1845 /*-----------------------------------------------------------------*/
1846 /* aopPut - puts a string for a aop */
1847 /*-----------------------------------------------------------------*/
1849 aopPut (asmop * aop, const char *s, int offset)
1853 if (aop->size && offset > (aop->size - 1))
1855 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1856 "aopPut got offset > aop->size");
1861 tsprintf(buffer2, sizeof(buffer2), s);
1864 /* will assign value to value */
1865 /* depending on where it is ofcourse */
1869 _moveA (s); /* in case s is volatile */
1875 if (strcmp (s, "a"))
1876 emit2 ("ld a,%s", s);
1877 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1884 if (strcmp (s, "a"))
1885 emit2 ("ld a,%s", s);
1886 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1889 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1892 if( aop->bcInUse ) emit2( "push bc" );
1894 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1896 if(( s[0] == '#' ) /* immediate number */
1897 ||( s[0] == '(' ) /* indirect register (ix or iy ??)*/
1898 ||( isdigit( s[0] )))/* indirect register with offset (ix or iy ??)*/
1900 emit2( "ld a,%s", s );
1901 emit2( "out (c),a" );
1905 emit2( "out (c),%s", s );
1911 spillPair (PAIR_BC);
1913 else if( z80_opts.port_mode == 180 )
1914 { /* z180 in0/out0 mode */
1915 emit2( "ld a,%s", s );
1916 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1920 emit2( "ld a,%s", s );
1921 emit2( "out (%s),a", aop->aopu.aop_dir );
1927 if (!strcmp (s, "!*hl"))
1928 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1931 aop->aopu.aop_reg[offset]->name, s);
1932 spillPairReg(aop->aopu.aop_reg[offset]->name);
1937 if (!canAssignToPtr (s))
1939 emit2 ("ld a,%s", s);
1940 setupPair (PAIR_IY, aop, offset);
1941 emit2 ("ld !*iyx,a", offset);
1945 setupPair (PAIR_IY, aop, offset);
1946 emit2 ("ld !*iyx,%s", offset, s);
1952 /* PENDING: for re-target */
1953 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1955 emit2 ("ld a,!*hl");
1958 setupPair (PAIR_HL, aop, offset);
1960 emit2 ("ld !*hl,%s", s);
1965 if (!canAssignToPtr (s))
1967 emit2 ("ld a,%s", s);
1968 setupPair (PAIR_IY, aop, offset);
1969 emit2 ("ld !*iyx,a", offset);
1973 setupPair (PAIR_IY, aop, offset);
1974 emit2 ("ld !*iyx,%s", offset, s);
1981 /* PENDING: re-target */
1982 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1984 emit2 ("ld a,!*hl");
1987 setupPair (PAIR_HL, aop, offset);
1988 if (!canAssignToPtr (s))
1990 emit2 ("ld a,%s", s);
1991 emit2 ("ld !*hl,a");
1994 emit2 ("ld !*hl,%s", s);
1998 if (aop->aopu.aop_stk >= 0)
1999 offset += _G.stack.param_offset;
2000 if (!canAssignToPtr (s))
2002 emit2 ("ld a,%s", s);
2003 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2007 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2013 /* if bit variable */
2014 if (!aop->aopu.aop_dir)
2016 emit2 ("ld a,!zero");
2021 /* In bit space but not in C - cant happen */
2022 wassertl (0, "Tried to write into a bit variable");
2028 if (strcmp (aop->aopu.aop_str[offset], s))
2030 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2032 spillPairReg(aop->aopu.aop_str[offset]);
2037 if (!offset && (strcmp (s, "acc") == 0))
2041 wassertl (0, "Tried to access past the end of A");
2045 if (strcmp (aop->aopu.aop_str[offset], s))
2047 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2048 spillPairReg(aop->aopu.aop_str[offset]);
2054 wassert (offset < 2);
2055 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2056 spillPairReg(aop->aopu.aop_str[offset]);
2060 setupPair (aop->aopu.aop_pairId, aop, offset);
2061 if (aop->aopu.aop_pairId==PAIR_IX)
2062 emit2 ("ld !*ixx,%s", 0, s);
2063 else if (aop->aopu.aop_pairId==PAIR_IY)
2064 emit2 ("ld !*ixy,%s", 0, s);
2066 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2070 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2071 "aopPut got unsupported aop->type");
2076 #define AOP(op) op->aop
2077 #define AOP_TYPE(op) AOP(op)->type
2078 #define AOP_SIZE(op) AOP(op)->size
2079 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2082 commitPair (asmop * aop, PAIR_ID id)
2084 /* PENDING: Verify this. */
2085 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2089 aopPut (aop, "a", 0);
2090 aopPut (aop, "d", 1);
2095 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2097 char *l = aopGetLitWordLong (aop, 0, FALSE);
2100 emit2 ("ld (%s),%s", l, _pairs[id].name);
2104 aopPut (aop, _pairs[id].l, 0);
2105 aopPut (aop, _pairs[id].h, 1);
2110 /*-----------------------------------------------------------------*/
2111 /* getDataSize - get the operand data size */
2112 /*-----------------------------------------------------------------*/
2114 getDataSize (operand * op)
2117 size = AOP_SIZE (op);
2121 wassertl (0, "Somehow got a three byte data pointer");
2126 /*-----------------------------------------------------------------*/
2127 /* movLeft2Result - move byte from left to result */
2128 /*-----------------------------------------------------------------*/
2130 movLeft2Result (operand * left, int offl,
2131 operand * result, int offr, int sign)
2135 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2137 l = aopGet (AOP (left), offl, FALSE);
2141 aopPut (AOP (result), l, offr);
2145 if (getDataSize (left) == offl + 1)
2147 emit2 ("ld a,%s", l);
2148 aopPut (AOP (result), "a", offr);
2155 movLeft2ResultLong (operand * left, int offl,
2156 operand * result, int offr, int sign,
2161 movLeft2Result (left, offl, result, offr, sign);
2165 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2166 wassertl (size == 2, "Only implemented for two bytes or one");
2168 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2170 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2171 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2173 spillPair (PAIR_HL);
2175 else if ( getPairId ( AOP (result)) == PAIR_IY)
2177 PAIR_ID id = getPairId (AOP (left));
2178 if (id != PAIR_INVALID)
2180 emit2("push %s", _pairs[id].name);
2191 movLeft2Result (left, offl, result, offr, sign);
2192 movLeft2Result (left, offl+1, result, offr+1, sign);
2197 /** Put Acc into a register set
2200 outAcc (operand * result)
2203 size = getDataSize (result);
2206 aopPut (AOP (result), "a", 0);
2209 /* unsigned or positive */
2212 aopPut (AOP (result), "!zero", offset++);
2217 /** Take the value in carry and put it into a register
2220 outBitCLong (operand * result, bool swap_sense)
2222 /* if the result is bit */
2223 if (AOP_TYPE (result) == AOP_CRY)
2225 wassertl (0, "Tried to write carry to a bit");
2229 emit2 ("ld a,!zero");
2232 emit2 ("xor a,!immedbyte", 1);
2238 outBitC (operand * result)
2240 outBitCLong (result, FALSE);
2243 /*-----------------------------------------------------------------*/
2244 /* toBoolean - emit code for orl a,operator(sizeop) */
2245 /*-----------------------------------------------------------------*/
2247 _toBoolean (operand * oper)
2249 int size = AOP_SIZE (oper);
2253 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2256 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2260 if (AOP (oper)->type != AOP_ACC)
2263 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2269 /*-----------------------------------------------------------------*/
2270 /* genNot - generate code for ! operation */
2271 /*-----------------------------------------------------------------*/
2276 /* assign asmOps to operand & result */
2277 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2278 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2280 /* if in bit space then a special case */
2281 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2283 wassertl (0, "Tried to negate a bit");
2286 _toBoolean (IC_LEFT (ic));
2291 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2292 emit2 ("sub a,!one");
2293 outBitC (IC_RESULT (ic));
2295 /* release the aops */
2296 freeAsmop (IC_LEFT (ic), NULL, ic);
2297 freeAsmop (IC_RESULT (ic), NULL, ic);
2300 /*-----------------------------------------------------------------*/
2301 /* genCpl - generate code for complement */
2302 /*-----------------------------------------------------------------*/
2310 /* assign asmOps to operand & result */
2311 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2312 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2314 /* if both are in bit space then
2316 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2317 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2319 wassertl (0, "Left and the result are in bit space");
2322 size = AOP_SIZE (IC_RESULT (ic));
2325 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2328 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2331 /* release the aops */
2332 freeAsmop (IC_LEFT (ic), NULL, ic);
2333 freeAsmop (IC_RESULT (ic), NULL, ic);
2337 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2344 store de into result
2349 store de into result
2351 const char *first = isAdd ? "add" : "sub";
2352 const char *later = isAdd ? "adc" : "sbc";
2354 wassertl (IS_GB, "Code is only relevent to the gbz80");
2355 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2357 fetchPair (PAIR_DE, left);
2360 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2363 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2366 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2367 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2369 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2370 aopGet (right, MSB24, FALSE);
2374 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2377 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2379 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2380 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2384 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2386 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2389 /*-----------------------------------------------------------------*/
2390 /* genUminusFloat - unary minus for floating points */
2391 /*-----------------------------------------------------------------*/
2393 genUminusFloat (operand * op, operand * result)
2395 int size, offset = 0;
2397 emitDebug("; genUminusFloat");
2399 /* for this we just need to flip the
2400 first bit then copy the rest in place */
2401 size = AOP_SIZE (op) - 1;
2403 _moveA(aopGet (AOP (op), MSB32, FALSE));
2405 emit2("xor a,!immedbyte", 0x80);
2406 aopPut (AOP (result), "a", MSB32);
2410 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2415 /*-----------------------------------------------------------------*/
2416 /* genUminus - unary minus code generation */
2417 /*-----------------------------------------------------------------*/
2419 genUminus (iCode * ic)
2422 sym_link *optype, *rtype;
2425 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2426 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2428 /* if both in bit space then special
2430 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2431 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2433 wassertl (0, "Left and right are in bit space");
2437 optype = operandType (IC_LEFT (ic));
2438 rtype = operandType (IC_RESULT (ic));
2440 /* if float then do float stuff */
2441 if (IS_FLOAT (optype))
2443 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2447 /* otherwise subtract from zero */
2448 size = AOP_SIZE (IC_LEFT (ic));
2450 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2452 /* Create a new asmop with value zero */
2453 asmop *azero = newAsmop (AOP_SIMPLELIT);
2454 azero->aopu.aop_simplelit = 0;
2456 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2464 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2465 emit2 ("ld a,!zero");
2466 emit2 ("sbc a,%s", l);
2467 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2470 /* if any remaining bytes in the result */
2471 /* we just need to propagate the sign */
2472 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2477 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2481 /* release the aops */
2482 freeAsmop (IC_LEFT (ic), NULL, ic);
2483 freeAsmop (IC_RESULT (ic), NULL, ic);
2486 /*-----------------------------------------------------------------*/
2487 /* assignResultValue - */
2488 /*-----------------------------------------------------------------*/
2490 assignResultValue (operand * oper)
2492 int size = AOP_SIZE (oper);
2495 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2496 topInA = requiresHL (AOP (oper));
2498 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2500 /* We do it the hard way here. */
2502 aopPut (AOP (oper), _fReturn[0], 0);
2503 aopPut (AOP (oper), _fReturn[1], 1);
2505 aopPut (AOP (oper), _fReturn[0], 2);
2506 aopPut (AOP (oper), _fReturn[1], 3);
2512 aopPut (AOP (oper), _fReturn[size], size);
2517 /** Simple restore that doesn't take into account what is used in the
2521 _restoreRegsAfterCall(void)
2523 if (_G.stack.pushedDE)
2526 _G.stack.pushedDE = FALSE;
2528 if (_G.stack.pushedBC)
2531 _G.stack.pushedBC = FALSE;
2533 _G.saves.saved = FALSE;
2537 _saveRegsForCall(iCode *ic, int sendSetSize)
2540 o Stack parameters are pushed before this function enters
2541 o DE and BC may be used in this function.
2542 o HL and DE may be used to return the result.
2543 o HL and DE may be used to send variables.
2544 o DE and BC may be used to store the result value.
2545 o HL may be used in computing the sent value of DE
2546 o The iPushes for other parameters occur before any addSets
2548 Logic: (to be run inside the first iPush or if none, before sending)
2549 o Compute if DE and/or BC are in use over the call
2550 o Compute if DE is used in the send set
2551 o Compute if DE and/or BC are used to hold the result value
2552 o If (DE is used, or in the send set) and is not used in the result, push.
2553 o If BC is used and is not in the result, push
2555 o If DE is used in the send set, fetch
2556 o If HL is used in the send set, fetch
2560 if (_G.saves.saved == FALSE) {
2561 bool deInUse, bcInUse;
2563 bool bcInRet = FALSE, deInRet = FALSE;
2566 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2567 z80_rUmaskForOp (IC_RESULT(ic)));
2569 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2570 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2572 deSending = (sendSetSize > 1);
2574 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2576 if (bcInUse && bcInRet == FALSE) {
2578 _G.stack.pushedBC = TRUE;
2580 if (deInUse && deInRet == FALSE) {
2582 _G.stack.pushedDE = TRUE;
2585 _G.saves.saved = TRUE;
2588 /* Already saved. */
2592 /*-----------------------------------------------------------------*/
2593 /* genIpush - genrate code for pushing this gets a little complex */
2594 /*-----------------------------------------------------------------*/
2596 genIpush (iCode * ic)
2598 int size, offset = 0;
2601 /* if this is not a parm push : ie. it is spill push
2602 and spill push is always done on the local stack */
2605 wassertl(0, "Encountered an unsupported spill push.");
2609 if (_G.saves.saved == FALSE) {
2610 /* Caller saves, and this is the first iPush. */
2611 /* Scan ahead until we find the function that we are pushing parameters to.
2612 Count the number of addSets on the way to figure out what registers
2613 are used in the send set.
2616 iCode *walk = ic->next;
2619 if (walk->op == SEND) {
2622 else if (walk->op == CALL || walk->op == PCALL) {
2631 _saveRegsForCall(walk, nAddSets);
2634 /* Already saved by another iPush. */
2637 /* then do the push */
2638 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2640 size = AOP_SIZE (IC_LEFT (ic));
2642 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2644 _G.stack.pushed += 2;
2645 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2651 fetchHL (AOP (IC_LEFT (ic)));
2653 spillPair (PAIR_HL);
2654 _G.stack.pushed += 2;
2659 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2661 spillPair (PAIR_HL);
2662 _G.stack.pushed += 2;
2663 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2665 spillPair (PAIR_HL);
2666 _G.stack.pushed += 2;
2672 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2674 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2676 emit2 ("ld a,(%s)", l);
2680 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2681 emit2 ("ld a,%s", l);
2689 freeAsmop (IC_LEFT (ic), NULL, ic);
2692 /*-----------------------------------------------------------------*/
2693 /* genIpop - recover the registers: can happen only for spilling */
2694 /*-----------------------------------------------------------------*/
2696 genIpop (iCode * ic)
2701 /* if the temp was not pushed then */
2702 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2705 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2706 size = AOP_SIZE (IC_LEFT (ic));
2707 offset = (size - 1);
2708 if (isPair (AOP (IC_LEFT (ic))))
2710 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2718 spillPair (PAIR_HL);
2719 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2723 freeAsmop (IC_LEFT (ic), NULL, ic);
2726 /* This is quite unfortunate */
2728 setArea (int inHome)
2731 static int lastArea = 0;
2733 if (_G.in_home != inHome) {
2735 const char *sz = port->mem.code_name;
2736 port->mem.code_name = "HOME";
2737 emit2("!area", CODE_NAME);
2738 port->mem.code_name = sz;
2741 emit2("!area", CODE_NAME); */
2742 _G.in_home = inHome;
2753 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2757 symbol *sym = OP_SYMBOL (op);
2759 if (sym->isspilt || sym->nRegs == 0)
2762 aopOp (op, ic, FALSE, FALSE);
2765 if (aop->type == AOP_REG)
2768 for (i = 0; i < aop->size; i++)
2770 if (pairId == PAIR_DE)
2772 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2773 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2775 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2778 else if (pairId == PAIR_BC)
2780 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2781 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2783 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2793 freeAsmop (IC_LEFT (ic), NULL, ic);
2797 /** Emit the code for a call statement
2800 emitCall (iCode * ic, bool ispcall)
2802 bool bInRet, cInRet, dInRet, eInRet;
2803 sym_link *dtype = operandType (IC_LEFT (ic));
2805 /* if caller saves & we have not saved then */
2811 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2813 /* if send set is not empty then assign */
2818 int nSend = elementsInSet(_G.sendSet);
2819 bool swapped = FALSE;
2821 int _z80_sendOrder[] = {
2826 /* Check if the parameters are swapped. If so route through hl instead. */
2827 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2829 sic = setFirstItem(_G.sendSet);
2830 sic = setNextItem(_G.sendSet);
2832 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2833 /* The second send value is loaded from one the one that holds the first
2834 send, i.e. it is overwritten. */
2835 /* Cache the first in HL, and load the second from HL instead. */
2836 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2837 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2843 for (sic = setFirstItem (_G.sendSet); sic;
2844 sic = setNextItem (_G.sendSet))
2847 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2849 size = AOP_SIZE (IC_LEFT (sic));
2850 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2851 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2853 // PENDING: Mild hack
2854 if (swapped == TRUE && send == 1) {
2856 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2859 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2861 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2864 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2868 freeAsmop (IC_LEFT (sic), NULL, sic);
2875 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2877 werror (W_INDIR_BANKED);
2879 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2881 if (isLitWord (AOP (IC_LEFT (ic))))
2883 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2887 symbol *rlbl = newiTempLabel (NULL);
2888 spillPair (PAIR_HL);
2889 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2891 _G.stack.pushed += 2;
2893 fetchHL (AOP (IC_LEFT (ic)));
2895 emit2 ("!tlabeldef", (rlbl->key + 100));
2896 _G.stack.pushed -= 2;
2898 freeAsmop (IC_LEFT (ic), NULL, ic);
2902 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2903 OP_SYMBOL (IC_LEFT (ic))->rname :
2904 OP_SYMBOL (IC_LEFT (ic))->name;
2905 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2907 emit2 ("call banked_call");
2908 emit2 ("!dws", name);
2909 emit2 ("!dw !bankimmeds", name);
2914 emit2 ("call %s", name);
2919 /* Mark the regsiters as restored. */
2920 _G.saves.saved = FALSE;
2922 /* if we need assign a result value */
2923 if ((IS_ITEMP (IC_RESULT (ic)) &&
2924 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2925 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2926 IS_TRUE_SYMOP (IC_RESULT (ic)))
2929 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2931 assignResultValue (IC_RESULT (ic));
2933 freeAsmop (IC_RESULT (ic), NULL, ic);
2936 /* adjust the stack for parameters if required */
2939 int i = ic->parmBytes;
2941 _G.stack.pushed -= i;
2944 emit2 ("!ldaspsp", i);
2951 emit2 ("ld iy,!immedword", i);
2952 emit2 ("add iy,sp");
2973 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2974 bInRet = bitVectBitValue(result, B_IDX);
2975 cInRet = bitVectBitValue(result, C_IDX);
2976 dInRet = bitVectBitValue(result, D_IDX);
2977 eInRet = bitVectBitValue(result, E_IDX);
2987 if (_G.stack.pushedDE)
2989 if (dInRet && eInRet)
2991 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2995 /* Only restore E */
3002 /* Only restore D */
3010 _G.stack.pushedDE = FALSE;
3013 if (_G.stack.pushedBC)
3015 if (bInRet && cInRet)
3017 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3021 /* Only restore C */
3028 /* Only restore B */
3036 _G.stack.pushedBC = FALSE;
3040 /*-----------------------------------------------------------------*/
3041 /* genCall - generates a call statement */
3042 /*-----------------------------------------------------------------*/
3044 genCall (iCode * ic)
3046 emitCall (ic, FALSE);
3049 /*-----------------------------------------------------------------*/
3050 /* genPcall - generates a call by pointer statement */
3051 /*-----------------------------------------------------------------*/
3053 genPcall (iCode * ic)
3055 emitCall (ic, TRUE);
3058 /*-----------------------------------------------------------------*/
3059 /* resultRemat - result is rematerializable */
3060 /*-----------------------------------------------------------------*/
3062 resultRemat (iCode * ic)
3064 if (SKIP_IC (ic) || ic->op == IFX)
3067 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3069 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3070 if (sym->remat && !POINTER_SET (ic))
3077 extern set *publics;
3079 /*-----------------------------------------------------------------*/
3080 /* genFunction - generated code for function entry */
3081 /*-----------------------------------------------------------------*/
3083 genFunction (iCode * ic)
3087 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3090 bool bcInUse = FALSE;
3091 bool deInUse = FALSE;
3093 setArea (IFFUNC_NONBANKED (sym->type));
3095 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
3098 _G.receiveOffset = 0;
3100 /* Record the last function name for debugging. */
3101 _G.lastFunctionName = sym->rname;
3103 /* Create the function header */
3104 emit2 ("!functionheader", sym->name);
3105 if (!IS_STATIC(sym->etype))
3107 sprintf (buffer, "%s_start", sym->rname);
3108 emit2 ("!labeldef", buffer);
3110 emit2 ("!functionlabeldef", sym->rname);
3112 if (options.profile)
3114 emit2 ("!profileenter");
3117 ftype = operandType (IC_LEFT (ic));
3119 /* if this is an interrupt service routine then save all potentially used registers. */
3120 if (IFFUNC_ISISR (sym->type))
3122 if (!FUNC_ISNAKED( sym->type ))
3129 /* if critical function then turn interrupts off */
3130 if (IFFUNC_ISCRITICAL (sym->type))
3136 /* PENDING: callee-save etc */
3138 _G.stack.param_offset = 0;
3140 if (z80_opts.calleeSavesBC)
3145 /* Detect which registers are used. */
3146 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3149 for (i = 0; i < sym->regsUsed->size; i++)
3151 if (bitVectBitValue (sym->regsUsed, i))
3165 /* Other systems use DE as a temporary. */
3176 _G.stack.param_offset += 2;
3179 _G.calleeSaves.pushedBC = bcInUse;
3184 _G.stack.param_offset += 2;
3187 _G.calleeSaves.pushedDE = deInUse;
3189 /* adjust the stack for the function */
3190 _G.stack.last = sym->stack;
3193 for (sym = setFirstItem (istack->syms); sym;
3194 sym = setNextItem (istack->syms))
3196 if (sym->_isparm && !IS_REGPARM (sym->etype))
3202 sym = OP_SYMBOL (IC_LEFT (ic));
3204 _G.omitFramePtr = options.ommitFramePtr;
3205 if (IS_Z80 && !stackParm && !sym->stack)
3207 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3208 /* the above !sym->stack condition can be removed. -- EEP */
3210 emit2 ("!ldaspsp", -sym->stack);
3211 _G.omitFramePtr = TRUE;
3213 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3214 emit2 ("!enterxl", sym->stack);
3215 else if (sym->stack)
3216 emit2 ("!enterx", sym->stack);
3217 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3220 _G.stack.offset = sym->stack;
3223 /*-----------------------------------------------------------------*/
3224 /* genEndFunction - generates epilogue for functions */
3225 /*-----------------------------------------------------------------*/
3227 genEndFunction (iCode * ic)
3229 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3232 /* PENDING: calleeSave */
3233 if (IS_Z80 && _G.omitFramePtr)
3235 if (_G.stack.offset)
3236 emit2 ("!ldaspsp", _G.stack.offset);
3238 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3240 emit2 ("!leavexl", _G.stack.offset);
3242 else if (_G.stack.offset)
3244 emit2 ("!leavex", _G.stack.offset);
3246 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3251 if (_G.calleeSaves.pushedDE)
3254 _G.calleeSaves.pushedDE = FALSE;
3257 if (_G.calleeSaves.pushedBC)
3260 _G.calleeSaves.pushedBC = FALSE;
3263 if (options.profile)
3265 emit2 ("!profileexit");
3268 /* if this is an interrupt service routine then restore all potentially used registers. */
3269 if (IFFUNC_ISISR (sym->type))
3271 if (!FUNC_ISNAKED( sym->type ))
3278 /* if critical function then turn interrupts back on */
3279 if (IFFUNC_ISCRITICAL (sym->type))
3283 if (options.debug && currFunc)
3285 debugFile->writeEndFunction (currFunc, ic, 1);
3288 if (IFFUNC_ISISR (sym->type))
3290 /* "critical interrupt" is used to imply NMI handler */
3291 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type))
3298 /* Both banked and non-banked just ret */
3302 if (!IS_STATIC(sym->etype))
3304 sprintf (buffer, "%s_end", sym->rname);
3305 emit2 ("!labeldef", buffer);
3308 _G.flushStatics = 1;
3309 _G.stack.pushed = 0;
3310 _G.stack.offset = 0;
3313 /*-----------------------------------------------------------------*/
3314 /* genRet - generate code for return statement */
3315 /*-----------------------------------------------------------------*/
3320 /* Errk. This is a hack until I can figure out how
3321 to cause dehl to spill on a call */
3322 int size, offset = 0;
3324 /* if we have no return value then
3325 just generate the "ret" */
3329 /* we have something to return then
3330 move the return value into place */
3331 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3332 size = AOP_SIZE (IC_LEFT (ic));
3334 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3337 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3341 emit2 ("ld de,%s", l);
3345 emit2 ("ld hl,%s", l);
3351 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3355 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3357 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3358 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3364 l = aopGet (AOP (IC_LEFT (ic)), offset,
3366 if (strcmp (_fReturn[offset], l))
3367 emit2 ("ld %s,%s", _fReturn[offset], l);
3372 freeAsmop (IC_LEFT (ic), NULL, ic);
3375 /* generate a jump to the return label
3376 if the next is not the return statement */
3377 if (!(ic->next && ic->next->op == LABEL &&
3378 IC_LABEL (ic->next) == returnLabel))
3380 emit2 ("jp !tlabel", returnLabel->key + 100);
3383 /*-----------------------------------------------------------------*/
3384 /* genLabel - generates a label */
3385 /*-----------------------------------------------------------------*/
3387 genLabel (iCode * ic)
3389 /* special case never generate */
3390 if (IC_LABEL (ic) == entryLabel)
3393 emitLabel (IC_LABEL (ic)->key + 100);
3396 /*-----------------------------------------------------------------*/
3397 /* genGoto - generates a ljmp */
3398 /*-----------------------------------------------------------------*/
3400 genGoto (iCode * ic)
3402 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3405 /*-----------------------------------------------------------------*/
3406 /* genPlusIncr :- does addition with increment if possible */
3407 /*-----------------------------------------------------------------*/
3409 genPlusIncr (iCode * ic)
3411 unsigned int icount;
3412 unsigned int size = getDataSize (IC_RESULT (ic));
3413 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3415 /* will try to generate an increment */
3416 /* if the right side is not a literal
3418 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3421 emitDebug ("; genPlusIncr");
3423 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3425 /* If result is a pair */
3426 if (resultId != PAIR_INVALID)
3428 if (isLitWord (AOP (IC_LEFT (ic))))
3430 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3433 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3435 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3437 PAIR_ID freep = getFreePairId (ic);
3438 if (freep != PAIR_INVALID)
3440 fetchPair (freep, AOP (IC_RIGHT (ic)));
3441 emit2 ("add hl,%s", _pairs[freep].name);
3447 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3448 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3455 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3459 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3463 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3468 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3470 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3471 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3475 /* if the literal value of the right hand side
3476 is greater than 4 then it is not worth it */
3480 /* if increment 16 bits in register */
3481 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3487 symbol *tlbl = NULL;
3488 tlbl = newiTempLabel (NULL);
3491 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3494 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3497 emitLabel (tlbl->key + 100);
3501 /* if the sizes are greater than 1 then we cannot */
3502 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3503 AOP_SIZE (IC_LEFT (ic)) > 1)
3506 /* If the result is in a register then we can load then increment.
3508 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3510 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3513 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3518 /* we can if the aops of the left & result match or
3519 if they are in registers and the registers are the
3521 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3525 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3533 /*-----------------------------------------------------------------*/
3534 /* outBitAcc - output a bit in acc */
3535 /*-----------------------------------------------------------------*/
3537 outBitAcc (operand * result)
3539 symbol *tlbl = newiTempLabel (NULL);
3540 /* if the result is a bit */
3541 if (AOP_TYPE (result) == AOP_CRY)
3543 wassertl (0, "Tried to write A into a bit");
3547 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3548 emit2 ("ld a,!one");
3549 emitLabel (tlbl->key + 100);
3555 couldDestroyCarry (asmop *aop)
3559 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3568 shiftIntoPair (int idx, asmop *aop)
3570 PAIR_ID id = PAIR_INVALID;
3572 wassertl (IS_Z80, "Only implemented for the Z80");
3573 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3585 wassertl (0, "Internal error - hit default case");
3588 emitDebug ("; Shift into pair idx %u", idx);
3592 setupPair (PAIR_HL, aop, 0);
3596 setupPair (PAIR_IY, aop, 0);
3598 emit2 ("pop %s", _pairs[id].name);
3601 aop->type = AOP_PAIRPTR;
3602 aop->aopu.aop_pairId = id;
3603 _G.pairs[id].offset = 0;
3604 _G.pairs[id].last_type = aop->type;
3608 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3610 wassert (left && right);
3614 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3616 shiftIntoPair (0, right);
3617 /* check result again, in case right == result */
3618 if (couldDestroyCarry (result))
3619 shiftIntoPair (1, result);
3621 else if (couldDestroyCarry (right))
3623 if (getPairId (result) == PAIR_HL)
3624 _G.preserveCarry = TRUE;
3626 shiftIntoPair (0, right);
3628 else if (couldDestroyCarry (result))
3630 shiftIntoPair (0, result);
3639 /*-----------------------------------------------------------------*/
3640 /* genPlus - generates code for addition */
3641 /*-----------------------------------------------------------------*/
3643 genPlus (iCode * ic)
3645 int size, offset = 0;
3647 /* special cases :- */
3649 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3650 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3651 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3653 /* Swap the left and right operands if:
3655 if literal, literal on the right or
3656 if left requires ACC or right is already
3659 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3660 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3661 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3663 operand *t = IC_RIGHT (ic);
3664 IC_RIGHT (ic) = IC_LEFT (ic);
3668 /* if both left & right are in bit
3670 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3671 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3674 wassertl (0, "Tried to add two bits");
3677 /* if left in bit space & right literal */
3678 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3679 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3681 /* Can happen I guess */
3682 wassertl (0, "Tried to add a bit to a literal");
3685 /* if I can do an increment instead
3686 of add then GOOD for ME */
3687 if (genPlusIncr (ic) == TRUE)
3690 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3692 size = getDataSize (IC_RESULT (ic));
3694 /* Special case when left and right are constant */
3695 if (isPair (AOP (IC_RESULT (ic))))
3698 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3699 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3701 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3707 sprintf (buffer, "#(%s + %s)", left, right);
3708 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3713 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3715 /* Fetch into HL then do the add */
3716 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3717 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3719 spillPair (PAIR_HL);
3721 if (left == PAIR_HL && right != PAIR_INVALID)
3723 emit2 ("add hl,%s", _pairs[right].name);
3726 else if (right == PAIR_HL && left != PAIR_INVALID)
3728 emit2 ("add hl,%s", _pairs[left].name);
3731 else if (right != PAIR_INVALID && right != PAIR_HL)
3733 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3734 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3737 else if (left != PAIR_INVALID && left != PAIR_HL)
3739 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3740 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3749 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3751 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3752 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3754 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3759 ld hl,sp+n trashes C so we cant afford to do it during an
3760 add with stack based varibles. Worst case is:
3773 So you cant afford to load up hl if either left, right, or result
3774 is on the stack (*sigh*) The alt is:
3782 Combinations in here are:
3783 * If left or right are in bc then the loss is small - trap later
3784 * If the result is in bc then the loss is also small
3788 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3789 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3790 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3792 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3793 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3794 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3795 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3797 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3799 /* Swap left and right */
3800 operand *t = IC_RIGHT (ic);
3801 IC_RIGHT (ic) = IC_LEFT (ic);
3804 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3806 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3807 emit2 ("add hl,bc");
3811 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3812 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3813 emit2 ("add hl,de");
3815 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3821 /* Be paranoid on the GB with 4 byte variables due to how C
3822 can be trashed by lda hl,n(sp).
3824 _gbz80_emitAddSubLong (ic, TRUE);
3829 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3833 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3835 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3838 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3841 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3845 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3848 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3851 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3853 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3857 _G.preserveCarry = FALSE;
3858 freeAsmop (IC_LEFT (ic), NULL, ic);
3859 freeAsmop (IC_RIGHT (ic), NULL, ic);
3860 freeAsmop (IC_RESULT (ic), NULL, ic);
3864 /*-----------------------------------------------------------------*/
3865 /* genMinusDec :- does subtraction with deccrement if possible */
3866 /*-----------------------------------------------------------------*/
3868 genMinusDec (iCode * ic)
3870 unsigned int icount;
3871 unsigned int size = getDataSize (IC_RESULT (ic));
3873 /* will try to generate an increment */
3874 /* if the right side is not a literal we cannot */
3875 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3878 /* if the literal value of the right hand side
3879 is greater than 4 then it is not worth it */
3880 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3883 size = getDataSize (IC_RESULT (ic));
3885 /* if decrement 16 bits in register */
3886 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3887 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3890 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3894 /* If result is a pair */
3895 if (isPair (AOP (IC_RESULT (ic))))
3897 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3899 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3903 /* if increment 16 bits in register */
3904 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3908 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3911 emit2 ("dec %s", _getTempPairName());
3914 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3920 /* if the sizes are greater than 1 then we cannot */
3921 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3922 AOP_SIZE (IC_LEFT (ic)) > 1)
3925 /* we can if the aops of the left & result match or if they are in
3926 registers and the registers are the same */
3927 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3930 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3937 /*-----------------------------------------------------------------*/
3938 /* genMinus - generates code for subtraction */
3939 /*-----------------------------------------------------------------*/
3941 genMinus (iCode * ic)
3943 int size, offset = 0;
3944 unsigned long lit = 0L;
3946 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3947 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3948 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3950 /* special cases :- */
3951 /* if both left & right are in bit space */
3952 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3953 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3955 wassertl (0, "Tried to subtract two bits");
3959 /* if I can do an decrement instead of subtract then GOOD for ME */
3960 if (genMinusDec (ic) == TRUE)
3963 size = getDataSize (IC_RESULT (ic));
3965 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3970 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3974 /* Same logic as genPlus */
3977 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3978 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3979 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3981 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3982 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3983 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3984 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3986 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3987 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3989 if (left == PAIR_INVALID && right == PAIR_INVALID)
3994 else if (right == PAIR_INVALID)
3996 else if (left == PAIR_INVALID)
3999 fetchPair (left, AOP (IC_LEFT (ic)));
4000 /* Order is important. Right may be HL */
4001 fetchPair (right, AOP (IC_RIGHT (ic)));
4003 emit2 ("ld a,%s", _pairs[left].l);
4004 emit2 ("sub a,%s", _pairs[right].l);
4006 emit2 ("ld a,%s", _pairs[left].h);
4007 emit2 ("sbc a,%s", _pairs[right].h);
4009 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4011 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4013 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4019 /* Be paranoid on the GB with 4 byte variables due to how C
4020 can be trashed by lda hl,n(sp).
4022 _gbz80_emitAddSubLong (ic, FALSE);
4027 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
4029 /* if literal, add a,#-lit, else normal subb */
4032 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4033 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4037 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4040 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4044 /* first add without previous c */
4046 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4048 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4050 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4053 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4054 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4055 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4057 wassertl (0, "Tried to subtract on a long pointer");
4061 _G.preserveCarry = FALSE;
4062 freeAsmop (IC_LEFT (ic), NULL, ic);
4063 freeAsmop (IC_RIGHT (ic), NULL, ic);
4064 freeAsmop (IC_RESULT (ic), NULL, ic);
4067 /*-----------------------------------------------------------------*/
4068 /* genMult - generates code for multiplication */
4069 /*-----------------------------------------------------------------*/
4071 genMult (iCode * ic)
4075 /* If true then the final operation should be a subtract */
4076 bool active = FALSE;
4079 /* Shouldn't occur - all done through function calls */
4080 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4081 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4082 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4084 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4086 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4087 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4088 AOP_SIZE (IC_RESULT (ic)) > 2)
4090 wassertl (0, "Multiplication is handled through support function calls");
4093 /* Swap left and right such that right is a literal */
4094 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4096 operand *t = IC_RIGHT (ic);
4097 IC_RIGHT (ic) = IC_LEFT (ic);
4101 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4103 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4104 // wassertl (val > 0, "Multiply must be positive");
4105 wassertl (val != 1, "Can't multiply by 1");
4107 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4109 _G.stack.pushedDE = TRUE;
4112 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4114 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4125 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4130 /* Fully unroled version of mul.s. Not the most efficient.
4132 for (count = 0; count < 16; count++)
4134 if (count != 0 && active)
4136 emit2 ("add hl,hl");
4140 if (active == FALSE)
4148 emit2 ("add hl,de");
4157 if (IS_Z80 && _G.stack.pushedDE)
4160 _G.stack.pushedDE = FALSE;
4164 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4166 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4168 freeAsmop (IC_LEFT (ic), NULL, ic);
4169 freeAsmop (IC_RIGHT (ic), NULL, ic);
4170 freeAsmop (IC_RESULT (ic), NULL, ic);
4173 /*-----------------------------------------------------------------*/
4174 /* genDiv - generates code for division */
4175 /*-----------------------------------------------------------------*/
4179 /* Shouldn't occur - all done through function calls */
4180 wassertl (0, "Division is handled through support function calls");
4183 /*-----------------------------------------------------------------*/
4184 /* genMod - generates code for division */
4185 /*-----------------------------------------------------------------*/
4189 /* Shouldn't occur - all done through function calls */
4193 /*-----------------------------------------------------------------*/
4194 /* genIfxJump :- will create a jump depending on the ifx */
4195 /*-----------------------------------------------------------------*/
4197 genIfxJump (iCode * ic, char *jval)
4202 /* if true label then we jump if condition
4206 jlbl = IC_TRUE (ic);
4207 if (!strcmp (jval, "a"))
4211 else if (!strcmp (jval, "c"))
4215 else if (!strcmp (jval, "nc"))
4219 else if (!strcmp (jval, "m"))
4223 else if (!strcmp (jval, "p"))
4229 /* The buffer contains the bit on A that we should test */
4235 /* false label is present */
4236 jlbl = IC_FALSE (ic);
4237 if (!strcmp (jval, "a"))
4241 else if (!strcmp (jval, "c"))
4245 else if (!strcmp (jval, "nc"))
4249 else if (!strcmp (jval, "m"))
4253 else if (!strcmp (jval, "p"))
4259 /* The buffer contains the bit on A that we should test */
4263 /* Z80 can do a conditional long jump */
4264 if (!strcmp (jval, "a"))
4268 else if (!strcmp (jval, "c"))
4271 else if (!strcmp (jval, "nc"))
4274 else if (!strcmp (jval, "m"))
4277 else if (!strcmp (jval, "p"))
4282 emit2 ("bit %s,a", jval);
4284 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4286 /* mark the icode as generated */
4292 _getPairIdName (PAIR_ID id)
4294 return _pairs[id].name;
4299 /* if unsigned char cmp with lit, just compare */
4301 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4303 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4306 emit2 ("xor a,!immedbyte", 0x80);
4307 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4310 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4312 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4314 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4315 // Pull left into DE and right into HL
4316 aopGet (AOP(left), LSB, FALSE);
4319 aopGet (AOP(right), LSB, FALSE);
4323 if (size == 0 && sign)
4325 // Highest byte when signed needs the bits flipped
4328 emit2 ("ld a,(de)");
4329 emit2 ("xor !immedbyte", 0x80);
4331 emit2 ("ld a,(hl)");
4332 emit2 ("xor !immedbyte", 0x80);
4336 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4340 emit2 ("ld a,(de)");
4341 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4351 spillPair (PAIR_HL);
4353 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4355 setupPair (PAIR_HL, AOP (left), 0);
4356 aopGet (AOP(right), LSB, FALSE);
4360 if (size == 0 && sign)
4362 // Highest byte when signed needs the bits flipped
4365 emit2 ("ld a,(hl)");
4366 emit2 ("xor !immedbyte", 0x80);
4368 emit2 ("ld a,%d(iy)", offset);
4369 emit2 ("xor !immedbyte", 0x80);
4373 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4377 emit2 ("ld a,(hl)");
4378 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4387 spillPair (PAIR_HL);
4388 spillPair (PAIR_IY);
4392 if (AOP_TYPE (right) == AOP_LIT)
4394 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4395 /* optimize if(x < 0) or if(x >= 0) */
4400 /* No sign so it's always false */
4405 /* Just load in the top most bit */
4406 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4407 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4409 genIfxJump (ifx, "7");
4421 /* First setup h and l contaning the top most bytes XORed */
4422 bool fDidXor = FALSE;
4423 if (AOP_TYPE (left) == AOP_LIT)
4425 unsigned long lit = (unsigned long)
4426 floatFromVal (AOP (left)->aopu.aop_lit);
4427 emit2 ("ld %s,!immedbyte", _fTmp[0],
4428 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4432 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4433 emit2 ("xor a,!immedbyte", 0x80);
4434 emit2 ("ld %s,a", _fTmp[0]);
4437 if (AOP_TYPE (right) == AOP_LIT)
4439 unsigned long lit = (unsigned long)
4440 floatFromVal (AOP (right)->aopu.aop_lit);
4441 emit2 ("ld %s,!immedbyte", _fTmp[1],
4442 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4446 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4447 emit2 ("xor a,!immedbyte", 0x80);
4448 emit2 ("ld %s,a", _fTmp[1]);
4454 /* Do a long subtract */
4457 _moveA (aopGet (AOP (left), offset, FALSE));
4459 if (sign && size == 0)
4461 emit2 ("ld a,%s", _fTmp[0]);
4462 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4466 /* Subtract through, propagating the carry */
4467 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4475 /** Generic compare for > or <
4478 genCmp (operand * left, operand * right,
4479 operand * result, iCode * ifx, int sign)
4481 int size, offset = 0;
4482 unsigned long lit = 0L;
4483 bool swap_sense = FALSE;
4485 /* if left & right are bit variables */
4486 if (AOP_TYPE (left) == AOP_CRY &&
4487 AOP_TYPE (right) == AOP_CRY)
4489 /* Cant happen on the Z80 */
4490 wassertl (0, "Tried to compare two bits");
4494 /* Do a long subtract of right from left. */
4495 size = max (AOP_SIZE (left), AOP_SIZE (right));
4497 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4499 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4500 // Pull left into DE and right into HL
4501 aopGet (AOP(left), LSB, FALSE);
4504 aopGet (AOP(right), LSB, FALSE);
4508 emit2 ("ld a,(de)");
4509 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4518 spillPair (PAIR_HL);
4522 if (AOP_TYPE (right) == AOP_LIT)
4524 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4525 /* optimize if(x < 0) or if(x >= 0) */
4530 /* No sign so it's always false */
4535 /* Just load in the top most bit */
4536 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4537 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4539 genIfxJump (ifx, "7");
4550 genIfxJump (ifx, swap_sense ? "c" : "nc");
4561 _moveA (aopGet (AOP (left), offset, FALSE));
4562 /* Subtract through, propagating the carry */
4563 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4569 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4573 /* Shift the sign bit up into carry */
4576 outBitCLong (result, swap_sense);
4580 /* if the result is used in the next
4581 ifx conditional branch then generate
4582 code a little differently */
4590 genIfxJump (ifx, swap_sense ? "nc" : "c");
4594 genIfxJump (ifx, swap_sense ? "p" : "m");
4599 genIfxJump (ifx, swap_sense ? "nc" : "c");
4606 /* Shift the sign bit up into carry */
4609 outBitCLong (result, swap_sense);
4611 /* leave the result in acc */
4615 /*-----------------------------------------------------------------*/
4616 /* genCmpGt :- greater than comparison */
4617 /*-----------------------------------------------------------------*/
4619 genCmpGt (iCode * ic, iCode * ifx)
4621 operand *left, *right, *result;
4622 sym_link *letype, *retype;
4625 left = IC_LEFT (ic);
4626 right = IC_RIGHT (ic);
4627 result = IC_RESULT (ic);
4629 letype = getSpec (operandType (left));
4630 retype = getSpec (operandType (right));
4631 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4632 /* assign the amsops */
4633 aopOp (left, ic, FALSE, FALSE);
4634 aopOp (right, ic, FALSE, FALSE);
4635 aopOp (result, ic, TRUE, FALSE);
4637 genCmp (right, left, result, ifx, sign);
4639 freeAsmop (left, NULL, ic);
4640 freeAsmop (right, NULL, ic);
4641 freeAsmop (result, NULL, ic);
4644 /*-----------------------------------------------------------------*/
4645 /* genCmpLt - less than comparisons */
4646 /*-----------------------------------------------------------------*/
4648 genCmpLt (iCode * ic, iCode * ifx)
4650 operand *left, *right, *result;
4651 sym_link *letype, *retype;
4654 left = IC_LEFT (ic);
4655 right = IC_RIGHT (ic);
4656 result = IC_RESULT (ic);
4658 letype = getSpec (operandType (left));
4659 retype = getSpec (operandType (right));
4660 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4662 /* assign the amsops */
4663 aopOp (left, ic, FALSE, FALSE);
4664 aopOp (right, ic, FALSE, FALSE);
4665 aopOp (result, ic, TRUE, FALSE);
4667 genCmp (left, right, result, ifx, sign);
4669 freeAsmop (left, NULL, ic);
4670 freeAsmop (right, NULL, ic);
4671 freeAsmop (result, NULL, ic);
4674 /*-----------------------------------------------------------------*/
4675 /* gencjneshort - compare and jump if not equal */
4676 /*-----------------------------------------------------------------*/
4678 gencjneshort (operand * left, operand * right, symbol * lbl)
4680 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4682 unsigned long lit = 0L;
4684 /* Swap the left and right if it makes the computation easier */
4685 if (AOP_TYPE (left) == AOP_LIT)
4692 if (AOP_TYPE (right) == AOP_LIT)
4694 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4697 /* if the right side is a literal then anything goes */
4698 if (AOP_TYPE (right) == AOP_LIT &&
4699 AOP_TYPE (left) != AOP_DIR)
4703 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4708 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4715 emit2 ("jp nz,!tlabel", lbl->key + 100);
4721 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4722 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4725 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4726 emit2 ("jp nz,!tlabel", lbl->key + 100);
4731 /* if the right side is in a register or in direct space or
4732 if the left is a pointer register & right is not */
4733 else if (AOP_TYPE (right) == AOP_REG ||
4734 AOP_TYPE (right) == AOP_DIR ||
4735 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4739 _moveA (aopGet (AOP (left), offset, FALSE));
4740 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4741 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4743 emit2 ("jp nz,!tlabel", lbl->key + 100);
4746 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4747 emit2 ("jp nz,!tlabel", lbl->key + 100);
4754 /* right is a pointer reg need both a & b */
4755 /* PENDING: is this required? */
4758 _moveA (aopGet (AOP (right), offset, FALSE));
4759 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4760 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4766 /*-----------------------------------------------------------------*/
4767 /* gencjne - compare and jump if not equal */
4768 /*-----------------------------------------------------------------*/
4770 gencjne (operand * left, operand * right, symbol * lbl)
4772 symbol *tlbl = newiTempLabel (NULL);
4774 gencjneshort (left, right, lbl);
4777 emit2 ("ld a,!one");
4778 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4779 emitLabel (lbl->key + 100);
4781 emitLabel (tlbl->key + 100);
4784 /*-----------------------------------------------------------------*/
4785 /* genCmpEq - generates code for equal to */
4786 /*-----------------------------------------------------------------*/
4788 genCmpEq (iCode * ic, iCode * ifx)
4790 operand *left, *right, *result;
4792 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4793 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4794 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4796 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4798 /* Swap operands if it makes the operation easier. ie if:
4799 1. Left is a literal.
4801 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4803 operand *t = IC_RIGHT (ic);
4804 IC_RIGHT (ic) = IC_LEFT (ic);
4808 if (ifx && !AOP_SIZE (result))
4811 /* if they are both bit variables */
4812 if (AOP_TYPE (left) == AOP_CRY &&
4813 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4815 wassertl (0, "Tried to compare two bits");
4819 tlbl = newiTempLabel (NULL);
4820 gencjneshort (left, right, tlbl);
4823 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4824 emitLabel (tlbl->key + 100);
4828 /* PENDING: do this better */
4829 symbol *lbl = newiTempLabel (NULL);
4830 emit2 ("!shortjp !tlabel", lbl->key + 100);
4831 emitLabel (tlbl->key + 100);
4832 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4833 emitLabel (lbl->key + 100);
4836 /* mark the icode as generated */
4841 /* if they are both bit variables */
4842 if (AOP_TYPE (left) == AOP_CRY &&
4843 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4845 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4851 gencjne (left, right, newiTempLabel (NULL));
4852 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4859 genIfxJump (ifx, "a");
4862 /* if the result is used in an arithmetic operation
4863 then put the result in place */
4864 if (AOP_TYPE (result) != AOP_CRY)
4869 /* leave the result in acc */
4873 freeAsmop (left, NULL, ic);
4874 freeAsmop (right, NULL, ic);
4875 freeAsmop (result, NULL, ic);
4878 /*-----------------------------------------------------------------*/
4879 /* ifxForOp - returns the icode containing the ifx for operand */
4880 /*-----------------------------------------------------------------*/
4882 ifxForOp (operand * op, iCode * ic)
4884 /* if true symbol then needs to be assigned */
4885 if (IS_TRUE_SYMOP (op))
4888 /* if this has register type condition and
4889 the next instruction is ifx with the same operand
4890 and live to of the operand is upto the ifx only then */
4892 ic->next->op == IFX &&
4893 IC_COND (ic->next)->key == op->key &&
4894 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4900 /*-----------------------------------------------------------------*/
4901 /* genAndOp - for && operation */
4902 /*-----------------------------------------------------------------*/
4904 genAndOp (iCode * ic)
4906 operand *left, *right, *result;
4909 /* note here that && operations that are in an if statement are
4910 taken away by backPatchLabels only those used in arthmetic
4911 operations remain */
4912 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4913 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4914 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4916 /* if both are bit variables */
4917 if (AOP_TYPE (left) == AOP_CRY &&
4918 AOP_TYPE (right) == AOP_CRY)
4920 wassertl (0, "Tried to and two bits");
4924 tlbl = newiTempLabel (NULL);
4926 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4928 emitLabel (tlbl->key + 100);
4932 freeAsmop (left, NULL, ic);
4933 freeAsmop (right, NULL, ic);
4934 freeAsmop (result, NULL, ic);
4937 /*-----------------------------------------------------------------*/
4938 /* genOrOp - for || operation */
4939 /*-----------------------------------------------------------------*/
4941 genOrOp (iCode * ic)
4943 operand *left, *right, *result;
4946 /* note here that || operations that are in an
4947 if statement are taken away by backPatchLabels
4948 only those used in arthmetic operations remain */
4949 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4950 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4951 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4953 /* if both are bit variables */
4954 if (AOP_TYPE (left) == AOP_CRY &&
4955 AOP_TYPE (right) == AOP_CRY)
4957 wassertl (0, "Tried to OR two bits");
4961 tlbl = newiTempLabel (NULL);
4963 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4965 emitLabel (tlbl->key + 100);
4969 freeAsmop (left, NULL, ic);
4970 freeAsmop (right, NULL, ic);
4971 freeAsmop (result, NULL, ic);
4974 /*-----------------------------------------------------------------*/
4975 /* isLiteralBit - test if lit == 2^n */
4976 /*-----------------------------------------------------------------*/
4978 isLiteralBit (unsigned long lit)
4980 unsigned long pw[32] =
4981 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4982 0x100L, 0x200L, 0x400L, 0x800L,
4983 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4984 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4985 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4986 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4987 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4990 for (idx = 0; idx < 32; idx++)
4996 /*-----------------------------------------------------------------*/
4997 /* jmpTrueOrFalse - */
4998 /*-----------------------------------------------------------------*/
5000 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5002 // ugly but optimized by peephole
5005 symbol *nlbl = newiTempLabel (NULL);
5006 emit2 ("jp !tlabel", nlbl->key + 100);
5007 emitLabel (tlbl->key + 100);
5008 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5009 emitLabel (nlbl->key + 100);
5013 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5014 emitLabel (tlbl->key + 100);
5019 /*-----------------------------------------------------------------*/
5020 /* genAnd - code for and */
5021 /*-----------------------------------------------------------------*/
5023 genAnd (iCode * ic, iCode * ifx)
5025 operand *left, *right, *result;
5026 int size, offset = 0;
5027 unsigned long lit = 0L;
5030 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5031 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5032 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5034 /* if left is a literal & right is not then exchange them */
5035 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5036 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5038 operand *tmp = right;
5043 /* if result = right then exchange them */
5044 if (sameRegs (AOP (result), AOP (right)))
5046 operand *tmp = right;
5051 /* if right is bit then exchange them */
5052 if (AOP_TYPE (right) == AOP_CRY &&
5053 AOP_TYPE (left) != AOP_CRY)
5055 operand *tmp = right;
5059 if (AOP_TYPE (right) == AOP_LIT)
5060 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5062 size = AOP_SIZE (result);
5064 if (AOP_TYPE (left) == AOP_CRY)
5066 wassertl (0, "Tried to perform an AND with a bit as an operand");
5070 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5071 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5072 if ((AOP_TYPE (right) == AOP_LIT) &&
5073 (AOP_TYPE (result) == AOP_CRY) &&
5074 (AOP_TYPE (left) != AOP_CRY))
5076 symbol *tlbl = newiTempLabel (NULL);
5077 int sizel = AOP_SIZE (left);
5080 /* PENDING: Test case for this. */
5085 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5087 _moveA (aopGet (AOP (left), offset, FALSE));
5088 if (bytelit != 0x0FFL)
5090 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5097 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5101 // bit = left & literal
5105 emit2 ("!tlabeldef", tlbl->key + 100);
5107 // if(left & literal)
5112 jmpTrueOrFalse (ifx, tlbl);
5120 /* if left is same as result */
5121 if (sameRegs (AOP (result), AOP (left)))
5123 for (; size--; offset++)
5125 if (AOP_TYPE (right) == AOP_LIT)
5127 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5132 aopPut (AOP (result), "!zero", offset);
5135 _moveA (aopGet (AOP (left), offset, FALSE));
5137 aopGet (AOP (right), offset, FALSE));
5138 aopPut (AOP (left), "a", offset);
5145 if (AOP_TYPE (left) == AOP_ACC)
5147 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5151 _moveA (aopGet (AOP (left), offset, FALSE));
5153 aopGet (AOP (right), offset, FALSE));
5154 aopPut (AOP (left), "a", offset);
5161 // left & result in different registers
5162 if (AOP_TYPE (result) == AOP_CRY)
5164 wassertl (0, "Tried to AND where the result is in carry");
5168 for (; (size--); offset++)
5171 // result = left & right
5172 if (AOP_TYPE (right) == AOP_LIT)
5174 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5176 aopPut (AOP (result),
5177 aopGet (AOP (left), offset, FALSE),
5181 else if (bytelit == 0)
5183 aopPut (AOP (result), "!zero", offset);
5187 // faster than result <- left, anl result,right
5188 // and better if result is SFR
5189 if (AOP_TYPE (left) == AOP_ACC)
5190 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5193 _moveA (aopGet (AOP (left), offset, FALSE));
5195 aopGet (AOP (right), offset, FALSE));
5197 aopPut (AOP (result), "a", offset);
5204 freeAsmop (left, NULL, ic);
5205 freeAsmop (right, NULL, ic);
5206 freeAsmop (result, NULL, ic);
5209 /*-----------------------------------------------------------------*/
5210 /* genOr - code for or */
5211 /*-----------------------------------------------------------------*/
5213 genOr (iCode * ic, iCode * ifx)
5215 operand *left, *right, *result;
5216 int size, offset = 0;
5217 unsigned long lit = 0L;
5220 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5221 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5222 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5224 /* if left is a literal & right is not then exchange them */
5225 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5226 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5228 operand *tmp = right;
5233 /* if result = right then exchange them */
5234 if (sameRegs (AOP (result), AOP (right)))
5236 operand *tmp = right;
5241 /* if right is bit then exchange them */
5242 if (AOP_TYPE (right) == AOP_CRY &&
5243 AOP_TYPE (left) != AOP_CRY)
5245 operand *tmp = right;
5249 if (AOP_TYPE (right) == AOP_LIT)
5250 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5252 size = AOP_SIZE (result);
5254 if (AOP_TYPE (left) == AOP_CRY)
5256 wassertl (0, "Tried to OR where left is a bit");
5260 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5261 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5262 if ((AOP_TYPE (right) == AOP_LIT) &&
5263 (AOP_TYPE (result) == AOP_CRY) &&
5264 (AOP_TYPE (left) != AOP_CRY))
5266 symbol *tlbl = newiTempLabel (NULL);
5267 int sizel = AOP_SIZE (left);
5271 wassertl (0, "Result is assigned to a bit");
5273 /* PENDING: Modeled after the AND code which is inefficent. */
5276 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5278 _moveA (aopGet (AOP (left), offset, FALSE));
5279 /* OR with any literal is the same as OR with itself. */
5281 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5287 jmpTrueOrFalse (ifx, tlbl);
5292 /* if left is same as result */
5293 if (sameRegs (AOP (result), AOP (left)))
5295 for (; size--; offset++)
5297 if (AOP_TYPE (right) == AOP_LIT)
5299 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5303 _moveA (aopGet (AOP (left), offset, FALSE));
5305 aopGet (AOP (right), offset, FALSE));
5306 aopPut (AOP (result), "a", offset);
5311 if (AOP_TYPE (left) == AOP_ACC)
5312 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5315 _moveA (aopGet (AOP (left), offset, FALSE));
5317 aopGet (AOP (right), offset, FALSE));
5318 aopPut (AOP (result), "a", offset);
5325 // left & result in different registers
5326 if (AOP_TYPE (result) == AOP_CRY)
5328 wassertl (0, "Result of OR is in a bit");
5331 for (; (size--); offset++)
5334 // result = left & right
5335 if (AOP_TYPE (right) == AOP_LIT)
5337 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5339 aopPut (AOP (result),
5340 aopGet (AOP (left), offset, FALSE),
5345 // faster than result <- left, anl result,right
5346 // and better if result is SFR
5347 if (AOP_TYPE (left) == AOP_ACC)
5348 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5351 _moveA (aopGet (AOP (left), offset, FALSE));
5353 aopGet (AOP (right), offset, FALSE));
5355 aopPut (AOP (result), "a", offset);
5356 /* PENDING: something weird is going on here. Add exception. */
5357 if (AOP_TYPE (result) == AOP_ACC)
5363 freeAsmop (left, NULL, ic);
5364 freeAsmop (right, NULL, ic);
5365 freeAsmop (result, NULL, ic);
5368 /*-----------------------------------------------------------------*/
5369 /* genXor - code for xclusive or */
5370 /*-----------------------------------------------------------------*/
5372 genXor (iCode * ic, iCode * ifx)
5374 operand *left, *right, *result;
5375 int size, offset = 0;
5376 unsigned long lit = 0L;
5378 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5379 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5380 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5382 /* if left is a literal & right is not then exchange them */
5383 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5384 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5386 operand *tmp = right;
5391 /* if result = right then exchange them */
5392 if (sameRegs (AOP (result), AOP (right)))
5394 operand *tmp = right;
5399 /* if right is bit then exchange them */
5400 if (AOP_TYPE (right) == AOP_CRY &&
5401 AOP_TYPE (left) != AOP_CRY)
5403 operand *tmp = right;
5407 if (AOP_TYPE (right) == AOP_LIT)
5408 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5410 size = AOP_SIZE (result);
5412 if (AOP_TYPE (left) == AOP_CRY)
5414 wassertl (0, "Tried to XOR a bit");
5418 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5419 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5420 if ((AOP_TYPE (right) == AOP_LIT) &&
5421 (AOP_TYPE (result) == AOP_CRY) &&
5422 (AOP_TYPE (left) != AOP_CRY))
5424 symbol *tlbl = newiTempLabel (NULL);
5425 int sizel = AOP_SIZE (left);
5429 /* PENDING: Test case for this. */
5430 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5434 _moveA (aopGet (AOP (left), offset, FALSE));
5435 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5436 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5441 jmpTrueOrFalse (ifx, tlbl);
5445 wassertl (0, "Result of XOR was destined for a bit");
5450 /* if left is same as result */
5451 if (sameRegs (AOP (result), AOP (left)))
5453 for (; size--; offset++)
5455 if (AOP_TYPE (right) == AOP_LIT)
5457 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5461 _moveA (aopGet (AOP (left), offset, FALSE));
5463 aopGet (AOP (right), offset, FALSE));
5464 aopPut (AOP (result), "a", offset);
5469 if (AOP_TYPE (left) == AOP_ACC)
5471 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5475 _moveA (aopGet (AOP (left), offset, FALSE));
5477 aopGet (AOP (right), offset, FALSE));
5478 aopPut (AOP (result), "a", offset);
5485 // left & result in different registers
5486 if (AOP_TYPE (result) == AOP_CRY)
5488 wassertl (0, "Result of XOR is in a bit");
5491 for (; (size--); offset++)
5494 // result = left & right
5495 if (AOP_TYPE (right) == AOP_LIT)
5497 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5499 aopPut (AOP (result),
5500 aopGet (AOP (left), offset, FALSE),
5505 // faster than result <- left, anl result,right
5506 // and better if result is SFR
5507 if (AOP_TYPE (left) == AOP_ACC)
5509 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5513 _moveA (aopGet (AOP (left), offset, FALSE));
5515 aopGet (AOP (right), offset, FALSE));
5517 aopPut (AOP (result), "a", offset);
5522 freeAsmop (left, NULL, ic);
5523 freeAsmop (right, NULL, ic);
5524 freeAsmop (result, NULL, ic);
5527 /*-----------------------------------------------------------------*/
5528 /* genInline - write the inline code out */
5529 /*-----------------------------------------------------------------*/
5531 genInline (iCode * ic)
5533 char *buffer, *bp, *bp1;
5535 _G.lines.isInline += (!options.asmpeep);
5537 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5538 strcpy (buffer, IC_INLINE (ic));
5540 /* emit each line as a code */
5565 _G.lines.isInline -= (!options.asmpeep);
5569 /*-----------------------------------------------------------------*/
5570 /* genRRC - rotate right with carry */
5571 /*-----------------------------------------------------------------*/
5578 /*-----------------------------------------------------------------*/
5579 /* genRLC - generate code for rotate left with carry */
5580 /*-----------------------------------------------------------------*/
5587 /*-----------------------------------------------------------------*/
5588 /* genGetHbit - generates code get highest order bit */
5589 /*-----------------------------------------------------------------*/
5591 genGetHbit (iCode * ic)
5593 operand *left, *result;
5594 left = IC_LEFT (ic);
5595 result = IC_RESULT (ic);
5597 aopOp (left, ic, FALSE, FALSE);
5598 aopOp (result, ic, FALSE, FALSE);
5600 /* get the highest order byte into a */
5601 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5603 if (AOP_TYPE (result) == AOP_CRY)
5611 emit2 ("and a,!one");
5616 freeAsmop (left, NULL, ic);
5617 freeAsmop (result, NULL, ic);
5621 emitRsh2 (asmop *aop, int size, int is_signed)
5627 const char *l = aopGet (aop, size, FALSE);
5630 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5640 /*-----------------------------------------------------------------*/
5641 /* shiftR2Left2Result - shift right two bytes from left to result */
5642 /*-----------------------------------------------------------------*/
5644 shiftR2Left2Result (operand * left, int offl,
5645 operand * result, int offr,
5646 int shCount, int is_signed)
5649 symbol *tlbl, *tlbl1;
5651 movLeft2Result (left, offl, result, offr, 0);
5652 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5654 /* if (AOP(result)->type == AOP_REG) { */
5656 tlbl = newiTempLabel (NULL);
5657 tlbl1 = newiTempLabel (NULL);
5659 /* Left is already in result - so now do the shift */
5664 emitRsh2 (AOP (result), size, is_signed);
5669 emit2 ("ld a,!immedbyte+1", shCount);
5670 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5671 emitLabel (tlbl->key + 100);
5673 emitRsh2 (AOP (result), size, is_signed);
5675 emitLabel (tlbl1->key + 100);
5677 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5681 /*-----------------------------------------------------------------*/
5682 /* shiftL2Left2Result - shift left two bytes from left to result */
5683 /*-----------------------------------------------------------------*/
5685 shiftL2Left2Result (operand * left, int offl,
5686 operand * result, int offr, int shCount)
5688 if (sameRegs (AOP (result), AOP (left)) &&
5689 ((offl + MSB16) == offr))
5695 /* Copy left into result */
5696 movLeft2Result (left, offl, result, offr, 0);
5697 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5700 if (getPairId (AOP (result)) == PAIR_HL)
5704 emit2 ("add hl,hl");
5711 symbol *tlbl, *tlbl1;
5714 tlbl = newiTempLabel (NULL);
5715 tlbl1 = newiTempLabel (NULL);
5717 if (AOP (result)->type == AOP_REG)
5721 for (offset = 0; offset < size; offset++)
5723 l = aopGet (AOP (result), offset, FALSE);
5727 emit2 ("sla %s", l);
5738 /* Left is already in result - so now do the shift */
5741 emit2 ("ld a,!immedbyte+1", shCount);
5742 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5743 emitLabel (tlbl->key + 100);
5748 l = aopGet (AOP (result), offset, FALSE);
5752 emit2 ("sla %s", l);
5763 emitLabel (tlbl1->key + 100);
5765 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5771 /*-----------------------------------------------------------------*/
5772 /* AccRol - rotate left accumulator by known count */
5773 /*-----------------------------------------------------------------*/
5775 AccRol (int shCount)
5777 shCount &= 0x0007; // shCount : 0..7
5854 /*-----------------------------------------------------------------*/
5855 /* AccLsh - left shift accumulator by known count */
5856 /*-----------------------------------------------------------------*/
5858 AccLsh (int shCount)
5860 static const unsigned char SLMask[] =
5862 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5871 else if (shCount == 2)
5878 /* rotate left accumulator */
5880 /* and kill the lower order bits */
5881 emit2 ("and a,!immedbyte", SLMask[shCount]);
5886 /*-----------------------------------------------------------------*/
5887 /* shiftL1Left2Result - shift left one byte from left to result */
5888 /*-----------------------------------------------------------------*/
5890 shiftL1Left2Result (operand * left, int offl,
5891 operand * result, int offr, int shCount)
5894 l = aopGet (AOP (left), offl, FALSE);
5896 /* shift left accumulator */
5898 aopPut (AOP (result), "a", offr);
5902 /*-----------------------------------------------------------------*/
5903 /* genlshTwo - left shift two bytes by known amount != 0 */
5904 /*-----------------------------------------------------------------*/
5906 genlshTwo (operand * result, operand * left, int shCount)
5908 int size = AOP_SIZE (result);
5910 wassert (size == 2);
5912 /* if shCount >= 8 */
5920 movLeft2Result (left, LSB, result, MSB16, 0);
5921 aopPut (AOP (result), "!zero", 0);
5922 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5926 movLeft2Result (left, LSB, result, MSB16, 0);
5927 aopPut (AOP (result), "!zero", 0);
5932 aopPut (AOP (result), "!zero", LSB);
5935 /* 1 <= shCount <= 7 */
5944 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5949 /*-----------------------------------------------------------------*/
5950 /* genlshOne - left shift a one byte quantity by known count */
5951 /*-----------------------------------------------------------------*/
5953 genlshOne (operand * result, operand * left, int shCount)
5955 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5958 /*-----------------------------------------------------------------*/
5959 /* genLeftShiftLiteral - left shifting by known count */
5960 /*-----------------------------------------------------------------*/
5962 genLeftShiftLiteral (operand * left,
5967 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5970 freeAsmop (right, NULL, ic);
5972 aopOp (left, ic, FALSE, FALSE);
5973 aopOp (result, ic, FALSE, FALSE);
5975 size = getSize (operandType (result));
5977 /* I suppose that the left size >= result size */
5983 else if (shCount >= (size * 8))
5987 aopPut (AOP (result), "!zero", size);
5995 genlshOne (result, left, shCount);
5998 genlshTwo (result, left, shCount);
6001 wassertl (0, "Shifting of longs is currently unsupported");
6007 freeAsmop (left, NULL, ic);
6008 freeAsmop (result, NULL, ic);
6011 /*-----------------------------------------------------------------*/
6012 /* genLeftShift - generates code for left shifting */
6013 /*-----------------------------------------------------------------*/
6015 genLeftShift (iCode * ic)
6019 symbol *tlbl, *tlbl1;
6020 operand *left, *right, *result;
6022 right = IC_RIGHT (ic);
6023 left = IC_LEFT (ic);
6024 result = IC_RESULT (ic);
6026 aopOp (right, ic, FALSE, FALSE);
6028 /* if the shift count is known then do it
6029 as efficiently as possible */
6030 if (AOP_TYPE (right) == AOP_LIT)
6032 genLeftShiftLiteral (left, right, result, ic);
6036 /* shift count is unknown then we have to form a loop get the loop
6037 count in B : Note: we take only the lower order byte since
6038 shifting more that 32 bits make no sense anyway, ( the largest
6039 size of an object can be only 32 bits ) */
6040 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6042 freeAsmop (right, NULL, ic);
6043 aopOp (left, ic, FALSE, FALSE);
6044 aopOp (result, ic, FALSE, FALSE);
6046 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6049 /* now move the left to the result if they are not the
6052 if (!sameRegs (AOP (left), AOP (result)))
6055 size = AOP_SIZE (result);
6059 l = aopGet (AOP (left), offset, FALSE);
6060 aopPut (AOP (result), l, offset);
6065 tlbl = newiTempLabel (NULL);
6066 size = AOP_SIZE (result);
6068 tlbl1 = newiTempLabel (NULL);
6070 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6073 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6074 emitLabel (tlbl->key + 100);
6075 l = aopGet (AOP (result), offset, FALSE);
6079 l = aopGet (AOP (result), offset, FALSE);
6083 emit2 ("sla %s", l);
6091 emitLabel (tlbl1->key + 100);
6093 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6095 freeAsmop (left, NULL, ic);
6096 freeAsmop (result, NULL, ic);
6099 /*-----------------------------------------------------------------*/
6100 /* genrshOne - left shift two bytes by known amount != 0 */
6101 /*-----------------------------------------------------------------*/
6103 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6106 int size = AOP_SIZE (result);
6109 wassert (size == 1);
6110 wassert (shCount < 8);
6112 l = aopGet (AOP (left), 0, FALSE);
6114 if (AOP (result)->type == AOP_REG)
6116 aopPut (AOP (result), l, 0);
6117 l = aopGet (AOP (result), 0, FALSE);
6120 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6128 emit2 ("%s a", is_signed ? "sra" : "srl");
6130 aopPut (AOP (result), "a", 0);
6134 /*-----------------------------------------------------------------*/
6135 /* AccRsh - right shift accumulator by known count */
6136 /*-----------------------------------------------------------------*/
6138 AccRsh (int shCount)
6140 static const unsigned char SRMask[] =
6142 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6147 /* rotate right accumulator */
6148 AccRol (8 - shCount);
6149 /* and kill the higher order bits */
6150 emit2 ("and a,!immedbyte", SRMask[shCount]);
6154 /*-----------------------------------------------------------------*/
6155 /* shiftR1Left2Result - shift right one byte from left to result */
6156 /*-----------------------------------------------------------------*/
6158 shiftR1Left2Result (operand * left, int offl,
6159 operand * result, int offr,
6160 int shCount, int sign)
6162 _moveA (aopGet (AOP (left), offl, FALSE));
6167 emit2 ("%s a", sign ? "sra" : "srl");
6174 aopPut (AOP (result), "a", offr);
6177 /*-----------------------------------------------------------------*/
6178 /* genrshTwo - right shift two bytes by known amount != 0 */
6179 /*-----------------------------------------------------------------*/
6181 genrshTwo (operand * result, operand * left,
6182 int shCount, int sign)
6184 /* if shCount >= 8 */
6190 shiftR1Left2Result (left, MSB16, result, LSB,
6195 movLeft2Result (left, MSB16, result, LSB, sign);
6199 /* Sign extend the result */
6200 _moveA(aopGet (AOP (result), 0, FALSE));
6204 aopPut (AOP (result), ACC_NAME, MSB16);
6208 aopPut (AOP (result), "!zero", 1);
6211 /* 1 <= shCount <= 7 */
6214 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6218 /*-----------------------------------------------------------------*/
6219 /* genRightShiftLiteral - left shifting by known count */
6220 /*-----------------------------------------------------------------*/
6222 genRightShiftLiteral (operand * left,
6228 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6231 freeAsmop (right, NULL, ic);
6233 aopOp (left, ic, FALSE, FALSE);
6234 aopOp (result, ic, FALSE, FALSE);
6236 size = getSize (operandType (result));
6238 /* I suppose that the left size >= result size */
6244 else if (shCount >= (size * 8)) {
6246 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6247 _moveA(aopGet (AOP (left), 0, FALSE));
6255 aopPut (AOP (result), s, size);
6262 genrshOne (result, left, shCount, sign);
6265 genrshTwo (result, left, shCount, sign);
6268 wassertl (0, "Asked to shift right a long which should be a function call");
6271 wassertl (0, "Entered default case in right shift delegate");
6274 freeAsmop (left, NULL, ic);
6275 freeAsmop (result, NULL, ic);
6278 /*-----------------------------------------------------------------*/
6279 /* genRightShift - generate code for right shifting */
6280 /*-----------------------------------------------------------------*/
6282 genRightShift (iCode * ic)
6284 operand *right, *left, *result;
6286 int size, offset, first = 1;
6290 symbol *tlbl, *tlbl1;
6292 /* if signed then we do it the hard way preserve the
6293 sign bit moving it inwards */
6294 retype = getSpec (operandType (IC_RESULT (ic)));
6296 is_signed = !SPEC_USIGN (retype);
6298 /* signed & unsigned types are treated the same : i.e. the
6299 signed is NOT propagated inwards : quoting from the
6300 ANSI - standard : "for E1 >> E2, is equivalent to division
6301 by 2**E2 if unsigned or if it has a non-negative value,
6302 otherwise the result is implementation defined ", MY definition
6303 is that the sign does not get propagated */
6305 right = IC_RIGHT (ic);
6306 left = IC_LEFT (ic);
6307 result = IC_RESULT (ic);
6309 aopOp (right, ic, FALSE, FALSE);
6311 /* if the shift count is known then do it
6312 as efficiently as possible */
6313 if (AOP_TYPE (right) == AOP_LIT)
6315 genRightShiftLiteral (left, right, result, ic, is_signed);
6319 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6321 freeAsmop (right, NULL, ic);
6323 aopOp (left, ic, FALSE, FALSE);
6324 aopOp (result, ic, FALSE, FALSE);
6326 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6329 /* now move the left to the result if they are not the
6331 if (!sameRegs (AOP (left), AOP (result)))
6334 size = AOP_SIZE (result);
6338 l = aopGet (AOP (left), offset, FALSE);
6339 aopPut (AOP (result), l, offset);
6344 tlbl = newiTempLabel (NULL);
6345 tlbl1 = newiTempLabel (NULL);
6346 size = AOP_SIZE (result);
6349 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6352 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6353 emitLabel (tlbl->key + 100);
6356 l = aopGet (AOP (result), offset--, FALSE);
6359 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6367 emitLabel (tlbl1->key + 100);
6369 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6371 freeAsmop (left, NULL, ic);
6372 freeAsmop (result, NULL, ic);
6376 /*-----------------------------------------------------------------*/
6377 /* genUnpackBits - generates code for unpacking bits */
6378 /*-----------------------------------------------------------------*/
6380 genUnpackBits (operand * result, int pair)
6382 int offset = 0; /* result byte offset */
6383 int rsize; /* result size */
6384 int rlen = 0; /* remaining bitfield length */
6385 sym_link *etype; /* bitfield type information */
6386 int blen; /* bitfield length */
6387 int bstr; /* bitfield starting bit within byte */
6389 emitDebug ("; genUnpackBits");
6391 etype = getSpec (operandType (result));
6392 rsize = getSize (operandType (result));
6393 blen = SPEC_BLEN (etype);
6394 bstr = SPEC_BSTR (etype);
6396 /* If the bitfield length is less than a byte */
6399 emit2 ("ld a,!*pair", _pairs[pair].name);
6401 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6402 aopPut (AOP (result), "a", offset++);
6406 /* TODO: what if pair == PAIR_DE ? */
6407 if (getPairId (AOP (result)) == PAIR_HL)
6409 wassertl (rsize == 2, "HL must be of size 2");
6410 emit2 ("ld a,!*hl");
6412 emit2 ("ld h,!*hl");
6415 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6417 spillPair (PAIR_HL);
6421 /* Bit field did not fit in a byte. Copy all
6422 but the partial byte at the end. */
6423 for (rlen=blen;rlen>=8;rlen-=8)
6425 emit2 ("ld a,!*pair", _pairs[pair].name);
6426 aopPut (AOP (result), "a", offset++);
6429 emit2 ("inc %s", _pairs[pair].name);
6430 _G.pairs[pair].offset++;
6434 /* Handle the partial byte at the end */
6437 emit2 ("ld a,!*pair", _pairs[pair].name);
6438 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6439 aopPut (AOP (result), "a", offset++);
6447 aopPut (AOP (result), "!zero", offset++);
6451 /*-----------------------------------------------------------------*/
6452 /* genGenPointerGet - get value from generic pointer space */
6453 /*-----------------------------------------------------------------*/
6455 genGenPointerGet (operand * left,
6456 operand * result, iCode * ic)
6459 sym_link *retype = getSpec (operandType (result));
6465 aopOp (left, ic, FALSE, FALSE);
6466 aopOp (result, ic, FALSE, FALSE);
6468 size = AOP_SIZE (result);
6470 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6473 if (isPtrPair (AOP (left)))
6475 tsprintf (buffer, sizeof(buffer),
6476 "!*pair", getPairName (AOP (left)));
6477 aopPut (AOP (result), buffer, 0);
6481 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6482 aopPut (AOP (result), "a", 0);
6484 freeAsmop (left, NULL, ic);
6488 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6495 tsprintf (at, sizeof(at), "!*iyx", offset);
6496 aopPut (AOP (result), at, offset);
6500 freeAsmop (left, NULL, ic);
6504 /* For now we always load into IY */
6505 /* if this is remateriazable */
6506 fetchPair (pair, AOP (left));
6508 /* if bit then unpack */
6509 if (IS_BITVAR (retype))
6511 genUnpackBits (result, pair);
6512 freeAsmop (left, NULL, ic);
6516 else if (getPairId (AOP (result)) == PAIR_HL)
6518 wassertl (size == 2, "HL must be of size 2");
6519 emit2 ("ld a,!*hl");
6521 emit2 ("ld h,!*hl");
6523 spillPair (PAIR_HL);
6525 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6527 size = AOP_SIZE (result);
6532 /* PENDING: make this better */
6533 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6535 aopPut (AOP (result), "!*hl", offset++);
6539 emit2 ("ld a,!*pair", _pairs[pair].name);
6540 aopPut (AOP (result), "a", offset++);
6544 emit2 ("inc %s", _pairs[pair].name);
6545 _G.pairs[pair].offset++;
6548 /* Fixup HL back down */
6549 for (size = AOP_SIZE (result)-1; size; size--)
6551 emit2 ("dec %s", _pairs[pair].name);
6556 size = AOP_SIZE (result);
6561 /* PENDING: make this better */
6563 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6565 aopPut (AOP (result), "!*hl", offset++);
6569 emit2 ("ld a,!*pair", _pairs[pair].name);
6570 aopPut (AOP (result), "a", offset++);
6574 emit2 ("inc %s", _pairs[pair].name);
6575 _G.pairs[pair].offset++;
6580 freeAsmop (left, NULL, ic);
6583 freeAsmop (result, NULL, ic);
6586 /*-----------------------------------------------------------------*/
6587 /* genPointerGet - generate code for pointer get */
6588 /*-----------------------------------------------------------------*/
6590 genPointerGet (iCode * ic)
6592 operand *left, *result;
6593 sym_link *type, *etype;
6595 left = IC_LEFT (ic);
6596 result = IC_RESULT (ic);
6598 /* depending on the type of pointer we need to
6599 move it to the correct pointer register */
6600 type = operandType (left);
6601 etype = getSpec (type);
6603 genGenPointerGet (left, result, ic);
6607 isRegOrLit (asmop * aop)
6609 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6615 /*-----------------------------------------------------------------*/
6616 /* genPackBits - generates code for packed bit storage */
6617 /*-----------------------------------------------------------------*/
6619 genPackBits (sym_link * etype,
6624 int offset = 0; /* source byte offset */
6625 int rlen = 0; /* remaining bitfield length */
6626 int blen; /* bitfield length */
6627 int bstr; /* bitfield starting bit within byte */
6628 int litval; /* source literal value (if AOP_LIT) */
6629 unsigned char mask; /* bitmask within current byte */
6630 int extraPair; /* a tempory register */
6631 bool needPopExtra=0; /* need to restore original value of temp reg */
6633 emitDebug ("; genPackBits","");
6635 blen = SPEC_BLEN (etype);
6636 bstr = SPEC_BSTR (etype);
6638 /* If the bitfield length is less than a byte */
6641 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6642 (unsigned char) (0xFF >> (8 - bstr)));
6644 if (AOP_TYPE (right) == AOP_LIT)
6646 /* Case with a bitfield length <8 and literal source
6648 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6650 litval &= (~mask) & 0xff;
6651 emit2 ("ld a,!*pair", _pairs[pair].name);
6652 if ((mask|litval)!=0xff)
6653 emit2 ("and a,!immedbyte", mask);
6655 emit2 ("or a,!immedbyte", litval);
6656 emit2 ("ld !*pair,a", _pairs[pair].name);
6661 /* Case with a bitfield length <8 and arbitrary source
6663 _moveA (aopGet (AOP (right), 0, FALSE));
6664 /* shift and mask source value */
6666 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6668 extraPair = getFreePairId(ic);
6669 if (extraPair == PAIR_INVALID)
6671 extraPair = PAIR_BC;
6672 if (getPairId (AOP (right)) != PAIR_BC
6673 || !isLastUse (ic, right))
6679 emit2 ("ld %s,a", _pairs[extraPair].l);
6680 emit2 ("ld a,!*pair", _pairs[pair].name);
6682 emit2 ("and a,!immedbyte", mask);
6683 emit2 ("or a,%s", _pairs[extraPair].l);
6684 emit2 ("ld !*pair,a", _pairs[pair].name);
6691 /* Bit length is greater than 7 bits. In this case, copy */
6692 /* all except the partial byte at the end */
6693 for (rlen=blen;rlen>=8;rlen-=8)
6695 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6696 emit2 ("ld !*pair,a", _pairs[pair].name);
6699 emit2 ("inc %s", _pairs[pair].name);
6700 _G.pairs[pair].offset++;
6704 /* If there was a partial byte at the end */
6707 mask = (((unsigned char) -1 << rlen) & 0xff);
6709 if (AOP_TYPE (right) == AOP_LIT)
6711 /* Case with partial byte and literal source
6713 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6714 litval >>= (blen-rlen);
6715 litval &= (~mask) & 0xff;
6716 emit2 ("ld a,!*pair", _pairs[pair].name);
6717 if ((mask|litval)!=0xff)
6718 emit2 ("and a,!immedbyte", mask);
6720 emit2 ("or a,!immedbyte", litval);
6724 /* Case with partial byte and arbitrary source
6726 _moveA (aopGet (AOP (right), offset++, FALSE));
6727 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6729 extraPair = getFreePairId(ic);
6730 if (extraPair == PAIR_INVALID)
6732 extraPair = getPairId (AOP (right));
6733 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6734 extraPair = PAIR_BC;
6736 if (getPairId (AOP (right)) != PAIR_BC
6737 || !isLastUse (ic, right))
6743 emit2 ("ld %s,a", _pairs[extraPair].l);
6744 emit2 ("ld a,!*pair", _pairs[pair].name);
6746 emit2 ("and a,!immedbyte", mask);
6747 emit2 ("or a,%s", _pairs[extraPair].l);
6752 emit2 ("ld !*pair,a", _pairs[pair].name);
6757 /*-----------------------------------------------------------------*/
6758 /* genGenPointerSet - stores the value into a pointer location */
6759 /*-----------------------------------------------------------------*/
6761 genGenPointerSet (operand * right,
6762 operand * result, iCode * ic)
6765 sym_link *retype = getSpec (operandType (right));
6766 sym_link *letype = getSpec (operandType (result));
6767 PAIR_ID pairId = PAIR_HL;
6770 aopOp (result, ic, FALSE, FALSE);
6771 aopOp (right, ic, FALSE, FALSE);
6776 size = AOP_SIZE (right);
6778 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6779 emitDebug("; isBitvar = %d", isBitvar);
6781 /* Handle the exceptions first */
6782 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6785 const char *l = aopGet (AOP (right), 0, FALSE);
6786 const char *pair = getPairName (AOP (result));
6787 if (canAssignToPtr (l) && isPtr (pair))
6789 emit2 ("ld !*pair,%s", pair, l);
6794 emit2 ("ld !*pair,a", pair);
6799 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6802 const char *l = aopGet (AOP (right), 0, FALSE);
6807 if (canAssignToPtr (l))
6809 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6813 _moveA (aopGet (AOP (right), offset, FALSE));
6814 emit2 ("ld !*iyx,a", offset);
6820 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6827 const char *l = aopGet (AOP (right), offset, FALSE);
6828 if (isRegOrLit (AOP (right)) && !IS_GB)
6830 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6835 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6839 emit2 ("inc %s", _pairs[PAIR_HL].name);
6840 _G.pairs[PAIR_HL].offset++;
6845 /* Fixup HL back down */
6846 for (size = AOP_SIZE (right)-1; size; size--)
6848 emit2 ("dec %s", _pairs[PAIR_HL].name);
6853 /* if the operand is already in dptr
6854 then we do nothing else we move the value to dptr */
6855 if (AOP_TYPE (result) != AOP_STR)
6857 fetchPair (pairId, AOP (result));
6859 /* so hl now contains the address */
6860 freeAsmop (result, NULL, ic);
6862 /* if bit then unpack */
6865 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6875 const char *l = aopGet (AOP (right), offset, FALSE);
6876 if (isRegOrLit (AOP (right)) && !IS_GB)
6878 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6883 emit2 ("ld !*pair,a", _pairs[pairId].name);
6887 emit2 ("inc %s", _pairs[pairId].name);
6888 _G.pairs[pairId].offset++;
6894 freeAsmop (right, NULL, ic);
6897 /*-----------------------------------------------------------------*/
6898 /* genPointerSet - stores the value into a pointer location */
6899 /*-----------------------------------------------------------------*/
6901 genPointerSet (iCode * ic)
6903 operand *right, *result;
6904 sym_link *type, *etype;
6906 right = IC_RIGHT (ic);
6907 result = IC_RESULT (ic);
6909 /* depending on the type of pointer we need to
6910 move it to the correct pointer register */
6911 type = operandType (result);
6912 etype = getSpec (type);
6914 genGenPointerSet (right, result, ic);
6917 /*-----------------------------------------------------------------*/
6918 /* genIfx - generate code for Ifx statement */
6919 /*-----------------------------------------------------------------*/
6921 genIfx (iCode * ic, iCode * popIc)
6923 operand *cond = IC_COND (ic);
6926 aopOp (cond, ic, FALSE, TRUE);
6928 /* get the value into acc */
6929 if (AOP_TYPE (cond) != AOP_CRY)
6933 /* the result is now in the accumulator */
6934 freeAsmop (cond, NULL, ic);
6936 /* if there was something to be popped then do it */
6940 /* if the condition is a bit variable */
6941 if (isbit && IS_ITEMP (cond) &&
6943 genIfxJump (ic, SPIL_LOC (cond)->rname);
6944 else if (isbit && !IS_ITEMP (cond))
6945 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6947 genIfxJump (ic, "a");
6952 /*-----------------------------------------------------------------*/
6953 /* genAddrOf - generates code for address of */
6954 /*-----------------------------------------------------------------*/
6956 genAddrOf (iCode * ic)
6958 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6960 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6962 /* if the operand is on the stack then we
6963 need to get the stack offset of this
6970 if (sym->stack <= 0)
6972 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6976 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6978 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6982 emit2 ("ld de,!hashedstr", sym->rname);
6983 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6991 /* if it has an offset then we need to compute it */
6993 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6995 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6996 emit2 ("add hl,sp");
7000 emit2 ("ld hl,!hashedstr", sym->rname);
7002 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7004 freeAsmop (IC_RESULT (ic), NULL, ic);
7007 /*-----------------------------------------------------------------*/
7008 /* genAssign - generate code for assignment */
7009 /*-----------------------------------------------------------------*/
7011 genAssign (iCode * ic)
7013 operand *result, *right;
7015 unsigned long lit = 0L;
7017 result = IC_RESULT (ic);
7018 right = IC_RIGHT (ic);
7020 /* Dont bother assigning if they are the same */
7021 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7023 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7027 aopOp (right, ic, FALSE, FALSE);
7028 aopOp (result, ic, TRUE, FALSE);
7030 /* if they are the same registers */
7031 if (sameRegs (AOP (right), AOP (result)))
7033 emitDebug ("; (registers are the same)");
7037 /* if the result is a bit */
7038 if (AOP_TYPE (result) == AOP_CRY)
7040 wassertl (0, "Tried to assign to a bit");
7044 size = AOP_SIZE (result);
7047 if (AOP_TYPE (right) == AOP_LIT)
7049 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7052 if (isPair (AOP (result)))
7054 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7056 else if ((size > 1) &&
7057 (AOP_TYPE (result) != AOP_REG) &&
7058 (AOP_TYPE (right) == AOP_LIT) &&
7059 !IS_FLOAT (operandType (right)) &&
7062 bool fXored = FALSE;
7064 /* Work from the top down.
7065 Done this way so that we can use the cached copy of 0
7066 in A for a fast clear */
7069 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7071 if (!fXored && size > 1)
7078 aopPut (AOP (result), "a", offset);
7082 aopPut (AOP (result), "!zero", offset);
7086 aopPut (AOP (result),
7087 aopGet (AOP (right), offset, FALSE),
7092 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7094 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7095 aopPut (AOP (result), "l", LSB);
7096 aopPut (AOP (result), "h", MSB16);
7098 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7100 /* Special case. Load into a and d, then load out. */
7101 _moveA (aopGet (AOP (right), 0, FALSE));
7102 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7103 aopPut (AOP (result), "a", 0);
7104 aopPut (AOP (result), "e", 1);
7106 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7108 /* Special case - simple memcpy */
7109 aopGet (AOP (right), LSB, FALSE);
7112 aopGet (AOP (result), LSB, FALSE);
7116 emit2 ("ld a,(de)");
7117 /* Peephole will optimise this. */
7118 emit2 ("ld (hl),a");
7126 spillPair (PAIR_HL);
7132 /* PENDING: do this check better */
7133 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7135 _moveA (aopGet (AOP (right), offset, FALSE));
7136 aopPut (AOP (result), "a", offset);
7139 aopPut (AOP (result),
7140 aopGet (AOP (right), offset, FALSE),
7147 freeAsmop (right, NULL, ic);
7148 freeAsmop (result, NULL, ic);
7151 /*-----------------------------------------------------------------*/
7152 /* genJumpTab - genrates code for jump table */
7153 /*-----------------------------------------------------------------*/
7155 genJumpTab (iCode * ic)
7160 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7161 /* get the condition into accumulator */
7162 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7165 emit2 ("ld e,%s", l);
7166 emit2 ("ld d,!zero");
7167 jtab = newiTempLabel (NULL);
7169 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7170 emit2 ("add hl,de");
7171 emit2 ("add hl,de");
7172 emit2 ("add hl,de");
7173 freeAsmop (IC_JTCOND (ic), NULL, ic);
7177 emitLabel (jtab->key + 100);
7178 /* now generate the jump labels */
7179 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7180 jtab = setNextItem (IC_JTLABELS (ic)))
7181 emit2 ("jp !tlabel", jtab->key + 100);
7184 /*-----------------------------------------------------------------*/
7185 /* genCast - gen code for casting */
7186 /*-----------------------------------------------------------------*/
7188 genCast (iCode * ic)
7190 operand *result = IC_RESULT (ic);
7191 sym_link *rtype = operandType (IC_RIGHT (ic));
7192 operand *right = IC_RIGHT (ic);
7195 /* if they are equivalent then do nothing */
7196 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7199 aopOp (right, ic, FALSE, FALSE);
7200 aopOp (result, ic, FALSE, FALSE);
7202 /* if the result is a bit */
7203 if (AOP_TYPE (result) == AOP_CRY)
7205 wassertl (0, "Tried to cast to a bit");
7208 /* if they are the same size : or less */
7209 if (AOP_SIZE (result) <= AOP_SIZE (right))
7212 /* if they are in the same place */
7213 if (sameRegs (AOP (right), AOP (result)))
7216 /* if they in different places then copy */
7217 size = AOP_SIZE (result);
7221 aopPut (AOP (result),
7222 aopGet (AOP (right), offset, FALSE),
7229 /* So we now know that the size of destination is greater
7230 than the size of the source */
7231 /* we move to result for the size of source */
7232 size = AOP_SIZE (right);
7236 aopPut (AOP (result),
7237 aopGet (AOP (right), offset, FALSE),
7242 /* now depending on the sign of the destination */
7243 size = AOP_SIZE (result) - AOP_SIZE (right);
7244 /* Unsigned or not an integral type - right fill with zeros */
7245 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7248 aopPut (AOP (result), "!zero", offset++);
7252 /* we need to extend the sign :{ */
7253 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7259 aopPut (AOP (result), "a", offset++);
7263 freeAsmop (right, NULL, ic);
7264 freeAsmop (result, NULL, ic);
7267 /*-----------------------------------------------------------------*/
7268 /* genReceive - generate code for a receive iCode */
7269 /*-----------------------------------------------------------------*/
7271 genReceive (iCode * ic)
7273 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7274 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7275 IS_TRUE_SYMOP (IC_RESULT (ic))))
7285 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7286 size = AOP_SIZE(IC_RESULT(ic));
7288 for (i = 0; i < size; i++) {
7289 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7293 freeAsmop (IC_RESULT (ic), NULL, ic);
7296 /*-----------------------------------------------------------------*/
7297 /* genDummyRead - generate code for dummy read of volatiles */
7298 /*-----------------------------------------------------------------*/
7300 genDummyRead (iCode * ic)
7306 if (op && IS_SYMOP (op))
7308 aopOp (op, ic, FALSE, FALSE);
7311 size = AOP_SIZE (op);
7316 _moveA (aopGet (AOP (op), offset, FALSE));
7320 freeAsmop (op, NULL, ic);
7324 if (op && IS_SYMOP (op))
7326 aopOp (op, ic, FALSE, FALSE);
7329 size = AOP_SIZE (op);
7334 _moveA (aopGet (AOP (op), offset, FALSE));
7338 freeAsmop (op, NULL, ic);
7344 /** Maximum number of bytes to emit per line. */
7348 /** Context for the byte output chunker. */
7351 unsigned char buffer[DBEMIT_MAX_RUN];
7356 /** Flushes a byte chunker by writing out all in the buffer and
7360 _dbFlush(DBEMITCTX *self)
7367 sprintf(line, ".db 0x%02X", self->buffer[0]);
7369 for (i = 1; i < self->pos; i++)
7371 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7378 /** Write out another byte, buffering until a decent line is
7382 _dbEmit(DBEMITCTX *self, int c)
7384 if (self->pos == DBEMIT_MAX_RUN)
7388 self->buffer[self->pos++] = c;
7391 /** Context for a simple run length encoder. */
7395 unsigned char buffer[128];
7397 /** runLen may be equivalent to pos. */
7403 RLE_CHANGE_COST = 4,
7407 /** Flush the buffer of a run length encoder by writing out the run or
7408 data that it currently contains.
7411 _rleCommit(RLECTX *self)
7417 memset(&db, 0, sizeof(db));
7419 emit2(".db %u", self->pos);
7421 for (i = 0; i < self->pos; i++)
7423 _dbEmit(&db, self->buffer[i]);
7432 Can get either a run or a block of random stuff.
7433 Only want to change state if a good run comes in or a run ends.
7434 Detecting run end is easy.
7437 Say initial state is in run, len zero, last zero. Then if you get a
7438 few zeros then something else then a short run will be output.
7439 Seems OK. While in run mode, keep counting. While in random mode,
7440 keep a count of the run. If run hits margin, output all up to run,
7441 restart, enter run mode.
7444 /** Add another byte into the run length encoder, flushing as
7445 required. The run length encoder uses the Amiga IFF style, where
7446 a block is prefixed by its run length. A positive length means
7447 the next n bytes pass straight through. A negative length means
7448 that the next byte is repeated -n times. A zero terminates the
7452 _rleAppend(RLECTX *self, unsigned c)
7456 if (c != self->last)
7458 /* The run has stopped. See if it is worthwhile writing it out
7459 as a run. Note that the random data comes in as runs of
7462 if (self->runLen > RLE_CHANGE_COST)
7464 /* Yes, worthwhile. */
7465 /* Commit whatever was in the buffer. */
7467 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7471 /* Not worthwhile. Append to the end of the random list. */
7472 for (i = 0; i < self->runLen; i++)
7474 if (self->pos >= RLE_MAX_BLOCK)
7479 self->buffer[self->pos++] = self->last;
7487 if (self->runLen >= RLE_MAX_BLOCK)
7489 /* Commit whatever was in the buffer. */
7492 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7500 _rleFlush(RLECTX *self)
7502 _rleAppend(self, -1);
7509 /** genArrayInit - Special code for initialising an array with constant
7513 genArrayInit (iCode * ic)
7517 int elementSize = 0, eIndex, i;
7518 unsigned val, lastVal;
7522 memset(&rle, 0, sizeof(rle));
7524 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7526 _saveRegsForCall(ic, 0);
7528 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7529 emit2 ("call __initrleblock");
7531 type = operandType(IC_LEFT(ic));
7533 if (type && type->next)
7535 if (IS_SPEC(type->next) || IS_PTR(type->next))
7537 elementSize = getSize(type->next);
7539 else if (IS_ARRAY(type->next) && type->next->next)
7541 elementSize = getSize(type->next->next);
7545 printTypeChainRaw (type, NULL);
7546 wassertl (0, "Can't determine element size in genArrayInit.");
7551 wassertl (0, "Can't determine element size in genArrayInit.");
7554 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7556 iLoop = IC_ARRAYILIST(ic);
7557 lastVal = (unsigned)-1;
7559 /* Feed all the bytes into the run length encoder which will handle
7561 This works well for mixed char data, and for random int and long
7568 for (i = 0; i < ix; i++)
7570 for (eIndex = 0; eIndex < elementSize; eIndex++)
7572 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7573 _rleAppend(&rle, val);
7577 iLoop = iLoop->next;
7581 /* Mark the end of the run. */
7584 _restoreRegsAfterCall();
7588 freeAsmop (IC_LEFT(ic), NULL, ic);
7592 _swap (PAIR_ID one, PAIR_ID two)
7594 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7600 emit2 ("ld a,%s", _pairs[one].l);
7601 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7602 emit2 ("ld %s,a", _pairs[two].l);
7603 emit2 ("ld a,%s", _pairs[one].h);
7604 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7605 emit2 ("ld %s,a", _pairs[two].h);
7609 /* The problem is that we may have all three pairs used and they may
7610 be needed in a different order.
7615 hl = hl => unity, fine
7619 hl = hl hl = hl, swap de <=> bc
7627 hl = bc de = de, swap bc <=> hl
7635 hl = de bc = bc, swap hl <=> de
7640 * Any pair = pair are done last
7641 * Any pair = iTemp are done last
7642 * Any swaps can be done any time
7650 So how do we detect the cases?
7651 How about a 3x3 matrix?
7655 x x x x (Fourth for iTemp/other)
7657 First determin which mode to use by counting the number of unity and
7660 Two - Assign the pair first, then the rest
7661 One - Swap the two, then the rest
7665 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7667 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7669 PAIR_BC, PAIR_HL, PAIR_DE
7671 int i, j, nunity = 0;
7672 memset (ids, PAIR_INVALID, sizeof (ids));
7675 wassert (nparams == 3);
7677 /* First save everything that needs to be saved. */
7678 _saveRegsForCall (ic, 0);
7680 /* Loading HL first means that DE is always fine. */
7681 for (i = 0; i < nparams; i++)
7683 aopOp (pparams[i], ic, FALSE, FALSE);
7684 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7687 /* Count the number of unity or iTemp assigns. */
7688 for (i = 0; i < 3; i++)
7690 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7698 /* Any order, fall through. */
7700 else if (nunity == 2)
7702 /* One is assigned. Pull it out and assign. */
7703 for (i = 0; i < 3; i++)
7705 for (j = 0; j < NUM_PAIRS; j++)
7707 if (ids[dest[i]][j] == TRUE)
7709 /* Found it. See if it's the right one. */
7710 if (j == PAIR_INVALID || j == dest[i])
7716 fetchPair(dest[i], AOP (pparams[i]));
7723 else if (nunity == 1)
7725 /* Find the pairs to swap. */
7726 for (i = 0; i < 3; i++)
7728 for (j = 0; j < NUM_PAIRS; j++)
7730 if (ids[dest[i]][j] == TRUE)
7732 if (j == PAIR_INVALID || j == dest[i])
7747 int next = getPairId (AOP (pparams[0]));
7748 emit2 ("push %s", _pairs[next].name);
7750 if (next == dest[1])
7752 fetchPair (dest[1], AOP (pparams[1]));
7753 fetchPair (dest[2], AOP (pparams[2]));
7757 fetchPair (dest[2], AOP (pparams[2]));
7758 fetchPair (dest[1], AOP (pparams[1]));
7760 emit2 ("pop %s", _pairs[dest[0]].name);
7763 /* Finally pull out all of the iTemps */
7764 for (i = 0; i < 3; i++)
7766 if (ids[dest[i]][PAIR_INVALID] == 1)
7768 fetchPair (dest[i], AOP (pparams[i]));
7774 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7780 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7784 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7786 setupForBuiltin3 (ic, nParams, pparams);
7788 label = newiTempLabel(NULL);
7790 emitLabel (label->key);
7791 emit2 ("ld a,(hl)");
7794 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7796 freeAsmop (from, NULL, ic->next);
7797 freeAsmop (to, NULL, ic);
7801 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7803 operand *from, *to, *count;
7806 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7811 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7813 setupForBuiltin3 (ic, nParams, pparams);
7817 freeAsmop (count, NULL, ic->next->next);
7818 freeAsmop (from, NULL, ic);
7820 _restoreRegsAfterCall();
7822 /* if we need assign a result value */
7823 if ((IS_ITEMP (IC_RESULT (ic)) &&
7824 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7825 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7826 IS_TRUE_SYMOP (IC_RESULT (ic)))
7828 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7829 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7830 freeAsmop (IC_RESULT (ic), NULL, ic);
7833 freeAsmop (to, NULL, ic->next);
7836 /*-----------------------------------------------------------------*/
7837 /* genBuiltIn - calls the appropriate function to generating code */
7838 /* for a built in function */
7839 /*-----------------------------------------------------------------*/
7840 static void genBuiltIn (iCode *ic)
7842 operand *bi_parms[MAX_BUILTIN_ARGS];
7847 /* get all the arguments for a built in function */
7848 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7850 /* which function is it */
7851 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7853 if (strcmp(bif->name,"__builtin_strcpy")==0)
7855 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7857 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7859 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7863 wassertl (0, "Unknown builtin function encountered");
7867 /*-----------------------------------------------------------------*/
7868 /* genZ80Code - generate code for Z80 based controllers */
7869 /*-----------------------------------------------------------------*/
7871 genZ80Code (iCode * lic)
7879 _fReturn = _gbz80_return;
7880 _fTmp = _gbz80_return;
7884 _fReturn = _z80_return;
7885 _fTmp = _z80_return;
7888 _G.lines.head = _G.lines.current = NULL;
7890 /* if debug information required */
7891 if (options.debug && currFunc)
7893 debugFile->writeFunction (currFunc, lic);
7896 for (ic = lic; ic; ic = ic->next)
7898 _G.current_iCode = ic;
7900 if (ic->lineno && cln != ic->lineno)
7904 debugFile->writeCLine (ic);
7906 if (!options.noCcodeInAsm) {
7907 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7908 printCLine(ic->filename, ic->lineno));
7912 if (options.iCodeInAsm) {
7913 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7915 /* if the result is marked as
7916 spilt and rematerializable or code for
7917 this has already been generated then
7919 if (resultRemat (ic) || ic->generated)
7922 /* depending on the operation */
7926 emitDebug ("; genNot");
7931 emitDebug ("; genCpl");
7936 emitDebug ("; genUminus");
7941 emitDebug ("; genIpush");
7946 /* IPOP happens only when trying to restore a
7947 spilt live range, if there is an ifx statement
7948 following this pop then the if statement might
7949 be using some of the registers being popped which
7950 would destory the contents of the register so
7951 we need to check for this condition and handle it */
7953 ic->next->op == IFX &&
7954 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7956 emitDebug ("; genIfx");
7957 genIfx (ic->next, ic);
7961 emitDebug ("; genIpop");
7967 emitDebug ("; genCall");
7972 emitDebug ("; genPcall");
7977 emitDebug ("; genFunction");
7982 emitDebug ("; genEndFunction");
7983 genEndFunction (ic);
7987 emitDebug ("; genRet");
7992 emitDebug ("; genLabel");
7997 emitDebug ("; genGoto");
8002 emitDebug ("; genPlus");
8007 emitDebug ("; genMinus");
8012 emitDebug ("; genMult");
8017 emitDebug ("; genDiv");
8022 emitDebug ("; genMod");
8027 emitDebug ("; genCmpGt");
8028 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8032 emitDebug ("; genCmpLt");
8033 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8040 /* note these two are xlated by algebraic equivalence
8041 during parsing SDCC.y */
8042 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8043 "got '>=' or '<=' shouldn't have come here");
8047 emitDebug ("; genCmpEq");
8048 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8052 emitDebug ("; genAndOp");
8057 emitDebug ("; genOrOp");
8062 emitDebug ("; genXor");
8063 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8067 emitDebug ("; genOr");
8068 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8072 emitDebug ("; genAnd");
8073 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8077 emitDebug ("; genInline");
8082 emitDebug ("; genRRC");
8087 emitDebug ("; genRLC");
8092 emitDebug ("; genGetHBIT");
8097 emitDebug ("; genLeftShift");
8102 emitDebug ("; genRightShift");
8106 case GET_VALUE_AT_ADDRESS:
8107 emitDebug ("; genPointerGet");
8113 if (POINTER_SET (ic))
8115 emitDebug ("; genAssign (pointer)");
8120 emitDebug ("; genAssign");
8126 emitDebug ("; genIfx");
8131 emitDebug ("; genAddrOf");
8136 emitDebug ("; genJumpTab");
8141 emitDebug ("; genCast");
8146 emitDebug ("; genReceive");
8151 if (ic->builtinSEND)
8153 emitDebug ("; genBuiltIn");
8158 emitDebug ("; addSet");
8159 addSet (&_G.sendSet, ic);
8164 emitDebug ("; genArrayInit");
8168 case DUMMY_READ_VOLATILE:
8169 emitDebug ("; genDummyRead");
8179 /* now we are ready to call the
8180 peep hole optimizer */
8181 if (!options.nopeep)
8182 peepHole (&_G.lines.head);
8184 /* This is unfortunate */
8185 /* now do the actual printing */
8187 FILE *fp = codeOutFile;
8188 if (isInHome () && codeOutFile == code->oFile)
8189 codeOutFile = home->oFile;
8190 printLine (_G.lines.head, codeOutFile);
8191 if (_G.flushStatics)
8194 _G.flushStatics = 0;
8199 freeTrace(&_G.lines.trace);
8200 freeTrace(&_G.trace.aops);
8206 _isPairUsed (iCode * ic, PAIR_ID pairId)
8212 if (bitVectBitValue (ic->rMask, D_IDX))
8214 if (bitVectBitValue (ic->rMask, E_IDX))
8224 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8227 value *val = aop->aopu.aop_lit;
8229 wassert (aop->type == AOP_LIT);
8230 wassert (!IS_FLOAT (val->type));
8232 v = (unsigned long) floatFromVal (val);
8240 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8241 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));