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 sprintf (buffer, "%s_start", sym->rname);
3106 emit2 ("!labeldef", buffer);
3107 emit2 ("!functionlabeldef", sym->rname);
3109 if (options.profile)
3111 emit2 ("!profileenter");
3114 ftype = operandType (IC_LEFT (ic));
3116 /* if this is an interrupt service routine then save all potentially used registers. */
3117 if (IFFUNC_ISISR (sym->type))
3119 if (!FUNC_ISNAKED( sym->type ))
3126 /* if critical function then turn interrupts off */
3127 if (IFFUNC_ISCRITICAL (sym->type))
3133 /* PENDING: callee-save etc */
3135 _G.stack.param_offset = 0;
3137 if (z80_opts.calleeSavesBC)
3142 /* Detect which registers are used. */
3143 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3146 for (i = 0; i < sym->regsUsed->size; i++)
3148 if (bitVectBitValue (sym->regsUsed, i))
3162 /* Other systems use DE as a temporary. */
3173 _G.stack.param_offset += 2;
3176 _G.calleeSaves.pushedBC = bcInUse;
3181 _G.stack.param_offset += 2;
3184 _G.calleeSaves.pushedDE = deInUse;
3186 /* adjust the stack for the function */
3187 _G.stack.last = sym->stack;
3190 for (sym = setFirstItem (istack->syms); sym;
3191 sym = setNextItem (istack->syms))
3193 if (sym->_isparm && !IS_REGPARM (sym->etype))
3199 sym = OP_SYMBOL (IC_LEFT (ic));
3201 _G.omitFramePtr = options.ommitFramePtr;
3202 if (IS_Z80 && !stackParm && !sym->stack)
3204 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3205 /* the above !sym->stack condition can be removed. -- EEP */
3207 emit2 ("!ldaspsp", -sym->stack);
3208 _G.omitFramePtr = TRUE;
3210 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3211 emit2 ("!enterxl", sym->stack);
3212 else if (sym->stack)
3213 emit2 ("!enterx", sym->stack);
3214 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3217 _G.stack.offset = sym->stack;
3220 /*-----------------------------------------------------------------*/
3221 /* genEndFunction - generates epilogue for functions */
3222 /*-----------------------------------------------------------------*/
3224 genEndFunction (iCode * ic)
3226 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3229 /* PENDING: calleeSave */
3230 if (IS_Z80 && _G.omitFramePtr)
3232 if (_G.stack.offset)
3233 emit2 ("!ldaspsp", _G.stack.offset);
3235 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3237 emit2 ("!leavexl", _G.stack.offset);
3239 else if (_G.stack.offset)
3241 emit2 ("!leavex", _G.stack.offset);
3243 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3248 if (_G.calleeSaves.pushedDE)
3251 _G.calleeSaves.pushedDE = FALSE;
3254 if (_G.calleeSaves.pushedBC)
3257 _G.calleeSaves.pushedBC = FALSE;
3260 if (options.profile)
3262 emit2 ("!profileexit");
3265 /* if this is an interrupt service routine then restore all potentially used registers. */
3266 if (IFFUNC_ISISR (sym->type))
3268 if (!FUNC_ISNAKED( sym->type ))
3275 /* if critical function then turn interrupts back on */
3276 if (IFFUNC_ISCRITICAL (sym->type))
3280 if (options.debug && currFunc)
3282 debugFile->writeEndFunction (currFunc, ic, 1);
3285 if (IFFUNC_ISISR (sym->type))
3287 /* "critical interrupt" is used to imply NMI handler */
3288 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type))
3295 /* Both banked and non-banked just ret */
3299 sprintf (buffer, "%s_end", sym->rname);
3300 emit2 ("!labeldef", buffer);
3302 _G.flushStatics = 1;
3303 _G.stack.pushed = 0;
3304 _G.stack.offset = 0;
3307 /*-----------------------------------------------------------------*/
3308 /* genRet - generate code for return statement */
3309 /*-----------------------------------------------------------------*/
3314 /* Errk. This is a hack until I can figure out how
3315 to cause dehl to spill on a call */
3316 int size, offset = 0;
3318 /* if we have no return value then
3319 just generate the "ret" */
3323 /* we have something to return then
3324 move the return value into place */
3325 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3326 size = AOP_SIZE (IC_LEFT (ic));
3328 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3331 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3335 emit2 ("ld de,%s", l);
3339 emit2 ("ld hl,%s", l);
3345 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3349 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3351 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3352 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3358 l = aopGet (AOP (IC_LEFT (ic)), offset,
3360 if (strcmp (_fReturn[offset], l))
3361 emit2 ("ld %s,%s", _fReturn[offset], l);
3366 freeAsmop (IC_LEFT (ic), NULL, ic);
3369 /* generate a jump to the return label
3370 if the next is not the return statement */
3371 if (!(ic->next && ic->next->op == LABEL &&
3372 IC_LABEL (ic->next) == returnLabel))
3374 emit2 ("jp !tlabel", returnLabel->key + 100);
3377 /*-----------------------------------------------------------------*/
3378 /* genLabel - generates a label */
3379 /*-----------------------------------------------------------------*/
3381 genLabel (iCode * ic)
3383 /* special case never generate */
3384 if (IC_LABEL (ic) == entryLabel)
3387 emitLabel (IC_LABEL (ic)->key + 100);
3390 /*-----------------------------------------------------------------*/
3391 /* genGoto - generates a ljmp */
3392 /*-----------------------------------------------------------------*/
3394 genGoto (iCode * ic)
3396 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3399 /*-----------------------------------------------------------------*/
3400 /* genPlusIncr :- does addition with increment if possible */
3401 /*-----------------------------------------------------------------*/
3403 genPlusIncr (iCode * ic)
3405 unsigned int icount;
3406 unsigned int size = getDataSize (IC_RESULT (ic));
3407 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3409 /* will try to generate an increment */
3410 /* if the right side is not a literal
3412 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3415 emitDebug ("; genPlusIncr");
3417 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3419 /* If result is a pair */
3420 if (resultId != PAIR_INVALID)
3422 if (isLitWord (AOP (IC_LEFT (ic))))
3424 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3427 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3429 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3431 PAIR_ID freep = getFreePairId (ic);
3432 if (freep != PAIR_INVALID)
3434 fetchPair (freep, AOP (IC_RIGHT (ic)));
3435 emit2 ("add hl,%s", _pairs[freep].name);
3441 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3442 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3449 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3453 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3457 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3462 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3464 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3465 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3469 /* if the literal value of the right hand side
3470 is greater than 4 then it is not worth it */
3474 /* if increment 16 bits in register */
3475 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3481 symbol *tlbl = NULL;
3482 tlbl = newiTempLabel (NULL);
3485 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3488 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3491 emitLabel (tlbl->key + 100);
3495 /* if the sizes are greater than 1 then we cannot */
3496 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3497 AOP_SIZE (IC_LEFT (ic)) > 1)
3500 /* If the result is in a register then we can load then increment.
3502 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3504 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3507 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3512 /* we can if the aops of the left & result match or
3513 if they are in registers and the registers are the
3515 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3519 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3527 /*-----------------------------------------------------------------*/
3528 /* outBitAcc - output a bit in acc */
3529 /*-----------------------------------------------------------------*/
3531 outBitAcc (operand * result)
3533 symbol *tlbl = newiTempLabel (NULL);
3534 /* if the result is a bit */
3535 if (AOP_TYPE (result) == AOP_CRY)
3537 wassertl (0, "Tried to write A into a bit");
3541 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3542 emit2 ("ld a,!one");
3543 emitLabel (tlbl->key + 100);
3549 couldDestroyCarry (asmop *aop)
3553 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3562 shiftIntoPair (int idx, asmop *aop)
3564 PAIR_ID id = PAIR_INVALID;
3566 wassertl (IS_Z80, "Only implemented for the Z80");
3567 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3579 wassertl (0, "Internal error - hit default case");
3582 emitDebug ("; Shift into pair idx %u", idx);
3586 setupPair (PAIR_HL, aop, 0);
3590 setupPair (PAIR_IY, aop, 0);
3592 emit2 ("pop %s", _pairs[id].name);
3595 aop->type = AOP_PAIRPTR;
3596 aop->aopu.aop_pairId = id;
3597 _G.pairs[id].offset = 0;
3598 _G.pairs[id].last_type = aop->type;
3602 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3604 wassert (left && right);
3608 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3610 shiftIntoPair (0, right);
3611 /* check result again, in case right == result */
3612 if (couldDestroyCarry (result))
3613 shiftIntoPair (1, result);
3615 else if (couldDestroyCarry (right))
3617 if (getPairId (result) == PAIR_HL)
3618 _G.preserveCarry = TRUE;
3620 shiftIntoPair (0, right);
3622 else if (couldDestroyCarry (result))
3624 shiftIntoPair (0, result);
3633 /*-----------------------------------------------------------------*/
3634 /* genPlus - generates code for addition */
3635 /*-----------------------------------------------------------------*/
3637 genPlus (iCode * ic)
3639 int size, offset = 0;
3641 /* special cases :- */
3643 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3644 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3645 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3647 /* Swap the left and right operands if:
3649 if literal, literal on the right or
3650 if left requires ACC or right is already
3653 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3654 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3655 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3657 operand *t = IC_RIGHT (ic);
3658 IC_RIGHT (ic) = IC_LEFT (ic);
3662 /* if both left & right are in bit
3664 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3665 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3668 wassertl (0, "Tried to add two bits");
3671 /* if left in bit space & right literal */
3672 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3673 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3675 /* Can happen I guess */
3676 wassertl (0, "Tried to add a bit to a literal");
3679 /* if I can do an increment instead
3680 of add then GOOD for ME */
3681 if (genPlusIncr (ic) == TRUE)
3684 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3686 size = getDataSize (IC_RESULT (ic));
3688 /* Special case when left and right are constant */
3689 if (isPair (AOP (IC_RESULT (ic))))
3692 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3693 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3695 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3701 sprintf (buffer, "#(%s + %s)", left, right);
3702 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3707 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3709 /* Fetch into HL then do the add */
3710 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3711 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3713 spillPair (PAIR_HL);
3715 if (left == PAIR_HL && right != PAIR_INVALID)
3717 emit2 ("add hl,%s", _pairs[right].name);
3720 else if (right == PAIR_HL && left != PAIR_INVALID)
3722 emit2 ("add hl,%s", _pairs[left].name);
3725 else if (right != PAIR_INVALID && right != PAIR_HL)
3727 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3728 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3731 else if (left != PAIR_INVALID && left != PAIR_HL)
3733 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3734 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3743 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3745 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3746 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3748 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3753 ld hl,sp+n trashes C so we cant afford to do it during an
3754 add with stack based varibles. Worst case is:
3767 So you cant afford to load up hl if either left, right, or result
3768 is on the stack (*sigh*) The alt is:
3776 Combinations in here are:
3777 * If left or right are in bc then the loss is small - trap later
3778 * If the result is in bc then the loss is also small
3782 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3783 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3784 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3786 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3787 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3788 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3789 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3791 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3793 /* Swap left and right */
3794 operand *t = IC_RIGHT (ic);
3795 IC_RIGHT (ic) = IC_LEFT (ic);
3798 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3800 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3801 emit2 ("add hl,bc");
3805 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3806 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3807 emit2 ("add hl,de");
3809 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3815 /* Be paranoid on the GB with 4 byte variables due to how C
3816 can be trashed by lda hl,n(sp).
3818 _gbz80_emitAddSubLong (ic, TRUE);
3823 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3827 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3829 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3832 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3835 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3839 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3842 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3845 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3847 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3851 _G.preserveCarry = FALSE;
3852 freeAsmop (IC_LEFT (ic), NULL, ic);
3853 freeAsmop (IC_RIGHT (ic), NULL, ic);
3854 freeAsmop (IC_RESULT (ic), NULL, ic);
3858 /*-----------------------------------------------------------------*/
3859 /* genMinusDec :- does subtraction with deccrement if possible */
3860 /*-----------------------------------------------------------------*/
3862 genMinusDec (iCode * ic)
3864 unsigned int icount;
3865 unsigned int size = getDataSize (IC_RESULT (ic));
3867 /* will try to generate an increment */
3868 /* if the right side is not a literal we cannot */
3869 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3872 /* if the literal value of the right hand side
3873 is greater than 4 then it is not worth it */
3874 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3877 size = getDataSize (IC_RESULT (ic));
3879 /* if decrement 16 bits in register */
3880 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3881 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3884 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3888 /* If result is a pair */
3889 if (isPair (AOP (IC_RESULT (ic))))
3891 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3893 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3897 /* if increment 16 bits in register */
3898 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3902 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3905 emit2 ("dec %s", _getTempPairName());
3908 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3914 /* if the sizes are greater than 1 then we cannot */
3915 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3916 AOP_SIZE (IC_LEFT (ic)) > 1)
3919 /* we can if the aops of the left & result match or if they are in
3920 registers and the registers are the same */
3921 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3924 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3931 /*-----------------------------------------------------------------*/
3932 /* genMinus - generates code for subtraction */
3933 /*-----------------------------------------------------------------*/
3935 genMinus (iCode * ic)
3937 int size, offset = 0;
3938 unsigned long lit = 0L;
3940 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3941 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3942 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3944 /* special cases :- */
3945 /* if both left & right are in bit space */
3946 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3947 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3949 wassertl (0, "Tried to subtract two bits");
3953 /* if I can do an decrement instead of subtract then GOOD for ME */
3954 if (genMinusDec (ic) == TRUE)
3957 size = getDataSize (IC_RESULT (ic));
3959 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3964 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3968 /* Same logic as genPlus */
3971 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3972 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3973 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3975 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3976 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3977 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3978 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3980 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3981 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3983 if (left == PAIR_INVALID && right == PAIR_INVALID)
3988 else if (right == PAIR_INVALID)
3990 else if (left == PAIR_INVALID)
3993 fetchPair (left, AOP (IC_LEFT (ic)));
3994 /* Order is important. Right may be HL */
3995 fetchPair (right, AOP (IC_RIGHT (ic)));
3997 emit2 ("ld a,%s", _pairs[left].l);
3998 emit2 ("sub a,%s", _pairs[right].l);
4000 emit2 ("ld a,%s", _pairs[left].h);
4001 emit2 ("sbc a,%s", _pairs[right].h);
4003 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4005 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4007 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4013 /* Be paranoid on the GB with 4 byte variables due to how C
4014 can be trashed by lda hl,n(sp).
4016 _gbz80_emitAddSubLong (ic, FALSE);
4021 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
4023 /* if literal, add a,#-lit, else normal subb */
4026 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4027 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4031 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4034 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4038 /* first add without previous c */
4040 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4042 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4044 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4047 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4048 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4049 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4051 wassertl (0, "Tried to subtract on a long pointer");
4055 _G.preserveCarry = FALSE;
4056 freeAsmop (IC_LEFT (ic), NULL, ic);
4057 freeAsmop (IC_RIGHT (ic), NULL, ic);
4058 freeAsmop (IC_RESULT (ic), NULL, ic);
4061 /*-----------------------------------------------------------------*/
4062 /* genMult - generates code for multiplication */
4063 /*-----------------------------------------------------------------*/
4065 genMult (iCode * ic)
4069 /* If true then the final operation should be a subtract */
4070 bool active = FALSE;
4073 /* Shouldn't occur - all done through function calls */
4074 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4075 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4076 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4078 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4080 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4081 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4082 AOP_SIZE (IC_RESULT (ic)) > 2)
4084 wassertl (0, "Multiplication is handled through support function calls");
4087 /* Swap left and right such that right is a literal */
4088 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4090 operand *t = IC_RIGHT (ic);
4091 IC_RIGHT (ic) = IC_LEFT (ic);
4095 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4097 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4098 // wassertl (val > 0, "Multiply must be positive");
4099 wassertl (val != 1, "Can't multiply by 1");
4101 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4103 _G.stack.pushedDE = TRUE;
4106 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4108 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4119 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4124 /* Fully unroled version of mul.s. Not the most efficient.
4126 for (count = 0; count < 16; count++)
4128 if (count != 0 && active)
4130 emit2 ("add hl,hl");
4134 if (active == FALSE)
4142 emit2 ("add hl,de");
4151 if (IS_Z80 && _G.stack.pushedDE)
4154 _G.stack.pushedDE = FALSE;
4158 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4160 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4162 freeAsmop (IC_LEFT (ic), NULL, ic);
4163 freeAsmop (IC_RIGHT (ic), NULL, ic);
4164 freeAsmop (IC_RESULT (ic), NULL, ic);
4167 /*-----------------------------------------------------------------*/
4168 /* genDiv - generates code for division */
4169 /*-----------------------------------------------------------------*/
4173 /* Shouldn't occur - all done through function calls */
4174 wassertl (0, "Division is handled through support function calls");
4177 /*-----------------------------------------------------------------*/
4178 /* genMod - generates code for division */
4179 /*-----------------------------------------------------------------*/
4183 /* Shouldn't occur - all done through function calls */
4187 /*-----------------------------------------------------------------*/
4188 /* genIfxJump :- will create a jump depending on the ifx */
4189 /*-----------------------------------------------------------------*/
4191 genIfxJump (iCode * ic, char *jval)
4196 /* if true label then we jump if condition
4200 jlbl = IC_TRUE (ic);
4201 if (!strcmp (jval, "a"))
4205 else if (!strcmp (jval, "c"))
4209 else if (!strcmp (jval, "nc"))
4213 else if (!strcmp (jval, "m"))
4217 else if (!strcmp (jval, "p"))
4223 /* The buffer contains the bit on A that we should test */
4229 /* false label is present */
4230 jlbl = IC_FALSE (ic);
4231 if (!strcmp (jval, "a"))
4235 else if (!strcmp (jval, "c"))
4239 else if (!strcmp (jval, "nc"))
4243 else if (!strcmp (jval, "m"))
4247 else if (!strcmp (jval, "p"))
4253 /* The buffer contains the bit on A that we should test */
4257 /* Z80 can do a conditional long jump */
4258 if (!strcmp (jval, "a"))
4262 else if (!strcmp (jval, "c"))
4265 else if (!strcmp (jval, "nc"))
4268 else if (!strcmp (jval, "m"))
4271 else if (!strcmp (jval, "p"))
4276 emit2 ("bit %s,a", jval);
4278 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4280 /* mark the icode as generated */
4286 _getPairIdName (PAIR_ID id)
4288 return _pairs[id].name;
4293 /* if unsigned char cmp with lit, just compare */
4295 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4297 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4300 emit2 ("xor a,!immedbyte", 0x80);
4301 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4304 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4306 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4308 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4309 // Pull left into DE and right into HL
4310 aopGet (AOP(left), LSB, FALSE);
4313 aopGet (AOP(right), LSB, FALSE);
4317 if (size == 0 && sign)
4319 // Highest byte when signed needs the bits flipped
4322 emit2 ("ld a,(de)");
4323 emit2 ("xor !immedbyte", 0x80);
4325 emit2 ("ld a,(hl)");
4326 emit2 ("xor !immedbyte", 0x80);
4330 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4334 emit2 ("ld a,(de)");
4335 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4345 spillPair (PAIR_HL);
4347 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4349 setupPair (PAIR_HL, AOP (left), 0);
4350 aopGet (AOP(right), LSB, FALSE);
4354 if (size == 0 && sign)
4356 // Highest byte when signed needs the bits flipped
4359 emit2 ("ld a,(hl)");
4360 emit2 ("xor !immedbyte", 0x80);
4362 emit2 ("ld a,%d(iy)", offset);
4363 emit2 ("xor !immedbyte", 0x80);
4367 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4371 emit2 ("ld a,(hl)");
4372 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4381 spillPair (PAIR_HL);
4382 spillPair (PAIR_IY);
4386 if (AOP_TYPE (right) == AOP_LIT)
4388 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4389 /* optimize if(x < 0) or if(x >= 0) */
4394 /* No sign so it's always false */
4399 /* Just load in the top most bit */
4400 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4401 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4403 genIfxJump (ifx, "7");
4415 /* First setup h and l contaning the top most bytes XORed */
4416 bool fDidXor = FALSE;
4417 if (AOP_TYPE (left) == AOP_LIT)
4419 unsigned long lit = (unsigned long)
4420 floatFromVal (AOP (left)->aopu.aop_lit);
4421 emit2 ("ld %s,!immedbyte", _fTmp[0],
4422 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4426 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4427 emit2 ("xor a,!immedbyte", 0x80);
4428 emit2 ("ld %s,a", _fTmp[0]);
4431 if (AOP_TYPE (right) == AOP_LIT)
4433 unsigned long lit = (unsigned long)
4434 floatFromVal (AOP (right)->aopu.aop_lit);
4435 emit2 ("ld %s,!immedbyte", _fTmp[1],
4436 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4440 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4441 emit2 ("xor a,!immedbyte", 0x80);
4442 emit2 ("ld %s,a", _fTmp[1]);
4448 /* Do a long subtract */
4451 _moveA (aopGet (AOP (left), offset, FALSE));
4453 if (sign && size == 0)
4455 emit2 ("ld a,%s", _fTmp[0]);
4456 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4460 /* Subtract through, propagating the carry */
4461 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4469 /** Generic compare for > or <
4472 genCmp (operand * left, operand * right,
4473 operand * result, iCode * ifx, int sign)
4475 int size, offset = 0;
4476 unsigned long lit = 0L;
4477 bool swap_sense = FALSE;
4479 /* if left & right are bit variables */
4480 if (AOP_TYPE (left) == AOP_CRY &&
4481 AOP_TYPE (right) == AOP_CRY)
4483 /* Cant happen on the Z80 */
4484 wassertl (0, "Tried to compare two bits");
4488 /* Do a long subtract of right from left. */
4489 size = max (AOP_SIZE (left), AOP_SIZE (right));
4491 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4493 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4494 // Pull left into DE and right into HL
4495 aopGet (AOP(left), LSB, FALSE);
4498 aopGet (AOP(right), LSB, FALSE);
4502 emit2 ("ld a,(de)");
4503 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4512 spillPair (PAIR_HL);
4516 if (AOP_TYPE (right) == AOP_LIT)
4518 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4519 /* optimize if(x < 0) or if(x >= 0) */
4524 /* No sign so it's always false */
4529 /* Just load in the top most bit */
4530 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4531 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4533 genIfxJump (ifx, "7");
4544 genIfxJump (ifx, swap_sense ? "c" : "nc");
4555 _moveA (aopGet (AOP (left), offset, FALSE));
4556 /* Subtract through, propagating the carry */
4557 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4563 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4567 /* Shift the sign bit up into carry */
4570 outBitCLong (result, swap_sense);
4574 /* if the result is used in the next
4575 ifx conditional branch then generate
4576 code a little differently */
4584 genIfxJump (ifx, swap_sense ? "nc" : "c");
4588 genIfxJump (ifx, swap_sense ? "p" : "m");
4593 genIfxJump (ifx, swap_sense ? "nc" : "c");
4600 /* Shift the sign bit up into carry */
4603 outBitCLong (result, swap_sense);
4605 /* leave the result in acc */
4609 /*-----------------------------------------------------------------*/
4610 /* genCmpGt :- greater than comparison */
4611 /*-----------------------------------------------------------------*/
4613 genCmpGt (iCode * ic, iCode * ifx)
4615 operand *left, *right, *result;
4616 sym_link *letype, *retype;
4619 left = IC_LEFT (ic);
4620 right = IC_RIGHT (ic);
4621 result = IC_RESULT (ic);
4623 letype = getSpec (operandType (left));
4624 retype = getSpec (operandType (right));
4625 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4626 /* assign the amsops */
4627 aopOp (left, ic, FALSE, FALSE);
4628 aopOp (right, ic, FALSE, FALSE);
4629 aopOp (result, ic, TRUE, FALSE);
4631 genCmp (right, left, result, ifx, sign);
4633 freeAsmop (left, NULL, ic);
4634 freeAsmop (right, NULL, ic);
4635 freeAsmop (result, NULL, ic);
4638 /*-----------------------------------------------------------------*/
4639 /* genCmpLt - less than comparisons */
4640 /*-----------------------------------------------------------------*/
4642 genCmpLt (iCode * ic, iCode * ifx)
4644 operand *left, *right, *result;
4645 sym_link *letype, *retype;
4648 left = IC_LEFT (ic);
4649 right = IC_RIGHT (ic);
4650 result = IC_RESULT (ic);
4652 letype = getSpec (operandType (left));
4653 retype = getSpec (operandType (right));
4654 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4656 /* assign the amsops */
4657 aopOp (left, ic, FALSE, FALSE);
4658 aopOp (right, ic, FALSE, FALSE);
4659 aopOp (result, ic, TRUE, FALSE);
4661 genCmp (left, right, result, ifx, sign);
4663 freeAsmop (left, NULL, ic);
4664 freeAsmop (right, NULL, ic);
4665 freeAsmop (result, NULL, ic);
4668 /*-----------------------------------------------------------------*/
4669 /* gencjneshort - compare and jump if not equal */
4670 /*-----------------------------------------------------------------*/
4672 gencjneshort (operand * left, operand * right, symbol * lbl)
4674 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4676 unsigned long lit = 0L;
4678 /* Swap the left and right if it makes the computation easier */
4679 if (AOP_TYPE (left) == AOP_LIT)
4686 if (AOP_TYPE (right) == AOP_LIT)
4688 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4691 /* if the right side is a literal then anything goes */
4692 if (AOP_TYPE (right) == AOP_LIT &&
4693 AOP_TYPE (left) != AOP_DIR)
4697 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4702 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4709 emit2 ("jp nz,!tlabel", lbl->key + 100);
4715 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4716 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4719 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4720 emit2 ("jp nz,!tlabel", lbl->key + 100);
4725 /* if the right side is in a register or in direct space or
4726 if the left is a pointer register & right is not */
4727 else if (AOP_TYPE (right) == AOP_REG ||
4728 AOP_TYPE (right) == AOP_DIR ||
4729 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4733 _moveA (aopGet (AOP (left), offset, FALSE));
4734 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4735 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4737 emit2 ("jp nz,!tlabel", lbl->key + 100);
4740 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4741 emit2 ("jp nz,!tlabel", lbl->key + 100);
4748 /* right is a pointer reg need both a & b */
4749 /* PENDING: is this required? */
4752 _moveA (aopGet (AOP (right), offset, FALSE));
4753 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4754 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4760 /*-----------------------------------------------------------------*/
4761 /* gencjne - compare and jump if not equal */
4762 /*-----------------------------------------------------------------*/
4764 gencjne (operand * left, operand * right, symbol * lbl)
4766 symbol *tlbl = newiTempLabel (NULL);
4768 gencjneshort (left, right, lbl);
4771 emit2 ("ld a,!one");
4772 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4773 emitLabel (lbl->key + 100);
4775 emitLabel (tlbl->key + 100);
4778 /*-----------------------------------------------------------------*/
4779 /* genCmpEq - generates code for equal to */
4780 /*-----------------------------------------------------------------*/
4782 genCmpEq (iCode * ic, iCode * ifx)
4784 operand *left, *right, *result;
4786 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4787 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4788 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4790 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4792 /* Swap operands if it makes the operation easier. ie if:
4793 1. Left is a literal.
4795 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4797 operand *t = IC_RIGHT (ic);
4798 IC_RIGHT (ic) = IC_LEFT (ic);
4802 if (ifx && !AOP_SIZE (result))
4805 /* if they are both bit variables */
4806 if (AOP_TYPE (left) == AOP_CRY &&
4807 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4809 wassertl (0, "Tried to compare two bits");
4813 tlbl = newiTempLabel (NULL);
4814 gencjneshort (left, right, tlbl);
4817 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4818 emitLabel (tlbl->key + 100);
4822 /* PENDING: do this better */
4823 symbol *lbl = newiTempLabel (NULL);
4824 emit2 ("!shortjp !tlabel", lbl->key + 100);
4825 emitLabel (tlbl->key + 100);
4826 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4827 emitLabel (lbl->key + 100);
4830 /* mark the icode as generated */
4835 /* if they are both bit variables */
4836 if (AOP_TYPE (left) == AOP_CRY &&
4837 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4839 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4845 gencjne (left, right, newiTempLabel (NULL));
4846 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4853 genIfxJump (ifx, "a");
4856 /* if the result is used in an arithmetic operation
4857 then put the result in place */
4858 if (AOP_TYPE (result) != AOP_CRY)
4863 /* leave the result in acc */
4867 freeAsmop (left, NULL, ic);
4868 freeAsmop (right, NULL, ic);
4869 freeAsmop (result, NULL, ic);
4872 /*-----------------------------------------------------------------*/
4873 /* ifxForOp - returns the icode containing the ifx for operand */
4874 /*-----------------------------------------------------------------*/
4876 ifxForOp (operand * op, iCode * ic)
4878 /* if true symbol then needs to be assigned */
4879 if (IS_TRUE_SYMOP (op))
4882 /* if this has register type condition and
4883 the next instruction is ifx with the same operand
4884 and live to of the operand is upto the ifx only then */
4886 ic->next->op == IFX &&
4887 IC_COND (ic->next)->key == op->key &&
4888 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4894 /*-----------------------------------------------------------------*/
4895 /* genAndOp - for && operation */
4896 /*-----------------------------------------------------------------*/
4898 genAndOp (iCode * ic)
4900 operand *left, *right, *result;
4903 /* note here that && operations that are in an if statement are
4904 taken away by backPatchLabels only those used in arthmetic
4905 operations remain */
4906 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4907 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4908 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4910 /* if both are bit variables */
4911 if (AOP_TYPE (left) == AOP_CRY &&
4912 AOP_TYPE (right) == AOP_CRY)
4914 wassertl (0, "Tried to and two bits");
4918 tlbl = newiTempLabel (NULL);
4920 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4922 emitLabel (tlbl->key + 100);
4926 freeAsmop (left, NULL, ic);
4927 freeAsmop (right, NULL, ic);
4928 freeAsmop (result, NULL, ic);
4931 /*-----------------------------------------------------------------*/
4932 /* genOrOp - for || operation */
4933 /*-----------------------------------------------------------------*/
4935 genOrOp (iCode * ic)
4937 operand *left, *right, *result;
4940 /* note here that || operations that are in an
4941 if statement are taken away by backPatchLabels
4942 only those used in arthmetic operations remain */
4943 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4944 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4945 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4947 /* if both are bit variables */
4948 if (AOP_TYPE (left) == AOP_CRY &&
4949 AOP_TYPE (right) == AOP_CRY)
4951 wassertl (0, "Tried to OR two bits");
4955 tlbl = newiTempLabel (NULL);
4957 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4959 emitLabel (tlbl->key + 100);
4963 freeAsmop (left, NULL, ic);
4964 freeAsmop (right, NULL, ic);
4965 freeAsmop (result, NULL, ic);
4968 /*-----------------------------------------------------------------*/
4969 /* isLiteralBit - test if lit == 2^n */
4970 /*-----------------------------------------------------------------*/
4972 isLiteralBit (unsigned long lit)
4974 unsigned long pw[32] =
4975 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4976 0x100L, 0x200L, 0x400L, 0x800L,
4977 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4978 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4979 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4980 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4981 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4984 for (idx = 0; idx < 32; idx++)
4990 /*-----------------------------------------------------------------*/
4991 /* jmpTrueOrFalse - */
4992 /*-----------------------------------------------------------------*/
4994 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4996 // ugly but optimized by peephole
4999 symbol *nlbl = newiTempLabel (NULL);
5000 emit2 ("jp !tlabel", nlbl->key + 100);
5001 emitLabel (tlbl->key + 100);
5002 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5003 emitLabel (nlbl->key + 100);
5007 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5008 emitLabel (tlbl->key + 100);
5013 /*-----------------------------------------------------------------*/
5014 /* genAnd - code for and */
5015 /*-----------------------------------------------------------------*/
5017 genAnd (iCode * ic, iCode * ifx)
5019 operand *left, *right, *result;
5020 int size, offset = 0;
5021 unsigned long lit = 0L;
5024 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5025 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5026 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5028 /* if left is a literal & right is not then exchange them */
5029 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5030 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5032 operand *tmp = right;
5037 /* if result = right then exchange them */
5038 if (sameRegs (AOP (result), AOP (right)))
5040 operand *tmp = right;
5045 /* if right is bit then exchange them */
5046 if (AOP_TYPE (right) == AOP_CRY &&
5047 AOP_TYPE (left) != AOP_CRY)
5049 operand *tmp = right;
5053 if (AOP_TYPE (right) == AOP_LIT)
5054 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5056 size = AOP_SIZE (result);
5058 if (AOP_TYPE (left) == AOP_CRY)
5060 wassertl (0, "Tried to perform an AND with a bit as an operand");
5064 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5065 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5066 if ((AOP_TYPE (right) == AOP_LIT) &&
5067 (AOP_TYPE (result) == AOP_CRY) &&
5068 (AOP_TYPE (left) != AOP_CRY))
5070 symbol *tlbl = newiTempLabel (NULL);
5071 int sizel = AOP_SIZE (left);
5074 /* PENDING: Test case for this. */
5079 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5081 _moveA (aopGet (AOP (left), offset, FALSE));
5082 if (bytelit != 0x0FFL)
5084 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5091 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5095 // bit = left & literal
5099 emit2 ("!tlabeldef", tlbl->key + 100);
5101 // if(left & literal)
5106 jmpTrueOrFalse (ifx, tlbl);
5114 /* if left is same as result */
5115 if (sameRegs (AOP (result), AOP (left)))
5117 for (; size--; offset++)
5119 if (AOP_TYPE (right) == AOP_LIT)
5121 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5126 aopPut (AOP (result), "!zero", offset);
5129 _moveA (aopGet (AOP (left), offset, FALSE));
5131 aopGet (AOP (right), offset, FALSE));
5132 aopPut (AOP (left), "a", offset);
5139 if (AOP_TYPE (left) == AOP_ACC)
5141 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5145 _moveA (aopGet (AOP (left), offset, FALSE));
5147 aopGet (AOP (right), offset, FALSE));
5148 aopPut (AOP (left), "a", offset);
5155 // left & result in different registers
5156 if (AOP_TYPE (result) == AOP_CRY)
5158 wassertl (0, "Tried to AND where the result is in carry");
5162 for (; (size--); offset++)
5165 // result = left & right
5166 if (AOP_TYPE (right) == AOP_LIT)
5168 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5170 aopPut (AOP (result),
5171 aopGet (AOP (left), offset, FALSE),
5175 else if (bytelit == 0)
5177 aopPut (AOP (result), "!zero", offset);
5181 // faster than result <- left, anl result,right
5182 // and better if result is SFR
5183 if (AOP_TYPE (left) == AOP_ACC)
5184 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5187 _moveA (aopGet (AOP (left), offset, FALSE));
5189 aopGet (AOP (right), offset, FALSE));
5191 aopPut (AOP (result), "a", offset);
5198 freeAsmop (left, NULL, ic);
5199 freeAsmop (right, NULL, ic);
5200 freeAsmop (result, NULL, ic);
5203 /*-----------------------------------------------------------------*/
5204 /* genOr - code for or */
5205 /*-----------------------------------------------------------------*/
5207 genOr (iCode * ic, iCode * ifx)
5209 operand *left, *right, *result;
5210 int size, offset = 0;
5211 unsigned long lit = 0L;
5214 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5215 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5216 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5218 /* if left is a literal & right is not then exchange them */
5219 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5220 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5222 operand *tmp = right;
5227 /* if result = right then exchange them */
5228 if (sameRegs (AOP (result), AOP (right)))
5230 operand *tmp = right;
5235 /* if right is bit then exchange them */
5236 if (AOP_TYPE (right) == AOP_CRY &&
5237 AOP_TYPE (left) != AOP_CRY)
5239 operand *tmp = right;
5243 if (AOP_TYPE (right) == AOP_LIT)
5244 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5246 size = AOP_SIZE (result);
5248 if (AOP_TYPE (left) == AOP_CRY)
5250 wassertl (0, "Tried to OR where left is a bit");
5254 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5255 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5256 if ((AOP_TYPE (right) == AOP_LIT) &&
5257 (AOP_TYPE (result) == AOP_CRY) &&
5258 (AOP_TYPE (left) != AOP_CRY))
5260 symbol *tlbl = newiTempLabel (NULL);
5261 int sizel = AOP_SIZE (left);
5265 wassertl (0, "Result is assigned to a bit");
5267 /* PENDING: Modeled after the AND code which is inefficent. */
5270 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5272 _moveA (aopGet (AOP (left), offset, FALSE));
5273 /* OR with any literal is the same as OR with itself. */
5275 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5281 jmpTrueOrFalse (ifx, tlbl);
5286 /* if left is same as result */
5287 if (sameRegs (AOP (result), AOP (left)))
5289 for (; size--; offset++)
5291 if (AOP_TYPE (right) == AOP_LIT)
5293 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5297 _moveA (aopGet (AOP (left), offset, FALSE));
5299 aopGet (AOP (right), offset, FALSE));
5300 aopPut (AOP (result), "a", offset);
5305 if (AOP_TYPE (left) == AOP_ACC)
5306 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5309 _moveA (aopGet (AOP (left), offset, FALSE));
5311 aopGet (AOP (right), offset, FALSE));
5312 aopPut (AOP (result), "a", offset);
5319 // left & result in different registers
5320 if (AOP_TYPE (result) == AOP_CRY)
5322 wassertl (0, "Result of OR is in a bit");
5325 for (; (size--); offset++)
5328 // result = left & right
5329 if (AOP_TYPE (right) == AOP_LIT)
5331 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5333 aopPut (AOP (result),
5334 aopGet (AOP (left), offset, FALSE),
5339 // faster than result <- left, anl result,right
5340 // and better if result is SFR
5341 if (AOP_TYPE (left) == AOP_ACC)
5342 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5345 _moveA (aopGet (AOP (left), offset, FALSE));
5347 aopGet (AOP (right), offset, FALSE));
5349 aopPut (AOP (result), "a", offset);
5350 /* PENDING: something weird is going on here. Add exception. */
5351 if (AOP_TYPE (result) == AOP_ACC)
5357 freeAsmop (left, NULL, ic);
5358 freeAsmop (right, NULL, ic);
5359 freeAsmop (result, NULL, ic);
5362 /*-----------------------------------------------------------------*/
5363 /* genXor - code for xclusive or */
5364 /*-----------------------------------------------------------------*/
5366 genXor (iCode * ic, iCode * ifx)
5368 operand *left, *right, *result;
5369 int size, offset = 0;
5370 unsigned long lit = 0L;
5372 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5373 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5374 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5376 /* if left is a literal & right is not then exchange them */
5377 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5378 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5380 operand *tmp = right;
5385 /* if result = right then exchange them */
5386 if (sameRegs (AOP (result), AOP (right)))
5388 operand *tmp = right;
5393 /* if right is bit then exchange them */
5394 if (AOP_TYPE (right) == AOP_CRY &&
5395 AOP_TYPE (left) != AOP_CRY)
5397 operand *tmp = right;
5401 if (AOP_TYPE (right) == AOP_LIT)
5402 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5404 size = AOP_SIZE (result);
5406 if (AOP_TYPE (left) == AOP_CRY)
5408 wassertl (0, "Tried to XOR a bit");
5412 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5413 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5414 if ((AOP_TYPE (right) == AOP_LIT) &&
5415 (AOP_TYPE (result) == AOP_CRY) &&
5416 (AOP_TYPE (left) != AOP_CRY))
5418 symbol *tlbl = newiTempLabel (NULL);
5419 int sizel = AOP_SIZE (left);
5423 /* PENDING: Test case for this. */
5424 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5428 _moveA (aopGet (AOP (left), offset, FALSE));
5429 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5430 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5435 jmpTrueOrFalse (ifx, tlbl);
5439 wassertl (0, "Result of XOR was destined for a bit");
5444 /* if left is same as result */
5445 if (sameRegs (AOP (result), AOP (left)))
5447 for (; size--; offset++)
5449 if (AOP_TYPE (right) == AOP_LIT)
5451 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5455 _moveA (aopGet (AOP (left), offset, FALSE));
5457 aopGet (AOP (right), offset, FALSE));
5458 aopPut (AOP (result), "a", offset);
5463 if (AOP_TYPE (left) == AOP_ACC)
5465 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5469 _moveA (aopGet (AOP (left), offset, FALSE));
5471 aopGet (AOP (right), offset, FALSE));
5472 aopPut (AOP (result), "a", offset);
5479 // left & result in different registers
5480 if (AOP_TYPE (result) == AOP_CRY)
5482 wassertl (0, "Result of XOR is in a bit");
5485 for (; (size--); offset++)
5488 // result = left & right
5489 if (AOP_TYPE (right) == AOP_LIT)
5491 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5493 aopPut (AOP (result),
5494 aopGet (AOP (left), offset, FALSE),
5499 // faster than result <- left, anl result,right
5500 // and better if result is SFR
5501 if (AOP_TYPE (left) == AOP_ACC)
5503 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5507 _moveA (aopGet (AOP (left), offset, FALSE));
5509 aopGet (AOP (right), offset, FALSE));
5511 aopPut (AOP (result), "a", offset);
5516 freeAsmop (left, NULL, ic);
5517 freeAsmop (right, NULL, ic);
5518 freeAsmop (result, NULL, ic);
5521 /*-----------------------------------------------------------------*/
5522 /* genInline - write the inline code out */
5523 /*-----------------------------------------------------------------*/
5525 genInline (iCode * ic)
5527 char *buffer, *bp, *bp1;
5529 _G.lines.isInline += (!options.asmpeep);
5531 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5532 strcpy (buffer, IC_INLINE (ic));
5534 /* emit each line as a code */
5559 _G.lines.isInline -= (!options.asmpeep);
5563 /*-----------------------------------------------------------------*/
5564 /* genRRC - rotate right with carry */
5565 /*-----------------------------------------------------------------*/
5572 /*-----------------------------------------------------------------*/
5573 /* genRLC - generate code for rotate left with carry */
5574 /*-----------------------------------------------------------------*/
5581 /*-----------------------------------------------------------------*/
5582 /* genGetHbit - generates code get highest order bit */
5583 /*-----------------------------------------------------------------*/
5585 genGetHbit (iCode * ic)
5587 operand *left, *result;
5588 left = IC_LEFT (ic);
5589 result = IC_RESULT (ic);
5591 aopOp (left, ic, FALSE, FALSE);
5592 aopOp (result, ic, FALSE, FALSE);
5594 /* get the highest order byte into a */
5595 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5597 if (AOP_TYPE (result) == AOP_CRY)
5605 emit2 ("and a,!one");
5610 freeAsmop (left, NULL, ic);
5611 freeAsmop (result, NULL, ic);
5615 emitRsh2 (asmop *aop, int size, int is_signed)
5621 const char *l = aopGet (aop, size, FALSE);
5624 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5634 /*-----------------------------------------------------------------*/
5635 /* shiftR2Left2Result - shift right two bytes from left to result */
5636 /*-----------------------------------------------------------------*/
5638 shiftR2Left2Result (operand * left, int offl,
5639 operand * result, int offr,
5640 int shCount, int is_signed)
5643 symbol *tlbl, *tlbl1;
5645 movLeft2Result (left, offl, result, offr, 0);
5646 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5648 /* if (AOP(result)->type == AOP_REG) { */
5650 tlbl = newiTempLabel (NULL);
5651 tlbl1 = newiTempLabel (NULL);
5653 /* Left is already in result - so now do the shift */
5658 emitRsh2 (AOP (result), size, is_signed);
5663 emit2 ("ld a,!immedbyte+1", shCount);
5664 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5665 emitLabel (tlbl->key + 100);
5667 emitRsh2 (AOP (result), size, is_signed);
5669 emitLabel (tlbl1->key + 100);
5671 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5675 /*-----------------------------------------------------------------*/
5676 /* shiftL2Left2Result - shift left two bytes from left to result */
5677 /*-----------------------------------------------------------------*/
5679 shiftL2Left2Result (operand * left, int offl,
5680 operand * result, int offr, int shCount)
5682 if (sameRegs (AOP (result), AOP (left)) &&
5683 ((offl + MSB16) == offr))
5689 /* Copy left into result */
5690 movLeft2Result (left, offl, result, offr, 0);
5691 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5694 if (getPairId (AOP (result)) == PAIR_HL)
5698 emit2 ("add hl,hl");
5705 symbol *tlbl, *tlbl1;
5708 tlbl = newiTempLabel (NULL);
5709 tlbl1 = newiTempLabel (NULL);
5711 if (AOP (result)->type == AOP_REG)
5715 for (offset = 0; offset < size; offset++)
5717 l = aopGet (AOP (result), offset, FALSE);
5721 emit2 ("sla %s", l);
5732 /* Left is already in result - so now do the shift */
5735 emit2 ("ld a,!immedbyte+1", shCount);
5736 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5737 emitLabel (tlbl->key + 100);
5742 l = aopGet (AOP (result), offset, FALSE);
5746 emit2 ("sla %s", l);
5757 emitLabel (tlbl1->key + 100);
5759 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5765 /*-----------------------------------------------------------------*/
5766 /* AccRol - rotate left accumulator by known count */
5767 /*-----------------------------------------------------------------*/
5769 AccRol (int shCount)
5771 shCount &= 0x0007; // shCount : 0..7
5848 /*-----------------------------------------------------------------*/
5849 /* AccLsh - left shift accumulator by known count */
5850 /*-----------------------------------------------------------------*/
5852 AccLsh (int shCount)
5854 static const unsigned char SLMask[] =
5856 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5865 else if (shCount == 2)
5872 /* rotate left accumulator */
5874 /* and kill the lower order bits */
5875 emit2 ("and a,!immedbyte", SLMask[shCount]);
5880 /*-----------------------------------------------------------------*/
5881 /* shiftL1Left2Result - shift left one byte from left to result */
5882 /*-----------------------------------------------------------------*/
5884 shiftL1Left2Result (operand * left, int offl,
5885 operand * result, int offr, int shCount)
5888 l = aopGet (AOP (left), offl, FALSE);
5890 /* shift left accumulator */
5892 aopPut (AOP (result), "a", offr);
5896 /*-----------------------------------------------------------------*/
5897 /* genlshTwo - left shift two bytes by known amount != 0 */
5898 /*-----------------------------------------------------------------*/
5900 genlshTwo (operand * result, operand * left, int shCount)
5902 int size = AOP_SIZE (result);
5904 wassert (size == 2);
5906 /* if shCount >= 8 */
5914 movLeft2Result (left, LSB, result, MSB16, 0);
5915 aopPut (AOP (result), "!zero", 0);
5916 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5920 movLeft2Result (left, LSB, result, MSB16, 0);
5921 aopPut (AOP (result), "!zero", 0);
5926 aopPut (AOP (result), "!zero", LSB);
5929 /* 1 <= shCount <= 7 */
5938 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5943 /*-----------------------------------------------------------------*/
5944 /* genlshOne - left shift a one byte quantity by known count */
5945 /*-----------------------------------------------------------------*/
5947 genlshOne (operand * result, operand * left, int shCount)
5949 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5952 /*-----------------------------------------------------------------*/
5953 /* genLeftShiftLiteral - left shifting by known count */
5954 /*-----------------------------------------------------------------*/
5956 genLeftShiftLiteral (operand * left,
5961 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5964 freeAsmop (right, NULL, ic);
5966 aopOp (left, ic, FALSE, FALSE);
5967 aopOp (result, ic, FALSE, FALSE);
5969 size = getSize (operandType (result));
5971 /* I suppose that the left size >= result size */
5977 else if (shCount >= (size * 8))
5981 aopPut (AOP (result), "!zero", size);
5989 genlshOne (result, left, shCount);
5992 genlshTwo (result, left, shCount);
5995 wassertl (0, "Shifting of longs is currently unsupported");
6001 freeAsmop (left, NULL, ic);
6002 freeAsmop (result, NULL, ic);
6005 /*-----------------------------------------------------------------*/
6006 /* genLeftShift - generates code for left shifting */
6007 /*-----------------------------------------------------------------*/
6009 genLeftShift (iCode * ic)
6013 symbol *tlbl, *tlbl1;
6014 operand *left, *right, *result;
6016 right = IC_RIGHT (ic);
6017 left = IC_LEFT (ic);
6018 result = IC_RESULT (ic);
6020 aopOp (right, ic, FALSE, FALSE);
6022 /* if the shift count is known then do it
6023 as efficiently as possible */
6024 if (AOP_TYPE (right) == AOP_LIT)
6026 genLeftShiftLiteral (left, right, result, ic);
6030 /* shift count is unknown then we have to form a loop get the loop
6031 count in B : Note: we take only the lower order byte since
6032 shifting more that 32 bits make no sense anyway, ( the largest
6033 size of an object can be only 32 bits ) */
6034 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6036 freeAsmop (right, NULL, ic);
6037 aopOp (left, ic, FALSE, FALSE);
6038 aopOp (result, ic, FALSE, FALSE);
6040 /* now move the left to the result if they are not the
6043 if (!sameRegs (AOP (left), AOP (result)))
6046 size = AOP_SIZE (result);
6050 l = aopGet (AOP (left), offset, FALSE);
6051 aopPut (AOP (result), l, offset);
6056 tlbl = newiTempLabel (NULL);
6057 size = AOP_SIZE (result);
6059 tlbl1 = newiTempLabel (NULL);
6061 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6062 emitLabel (tlbl->key + 100);
6063 l = aopGet (AOP (result), offset, FALSE);
6067 l = aopGet (AOP (result), offset, FALSE);
6071 emit2 ("sla %s", l);
6079 emitLabel (tlbl1->key + 100);
6081 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6083 freeAsmop (left, NULL, ic);
6084 freeAsmop (result, NULL, ic);
6087 /*-----------------------------------------------------------------*/
6088 /* genrshOne - left shift two bytes by known amount != 0 */
6089 /*-----------------------------------------------------------------*/
6091 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6094 int size = AOP_SIZE (result);
6097 wassert (size == 1);
6098 wassert (shCount < 8);
6100 l = aopGet (AOP (left), 0, FALSE);
6102 if (AOP (result)->type == AOP_REG)
6104 aopPut (AOP (result), l, 0);
6105 l = aopGet (AOP (result), 0, FALSE);
6108 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6116 emit2 ("%s a", is_signed ? "sra" : "srl");
6118 aopPut (AOP (result), "a", 0);
6122 /*-----------------------------------------------------------------*/
6123 /* AccRsh - right shift accumulator by known count */
6124 /*-----------------------------------------------------------------*/
6126 AccRsh (int shCount)
6128 static const unsigned char SRMask[] =
6130 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6135 /* rotate right accumulator */
6136 AccRol (8 - shCount);
6137 /* and kill the higher order bits */
6138 emit2 ("and a,!immedbyte", SRMask[shCount]);
6142 /*-----------------------------------------------------------------*/
6143 /* shiftR1Left2Result - shift right one byte from left to result */
6144 /*-----------------------------------------------------------------*/
6146 shiftR1Left2Result (operand * left, int offl,
6147 operand * result, int offr,
6148 int shCount, int sign)
6150 _moveA (aopGet (AOP (left), offl, FALSE));
6155 emit2 ("%s a", sign ? "sra" : "srl");
6162 aopPut (AOP (result), "a", offr);
6165 /*-----------------------------------------------------------------*/
6166 /* genrshTwo - right shift two bytes by known amount != 0 */
6167 /*-----------------------------------------------------------------*/
6169 genrshTwo (operand * result, operand * left,
6170 int shCount, int sign)
6172 /* if shCount >= 8 */
6178 shiftR1Left2Result (left, MSB16, result, LSB,
6183 movLeft2Result (left, MSB16, result, LSB, sign);
6187 /* Sign extend the result */
6188 _moveA(aopGet (AOP (result), 0, FALSE));
6192 aopPut (AOP (result), ACC_NAME, MSB16);
6196 aopPut (AOP (result), "!zero", 1);
6199 /* 1 <= shCount <= 7 */
6202 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6206 /*-----------------------------------------------------------------*/
6207 /* genRightShiftLiteral - left shifting by known count */
6208 /*-----------------------------------------------------------------*/
6210 genRightShiftLiteral (operand * left,
6216 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6219 freeAsmop (right, NULL, ic);
6221 aopOp (left, ic, FALSE, FALSE);
6222 aopOp (result, ic, FALSE, FALSE);
6224 size = getSize (operandType (result));
6226 /* I suppose that the left size >= result size */
6232 else if (shCount >= (size * 8)) {
6234 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6235 _moveA(aopGet (AOP (left), 0, FALSE));
6243 aopPut (AOP (result), s, size);
6250 genrshOne (result, left, shCount, sign);
6253 genrshTwo (result, left, shCount, sign);
6256 wassertl (0, "Asked to shift right a long which should be a function call");
6259 wassertl (0, "Entered default case in right shift delegate");
6262 freeAsmop (left, NULL, ic);
6263 freeAsmop (result, NULL, ic);
6266 /*-----------------------------------------------------------------*/
6267 /* genRightShift - generate code for right shifting */
6268 /*-----------------------------------------------------------------*/
6270 genRightShift (iCode * ic)
6272 operand *right, *left, *result;
6274 int size, offset, first = 1;
6278 symbol *tlbl, *tlbl1;
6280 /* if signed then we do it the hard way preserve the
6281 sign bit moving it inwards */
6282 retype = getSpec (operandType (IC_RESULT (ic)));
6284 is_signed = !SPEC_USIGN (retype);
6286 /* signed & unsigned types are treated the same : i.e. the
6287 signed is NOT propagated inwards : quoting from the
6288 ANSI - standard : "for E1 >> E2, is equivalent to division
6289 by 2**E2 if unsigned or if it has a non-negative value,
6290 otherwise the result is implementation defined ", MY definition
6291 is that the sign does not get propagated */
6293 right = IC_RIGHT (ic);
6294 left = IC_LEFT (ic);
6295 result = IC_RESULT (ic);
6297 aopOp (right, ic, FALSE, FALSE);
6299 /* if the shift count is known then do it
6300 as efficiently as possible */
6301 if (AOP_TYPE (right) == AOP_LIT)
6303 genRightShiftLiteral (left, right, result, ic, is_signed);
6307 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6309 freeAsmop (right, NULL, ic);
6311 aopOp (left, ic, FALSE, FALSE);
6312 aopOp (result, ic, FALSE, FALSE);
6314 /* now move the left to the result if they are not the
6316 if (!sameRegs (AOP (left), AOP (result)))
6319 size = AOP_SIZE (result);
6323 l = aopGet (AOP (left), offset, FALSE);
6324 aopPut (AOP (result), l, offset);
6329 tlbl = newiTempLabel (NULL);
6330 tlbl1 = newiTempLabel (NULL);
6331 size = AOP_SIZE (result);
6334 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6335 emitLabel (tlbl->key + 100);
6338 l = aopGet (AOP (result), offset--, FALSE);
6341 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6349 emitLabel (tlbl1->key + 100);
6351 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6353 freeAsmop (left, NULL, ic);
6354 freeAsmop (result, NULL, ic);
6358 /*-----------------------------------------------------------------*/
6359 /* genUnpackBits - generates code for unpacking bits */
6360 /*-----------------------------------------------------------------*/
6362 genUnpackBits (operand * result, int pair)
6364 int offset = 0; /* result byte offset */
6365 int rsize; /* result size */
6366 int rlen = 0; /* remaining bitfield length */
6367 sym_link *etype; /* bitfield type information */
6368 int blen; /* bitfield length */
6369 int bstr; /* bitfield starting bit within byte */
6371 emitDebug ("; genUnpackBits");
6373 etype = getSpec (operandType (result));
6374 rsize = getSize (operandType (result));
6375 blen = SPEC_BLEN (etype);
6376 bstr = SPEC_BSTR (etype);
6378 /* If the bitfield length is less than a byte */
6381 emit2 ("ld a,!*pair", _pairs[pair].name);
6383 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6384 aopPut (AOP (result), "a", offset++);
6388 /* TODO: what if pair == PAIR_DE ? */
6389 if (getPairId (AOP (result)) == PAIR_HL)
6391 wassertl (rsize == 2, "HL must be of size 2");
6392 emit2 ("ld a,!*hl");
6394 emit2 ("ld h,!*hl");
6397 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6399 spillPair (PAIR_HL);
6403 /* Bit field did not fit in a byte. Copy all
6404 but the partial byte at the end. */
6405 for (rlen=blen;rlen>=8;rlen-=8)
6407 emit2 ("ld a,!*pair", _pairs[pair].name);
6408 aopPut (AOP (result), "a", offset++);
6411 emit2 ("inc %s", _pairs[pair].name);
6412 _G.pairs[pair].offset++;
6416 /* Handle the partial byte at the end */
6419 emit2 ("ld a,!*pair", _pairs[pair].name);
6420 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6421 aopPut (AOP (result), "a", offset++);
6429 aopPut (AOP (result), "!zero", offset++);
6433 /*-----------------------------------------------------------------*/
6434 /* genGenPointerGet - get value from generic pointer space */
6435 /*-----------------------------------------------------------------*/
6437 genGenPointerGet (operand * left,
6438 operand * result, iCode * ic)
6441 sym_link *retype = getSpec (operandType (result));
6447 aopOp (left, ic, FALSE, FALSE);
6448 aopOp (result, ic, FALSE, FALSE);
6450 size = AOP_SIZE (result);
6452 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6455 if (isPtrPair (AOP (left)))
6457 tsprintf (buffer, sizeof(buffer),
6458 "!*pair", getPairName (AOP (left)));
6459 aopPut (AOP (result), buffer, 0);
6463 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6464 aopPut (AOP (result), "a", 0);
6466 freeAsmop (left, NULL, ic);
6470 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6477 tsprintf (at, sizeof(at), "!*iyx", offset);
6478 aopPut (AOP (result), at, offset);
6482 freeAsmop (left, NULL, ic);
6486 /* For now we always load into IY */
6487 /* if this is remateriazable */
6488 fetchPair (pair, AOP (left));
6490 /* if bit then unpack */
6491 if (IS_BITVAR (retype))
6493 genUnpackBits (result, pair);
6494 freeAsmop (left, NULL, ic);
6498 else if (getPairId (AOP (result)) == PAIR_HL)
6500 wassertl (size == 2, "HL must be of size 2");
6501 emit2 ("ld a,!*hl");
6503 emit2 ("ld h,!*hl");
6505 spillPair (PAIR_HL);
6507 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6509 size = AOP_SIZE (result);
6514 /* PENDING: make this better */
6515 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6517 aopPut (AOP (result), "!*hl", offset++);
6521 emit2 ("ld a,!*pair", _pairs[pair].name);
6522 aopPut (AOP (result), "a", offset++);
6526 emit2 ("inc %s", _pairs[pair].name);
6527 _G.pairs[pair].offset++;
6530 /* Fixup HL back down */
6531 for (size = AOP_SIZE (result)-1; size; size--)
6533 emit2 ("dec %s", _pairs[pair].name);
6538 size = AOP_SIZE (result);
6543 /* PENDING: make this better */
6545 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6547 aopPut (AOP (result), "!*hl", offset++);
6551 emit2 ("ld a,!*pair", _pairs[pair].name);
6552 aopPut (AOP (result), "a", offset++);
6556 emit2 ("inc %s", _pairs[pair].name);
6557 _G.pairs[pair].offset++;
6562 freeAsmop (left, NULL, ic);
6565 freeAsmop (result, NULL, ic);
6568 /*-----------------------------------------------------------------*/
6569 /* genPointerGet - generate code for pointer get */
6570 /*-----------------------------------------------------------------*/
6572 genPointerGet (iCode * ic)
6574 operand *left, *result;
6575 sym_link *type, *etype;
6577 left = IC_LEFT (ic);
6578 result = IC_RESULT (ic);
6580 /* depending on the type of pointer we need to
6581 move it to the correct pointer register */
6582 type = operandType (left);
6583 etype = getSpec (type);
6585 genGenPointerGet (left, result, ic);
6589 isRegOrLit (asmop * aop)
6591 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6597 /*-----------------------------------------------------------------*/
6598 /* genPackBits - generates code for packed bit storage */
6599 /*-----------------------------------------------------------------*/
6601 genPackBits (sym_link * etype,
6606 int offset = 0; /* source byte offset */
6607 int rlen = 0; /* remaining bitfield length */
6608 int blen; /* bitfield length */
6609 int bstr; /* bitfield starting bit within byte */
6610 int litval; /* source literal value (if AOP_LIT) */
6611 unsigned char mask; /* bitmask within current byte */
6612 int extraPair; /* a tempory register */
6613 bool needPopExtra=0; /* need to restore original value of temp reg */
6615 emitDebug ("; genPackBits","");
6617 blen = SPEC_BLEN (etype);
6618 bstr = SPEC_BSTR (etype);
6620 /* If the bitfield length is less than a byte */
6623 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6624 (unsigned char) (0xFF >> (8 - bstr)));
6626 if (AOP_TYPE (right) == AOP_LIT)
6628 /* Case with a bitfield length <8 and literal source
6630 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6632 litval &= (~mask) & 0xff;
6633 emit2 ("ld a,!*pair", _pairs[pair].name);
6634 if ((mask|litval)!=0xff)
6635 emit2 ("and a,!immedbyte", mask);
6637 emit2 ("or a,!immedbyte", litval);
6638 emit2 ("ld !*pair,a", _pairs[pair].name);
6643 /* Case with a bitfield length <8 and arbitrary source
6645 _moveA (aopGet (AOP (right), 0, FALSE));
6646 /* shift and mask source value */
6648 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6650 extraPair = getFreePairId(ic);
6651 if (extraPair == PAIR_INVALID)
6653 extraPair = PAIR_BC;
6654 if (getPairId (AOP (right)) != PAIR_BC
6655 || !isLastUse (ic, right))
6661 emit2 ("ld %s,a", _pairs[extraPair].l);
6662 emit2 ("ld a,!*pair", _pairs[pair].name);
6664 emit2 ("and a,!immedbyte", mask);
6665 emit2 ("or a,%s", _pairs[extraPair].l);
6666 emit2 ("ld !*pair,a", _pairs[pair].name);
6673 /* Bit length is greater than 7 bits. In this case, copy */
6674 /* all except the partial byte at the end */
6675 for (rlen=blen;rlen>=8;rlen-=8)
6677 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6678 emit2 ("ld !*pair,a", _pairs[pair].name);
6681 emit2 ("inc %s", _pairs[pair].name);
6682 _G.pairs[pair].offset++;
6686 /* If there was a partial byte at the end */
6689 mask = (((unsigned char) -1 << rlen) & 0xff);
6691 if (AOP_TYPE (right) == AOP_LIT)
6693 /* Case with partial byte and literal source
6695 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6696 litval >>= (blen-rlen);
6697 litval &= (~mask) & 0xff;
6698 emit2 ("ld a,!*pair", _pairs[pair].name);
6699 if ((mask|litval)!=0xff)
6700 emit2 ("and a,!immedbyte", mask);
6702 emit2 ("or a,!immedbyte", litval);
6706 /* Case with partial byte and arbitrary source
6708 _moveA (aopGet (AOP (right), offset++, FALSE));
6709 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6711 extraPair = getFreePairId(ic);
6712 if (extraPair == PAIR_INVALID)
6714 extraPair = getPairId (AOP (right));
6715 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6716 extraPair = PAIR_BC;
6718 if (getPairId (AOP (right)) != PAIR_BC
6719 || !isLastUse (ic, right))
6725 emit2 ("ld %s,a", _pairs[extraPair].l);
6726 emit2 ("ld a,!*pair", _pairs[pair].name);
6728 emit2 ("and a,!immedbyte", mask);
6729 emit2 ("or a,%s", _pairs[extraPair].l);
6734 emit2 ("ld !*pair,a", _pairs[pair].name);
6739 /*-----------------------------------------------------------------*/
6740 /* genGenPointerSet - stores the value into a pointer location */
6741 /*-----------------------------------------------------------------*/
6743 genGenPointerSet (operand * right,
6744 operand * result, iCode * ic)
6747 sym_link *retype = getSpec (operandType (right));
6748 sym_link *letype = getSpec (operandType (result));
6749 PAIR_ID pairId = PAIR_HL;
6752 aopOp (result, ic, FALSE, FALSE);
6753 aopOp (right, ic, FALSE, FALSE);
6758 size = AOP_SIZE (right);
6760 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6761 emitDebug("; isBitvar = %d", isBitvar);
6763 /* Handle the exceptions first */
6764 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6767 const char *l = aopGet (AOP (right), 0, FALSE);
6768 const char *pair = getPairName (AOP (result));
6769 if (canAssignToPtr (l) && isPtr (pair))
6771 emit2 ("ld !*pair,%s", pair, l);
6776 emit2 ("ld !*pair,a", pair);
6781 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6784 const char *l = aopGet (AOP (right), 0, FALSE);
6789 if (canAssignToPtr (l))
6791 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6795 _moveA (aopGet (AOP (right), offset, FALSE));
6796 emit2 ("ld !*iyx,a", offset);
6802 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6809 const char *l = aopGet (AOP (right), offset, FALSE);
6810 if (isRegOrLit (AOP (right)) && !IS_GB)
6812 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6817 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6821 emit2 ("inc %s", _pairs[PAIR_HL].name);
6822 _G.pairs[PAIR_HL].offset++;
6827 /* Fixup HL back down */
6828 for (size = AOP_SIZE (right)-1; size; size--)
6830 emit2 ("dec %s", _pairs[PAIR_HL].name);
6835 /* if the operand is already in dptr
6836 then we do nothing else we move the value to dptr */
6837 if (AOP_TYPE (result) != AOP_STR)
6839 fetchPair (pairId, AOP (result));
6841 /* so hl now contains the address */
6842 freeAsmop (result, NULL, ic);
6844 /* if bit then unpack */
6847 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6857 const char *l = aopGet (AOP (right), offset, FALSE);
6858 if (isRegOrLit (AOP (right)) && !IS_GB)
6860 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6865 emit2 ("ld !*pair,a", _pairs[pairId].name);
6869 emit2 ("inc %s", _pairs[pairId].name);
6870 _G.pairs[pairId].offset++;
6876 freeAsmop (right, NULL, ic);
6879 /*-----------------------------------------------------------------*/
6880 /* genPointerSet - stores the value into a pointer location */
6881 /*-----------------------------------------------------------------*/
6883 genPointerSet (iCode * ic)
6885 operand *right, *result;
6886 sym_link *type, *etype;
6888 right = IC_RIGHT (ic);
6889 result = IC_RESULT (ic);
6891 /* depending on the type of pointer we need to
6892 move it to the correct pointer register */
6893 type = operandType (result);
6894 etype = getSpec (type);
6896 genGenPointerSet (right, result, ic);
6899 /*-----------------------------------------------------------------*/
6900 /* genIfx - generate code for Ifx statement */
6901 /*-----------------------------------------------------------------*/
6903 genIfx (iCode * ic, iCode * popIc)
6905 operand *cond = IC_COND (ic);
6908 aopOp (cond, ic, FALSE, TRUE);
6910 /* get the value into acc */
6911 if (AOP_TYPE (cond) != AOP_CRY)
6915 /* the result is now in the accumulator */
6916 freeAsmop (cond, NULL, ic);
6918 /* if there was something to be popped then do it */
6922 /* if the condition is a bit variable */
6923 if (isbit && IS_ITEMP (cond) &&
6925 genIfxJump (ic, SPIL_LOC (cond)->rname);
6926 else if (isbit && !IS_ITEMP (cond))
6927 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6929 genIfxJump (ic, "a");
6934 /*-----------------------------------------------------------------*/
6935 /* genAddrOf - generates code for address of */
6936 /*-----------------------------------------------------------------*/
6938 genAddrOf (iCode * ic)
6940 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6942 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6944 /* if the operand is on the stack then we
6945 need to get the stack offset of this
6952 if (sym->stack <= 0)
6954 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6958 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6960 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6964 emit2 ("ld de,!hashedstr", sym->rname);
6965 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6973 /* if it has an offset then we need to compute it */
6975 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6977 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6978 emit2 ("add hl,sp");
6982 emit2 ("ld hl,!hashedstr", sym->rname);
6984 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6986 freeAsmop (IC_RESULT (ic), NULL, ic);
6989 /*-----------------------------------------------------------------*/
6990 /* genAssign - generate code for assignment */
6991 /*-----------------------------------------------------------------*/
6993 genAssign (iCode * ic)
6995 operand *result, *right;
6997 unsigned long lit = 0L;
6999 result = IC_RESULT (ic);
7000 right = IC_RIGHT (ic);
7002 /* Dont bother assigning if they are the same */
7003 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7005 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7009 aopOp (right, ic, FALSE, FALSE);
7010 aopOp (result, ic, TRUE, FALSE);
7012 /* if they are the same registers */
7013 if (sameRegs (AOP (right), AOP (result)))
7015 emitDebug ("; (registers are the same)");
7019 /* if the result is a bit */
7020 if (AOP_TYPE (result) == AOP_CRY)
7022 wassertl (0, "Tried to assign to a bit");
7026 size = AOP_SIZE (result);
7029 if (AOP_TYPE (right) == AOP_LIT)
7031 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7034 if (isPair (AOP (result)))
7036 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7038 else if ((size > 1) &&
7039 (AOP_TYPE (result) != AOP_REG) &&
7040 (AOP_TYPE (right) == AOP_LIT) &&
7041 !IS_FLOAT (operandType (right)) &&
7044 bool fXored = FALSE;
7046 /* Work from the top down.
7047 Done this way so that we can use the cached copy of 0
7048 in A for a fast clear */
7051 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7053 if (!fXored && size > 1)
7060 aopPut (AOP (result), "a", offset);
7064 aopPut (AOP (result), "!zero", offset);
7068 aopPut (AOP (result),
7069 aopGet (AOP (right), offset, FALSE),
7074 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7076 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7077 aopPut (AOP (result), "l", LSB);
7078 aopPut (AOP (result), "h", MSB16);
7080 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7082 /* Special case. Load into a and d, then load out. */
7083 _moveA (aopGet (AOP (right), 0, FALSE));
7084 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7085 aopPut (AOP (result), "a", 0);
7086 aopPut (AOP (result), "e", 1);
7088 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7090 /* Special case - simple memcpy */
7091 aopGet (AOP (right), LSB, FALSE);
7094 aopGet (AOP (result), LSB, FALSE);
7098 emit2 ("ld a,(de)");
7099 /* Peephole will optimise this. */
7100 emit2 ("ld (hl),a");
7108 spillPair (PAIR_HL);
7114 /* PENDING: do this check better */
7115 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7117 _moveA (aopGet (AOP (right), offset, FALSE));
7118 aopPut (AOP (result), "a", offset);
7121 aopPut (AOP (result),
7122 aopGet (AOP (right), offset, FALSE),
7129 freeAsmop (right, NULL, ic);
7130 freeAsmop (result, NULL, ic);
7133 /*-----------------------------------------------------------------*/
7134 /* genJumpTab - genrates code for jump table */
7135 /*-----------------------------------------------------------------*/
7137 genJumpTab (iCode * ic)
7142 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7143 /* get the condition into accumulator */
7144 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7147 emit2 ("ld e,%s", l);
7148 emit2 ("ld d,!zero");
7149 jtab = newiTempLabel (NULL);
7151 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7152 emit2 ("add hl,de");
7153 emit2 ("add hl,de");
7154 emit2 ("add hl,de");
7155 freeAsmop (IC_JTCOND (ic), NULL, ic);
7159 emitLabel (jtab->key + 100);
7160 /* now generate the jump labels */
7161 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7162 jtab = setNextItem (IC_JTLABELS (ic)))
7163 emit2 ("jp !tlabel", jtab->key + 100);
7166 /*-----------------------------------------------------------------*/
7167 /* genCast - gen code for casting */
7168 /*-----------------------------------------------------------------*/
7170 genCast (iCode * ic)
7172 operand *result = IC_RESULT (ic);
7173 sym_link *rtype = operandType (IC_RIGHT (ic));
7174 operand *right = IC_RIGHT (ic);
7177 /* if they are equivalent then do nothing */
7178 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7181 aopOp (right, ic, FALSE, FALSE);
7182 aopOp (result, ic, FALSE, FALSE);
7184 /* if the result is a bit */
7185 if (AOP_TYPE (result) == AOP_CRY)
7187 wassertl (0, "Tried to cast to a bit");
7190 /* if they are the same size : or less */
7191 if (AOP_SIZE (result) <= AOP_SIZE (right))
7194 /* if they are in the same place */
7195 if (sameRegs (AOP (right), AOP (result)))
7198 /* if they in different places then copy */
7199 size = AOP_SIZE (result);
7203 aopPut (AOP (result),
7204 aopGet (AOP (right), offset, FALSE),
7211 /* So we now know that the size of destination is greater
7212 than the size of the source */
7213 /* we move to result for the size of source */
7214 size = AOP_SIZE (right);
7218 aopPut (AOP (result),
7219 aopGet (AOP (right), offset, FALSE),
7224 /* now depending on the sign of the destination */
7225 size = AOP_SIZE (result) - AOP_SIZE (right);
7226 /* Unsigned or not an integral type - right fill with zeros */
7227 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7230 aopPut (AOP (result), "!zero", offset++);
7234 /* we need to extend the sign :{ */
7235 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7241 aopPut (AOP (result), "a", offset++);
7245 freeAsmop (right, NULL, ic);
7246 freeAsmop (result, NULL, ic);
7249 /*-----------------------------------------------------------------*/
7250 /* genReceive - generate code for a receive iCode */
7251 /*-----------------------------------------------------------------*/
7253 genReceive (iCode * ic)
7255 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7256 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7257 IS_TRUE_SYMOP (IC_RESULT (ic))))
7267 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7268 size = AOP_SIZE(IC_RESULT(ic));
7270 for (i = 0; i < size; i++) {
7271 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7275 freeAsmop (IC_RESULT (ic), NULL, ic);
7278 /*-----------------------------------------------------------------*/
7279 /* genDummyRead - generate code for dummy read of volatiles */
7280 /*-----------------------------------------------------------------*/
7282 genDummyRead (iCode * ic)
7288 if (op && IS_SYMOP (op))
7290 aopOp (op, ic, FALSE, FALSE);
7293 size = AOP_SIZE (op);
7298 _moveA (aopGet (AOP (op), offset, FALSE));
7302 freeAsmop (op, NULL, ic);
7306 if (op && IS_SYMOP (op))
7308 aopOp (op, ic, FALSE, FALSE);
7311 size = AOP_SIZE (op);
7316 _moveA (aopGet (AOP (op), offset, FALSE));
7320 freeAsmop (op, NULL, ic);
7326 /** Maximum number of bytes to emit per line. */
7330 /** Context for the byte output chunker. */
7333 unsigned char buffer[DBEMIT_MAX_RUN];
7338 /** Flushes a byte chunker by writing out all in the buffer and
7342 _dbFlush(DBEMITCTX *self)
7349 sprintf(line, ".db 0x%02X", self->buffer[0]);
7351 for (i = 1; i < self->pos; i++)
7353 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7360 /** Write out another byte, buffering until a decent line is
7364 _dbEmit(DBEMITCTX *self, int c)
7366 if (self->pos == DBEMIT_MAX_RUN)
7370 self->buffer[self->pos++] = c;
7373 /** Context for a simple run length encoder. */
7377 unsigned char buffer[128];
7379 /** runLen may be equivalent to pos. */
7385 RLE_CHANGE_COST = 4,
7389 /** Flush the buffer of a run length encoder by writing out the run or
7390 data that it currently contains.
7393 _rleCommit(RLECTX *self)
7399 memset(&db, 0, sizeof(db));
7401 emit2(".db %u", self->pos);
7403 for (i = 0; i < self->pos; i++)
7405 _dbEmit(&db, self->buffer[i]);
7414 Can get either a run or a block of random stuff.
7415 Only want to change state if a good run comes in or a run ends.
7416 Detecting run end is easy.
7419 Say initial state is in run, len zero, last zero. Then if you get a
7420 few zeros then something else then a short run will be output.
7421 Seems OK. While in run mode, keep counting. While in random mode,
7422 keep a count of the run. If run hits margin, output all up to run,
7423 restart, enter run mode.
7426 /** Add another byte into the run length encoder, flushing as
7427 required. The run length encoder uses the Amiga IFF style, where
7428 a block is prefixed by its run length. A positive length means
7429 the next n bytes pass straight through. A negative length means
7430 that the next byte is repeated -n times. A zero terminates the
7434 _rleAppend(RLECTX *self, unsigned c)
7438 if (c != self->last)
7440 /* The run has stopped. See if it is worthwhile writing it out
7441 as a run. Note that the random data comes in as runs of
7444 if (self->runLen > RLE_CHANGE_COST)
7446 /* Yes, worthwhile. */
7447 /* Commit whatever was in the buffer. */
7449 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7453 /* Not worthwhile. Append to the end of the random list. */
7454 for (i = 0; i < self->runLen; i++)
7456 if (self->pos >= RLE_MAX_BLOCK)
7461 self->buffer[self->pos++] = self->last;
7469 if (self->runLen >= RLE_MAX_BLOCK)
7471 /* Commit whatever was in the buffer. */
7474 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7482 _rleFlush(RLECTX *self)
7484 _rleAppend(self, -1);
7491 /** genArrayInit - Special code for initialising an array with constant
7495 genArrayInit (iCode * ic)
7499 int elementSize = 0, eIndex, i;
7500 unsigned val, lastVal;
7504 memset(&rle, 0, sizeof(rle));
7506 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7508 _saveRegsForCall(ic, 0);
7510 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7511 emit2 ("call __initrleblock");
7513 type = operandType(IC_LEFT(ic));
7515 if (type && type->next)
7517 if (IS_SPEC(type->next) || IS_PTR(type->next))
7519 elementSize = getSize(type->next);
7521 else if (IS_ARRAY(type->next) && type->next->next)
7523 elementSize = getSize(type->next->next);
7527 printTypeChainRaw (type, NULL);
7528 wassertl (0, "Can't determine element size in genArrayInit.");
7533 wassertl (0, "Can't determine element size in genArrayInit.");
7536 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7538 iLoop = IC_ARRAYILIST(ic);
7539 lastVal = (unsigned)-1;
7541 /* Feed all the bytes into the run length encoder which will handle
7543 This works well for mixed char data, and for random int and long
7550 for (i = 0; i < ix; i++)
7552 for (eIndex = 0; eIndex < elementSize; eIndex++)
7554 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7555 _rleAppend(&rle, val);
7559 iLoop = iLoop->next;
7563 /* Mark the end of the run. */
7566 _restoreRegsAfterCall();
7570 freeAsmop (IC_LEFT(ic), NULL, ic);
7574 _swap (PAIR_ID one, PAIR_ID two)
7576 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7582 emit2 ("ld a,%s", _pairs[one].l);
7583 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7584 emit2 ("ld %s,a", _pairs[two].l);
7585 emit2 ("ld a,%s", _pairs[one].h);
7586 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7587 emit2 ("ld %s,a", _pairs[two].h);
7591 /* The problem is that we may have all three pairs used and they may
7592 be needed in a different order.
7597 hl = hl => unity, fine
7601 hl = hl hl = hl, swap de <=> bc
7609 hl = bc de = de, swap bc <=> hl
7617 hl = de bc = bc, swap hl <=> de
7622 * Any pair = pair are done last
7623 * Any pair = iTemp are done last
7624 * Any swaps can be done any time
7632 So how do we detect the cases?
7633 How about a 3x3 matrix?
7637 x x x x (Fourth for iTemp/other)
7639 First determin which mode to use by counting the number of unity and
7642 Two - Assign the pair first, then the rest
7643 One - Swap the two, then the rest
7647 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7649 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7651 PAIR_BC, PAIR_HL, PAIR_DE
7653 int i, j, nunity = 0;
7654 memset (ids, PAIR_INVALID, sizeof (ids));
7657 wassert (nparams == 3);
7659 /* First save everything that needs to be saved. */
7660 _saveRegsForCall (ic, 0);
7662 /* Loading HL first means that DE is always fine. */
7663 for (i = 0; i < nparams; i++)
7665 aopOp (pparams[i], ic, FALSE, FALSE);
7666 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7669 /* Count the number of unity or iTemp assigns. */
7670 for (i = 0; i < 3; i++)
7672 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7680 /* Any order, fall through. */
7682 else if (nunity == 2)
7684 /* One is assigned. Pull it out and assign. */
7685 for (i = 0; i < 3; i++)
7687 for (j = 0; j < NUM_PAIRS; j++)
7689 if (ids[dest[i]][j] == TRUE)
7691 /* Found it. See if it's the right one. */
7692 if (j == PAIR_INVALID || j == dest[i])
7698 fetchPair(dest[i], AOP (pparams[i]));
7705 else if (nunity == 1)
7707 /* Find the pairs to swap. */
7708 for (i = 0; i < 3; i++)
7710 for (j = 0; j < NUM_PAIRS; j++)
7712 if (ids[dest[i]][j] == TRUE)
7714 if (j == PAIR_INVALID || j == dest[i])
7729 int next = getPairId (AOP (pparams[0]));
7730 emit2 ("push %s", _pairs[next].name);
7732 if (next == dest[1])
7734 fetchPair (dest[1], AOP (pparams[1]));
7735 fetchPair (dest[2], AOP (pparams[2]));
7739 fetchPair (dest[2], AOP (pparams[2]));
7740 fetchPair (dest[1], AOP (pparams[1]));
7742 emit2 ("pop %s", _pairs[dest[0]].name);
7745 /* Finally pull out all of the iTemps */
7746 for (i = 0; i < 3; i++)
7748 if (ids[dest[i]][PAIR_INVALID] == 1)
7750 fetchPair (dest[i], AOP (pparams[i]));
7756 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7762 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7766 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7768 setupForBuiltin3 (ic, nParams, pparams);
7770 label = newiTempLabel(NULL);
7772 emitLabel (label->key);
7773 emit2 ("ld a,(hl)");
7776 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7778 freeAsmop (from, NULL, ic->next);
7779 freeAsmop (to, NULL, ic);
7783 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7785 operand *from, *to, *count;
7788 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7793 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7795 setupForBuiltin3 (ic, nParams, pparams);
7799 freeAsmop (count, NULL, ic->next->next);
7800 freeAsmop (from, NULL, ic);
7802 _restoreRegsAfterCall();
7804 /* if we need assign a result value */
7805 if ((IS_ITEMP (IC_RESULT (ic)) &&
7806 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7807 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7808 IS_TRUE_SYMOP (IC_RESULT (ic)))
7810 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7811 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7812 freeAsmop (IC_RESULT (ic), NULL, ic);
7815 freeAsmop (to, NULL, ic->next);
7818 /*-----------------------------------------------------------------*/
7819 /* genBuiltIn - calls the appropriate function to generating code */
7820 /* for a built in function */
7821 /*-----------------------------------------------------------------*/
7822 static void genBuiltIn (iCode *ic)
7824 operand *bi_parms[MAX_BUILTIN_ARGS];
7829 /* get all the arguments for a built in function */
7830 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7832 /* which function is it */
7833 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7835 if (strcmp(bif->name,"__builtin_strcpy")==0)
7837 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7839 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7841 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7845 wassertl (0, "Unknown builtin function encountered");
7849 /*-----------------------------------------------------------------*/
7850 /* genZ80Code - generate code for Z80 based controllers */
7851 /*-----------------------------------------------------------------*/
7853 genZ80Code (iCode * lic)
7861 _fReturn = _gbz80_return;
7862 _fTmp = _gbz80_return;
7866 _fReturn = _z80_return;
7867 _fTmp = _z80_return;
7870 _G.lines.head = _G.lines.current = NULL;
7872 /* if debug information required */
7873 if (options.debug && currFunc)
7875 debugFile->writeFunction (currFunc, lic);
7878 for (ic = lic; ic; ic = ic->next)
7880 _G.current_iCode = ic;
7882 if (ic->lineno && cln != ic->lineno)
7886 debugFile->writeCLine (ic);
7888 if (!options.noCcodeInAsm) {
7889 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7890 printCLine(ic->filename, ic->lineno));
7894 if (options.iCodeInAsm) {
7895 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7897 /* if the result is marked as
7898 spilt and rematerializable or code for
7899 this has already been generated then
7901 if (resultRemat (ic) || ic->generated)
7904 /* depending on the operation */
7908 emitDebug ("; genNot");
7913 emitDebug ("; genCpl");
7918 emitDebug ("; genUminus");
7923 emitDebug ("; genIpush");
7928 /* IPOP happens only when trying to restore a
7929 spilt live range, if there is an ifx statement
7930 following this pop then the if statement might
7931 be using some of the registers being popped which
7932 would destory the contents of the register so
7933 we need to check for this condition and handle it */
7935 ic->next->op == IFX &&
7936 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7938 emitDebug ("; genIfx");
7939 genIfx (ic->next, ic);
7943 emitDebug ("; genIpop");
7949 emitDebug ("; genCall");
7954 emitDebug ("; genPcall");
7959 emitDebug ("; genFunction");
7964 emitDebug ("; genEndFunction");
7965 genEndFunction (ic);
7969 emitDebug ("; genRet");
7974 emitDebug ("; genLabel");
7979 emitDebug ("; genGoto");
7984 emitDebug ("; genPlus");
7989 emitDebug ("; genMinus");
7994 emitDebug ("; genMult");
7999 emitDebug ("; genDiv");
8004 emitDebug ("; genMod");
8009 emitDebug ("; genCmpGt");
8010 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8014 emitDebug ("; genCmpLt");
8015 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8022 /* note these two are xlated by algebraic equivalence
8023 during parsing SDCC.y */
8024 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8025 "got '>=' or '<=' shouldn't have come here");
8029 emitDebug ("; genCmpEq");
8030 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8034 emitDebug ("; genAndOp");
8039 emitDebug ("; genOrOp");
8044 emitDebug ("; genXor");
8045 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8049 emitDebug ("; genOr");
8050 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8054 emitDebug ("; genAnd");
8055 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8059 emitDebug ("; genInline");
8064 emitDebug ("; genRRC");
8069 emitDebug ("; genRLC");
8074 emitDebug ("; genGetHBIT");
8079 emitDebug ("; genLeftShift");
8084 emitDebug ("; genRightShift");
8088 case GET_VALUE_AT_ADDRESS:
8089 emitDebug ("; genPointerGet");
8095 if (POINTER_SET (ic))
8097 emitDebug ("; genAssign (pointer)");
8102 emitDebug ("; genAssign");
8108 emitDebug ("; genIfx");
8113 emitDebug ("; genAddrOf");
8118 emitDebug ("; genJumpTab");
8123 emitDebug ("; genCast");
8128 emitDebug ("; genReceive");
8133 if (ic->builtinSEND)
8135 emitDebug ("; genBuiltIn");
8140 emitDebug ("; addSet");
8141 addSet (&_G.sendSet, ic);
8146 emitDebug ("; genArrayInit");
8150 case DUMMY_READ_VOLATILE:
8151 emitDebug ("; genDummyRead");
8161 /* now we are ready to call the
8162 peep hole optimizer */
8163 if (!options.nopeep)
8164 peepHole (&_G.lines.head);
8166 /* This is unfortunate */
8167 /* now do the actual printing */
8169 FILE *fp = codeOutFile;
8170 if (isInHome () && codeOutFile == code->oFile)
8171 codeOutFile = home->oFile;
8172 printLine (_G.lines.head, codeOutFile);
8173 if (_G.flushStatics)
8176 _G.flushStatics = 0;
8181 freeTrace(&_G.lines.trace);
8182 freeTrace(&_G.trace.aops);
8188 _isPairUsed (iCode * ic, PAIR_ID pairId)
8194 if (bitVectBitValue (ic->rMask, D_IDX))
8196 if (bitVectBitValue (ic->rMask, E_IDX))
8206 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8209 value *val = aop->aopu.aop_lit;
8211 wassert (aop->type == AOP_LIT);
8212 wassert (!IS_FLOAT (val->type));
8214 v = (unsigned long) floatFromVal (val);
8222 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8223 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));