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 /* now move the left to the result if they are not the
6049 if (!sameRegs (AOP (left), AOP (result)))
6052 size = AOP_SIZE (result);
6056 l = aopGet (AOP (left), offset, FALSE);
6057 aopPut (AOP (result), l, offset);
6062 tlbl = newiTempLabel (NULL);
6063 size = AOP_SIZE (result);
6065 tlbl1 = newiTempLabel (NULL);
6067 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6068 emitLabel (tlbl->key + 100);
6069 l = aopGet (AOP (result), offset, FALSE);
6073 l = aopGet (AOP (result), offset, FALSE);
6077 emit2 ("sla %s", l);
6085 emitLabel (tlbl1->key + 100);
6087 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6089 freeAsmop (left, NULL, ic);
6090 freeAsmop (result, NULL, ic);
6093 /*-----------------------------------------------------------------*/
6094 /* genrshOne - left shift two bytes by known amount != 0 */
6095 /*-----------------------------------------------------------------*/
6097 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6100 int size = AOP_SIZE (result);
6103 wassert (size == 1);
6104 wassert (shCount < 8);
6106 l = aopGet (AOP (left), 0, FALSE);
6108 if (AOP (result)->type == AOP_REG)
6110 aopPut (AOP (result), l, 0);
6111 l = aopGet (AOP (result), 0, FALSE);
6114 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6122 emit2 ("%s a", is_signed ? "sra" : "srl");
6124 aopPut (AOP (result), "a", 0);
6128 /*-----------------------------------------------------------------*/
6129 /* AccRsh - right shift accumulator by known count */
6130 /*-----------------------------------------------------------------*/
6132 AccRsh (int shCount)
6134 static const unsigned char SRMask[] =
6136 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6141 /* rotate right accumulator */
6142 AccRol (8 - shCount);
6143 /* and kill the higher order bits */
6144 emit2 ("and a,!immedbyte", SRMask[shCount]);
6148 /*-----------------------------------------------------------------*/
6149 /* shiftR1Left2Result - shift right one byte from left to result */
6150 /*-----------------------------------------------------------------*/
6152 shiftR1Left2Result (operand * left, int offl,
6153 operand * result, int offr,
6154 int shCount, int sign)
6156 _moveA (aopGet (AOP (left), offl, FALSE));
6161 emit2 ("%s a", sign ? "sra" : "srl");
6168 aopPut (AOP (result), "a", offr);
6171 /*-----------------------------------------------------------------*/
6172 /* genrshTwo - right shift two bytes by known amount != 0 */
6173 /*-----------------------------------------------------------------*/
6175 genrshTwo (operand * result, operand * left,
6176 int shCount, int sign)
6178 /* if shCount >= 8 */
6184 shiftR1Left2Result (left, MSB16, result, LSB,
6189 movLeft2Result (left, MSB16, result, LSB, sign);
6193 /* Sign extend the result */
6194 _moveA(aopGet (AOP (result), 0, FALSE));
6198 aopPut (AOP (result), ACC_NAME, MSB16);
6202 aopPut (AOP (result), "!zero", 1);
6205 /* 1 <= shCount <= 7 */
6208 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6212 /*-----------------------------------------------------------------*/
6213 /* genRightShiftLiteral - left shifting by known count */
6214 /*-----------------------------------------------------------------*/
6216 genRightShiftLiteral (operand * left,
6222 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6225 freeAsmop (right, NULL, ic);
6227 aopOp (left, ic, FALSE, FALSE);
6228 aopOp (result, ic, FALSE, FALSE);
6230 size = getSize (operandType (result));
6232 /* I suppose that the left size >= result size */
6238 else if (shCount >= (size * 8)) {
6240 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6241 _moveA(aopGet (AOP (left), 0, FALSE));
6249 aopPut (AOP (result), s, size);
6256 genrshOne (result, left, shCount, sign);
6259 genrshTwo (result, left, shCount, sign);
6262 wassertl (0, "Asked to shift right a long which should be a function call");
6265 wassertl (0, "Entered default case in right shift delegate");
6268 freeAsmop (left, NULL, ic);
6269 freeAsmop (result, NULL, ic);
6272 /*-----------------------------------------------------------------*/
6273 /* genRightShift - generate code for right shifting */
6274 /*-----------------------------------------------------------------*/
6276 genRightShift (iCode * ic)
6278 operand *right, *left, *result;
6280 int size, offset, first = 1;
6284 symbol *tlbl, *tlbl1;
6286 /* if signed then we do it the hard way preserve the
6287 sign bit moving it inwards */
6288 retype = getSpec (operandType (IC_RESULT (ic)));
6290 is_signed = !SPEC_USIGN (retype);
6292 /* signed & unsigned types are treated the same : i.e. the
6293 signed is NOT propagated inwards : quoting from the
6294 ANSI - standard : "for E1 >> E2, is equivalent to division
6295 by 2**E2 if unsigned or if it has a non-negative value,
6296 otherwise the result is implementation defined ", MY definition
6297 is that the sign does not get propagated */
6299 right = IC_RIGHT (ic);
6300 left = IC_LEFT (ic);
6301 result = IC_RESULT (ic);
6303 aopOp (right, ic, FALSE, FALSE);
6305 /* if the shift count is known then do it
6306 as efficiently as possible */
6307 if (AOP_TYPE (right) == AOP_LIT)
6309 genRightShiftLiteral (left, right, result, ic, is_signed);
6313 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6315 freeAsmop (right, NULL, ic);
6317 aopOp (left, ic, FALSE, FALSE);
6318 aopOp (result, ic, FALSE, FALSE);
6320 /* now move the left to the result if they are not the
6322 if (!sameRegs (AOP (left), AOP (result)))
6325 size = AOP_SIZE (result);
6329 l = aopGet (AOP (left), offset, FALSE);
6330 aopPut (AOP (result), l, offset);
6335 tlbl = newiTempLabel (NULL);
6336 tlbl1 = newiTempLabel (NULL);
6337 size = AOP_SIZE (result);
6340 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6341 emitLabel (tlbl->key + 100);
6344 l = aopGet (AOP (result), offset--, FALSE);
6347 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6355 emitLabel (tlbl1->key + 100);
6357 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6359 freeAsmop (left, NULL, ic);
6360 freeAsmop (result, NULL, ic);
6364 /*-----------------------------------------------------------------*/
6365 /* genUnpackBits - generates code for unpacking bits */
6366 /*-----------------------------------------------------------------*/
6368 genUnpackBits (operand * result, int pair)
6370 int offset = 0; /* result byte offset */
6371 int rsize; /* result size */
6372 int rlen = 0; /* remaining bitfield length */
6373 sym_link *etype; /* bitfield type information */
6374 int blen; /* bitfield length */
6375 int bstr; /* bitfield starting bit within byte */
6377 emitDebug ("; genUnpackBits");
6379 etype = getSpec (operandType (result));
6380 rsize = getSize (operandType (result));
6381 blen = SPEC_BLEN (etype);
6382 bstr = SPEC_BSTR (etype);
6384 /* If the bitfield length is less than a byte */
6387 emit2 ("ld a,!*pair", _pairs[pair].name);
6389 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6390 aopPut (AOP (result), "a", offset++);
6394 /* TODO: what if pair == PAIR_DE ? */
6395 if (getPairId (AOP (result)) == PAIR_HL)
6397 wassertl (rsize == 2, "HL must be of size 2");
6398 emit2 ("ld a,!*hl");
6400 emit2 ("ld h,!*hl");
6403 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6405 spillPair (PAIR_HL);
6409 /* Bit field did not fit in a byte. Copy all
6410 but the partial byte at the end. */
6411 for (rlen=blen;rlen>=8;rlen-=8)
6413 emit2 ("ld a,!*pair", _pairs[pair].name);
6414 aopPut (AOP (result), "a", offset++);
6417 emit2 ("inc %s", _pairs[pair].name);
6418 _G.pairs[pair].offset++;
6422 /* Handle the partial byte at the end */
6425 emit2 ("ld a,!*pair", _pairs[pair].name);
6426 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6427 aopPut (AOP (result), "a", offset++);
6435 aopPut (AOP (result), "!zero", offset++);
6439 /*-----------------------------------------------------------------*/
6440 /* genGenPointerGet - get value from generic pointer space */
6441 /*-----------------------------------------------------------------*/
6443 genGenPointerGet (operand * left,
6444 operand * result, iCode * ic)
6447 sym_link *retype = getSpec (operandType (result));
6453 aopOp (left, ic, FALSE, FALSE);
6454 aopOp (result, ic, FALSE, FALSE);
6456 size = AOP_SIZE (result);
6458 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6461 if (isPtrPair (AOP (left)))
6463 tsprintf (buffer, sizeof(buffer),
6464 "!*pair", getPairName (AOP (left)));
6465 aopPut (AOP (result), buffer, 0);
6469 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6470 aopPut (AOP (result), "a", 0);
6472 freeAsmop (left, NULL, ic);
6476 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6483 tsprintf (at, sizeof(at), "!*iyx", offset);
6484 aopPut (AOP (result), at, offset);
6488 freeAsmop (left, NULL, ic);
6492 /* For now we always load into IY */
6493 /* if this is remateriazable */
6494 fetchPair (pair, AOP (left));
6496 /* if bit then unpack */
6497 if (IS_BITVAR (retype))
6499 genUnpackBits (result, pair);
6500 freeAsmop (left, NULL, ic);
6504 else if (getPairId (AOP (result)) == PAIR_HL)
6506 wassertl (size == 2, "HL must be of size 2");
6507 emit2 ("ld a,!*hl");
6509 emit2 ("ld h,!*hl");
6511 spillPair (PAIR_HL);
6513 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6515 size = AOP_SIZE (result);
6520 /* PENDING: make this better */
6521 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6523 aopPut (AOP (result), "!*hl", offset++);
6527 emit2 ("ld a,!*pair", _pairs[pair].name);
6528 aopPut (AOP (result), "a", offset++);
6532 emit2 ("inc %s", _pairs[pair].name);
6533 _G.pairs[pair].offset++;
6536 /* Fixup HL back down */
6537 for (size = AOP_SIZE (result)-1; size; size--)
6539 emit2 ("dec %s", _pairs[pair].name);
6544 size = AOP_SIZE (result);
6549 /* PENDING: make this better */
6551 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6553 aopPut (AOP (result), "!*hl", offset++);
6557 emit2 ("ld a,!*pair", _pairs[pair].name);
6558 aopPut (AOP (result), "a", offset++);
6562 emit2 ("inc %s", _pairs[pair].name);
6563 _G.pairs[pair].offset++;
6568 freeAsmop (left, NULL, ic);
6571 freeAsmop (result, NULL, ic);
6574 /*-----------------------------------------------------------------*/
6575 /* genPointerGet - generate code for pointer get */
6576 /*-----------------------------------------------------------------*/
6578 genPointerGet (iCode * ic)
6580 operand *left, *result;
6581 sym_link *type, *etype;
6583 left = IC_LEFT (ic);
6584 result = IC_RESULT (ic);
6586 /* depending on the type of pointer we need to
6587 move it to the correct pointer register */
6588 type = operandType (left);
6589 etype = getSpec (type);
6591 genGenPointerGet (left, result, ic);
6595 isRegOrLit (asmop * aop)
6597 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6603 /*-----------------------------------------------------------------*/
6604 /* genPackBits - generates code for packed bit storage */
6605 /*-----------------------------------------------------------------*/
6607 genPackBits (sym_link * etype,
6612 int offset = 0; /* source byte offset */
6613 int rlen = 0; /* remaining bitfield length */
6614 int blen; /* bitfield length */
6615 int bstr; /* bitfield starting bit within byte */
6616 int litval; /* source literal value (if AOP_LIT) */
6617 unsigned char mask; /* bitmask within current byte */
6618 int extraPair; /* a tempory register */
6619 bool needPopExtra=0; /* need to restore original value of temp reg */
6621 emitDebug ("; genPackBits","");
6623 blen = SPEC_BLEN (etype);
6624 bstr = SPEC_BSTR (etype);
6626 /* If the bitfield length is less than a byte */
6629 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6630 (unsigned char) (0xFF >> (8 - bstr)));
6632 if (AOP_TYPE (right) == AOP_LIT)
6634 /* Case with a bitfield length <8 and literal source
6636 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6638 litval &= (~mask) & 0xff;
6639 emit2 ("ld a,!*pair", _pairs[pair].name);
6640 if ((mask|litval)!=0xff)
6641 emit2 ("and a,!immedbyte", mask);
6643 emit2 ("or a,!immedbyte", litval);
6644 emit2 ("ld !*pair,a", _pairs[pair].name);
6649 /* Case with a bitfield length <8 and arbitrary source
6651 _moveA (aopGet (AOP (right), 0, FALSE));
6652 /* shift and mask source value */
6654 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6656 extraPair = getFreePairId(ic);
6657 if (extraPair == PAIR_INVALID)
6659 extraPair = PAIR_BC;
6660 if (getPairId (AOP (right)) != PAIR_BC
6661 || !isLastUse (ic, right))
6667 emit2 ("ld %s,a", _pairs[extraPair].l);
6668 emit2 ("ld a,!*pair", _pairs[pair].name);
6670 emit2 ("and a,!immedbyte", mask);
6671 emit2 ("or a,%s", _pairs[extraPair].l);
6672 emit2 ("ld !*pair,a", _pairs[pair].name);
6679 /* Bit length is greater than 7 bits. In this case, copy */
6680 /* all except the partial byte at the end */
6681 for (rlen=blen;rlen>=8;rlen-=8)
6683 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6684 emit2 ("ld !*pair,a", _pairs[pair].name);
6687 emit2 ("inc %s", _pairs[pair].name);
6688 _G.pairs[pair].offset++;
6692 /* If there was a partial byte at the end */
6695 mask = (((unsigned char) -1 << rlen) & 0xff);
6697 if (AOP_TYPE (right) == AOP_LIT)
6699 /* Case with partial byte and literal source
6701 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6702 litval >>= (blen-rlen);
6703 litval &= (~mask) & 0xff;
6704 emit2 ("ld a,!*pair", _pairs[pair].name);
6705 if ((mask|litval)!=0xff)
6706 emit2 ("and a,!immedbyte", mask);
6708 emit2 ("or a,!immedbyte", litval);
6712 /* Case with partial byte and arbitrary source
6714 _moveA (aopGet (AOP (right), offset++, FALSE));
6715 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6717 extraPair = getFreePairId(ic);
6718 if (extraPair == PAIR_INVALID)
6720 extraPair = getPairId (AOP (right));
6721 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6722 extraPair = PAIR_BC;
6724 if (getPairId (AOP (right)) != PAIR_BC
6725 || !isLastUse (ic, right))
6731 emit2 ("ld %s,a", _pairs[extraPair].l);
6732 emit2 ("ld a,!*pair", _pairs[pair].name);
6734 emit2 ("and a,!immedbyte", mask);
6735 emit2 ("or a,%s", _pairs[extraPair].l);
6740 emit2 ("ld !*pair,a", _pairs[pair].name);
6745 /*-----------------------------------------------------------------*/
6746 /* genGenPointerSet - stores the value into a pointer location */
6747 /*-----------------------------------------------------------------*/
6749 genGenPointerSet (operand * right,
6750 operand * result, iCode * ic)
6753 sym_link *retype = getSpec (operandType (right));
6754 sym_link *letype = getSpec (operandType (result));
6755 PAIR_ID pairId = PAIR_HL;
6758 aopOp (result, ic, FALSE, FALSE);
6759 aopOp (right, ic, FALSE, FALSE);
6764 size = AOP_SIZE (right);
6766 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6767 emitDebug("; isBitvar = %d", isBitvar);
6769 /* Handle the exceptions first */
6770 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6773 const char *l = aopGet (AOP (right), 0, FALSE);
6774 const char *pair = getPairName (AOP (result));
6775 if (canAssignToPtr (l) && isPtr (pair))
6777 emit2 ("ld !*pair,%s", pair, l);
6782 emit2 ("ld !*pair,a", pair);
6787 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6790 const char *l = aopGet (AOP (right), 0, FALSE);
6795 if (canAssignToPtr (l))
6797 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6801 _moveA (aopGet (AOP (right), offset, FALSE));
6802 emit2 ("ld !*iyx,a", offset);
6808 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6815 const char *l = aopGet (AOP (right), offset, FALSE);
6816 if (isRegOrLit (AOP (right)) && !IS_GB)
6818 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6823 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6827 emit2 ("inc %s", _pairs[PAIR_HL].name);
6828 _G.pairs[PAIR_HL].offset++;
6833 /* Fixup HL back down */
6834 for (size = AOP_SIZE (right)-1; size; size--)
6836 emit2 ("dec %s", _pairs[PAIR_HL].name);
6841 /* if the operand is already in dptr
6842 then we do nothing else we move the value to dptr */
6843 if (AOP_TYPE (result) != AOP_STR)
6845 fetchPair (pairId, AOP (result));
6847 /* so hl now contains the address */
6848 freeAsmop (result, NULL, ic);
6850 /* if bit then unpack */
6853 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6863 const char *l = aopGet (AOP (right), offset, FALSE);
6864 if (isRegOrLit (AOP (right)) && !IS_GB)
6866 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6871 emit2 ("ld !*pair,a", _pairs[pairId].name);
6875 emit2 ("inc %s", _pairs[pairId].name);
6876 _G.pairs[pairId].offset++;
6882 freeAsmop (right, NULL, ic);
6885 /*-----------------------------------------------------------------*/
6886 /* genPointerSet - stores the value into a pointer location */
6887 /*-----------------------------------------------------------------*/
6889 genPointerSet (iCode * ic)
6891 operand *right, *result;
6892 sym_link *type, *etype;
6894 right = IC_RIGHT (ic);
6895 result = IC_RESULT (ic);
6897 /* depending on the type of pointer we need to
6898 move it to the correct pointer register */
6899 type = operandType (result);
6900 etype = getSpec (type);
6902 genGenPointerSet (right, result, ic);
6905 /*-----------------------------------------------------------------*/
6906 /* genIfx - generate code for Ifx statement */
6907 /*-----------------------------------------------------------------*/
6909 genIfx (iCode * ic, iCode * popIc)
6911 operand *cond = IC_COND (ic);
6914 aopOp (cond, ic, FALSE, TRUE);
6916 /* get the value into acc */
6917 if (AOP_TYPE (cond) != AOP_CRY)
6921 /* the result is now in the accumulator */
6922 freeAsmop (cond, NULL, ic);
6924 /* if there was something to be popped then do it */
6928 /* if the condition is a bit variable */
6929 if (isbit && IS_ITEMP (cond) &&
6931 genIfxJump (ic, SPIL_LOC (cond)->rname);
6932 else if (isbit && !IS_ITEMP (cond))
6933 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6935 genIfxJump (ic, "a");
6940 /*-----------------------------------------------------------------*/
6941 /* genAddrOf - generates code for address of */
6942 /*-----------------------------------------------------------------*/
6944 genAddrOf (iCode * ic)
6946 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6948 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6950 /* if the operand is on the stack then we
6951 need to get the stack offset of this
6958 if (sym->stack <= 0)
6960 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6964 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6966 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6970 emit2 ("ld de,!hashedstr", sym->rname);
6971 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6979 /* if it has an offset then we need to compute it */
6981 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6983 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6984 emit2 ("add hl,sp");
6988 emit2 ("ld hl,!hashedstr", sym->rname);
6990 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6992 freeAsmop (IC_RESULT (ic), NULL, ic);
6995 /*-----------------------------------------------------------------*/
6996 /* genAssign - generate code for assignment */
6997 /*-----------------------------------------------------------------*/
6999 genAssign (iCode * ic)
7001 operand *result, *right;
7003 unsigned long lit = 0L;
7005 result = IC_RESULT (ic);
7006 right = IC_RIGHT (ic);
7008 /* Dont bother assigning if they are the same */
7009 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7011 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7015 aopOp (right, ic, FALSE, FALSE);
7016 aopOp (result, ic, TRUE, FALSE);
7018 /* if they are the same registers */
7019 if (sameRegs (AOP (right), AOP (result)))
7021 emitDebug ("; (registers are the same)");
7025 /* if the result is a bit */
7026 if (AOP_TYPE (result) == AOP_CRY)
7028 wassertl (0, "Tried to assign to a bit");
7032 size = AOP_SIZE (result);
7035 if (AOP_TYPE (right) == AOP_LIT)
7037 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7040 if (isPair (AOP (result)))
7042 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7044 else if ((size > 1) &&
7045 (AOP_TYPE (result) != AOP_REG) &&
7046 (AOP_TYPE (right) == AOP_LIT) &&
7047 !IS_FLOAT (operandType (right)) &&
7050 bool fXored = FALSE;
7052 /* Work from the top down.
7053 Done this way so that we can use the cached copy of 0
7054 in A for a fast clear */
7057 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7059 if (!fXored && size > 1)
7066 aopPut (AOP (result), "a", offset);
7070 aopPut (AOP (result), "!zero", offset);
7074 aopPut (AOP (result),
7075 aopGet (AOP (right), offset, FALSE),
7080 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7082 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7083 aopPut (AOP (result), "l", LSB);
7084 aopPut (AOP (result), "h", MSB16);
7086 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7088 /* Special case. Load into a and d, then load out. */
7089 _moveA (aopGet (AOP (right), 0, FALSE));
7090 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7091 aopPut (AOP (result), "a", 0);
7092 aopPut (AOP (result), "e", 1);
7094 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7096 /* Special case - simple memcpy */
7097 aopGet (AOP (right), LSB, FALSE);
7100 aopGet (AOP (result), LSB, FALSE);
7104 emit2 ("ld a,(de)");
7105 /* Peephole will optimise this. */
7106 emit2 ("ld (hl),a");
7114 spillPair (PAIR_HL);
7120 /* PENDING: do this check better */
7121 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7123 _moveA (aopGet (AOP (right), offset, FALSE));
7124 aopPut (AOP (result), "a", offset);
7127 aopPut (AOP (result),
7128 aopGet (AOP (right), offset, FALSE),
7135 freeAsmop (right, NULL, ic);
7136 freeAsmop (result, NULL, ic);
7139 /*-----------------------------------------------------------------*/
7140 /* genJumpTab - genrates code for jump table */
7141 /*-----------------------------------------------------------------*/
7143 genJumpTab (iCode * ic)
7148 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7149 /* get the condition into accumulator */
7150 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7153 emit2 ("ld e,%s", l);
7154 emit2 ("ld d,!zero");
7155 jtab = newiTempLabel (NULL);
7157 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7158 emit2 ("add hl,de");
7159 emit2 ("add hl,de");
7160 emit2 ("add hl,de");
7161 freeAsmop (IC_JTCOND (ic), NULL, ic);
7165 emitLabel (jtab->key + 100);
7166 /* now generate the jump labels */
7167 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7168 jtab = setNextItem (IC_JTLABELS (ic)))
7169 emit2 ("jp !tlabel", jtab->key + 100);
7172 /*-----------------------------------------------------------------*/
7173 /* genCast - gen code for casting */
7174 /*-----------------------------------------------------------------*/
7176 genCast (iCode * ic)
7178 operand *result = IC_RESULT (ic);
7179 sym_link *rtype = operandType (IC_RIGHT (ic));
7180 operand *right = IC_RIGHT (ic);
7183 /* if they are equivalent then do nothing */
7184 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7187 aopOp (right, ic, FALSE, FALSE);
7188 aopOp (result, ic, FALSE, FALSE);
7190 /* if the result is a bit */
7191 if (AOP_TYPE (result) == AOP_CRY)
7193 wassertl (0, "Tried to cast to a bit");
7196 /* if they are the same size : or less */
7197 if (AOP_SIZE (result) <= AOP_SIZE (right))
7200 /* if they are in the same place */
7201 if (sameRegs (AOP (right), AOP (result)))
7204 /* if they in different places then copy */
7205 size = AOP_SIZE (result);
7209 aopPut (AOP (result),
7210 aopGet (AOP (right), offset, FALSE),
7217 /* So we now know that the size of destination is greater
7218 than the size of the source */
7219 /* we move to result for the size of source */
7220 size = AOP_SIZE (right);
7224 aopPut (AOP (result),
7225 aopGet (AOP (right), offset, FALSE),
7230 /* now depending on the sign of the destination */
7231 size = AOP_SIZE (result) - AOP_SIZE (right);
7232 /* Unsigned or not an integral type - right fill with zeros */
7233 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7236 aopPut (AOP (result), "!zero", offset++);
7240 /* we need to extend the sign :{ */
7241 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7247 aopPut (AOP (result), "a", offset++);
7251 freeAsmop (right, NULL, ic);
7252 freeAsmop (result, NULL, ic);
7255 /*-----------------------------------------------------------------*/
7256 /* genReceive - generate code for a receive iCode */
7257 /*-----------------------------------------------------------------*/
7259 genReceive (iCode * ic)
7261 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7262 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7263 IS_TRUE_SYMOP (IC_RESULT (ic))))
7273 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7274 size = AOP_SIZE(IC_RESULT(ic));
7276 for (i = 0; i < size; i++) {
7277 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7281 freeAsmop (IC_RESULT (ic), NULL, ic);
7284 /*-----------------------------------------------------------------*/
7285 /* genDummyRead - generate code for dummy read of volatiles */
7286 /*-----------------------------------------------------------------*/
7288 genDummyRead (iCode * ic)
7294 if (op && IS_SYMOP (op))
7296 aopOp (op, ic, FALSE, FALSE);
7299 size = AOP_SIZE (op);
7304 _moveA (aopGet (AOP (op), offset, FALSE));
7308 freeAsmop (op, NULL, ic);
7312 if (op && IS_SYMOP (op))
7314 aopOp (op, ic, FALSE, FALSE);
7317 size = AOP_SIZE (op);
7322 _moveA (aopGet (AOP (op), offset, FALSE));
7326 freeAsmop (op, NULL, ic);
7332 /** Maximum number of bytes to emit per line. */
7336 /** Context for the byte output chunker. */
7339 unsigned char buffer[DBEMIT_MAX_RUN];
7344 /** Flushes a byte chunker by writing out all in the buffer and
7348 _dbFlush(DBEMITCTX *self)
7355 sprintf(line, ".db 0x%02X", self->buffer[0]);
7357 for (i = 1; i < self->pos; i++)
7359 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7366 /** Write out another byte, buffering until a decent line is
7370 _dbEmit(DBEMITCTX *self, int c)
7372 if (self->pos == DBEMIT_MAX_RUN)
7376 self->buffer[self->pos++] = c;
7379 /** Context for a simple run length encoder. */
7383 unsigned char buffer[128];
7385 /** runLen may be equivalent to pos. */
7391 RLE_CHANGE_COST = 4,
7395 /** Flush the buffer of a run length encoder by writing out the run or
7396 data that it currently contains.
7399 _rleCommit(RLECTX *self)
7405 memset(&db, 0, sizeof(db));
7407 emit2(".db %u", self->pos);
7409 for (i = 0; i < self->pos; i++)
7411 _dbEmit(&db, self->buffer[i]);
7420 Can get either a run or a block of random stuff.
7421 Only want to change state if a good run comes in or a run ends.
7422 Detecting run end is easy.
7425 Say initial state is in run, len zero, last zero. Then if you get a
7426 few zeros then something else then a short run will be output.
7427 Seems OK. While in run mode, keep counting. While in random mode,
7428 keep a count of the run. If run hits margin, output all up to run,
7429 restart, enter run mode.
7432 /** Add another byte into the run length encoder, flushing as
7433 required. The run length encoder uses the Amiga IFF style, where
7434 a block is prefixed by its run length. A positive length means
7435 the next n bytes pass straight through. A negative length means
7436 that the next byte is repeated -n times. A zero terminates the
7440 _rleAppend(RLECTX *self, unsigned c)
7444 if (c != self->last)
7446 /* The run has stopped. See if it is worthwhile writing it out
7447 as a run. Note that the random data comes in as runs of
7450 if (self->runLen > RLE_CHANGE_COST)
7452 /* Yes, worthwhile. */
7453 /* Commit whatever was in the buffer. */
7455 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7459 /* Not worthwhile. Append to the end of the random list. */
7460 for (i = 0; i < self->runLen; i++)
7462 if (self->pos >= RLE_MAX_BLOCK)
7467 self->buffer[self->pos++] = self->last;
7475 if (self->runLen >= RLE_MAX_BLOCK)
7477 /* Commit whatever was in the buffer. */
7480 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7488 _rleFlush(RLECTX *self)
7490 _rleAppend(self, -1);
7497 /** genArrayInit - Special code for initialising an array with constant
7501 genArrayInit (iCode * ic)
7505 int elementSize = 0, eIndex, i;
7506 unsigned val, lastVal;
7510 memset(&rle, 0, sizeof(rle));
7512 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7514 _saveRegsForCall(ic, 0);
7516 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7517 emit2 ("call __initrleblock");
7519 type = operandType(IC_LEFT(ic));
7521 if (type && type->next)
7523 if (IS_SPEC(type->next) || IS_PTR(type->next))
7525 elementSize = getSize(type->next);
7527 else if (IS_ARRAY(type->next) && type->next->next)
7529 elementSize = getSize(type->next->next);
7533 printTypeChainRaw (type, NULL);
7534 wassertl (0, "Can't determine element size in genArrayInit.");
7539 wassertl (0, "Can't determine element size in genArrayInit.");
7542 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7544 iLoop = IC_ARRAYILIST(ic);
7545 lastVal = (unsigned)-1;
7547 /* Feed all the bytes into the run length encoder which will handle
7549 This works well for mixed char data, and for random int and long
7556 for (i = 0; i < ix; i++)
7558 for (eIndex = 0; eIndex < elementSize; eIndex++)
7560 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7561 _rleAppend(&rle, val);
7565 iLoop = iLoop->next;
7569 /* Mark the end of the run. */
7572 _restoreRegsAfterCall();
7576 freeAsmop (IC_LEFT(ic), NULL, ic);
7580 _swap (PAIR_ID one, PAIR_ID two)
7582 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7588 emit2 ("ld a,%s", _pairs[one].l);
7589 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7590 emit2 ("ld %s,a", _pairs[two].l);
7591 emit2 ("ld a,%s", _pairs[one].h);
7592 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7593 emit2 ("ld %s,a", _pairs[two].h);
7597 /* The problem is that we may have all three pairs used and they may
7598 be needed in a different order.
7603 hl = hl => unity, fine
7607 hl = hl hl = hl, swap de <=> bc
7615 hl = bc de = de, swap bc <=> hl
7623 hl = de bc = bc, swap hl <=> de
7628 * Any pair = pair are done last
7629 * Any pair = iTemp are done last
7630 * Any swaps can be done any time
7638 So how do we detect the cases?
7639 How about a 3x3 matrix?
7643 x x x x (Fourth for iTemp/other)
7645 First determin which mode to use by counting the number of unity and
7648 Two - Assign the pair first, then the rest
7649 One - Swap the two, then the rest
7653 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7655 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7657 PAIR_BC, PAIR_HL, PAIR_DE
7659 int i, j, nunity = 0;
7660 memset (ids, PAIR_INVALID, sizeof (ids));
7663 wassert (nparams == 3);
7665 /* First save everything that needs to be saved. */
7666 _saveRegsForCall (ic, 0);
7668 /* Loading HL first means that DE is always fine. */
7669 for (i = 0; i < nparams; i++)
7671 aopOp (pparams[i], ic, FALSE, FALSE);
7672 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7675 /* Count the number of unity or iTemp assigns. */
7676 for (i = 0; i < 3; i++)
7678 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7686 /* Any order, fall through. */
7688 else if (nunity == 2)
7690 /* One is assigned. Pull it out and assign. */
7691 for (i = 0; i < 3; i++)
7693 for (j = 0; j < NUM_PAIRS; j++)
7695 if (ids[dest[i]][j] == TRUE)
7697 /* Found it. See if it's the right one. */
7698 if (j == PAIR_INVALID || j == dest[i])
7704 fetchPair(dest[i], AOP (pparams[i]));
7711 else if (nunity == 1)
7713 /* Find the pairs to swap. */
7714 for (i = 0; i < 3; i++)
7716 for (j = 0; j < NUM_PAIRS; j++)
7718 if (ids[dest[i]][j] == TRUE)
7720 if (j == PAIR_INVALID || j == dest[i])
7735 int next = getPairId (AOP (pparams[0]));
7736 emit2 ("push %s", _pairs[next].name);
7738 if (next == dest[1])
7740 fetchPair (dest[1], AOP (pparams[1]));
7741 fetchPair (dest[2], AOP (pparams[2]));
7745 fetchPair (dest[2], AOP (pparams[2]));
7746 fetchPair (dest[1], AOP (pparams[1]));
7748 emit2 ("pop %s", _pairs[dest[0]].name);
7751 /* Finally pull out all of the iTemps */
7752 for (i = 0; i < 3; i++)
7754 if (ids[dest[i]][PAIR_INVALID] == 1)
7756 fetchPair (dest[i], AOP (pparams[i]));
7762 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7768 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7772 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7774 setupForBuiltin3 (ic, nParams, pparams);
7776 label = newiTempLabel(NULL);
7778 emitLabel (label->key);
7779 emit2 ("ld a,(hl)");
7782 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7784 freeAsmop (from, NULL, ic->next);
7785 freeAsmop (to, NULL, ic);
7789 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7791 operand *from, *to, *count;
7794 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7799 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7801 setupForBuiltin3 (ic, nParams, pparams);
7805 freeAsmop (count, NULL, ic->next->next);
7806 freeAsmop (from, NULL, ic);
7808 _restoreRegsAfterCall();
7810 /* if we need assign a result value */
7811 if ((IS_ITEMP (IC_RESULT (ic)) &&
7812 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7813 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7814 IS_TRUE_SYMOP (IC_RESULT (ic)))
7816 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7817 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7818 freeAsmop (IC_RESULT (ic), NULL, ic);
7821 freeAsmop (to, NULL, ic->next);
7824 /*-----------------------------------------------------------------*/
7825 /* genBuiltIn - calls the appropriate function to generating code */
7826 /* for a built in function */
7827 /*-----------------------------------------------------------------*/
7828 static void genBuiltIn (iCode *ic)
7830 operand *bi_parms[MAX_BUILTIN_ARGS];
7835 /* get all the arguments for a built in function */
7836 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7838 /* which function is it */
7839 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7841 if (strcmp(bif->name,"__builtin_strcpy")==0)
7843 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7845 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7847 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7851 wassertl (0, "Unknown builtin function encountered");
7855 /*-----------------------------------------------------------------*/
7856 /* genZ80Code - generate code for Z80 based controllers */
7857 /*-----------------------------------------------------------------*/
7859 genZ80Code (iCode * lic)
7867 _fReturn = _gbz80_return;
7868 _fTmp = _gbz80_return;
7872 _fReturn = _z80_return;
7873 _fTmp = _z80_return;
7876 _G.lines.head = _G.lines.current = NULL;
7878 /* if debug information required */
7879 if (options.debug && currFunc)
7881 debugFile->writeFunction (currFunc, lic);
7884 for (ic = lic; ic; ic = ic->next)
7886 _G.current_iCode = ic;
7888 if (ic->lineno && cln != ic->lineno)
7892 debugFile->writeCLine (ic);
7894 if (!options.noCcodeInAsm) {
7895 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7896 printCLine(ic->filename, ic->lineno));
7900 if (options.iCodeInAsm) {
7901 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7903 /* if the result is marked as
7904 spilt and rematerializable or code for
7905 this has already been generated then
7907 if (resultRemat (ic) || ic->generated)
7910 /* depending on the operation */
7914 emitDebug ("; genNot");
7919 emitDebug ("; genCpl");
7924 emitDebug ("; genUminus");
7929 emitDebug ("; genIpush");
7934 /* IPOP happens only when trying to restore a
7935 spilt live range, if there is an ifx statement
7936 following this pop then the if statement might
7937 be using some of the registers being popped which
7938 would destory the contents of the register so
7939 we need to check for this condition and handle it */
7941 ic->next->op == IFX &&
7942 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7944 emitDebug ("; genIfx");
7945 genIfx (ic->next, ic);
7949 emitDebug ("; genIpop");
7955 emitDebug ("; genCall");
7960 emitDebug ("; genPcall");
7965 emitDebug ("; genFunction");
7970 emitDebug ("; genEndFunction");
7971 genEndFunction (ic);
7975 emitDebug ("; genRet");
7980 emitDebug ("; genLabel");
7985 emitDebug ("; genGoto");
7990 emitDebug ("; genPlus");
7995 emitDebug ("; genMinus");
8000 emitDebug ("; genMult");
8005 emitDebug ("; genDiv");
8010 emitDebug ("; genMod");
8015 emitDebug ("; genCmpGt");
8016 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8020 emitDebug ("; genCmpLt");
8021 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8028 /* note these two are xlated by algebraic equivalence
8029 during parsing SDCC.y */
8030 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8031 "got '>=' or '<=' shouldn't have come here");
8035 emitDebug ("; genCmpEq");
8036 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8040 emitDebug ("; genAndOp");
8045 emitDebug ("; genOrOp");
8050 emitDebug ("; genXor");
8051 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8055 emitDebug ("; genOr");
8056 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8060 emitDebug ("; genAnd");
8061 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8065 emitDebug ("; genInline");
8070 emitDebug ("; genRRC");
8075 emitDebug ("; genRLC");
8080 emitDebug ("; genGetHBIT");
8085 emitDebug ("; genLeftShift");
8090 emitDebug ("; genRightShift");
8094 case GET_VALUE_AT_ADDRESS:
8095 emitDebug ("; genPointerGet");
8101 if (POINTER_SET (ic))
8103 emitDebug ("; genAssign (pointer)");
8108 emitDebug ("; genAssign");
8114 emitDebug ("; genIfx");
8119 emitDebug ("; genAddrOf");
8124 emitDebug ("; genJumpTab");
8129 emitDebug ("; genCast");
8134 emitDebug ("; genReceive");
8139 if (ic->builtinSEND)
8141 emitDebug ("; genBuiltIn");
8146 emitDebug ("; addSet");
8147 addSet (&_G.sendSet, ic);
8152 emitDebug ("; genArrayInit");
8156 case DUMMY_READ_VOLATILE:
8157 emitDebug ("; genDummyRead");
8167 /* now we are ready to call the
8168 peep hole optimizer */
8169 if (!options.nopeep)
8170 peepHole (&_G.lines.head);
8172 /* This is unfortunate */
8173 /* now do the actual printing */
8175 FILE *fp = codeOutFile;
8176 if (isInHome () && codeOutFile == code->oFile)
8177 codeOutFile = home->oFile;
8178 printLine (_G.lines.head, codeOutFile);
8179 if (_G.flushStatics)
8182 _G.flushStatics = 0;
8187 freeTrace(&_G.lines.trace);
8188 freeTrace(&_G.trace.aops);
8194 _isPairUsed (iCode * ic, PAIR_ID pairId)
8200 if (bitVectBitValue (ic->rMask, D_IDX))
8202 if (bitVectBitValue (ic->rMask, E_IDX))
8212 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8215 value *val = aop->aopu.aop_lit;
8217 wassert (aop->type == AOP_LIT);
8218 wassert (!IS_FLOAT (val->type));
8220 v = (unsigned long) floatFromVal (val);
8228 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8229 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));