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];
466 unsigned char *lbp = lb;
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 */
1896 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1897 && s[0] != 'h' && s[0] != 'l'))
1899 emit2( "ld a,%s", s );
1903 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1904 emit2( "out (c),%s", s );
1909 spillPair (PAIR_BC);
1911 else if( z80_opts.port_mode == 180 )
1912 { /* z180 in0/out0 mode */
1913 emit2( "ld a,%s", s );
1914 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1918 emit2( "ld a,%s", s );
1919 emit2( "out (%s),a", aop->aopu.aop_dir );
1925 if (!strcmp (s, "!*hl"))
1926 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1929 aop->aopu.aop_reg[offset]->name, s);
1930 spillPairReg(aop->aopu.aop_reg[offset]->name);
1935 if (!canAssignToPtr (s))
1937 emit2 ("ld a,%s", s);
1938 setupPair (PAIR_IY, aop, offset);
1939 emit2 ("ld !*iyx,a", offset);
1943 setupPair (PAIR_IY, aop, offset);
1944 emit2 ("ld !*iyx,%s", offset, s);
1950 /* PENDING: for re-target */
1951 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1953 emit2 ("ld a,!*hl");
1956 setupPair (PAIR_HL, aop, offset);
1958 emit2 ("ld !*hl,%s", s);
1963 if (!canAssignToPtr (s))
1965 emit2 ("ld a,%s", s);
1966 setupPair (PAIR_IY, aop, offset);
1967 emit2 ("ld !*iyx,a", offset);
1971 setupPair (PAIR_IY, aop, offset);
1972 emit2 ("ld !*iyx,%s", offset, s);
1979 /* PENDING: re-target */
1980 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1982 emit2 ("ld a,!*hl");
1985 setupPair (PAIR_HL, aop, offset);
1986 if (!canAssignToPtr (s))
1988 emit2 ("ld a,%s", s);
1989 emit2 ("ld !*hl,a");
1992 emit2 ("ld !*hl,%s", s);
1996 if (aop->aopu.aop_stk >= 0)
1997 offset += _G.stack.param_offset;
1998 if (!canAssignToPtr (s))
2000 emit2 ("ld a,%s", s);
2001 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2005 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2011 /* if bit variable */
2012 if (!aop->aopu.aop_dir)
2014 emit2 ("ld a,!zero");
2019 /* In bit space but not in C - cant happen */
2020 wassertl (0, "Tried to write into a bit variable");
2026 if (strcmp (aop->aopu.aop_str[offset], s))
2028 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2030 spillPairReg(aop->aopu.aop_str[offset]);
2035 if (!offset && (strcmp (s, "acc") == 0))
2039 wassertl (0, "Tried to access past the end of A");
2043 if (strcmp (aop->aopu.aop_str[offset], s))
2045 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2046 spillPairReg(aop->aopu.aop_str[offset]);
2052 wassert (offset < 2);
2053 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2054 spillPairReg(aop->aopu.aop_str[offset]);
2058 setupPair (aop->aopu.aop_pairId, aop, offset);
2059 if (aop->aopu.aop_pairId==PAIR_IX)
2060 emit2 ("ld !*ixx,%s", 0, s);
2061 else if (aop->aopu.aop_pairId==PAIR_IY)
2062 emit2 ("ld !*ixy,%s", 0, s);
2064 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2068 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2069 "aopPut got unsupported aop->type");
2074 #define AOP(op) op->aop
2075 #define AOP_TYPE(op) AOP(op)->type
2076 #define AOP_SIZE(op) AOP(op)->size
2077 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2080 commitPair (asmop * aop, PAIR_ID id)
2082 /* PENDING: Verify this. */
2083 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2087 aopPut (aop, "a", 0);
2088 aopPut (aop, "d", 1);
2093 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2095 char *l = aopGetLitWordLong (aop, 0, FALSE);
2098 emit2 ("ld (%s),%s", l, _pairs[id].name);
2102 aopPut (aop, _pairs[id].l, 0);
2103 aopPut (aop, _pairs[id].h, 1);
2108 /*-----------------------------------------------------------------*/
2109 /* getDataSize - get the operand data size */
2110 /*-----------------------------------------------------------------*/
2112 getDataSize (operand * op)
2115 size = AOP_SIZE (op);
2119 wassertl (0, "Somehow got a three byte data pointer");
2124 /*-----------------------------------------------------------------*/
2125 /* movLeft2Result - move byte from left to result */
2126 /*-----------------------------------------------------------------*/
2128 movLeft2Result (operand * left, int offl,
2129 operand * result, int offr, int sign)
2133 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2135 l = aopGet (AOP (left), offl, FALSE);
2139 aopPut (AOP (result), l, offr);
2143 if (getDataSize (left) == offl + 1)
2145 emit2 ("ld a,%s", l);
2146 aopPut (AOP (result), "a", offr);
2153 movLeft2ResultLong (operand * left, int offl,
2154 operand * result, int offr, int sign,
2159 movLeft2Result (left, offl, result, offr, sign);
2163 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2164 wassertl (size == 2, "Only implemented for two bytes or one");
2166 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2168 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2169 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2171 spillPair (PAIR_HL);
2173 else if ( getPairId ( AOP (result)) == PAIR_IY)
2175 PAIR_ID id = getPairId (AOP (left));
2176 if (id != PAIR_INVALID)
2178 emit2("push %s", _pairs[id].name);
2189 movLeft2Result (left, offl, result, offr, sign);
2190 movLeft2Result (left, offl+1, result, offr+1, sign);
2195 /** Put Acc into a register set
2198 outAcc (operand * result)
2201 size = getDataSize (result);
2204 aopPut (AOP (result), "a", 0);
2207 /* unsigned or positive */
2210 aopPut (AOP (result), "!zero", offset++);
2215 /** Take the value in carry and put it into a register
2218 outBitCLong (operand * result, bool swap_sense)
2220 /* if the result is bit */
2221 if (AOP_TYPE (result) == AOP_CRY)
2223 wassertl (0, "Tried to write carry to a bit");
2227 emit2 ("ld a,!zero");
2230 emit2 ("xor a,!immedbyte", 1);
2236 outBitC (operand * result)
2238 outBitCLong (result, FALSE);
2241 /*-----------------------------------------------------------------*/
2242 /* toBoolean - emit code for orl a,operator(sizeop) */
2243 /*-----------------------------------------------------------------*/
2245 _toBoolean (operand * oper)
2247 int size = AOP_SIZE (oper);
2251 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2254 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2258 if (AOP (oper)->type != AOP_ACC)
2261 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2267 /*-----------------------------------------------------------------*/
2268 /* genNot - generate code for ! operation */
2269 /*-----------------------------------------------------------------*/
2274 /* assign asmOps to operand & result */
2275 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2276 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2278 /* if in bit space then a special case */
2279 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2281 wassertl (0, "Tried to negate a bit");
2284 _toBoolean (IC_LEFT (ic));
2289 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2290 emit2 ("sub a,!one");
2291 outBitC (IC_RESULT (ic));
2293 /* release the aops */
2294 freeAsmop (IC_LEFT (ic), NULL, ic);
2295 freeAsmop (IC_RESULT (ic), NULL, ic);
2298 /*-----------------------------------------------------------------*/
2299 /* genCpl - generate code for complement */
2300 /*-----------------------------------------------------------------*/
2308 /* assign asmOps to operand & result */
2309 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2310 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2312 /* if both are in bit space then
2314 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2315 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2317 wassertl (0, "Left and the result are in bit space");
2320 size = AOP_SIZE (IC_RESULT (ic));
2323 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2326 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2329 /* release the aops */
2330 freeAsmop (IC_LEFT (ic), NULL, ic);
2331 freeAsmop (IC_RESULT (ic), NULL, ic);
2335 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2342 store de into result
2347 store de into result
2349 const char *first = isAdd ? "add" : "sub";
2350 const char *later = isAdd ? "adc" : "sbc";
2352 wassertl (IS_GB, "Code is only relevent to the gbz80");
2353 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2355 fetchPair (PAIR_DE, left);
2358 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2361 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2364 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2365 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2367 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2368 aopGet (right, MSB24, FALSE);
2372 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2375 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2377 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2378 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2382 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2384 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2387 /*-----------------------------------------------------------------*/
2388 /* genUminusFloat - unary minus for floating points */
2389 /*-----------------------------------------------------------------*/
2391 genUminusFloat (operand * op, operand * result)
2393 int size, offset = 0;
2395 emitDebug("; genUminusFloat");
2397 /* for this we just need to flip the
2398 first bit then copy the rest in place */
2399 size = AOP_SIZE (op) - 1;
2401 _moveA(aopGet (AOP (op), MSB32, FALSE));
2403 emit2("xor a,!immedbyte", 0x80);
2404 aopPut (AOP (result), "a", MSB32);
2408 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2413 /*-----------------------------------------------------------------*/
2414 /* genUminus - unary minus code generation */
2415 /*-----------------------------------------------------------------*/
2417 genUminus (iCode * ic)
2420 sym_link *optype, *rtype;
2423 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2424 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2426 /* if both in bit space then special
2428 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2429 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2431 wassertl (0, "Left and right are in bit space");
2435 optype = operandType (IC_LEFT (ic));
2436 rtype = operandType (IC_RESULT (ic));
2438 /* if float then do float stuff */
2439 if (IS_FLOAT (optype))
2441 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2445 /* otherwise subtract from zero */
2446 size = AOP_SIZE (IC_LEFT (ic));
2448 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2450 /* Create a new asmop with value zero */
2451 asmop *azero = newAsmop (AOP_SIMPLELIT);
2452 azero->aopu.aop_simplelit = 0;
2454 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2462 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2463 emit2 ("ld a,!zero");
2464 emit2 ("sbc a,%s", l);
2465 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2468 /* if any remaining bytes in the result */
2469 /* we just need to propagate the sign */
2470 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2475 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2479 /* release the aops */
2480 freeAsmop (IC_LEFT (ic), NULL, ic);
2481 freeAsmop (IC_RESULT (ic), NULL, ic);
2484 /*-----------------------------------------------------------------*/
2485 /* assignResultValue - */
2486 /*-----------------------------------------------------------------*/
2488 assignResultValue (operand * oper)
2490 int size = AOP_SIZE (oper);
2493 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2494 topInA = requiresHL (AOP (oper));
2496 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2498 /* We do it the hard way here. */
2500 aopPut (AOP (oper), _fReturn[0], 0);
2501 aopPut (AOP (oper), _fReturn[1], 1);
2503 aopPut (AOP (oper), _fReturn[0], 2);
2504 aopPut (AOP (oper), _fReturn[1], 3);
2510 aopPut (AOP (oper), _fReturn[size], size);
2515 /** Simple restore that doesn't take into account what is used in the
2519 _restoreRegsAfterCall(void)
2521 if (_G.stack.pushedDE)
2524 _G.stack.pushedDE = FALSE;
2526 if (_G.stack.pushedBC)
2529 _G.stack.pushedBC = FALSE;
2531 _G.saves.saved = FALSE;
2535 _saveRegsForCall(iCode *ic, int sendSetSize)
2538 o Stack parameters are pushed before this function enters
2539 o DE and BC may be used in this function.
2540 o HL and DE may be used to return the result.
2541 o HL and DE may be used to send variables.
2542 o DE and BC may be used to store the result value.
2543 o HL may be used in computing the sent value of DE
2544 o The iPushes for other parameters occur before any addSets
2546 Logic: (to be run inside the first iPush or if none, before sending)
2547 o Compute if DE and/or BC are in use over the call
2548 o Compute if DE is used in the send set
2549 o Compute if DE and/or BC are used to hold the result value
2550 o If (DE is used, or in the send set) and is not used in the result, push.
2551 o If BC is used and is not in the result, push
2553 o If DE is used in the send set, fetch
2554 o If HL is used in the send set, fetch
2558 if (_G.saves.saved == FALSE) {
2559 bool deInUse, bcInUse;
2561 bool bcInRet = FALSE, deInRet = FALSE;
2564 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2565 z80_rUmaskForOp (IC_RESULT(ic)));
2567 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2568 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2570 deSending = (sendSetSize > 1);
2572 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2574 if (bcInUse && bcInRet == FALSE) {
2576 _G.stack.pushedBC = TRUE;
2578 if (deInUse && deInRet == FALSE) {
2580 _G.stack.pushedDE = TRUE;
2583 _G.saves.saved = TRUE;
2586 /* Already saved. */
2590 /*-----------------------------------------------------------------*/
2591 /* genIpush - genrate code for pushing this gets a little complex */
2592 /*-----------------------------------------------------------------*/
2594 genIpush (iCode * ic)
2596 int size, offset = 0;
2599 /* if this is not a parm push : ie. it is spill push
2600 and spill push is always done on the local stack */
2603 wassertl(0, "Encountered an unsupported spill push.");
2607 if (_G.saves.saved == FALSE) {
2608 /* Caller saves, and this is the first iPush. */
2609 /* Scan ahead until we find the function that we are pushing parameters to.
2610 Count the number of addSets on the way to figure out what registers
2611 are used in the send set.
2614 iCode *walk = ic->next;
2617 if (walk->op == SEND) {
2620 else if (walk->op == CALL || walk->op == PCALL) {
2629 _saveRegsForCall(walk, nAddSets);
2632 /* Already saved by another iPush. */
2635 /* then do the push */
2636 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2638 size = AOP_SIZE (IC_LEFT (ic));
2640 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2642 _G.stack.pushed += 2;
2643 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2649 fetchHL (AOP (IC_LEFT (ic)));
2651 spillPair (PAIR_HL);
2652 _G.stack.pushed += 2;
2657 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2659 spillPair (PAIR_HL);
2660 _G.stack.pushed += 2;
2661 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2663 spillPair (PAIR_HL);
2664 _G.stack.pushed += 2;
2670 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2672 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2674 emit2 ("ld a,(%s)", l);
2678 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2679 emit2 ("ld a,%s", l);
2687 freeAsmop (IC_LEFT (ic), NULL, ic);
2690 /*-----------------------------------------------------------------*/
2691 /* genIpop - recover the registers: can happen only for spilling */
2692 /*-----------------------------------------------------------------*/
2694 genIpop (iCode * ic)
2699 /* if the temp was not pushed then */
2700 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2703 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2704 size = AOP_SIZE (IC_LEFT (ic));
2705 offset = (size - 1);
2706 if (isPair (AOP (IC_LEFT (ic))))
2708 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2716 spillPair (PAIR_HL);
2717 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2721 freeAsmop (IC_LEFT (ic), NULL, ic);
2724 /* This is quite unfortunate */
2726 setArea (int inHome)
2729 static int lastArea = 0;
2731 if (_G.in_home != inHome) {
2733 const char *sz = port->mem.code_name;
2734 port->mem.code_name = "HOME";
2735 emit2("!area", CODE_NAME);
2736 port->mem.code_name = sz;
2739 emit2("!area", CODE_NAME); */
2740 _G.in_home = inHome;
2751 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2755 symbol *sym = OP_SYMBOL (op);
2757 if (sym->isspilt || sym->nRegs == 0)
2760 aopOp (op, ic, FALSE, FALSE);
2763 if (aop->type == AOP_REG)
2766 for (i = 0; i < aop->size; i++)
2768 if (pairId == PAIR_DE)
2770 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2771 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2773 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2776 else if (pairId == PAIR_BC)
2778 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2779 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2781 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2791 freeAsmop (IC_LEFT (ic), NULL, ic);
2795 /** Emit the code for a call statement
2798 emitCall (iCode * ic, bool ispcall)
2800 bool bInRet, cInRet, dInRet, eInRet;
2801 sym_link *dtype = operandType (IC_LEFT (ic));
2803 /* if caller saves & we have not saved then */
2809 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2811 /* if send set is not empty then assign */
2816 int nSend = elementsInSet(_G.sendSet);
2817 bool swapped = FALSE;
2819 int _z80_sendOrder[] = {
2824 /* Check if the parameters are swapped. If so route through hl instead. */
2825 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2827 sic = setFirstItem(_G.sendSet);
2828 sic = setNextItem(_G.sendSet);
2830 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2831 /* The second send value is loaded from one the one that holds the first
2832 send, i.e. it is overwritten. */
2833 /* Cache the first in HL, and load the second from HL instead. */
2834 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2835 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2841 for (sic = setFirstItem (_G.sendSet); sic;
2842 sic = setNextItem (_G.sendSet))
2845 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2847 size = AOP_SIZE (IC_LEFT (sic));
2848 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2849 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2851 // PENDING: Mild hack
2852 if (swapped == TRUE && send == 1) {
2854 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2857 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2859 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2862 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2866 freeAsmop (IC_LEFT (sic), NULL, sic);
2873 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2875 werror (W_INDIR_BANKED);
2877 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2879 if (isLitWord (AOP (IC_LEFT (ic))))
2881 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2885 symbol *rlbl = newiTempLabel (NULL);
2886 spillPair (PAIR_HL);
2887 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2889 _G.stack.pushed += 2;
2891 fetchHL (AOP (IC_LEFT (ic)));
2893 emit2 ("!tlabeldef", (rlbl->key + 100));
2894 _G.stack.pushed -= 2;
2896 freeAsmop (IC_LEFT (ic), NULL, ic);
2900 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2901 OP_SYMBOL (IC_LEFT (ic))->rname :
2902 OP_SYMBOL (IC_LEFT (ic))->name;
2903 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2905 emit2 ("call banked_call");
2906 emit2 ("!dws", name);
2907 emit2 ("!dw !bankimmeds", name);
2912 emit2 ("call %s", name);
2917 /* Mark the registers as restored. */
2918 _G.saves.saved = FALSE;
2920 /* if we need assign a result value */
2921 if ((IS_ITEMP (IC_RESULT (ic)) &&
2922 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2923 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2924 IS_TRUE_SYMOP (IC_RESULT (ic)))
2927 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2929 assignResultValue (IC_RESULT (ic));
2931 freeAsmop (IC_RESULT (ic), NULL, ic);
2934 /* adjust the stack for parameters if required */
2937 int i = ic->parmBytes;
2939 _G.stack.pushed -= i;
2942 emit2 ("!ldaspsp", i);
2949 emit2 ("ld iy,!immedword", i);
2950 emit2 ("add iy,sp");
2971 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2972 bInRet = bitVectBitValue(result, B_IDX);
2973 cInRet = bitVectBitValue(result, C_IDX);
2974 dInRet = bitVectBitValue(result, D_IDX);
2975 eInRet = bitVectBitValue(result, E_IDX);
2985 if (_G.stack.pushedDE)
2987 if (dInRet && eInRet)
2989 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2993 /* Only restore E */
3000 /* Only restore D */
3008 _G.stack.pushedDE = FALSE;
3011 if (_G.stack.pushedBC)
3013 if (bInRet && cInRet)
3015 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3019 /* Only restore C */
3026 /* Only restore B */
3034 _G.stack.pushedBC = FALSE;
3038 /*-----------------------------------------------------------------*/
3039 /* genCall - generates a call statement */
3040 /*-----------------------------------------------------------------*/
3042 genCall (iCode * ic)
3044 emitCall (ic, FALSE);
3047 /*-----------------------------------------------------------------*/
3048 /* genPcall - generates a call by pointer statement */
3049 /*-----------------------------------------------------------------*/
3051 genPcall (iCode * ic)
3053 emitCall (ic, TRUE);
3056 /*-----------------------------------------------------------------*/
3057 /* resultRemat - result is rematerializable */
3058 /*-----------------------------------------------------------------*/
3060 resultRemat (iCode * ic)
3062 if (SKIP_IC (ic) || ic->op == IFX)
3065 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3067 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3068 if (sym->remat && !POINTER_SET (ic))
3075 extern set *publics;
3077 /*-----------------------------------------------------------------*/
3078 /* genFunction - generated code for function entry */
3079 /*-----------------------------------------------------------------*/
3081 genFunction (iCode * ic)
3085 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3088 bool bcInUse = FALSE;
3089 bool deInUse = FALSE;
3091 setArea (IFFUNC_NONBANKED (sym->type));
3093 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
3096 _G.receiveOffset = 0;
3098 /* Record the last function name for debugging. */
3099 _G.lastFunctionName = sym->rname;
3101 /* Create the function header */
3102 emit2 ("!functionheader", sym->name);
3103 if (!IS_STATIC(sym->etype))
3105 sprintf (buffer, "%s_start", sym->rname);
3106 emit2 ("!labeldef", buffer);
3108 emit2 ("!functionlabeldef", sym->rname);
3110 if (options.profile)
3112 emit2 ("!profileenter");
3115 ftype = operandType (IC_LEFT (ic));
3117 /* if this is an interrupt service routine then save all potentially used registers. */
3118 if (IFFUNC_ISISR (sym->type))
3120 if (!FUNC_ISNAKED( sym->type ))
3127 /* if critical function then turn interrupts off */
3128 if (IFFUNC_ISCRITICAL (sym->type))
3134 /* PENDING: callee-save etc */
3136 _G.stack.param_offset = 0;
3138 if (z80_opts.calleeSavesBC)
3143 /* Detect which registers are used. */
3144 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3147 for (i = 0; i < sym->regsUsed->size; i++)
3149 if (bitVectBitValue (sym->regsUsed, i))
3163 /* Other systems use DE as a temporary. */
3174 _G.stack.param_offset += 2;
3177 _G.calleeSaves.pushedBC = bcInUse;
3182 _G.stack.param_offset += 2;
3185 _G.calleeSaves.pushedDE = deInUse;
3187 /* adjust the stack for the function */
3188 _G.stack.last = sym->stack;
3191 for (sym = setFirstItem (istack->syms); sym;
3192 sym = setNextItem (istack->syms))
3194 if (sym->_isparm && !IS_REGPARM (sym->etype))
3200 sym = OP_SYMBOL (IC_LEFT (ic));
3202 _G.omitFramePtr = options.ommitFramePtr;
3203 if (IS_Z80 && !stackParm && !sym->stack)
3205 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3206 /* the above !sym->stack condition can be removed. -- EEP */
3208 emit2 ("!ldaspsp", -sym->stack);
3209 _G.omitFramePtr = TRUE;
3211 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3212 emit2 ("!enterxl", sym->stack);
3213 else if (sym->stack)
3214 emit2 ("!enterx", sym->stack);
3215 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3218 _G.stack.offset = sym->stack;
3221 /*-----------------------------------------------------------------*/
3222 /* genEndFunction - generates epilogue for functions */
3223 /*-----------------------------------------------------------------*/
3225 genEndFunction (iCode * ic)
3227 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3230 /* PENDING: calleeSave */
3231 if (IS_Z80 && _G.omitFramePtr)
3233 if (_G.stack.offset)
3234 emit2 ("!ldaspsp", _G.stack.offset);
3236 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3238 emit2 ("!leavexl", _G.stack.offset);
3240 else if (_G.stack.offset)
3242 emit2 ("!leavex", _G.stack.offset);
3244 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3249 if (_G.calleeSaves.pushedDE)
3252 _G.calleeSaves.pushedDE = FALSE;
3255 if (_G.calleeSaves.pushedBC)
3258 _G.calleeSaves.pushedBC = FALSE;
3261 if (options.profile)
3263 emit2 ("!profileexit");
3266 /* if this is an interrupt service routine then restore all potentially used registers. */
3267 if (IFFUNC_ISISR (sym->type))
3269 if (!FUNC_ISNAKED( sym->type ))
3276 /* if critical function then turn interrupts back on */
3277 if (IFFUNC_ISCRITICAL (sym->type))
3281 if (options.debug && currFunc)
3283 debugFile->writeEndFunction (currFunc, ic, 1);
3286 if (IFFUNC_ISISR (sym->type))
3288 /* "critical interrupt" is used to imply NMI handler */
3289 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type))
3296 /* Both banked and non-banked just ret */
3300 if (!IS_STATIC(sym->etype))
3302 sprintf (buffer, "%s_end", sym->rname);
3303 emit2 ("!labeldef", buffer);
3306 _G.flushStatics = 1;
3307 _G.stack.pushed = 0;
3308 _G.stack.offset = 0;
3311 /*-----------------------------------------------------------------*/
3312 /* genRet - generate code for return statement */
3313 /*-----------------------------------------------------------------*/
3318 /* Errk. This is a hack until I can figure out how
3319 to cause dehl to spill on a call */
3320 int size, offset = 0;
3322 /* if we have no return value then
3323 just generate the "ret" */
3327 /* we have something to return then
3328 move the return value into place */
3329 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3330 size = AOP_SIZE (IC_LEFT (ic));
3332 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3335 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3339 emit2 ("ld de,%s", l);
3343 emit2 ("ld hl,%s", l);
3349 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3353 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3355 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3356 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3362 l = aopGet (AOP (IC_LEFT (ic)), offset,
3364 if (strcmp (_fReturn[offset], l))
3365 emit2 ("ld %s,%s", _fReturn[offset], l);
3370 freeAsmop (IC_LEFT (ic), NULL, ic);
3373 /* generate a jump to the return label
3374 if the next is not the return statement */
3375 if (!(ic->next && ic->next->op == LABEL &&
3376 IC_LABEL (ic->next) == returnLabel))
3378 emit2 ("jp !tlabel", returnLabel->key + 100);
3381 /*-----------------------------------------------------------------*/
3382 /* genLabel - generates a label */
3383 /*-----------------------------------------------------------------*/
3385 genLabel (iCode * ic)
3387 /* special case never generate */
3388 if (IC_LABEL (ic) == entryLabel)
3391 emitLabel (IC_LABEL (ic)->key + 100);
3394 /*-----------------------------------------------------------------*/
3395 /* genGoto - generates a ljmp */
3396 /*-----------------------------------------------------------------*/
3398 genGoto (iCode * ic)
3400 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3403 /*-----------------------------------------------------------------*/
3404 /* genPlusIncr :- does addition with increment if possible */
3405 /*-----------------------------------------------------------------*/
3407 genPlusIncr (iCode * ic)
3409 unsigned int icount;
3410 unsigned int size = getDataSize (IC_RESULT (ic));
3411 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3413 /* will try to generate an increment */
3414 /* if the right side is not a literal
3416 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3419 emitDebug ("; genPlusIncr");
3421 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3423 /* If result is a pair */
3424 if (resultId != PAIR_INVALID)
3426 if (isLitWord (AOP (IC_LEFT (ic))))
3428 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3431 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3433 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3435 PAIR_ID freep = getFreePairId (ic);
3436 if (freep != PAIR_INVALID)
3438 fetchPair (freep, AOP (IC_RIGHT (ic)));
3439 emit2 ("add hl,%s", _pairs[freep].name);
3445 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3446 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3453 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3457 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3461 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3466 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3468 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3469 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3473 /* if the literal value of the right hand side
3474 is greater than 4 then it is not worth it */
3478 /* if increment 16 bits in register */
3479 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3485 symbol *tlbl = NULL;
3486 tlbl = newiTempLabel (NULL);
3489 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3492 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3495 emitLabel (tlbl->key + 100);
3499 /* if the sizes are greater than 1 then we cannot */
3500 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3501 AOP_SIZE (IC_LEFT (ic)) > 1)
3504 /* If the result is in a register then we can load then increment.
3506 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3508 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3511 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3516 /* we can if the aops of the left & result match or
3517 if they are in registers and the registers are the
3519 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3523 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3531 /*-----------------------------------------------------------------*/
3532 /* outBitAcc - output a bit in acc */
3533 /*-----------------------------------------------------------------*/
3535 outBitAcc (operand * result)
3537 symbol *tlbl = newiTempLabel (NULL);
3538 /* if the result is a bit */
3539 if (AOP_TYPE (result) == AOP_CRY)
3541 wassertl (0, "Tried to write A into a bit");
3545 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3546 emit2 ("ld a,!one");
3547 emitLabel (tlbl->key + 100);
3553 couldDestroyCarry (asmop *aop)
3557 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3566 shiftIntoPair (int idx, asmop *aop)
3568 PAIR_ID id = PAIR_INVALID;
3570 wassertl (IS_Z80, "Only implemented for the Z80");
3571 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3583 wassertl (0, "Internal error - hit default case");
3586 emitDebug ("; Shift into pair idx %u", idx);
3590 setupPair (PAIR_HL, aop, 0);
3594 setupPair (PAIR_IY, aop, 0);
3596 emit2 ("pop %s", _pairs[id].name);
3599 aop->type = AOP_PAIRPTR;
3600 aop->aopu.aop_pairId = id;
3601 _G.pairs[id].offset = 0;
3602 _G.pairs[id].last_type = aop->type;
3606 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3608 wassert (left && right);
3612 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3614 shiftIntoPair (0, right);
3615 /* check result again, in case right == result */
3616 if (couldDestroyCarry (result))
3617 shiftIntoPair (1, result);
3619 else if (couldDestroyCarry (right))
3621 if (getPairId (result) == PAIR_HL)
3622 _G.preserveCarry = TRUE;
3624 shiftIntoPair (0, right);
3626 else if (couldDestroyCarry (result))
3628 shiftIntoPair (0, result);
3637 /*-----------------------------------------------------------------*/
3638 /* genPlus - generates code for addition */
3639 /*-----------------------------------------------------------------*/
3641 genPlus (iCode * ic)
3643 int size, offset = 0;
3645 /* special cases :- */
3647 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3648 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3649 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3651 /* Swap the left and right operands if:
3653 if literal, literal on the right or
3654 if left requires ACC or right is already
3657 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3658 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3659 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3661 operand *t = IC_RIGHT (ic);
3662 IC_RIGHT (ic) = IC_LEFT (ic);
3666 /* if both left & right are in bit
3668 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3669 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3672 wassertl (0, "Tried to add two bits");
3675 /* if left in bit space & right literal */
3676 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3677 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3679 /* Can happen I guess */
3680 wassertl (0, "Tried to add a bit to a literal");
3683 /* if I can do an increment instead
3684 of add then GOOD for ME */
3685 if (genPlusIncr (ic) == TRUE)
3688 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3690 size = getDataSize (IC_RESULT (ic));
3692 /* Special case when left and right are constant */
3693 if (isPair (AOP (IC_RESULT (ic))))
3696 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3697 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3699 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3705 sprintf (buffer, "#(%s + %s)", left, right);
3706 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3711 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3713 /* Fetch into HL then do the add */
3714 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3715 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3717 spillPair (PAIR_HL);
3719 if (left == PAIR_HL && right != PAIR_INVALID)
3721 emit2 ("add hl,%s", _pairs[right].name);
3724 else if (right == PAIR_HL && left != PAIR_INVALID)
3726 emit2 ("add hl,%s", _pairs[left].name);
3729 else if (right != PAIR_INVALID && right != PAIR_HL)
3731 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3732 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3735 else if (left != PAIR_INVALID && left != PAIR_HL)
3737 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3738 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3747 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3749 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3750 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3752 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3757 ld hl,sp+n trashes C so we cant afford to do it during an
3758 add with stack based varibles. Worst case is:
3771 So you cant afford to load up hl if either left, right, or result
3772 is on the stack (*sigh*) The alt is:
3780 Combinations in here are:
3781 * If left or right are in bc then the loss is small - trap later
3782 * If the result is in bc then the loss is also small
3786 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3787 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3788 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3790 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3791 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3792 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3793 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3795 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3797 /* Swap left and right */
3798 operand *t = IC_RIGHT (ic);
3799 IC_RIGHT (ic) = IC_LEFT (ic);
3802 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3804 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3805 emit2 ("add hl,bc");
3809 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3810 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3811 emit2 ("add hl,de");
3813 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3819 /* Be paranoid on the GB with 4 byte variables due to how C
3820 can be trashed by lda hl,n(sp).
3822 _gbz80_emitAddSubLong (ic, TRUE);
3827 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3831 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3833 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3836 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3839 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3843 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3846 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3849 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3851 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3855 _G.preserveCarry = FALSE;
3856 freeAsmop (IC_LEFT (ic), NULL, ic);
3857 freeAsmop (IC_RIGHT (ic), NULL, ic);
3858 freeAsmop (IC_RESULT (ic), NULL, ic);
3862 /*-----------------------------------------------------------------*/
3863 /* genMinusDec :- does subtraction with deccrement if possible */
3864 /*-----------------------------------------------------------------*/
3866 genMinusDec (iCode * ic)
3868 unsigned int icount;
3869 unsigned int size = getDataSize (IC_RESULT (ic));
3871 /* will try to generate an increment */
3872 /* if the right side is not a literal we cannot */
3873 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3876 /* if the literal value of the right hand side
3877 is greater than 4 then it is not worth it */
3878 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3881 size = getDataSize (IC_RESULT (ic));
3883 /* if decrement 16 bits in register */
3884 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3885 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3888 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3892 /* If result is a pair */
3893 if (isPair (AOP (IC_RESULT (ic))))
3895 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3897 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3901 /* if increment 16 bits in register */
3902 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3906 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3909 emit2 ("dec %s", _getTempPairName());
3912 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3918 /* if the sizes are greater than 1 then we cannot */
3919 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3920 AOP_SIZE (IC_LEFT (ic)) > 1)
3923 /* we can if the aops of the left & result match or if they are in
3924 registers and the registers are the same */
3925 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3928 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3935 /*-----------------------------------------------------------------*/
3936 /* genMinus - generates code for subtraction */
3937 /*-----------------------------------------------------------------*/
3939 genMinus (iCode * ic)
3941 int size, offset = 0;
3942 unsigned long lit = 0L;
3944 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3945 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3946 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3948 /* special cases :- */
3949 /* if both left & right are in bit space */
3950 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3951 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3953 wassertl (0, "Tried to subtract two bits");
3957 /* if I can do an decrement instead of subtract then GOOD for ME */
3958 if (genMinusDec (ic) == TRUE)
3961 size = getDataSize (IC_RESULT (ic));
3963 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3968 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3972 /* Same logic as genPlus */
3975 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3976 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3977 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3979 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3980 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3981 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3982 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3984 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3985 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3987 if (left == PAIR_INVALID && right == PAIR_INVALID)
3992 else if (right == PAIR_INVALID)
3994 else if (left == PAIR_INVALID)
3997 fetchPair (left, AOP (IC_LEFT (ic)));
3998 /* Order is important. Right may be HL */
3999 fetchPair (right, AOP (IC_RIGHT (ic)));
4001 emit2 ("ld a,%s", _pairs[left].l);
4002 emit2 ("sub a,%s", _pairs[right].l);
4004 emit2 ("ld a,%s", _pairs[left].h);
4005 emit2 ("sbc a,%s", _pairs[right].h);
4007 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4009 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4011 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4017 /* Be paranoid on the GB with 4 byte variables due to how C
4018 can be trashed by lda hl,n(sp).
4020 _gbz80_emitAddSubLong (ic, FALSE);
4025 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
4027 /* if literal, add a,#-lit, else normal subb */
4030 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4031 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4035 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4038 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4042 /* first add without previous c */
4044 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4046 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4048 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4051 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4052 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4053 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4055 wassertl (0, "Tried to subtract on a long pointer");
4059 _G.preserveCarry = FALSE;
4060 freeAsmop (IC_LEFT (ic), NULL, ic);
4061 freeAsmop (IC_RIGHT (ic), NULL, ic);
4062 freeAsmop (IC_RESULT (ic), NULL, ic);
4065 /*-----------------------------------------------------------------*/
4066 /* genMult - generates code for multiplication */
4067 /*-----------------------------------------------------------------*/
4069 genMult (iCode * ic)
4073 /* If true then the final operation should be a subtract */
4074 bool active = FALSE;
4077 /* Shouldn't occur - all done through function calls */
4078 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4079 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4080 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4082 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4084 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4085 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4086 AOP_SIZE (IC_RESULT (ic)) > 2)
4088 wassertl (0, "Multiplication is handled through support function calls");
4091 /* Swap left and right such that right is a literal */
4092 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4094 operand *t = IC_RIGHT (ic);
4095 IC_RIGHT (ic) = IC_LEFT (ic);
4099 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4101 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4102 // wassertl (val > 0, "Multiply must be positive");
4103 wassertl (val != 1, "Can't multiply by 1");
4105 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4107 _G.stack.pushedDE = TRUE;
4110 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4112 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4123 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4128 /* Fully unroled version of mul.s. Not the most efficient.
4130 for (count = 0; count < 16; count++)
4132 if (count != 0 && active)
4134 emit2 ("add hl,hl");
4138 if (active == FALSE)
4146 emit2 ("add hl,de");
4155 if (IS_Z80 && _G.stack.pushedDE)
4158 _G.stack.pushedDE = FALSE;
4162 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4164 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4166 freeAsmop (IC_LEFT (ic), NULL, ic);
4167 freeAsmop (IC_RIGHT (ic), NULL, ic);
4168 freeAsmop (IC_RESULT (ic), NULL, ic);
4171 /*-----------------------------------------------------------------*/
4172 /* genDiv - generates code for division */
4173 /*-----------------------------------------------------------------*/
4177 /* Shouldn't occur - all done through function calls */
4178 wassertl (0, "Division is handled through support function calls");
4181 /*-----------------------------------------------------------------*/
4182 /* genMod - generates code for division */
4183 /*-----------------------------------------------------------------*/
4187 /* Shouldn't occur - all done through function calls */
4191 /*-----------------------------------------------------------------*/
4192 /* genIfxJump :- will create a jump depending on the ifx */
4193 /*-----------------------------------------------------------------*/
4195 genIfxJump (iCode * ic, char *jval)
4200 /* if true label then we jump if condition
4204 jlbl = IC_TRUE (ic);
4205 if (!strcmp (jval, "a"))
4209 else if (!strcmp (jval, "c"))
4213 else if (!strcmp (jval, "nc"))
4217 else if (!strcmp (jval, "m"))
4221 else if (!strcmp (jval, "p"))
4227 /* The buffer contains the bit on A that we should test */
4233 /* false label is present */
4234 jlbl = IC_FALSE (ic);
4235 if (!strcmp (jval, "a"))
4239 else if (!strcmp (jval, "c"))
4243 else if (!strcmp (jval, "nc"))
4247 else if (!strcmp (jval, "m"))
4251 else if (!strcmp (jval, "p"))
4257 /* The buffer contains the bit on A that we should test */
4261 /* Z80 can do a conditional long jump */
4262 if (!strcmp (jval, "a"))
4266 else if (!strcmp (jval, "c"))
4269 else if (!strcmp (jval, "nc"))
4272 else if (!strcmp (jval, "m"))
4275 else if (!strcmp (jval, "p"))
4280 emit2 ("bit %s,a", jval);
4282 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4284 /* mark the icode as generated */
4290 _getPairIdName (PAIR_ID id)
4292 return _pairs[id].name;
4297 /* if unsigned char cmp with lit, just compare */
4299 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4301 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4304 emit2 ("xor a,!immedbyte", 0x80);
4305 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4308 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4310 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4312 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4313 // Pull left into DE and right into HL
4314 aopGet (AOP(left), LSB, FALSE);
4317 aopGet (AOP(right), LSB, FALSE);
4321 if (size == 0 && sign)
4323 // Highest byte when signed needs the bits flipped
4326 emit2 ("ld a,(de)");
4327 emit2 ("xor !immedbyte", 0x80);
4329 emit2 ("ld a,(hl)");
4330 emit2 ("xor !immedbyte", 0x80);
4334 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4338 emit2 ("ld a,(de)");
4339 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4349 spillPair (PAIR_HL);
4351 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4353 setupPair (PAIR_HL, AOP (left), 0);
4354 aopGet (AOP(right), LSB, FALSE);
4358 if (size == 0 && sign)
4360 // Highest byte when signed needs the bits flipped
4363 emit2 ("ld a,(hl)");
4364 emit2 ("xor !immedbyte", 0x80);
4366 emit2 ("ld a,%d(iy)", offset);
4367 emit2 ("xor !immedbyte", 0x80);
4371 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4375 emit2 ("ld a,(hl)");
4376 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4385 spillPair (PAIR_HL);
4386 spillPair (PAIR_IY);
4390 if (AOP_TYPE (right) == AOP_LIT)
4392 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4393 /* optimize if(x < 0) or if(x >= 0) */
4398 /* No sign so it's always false */
4403 /* Just load in the top most bit */
4404 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4405 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4407 genIfxJump (ifx, "7");
4419 /* First setup h and l contaning the top most bytes XORed */
4420 bool fDidXor = FALSE;
4421 if (AOP_TYPE (left) == AOP_LIT)
4423 unsigned long lit = (unsigned long)
4424 floatFromVal (AOP (left)->aopu.aop_lit);
4425 emit2 ("ld %s,!immedbyte", _fTmp[0],
4426 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4430 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4431 emit2 ("xor a,!immedbyte", 0x80);
4432 emit2 ("ld %s,a", _fTmp[0]);
4435 if (AOP_TYPE (right) == AOP_LIT)
4437 unsigned long lit = (unsigned long)
4438 floatFromVal (AOP (right)->aopu.aop_lit);
4439 emit2 ("ld %s,!immedbyte", _fTmp[1],
4440 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4444 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4445 emit2 ("xor a,!immedbyte", 0x80);
4446 emit2 ("ld %s,a", _fTmp[1]);
4452 /* Do a long subtract */
4455 _moveA (aopGet (AOP (left), offset, FALSE));
4457 if (sign && size == 0)
4459 emit2 ("ld a,%s", _fTmp[0]);
4460 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4464 /* Subtract through, propagating the carry */
4465 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4473 /** Generic compare for > or <
4476 genCmp (operand * left, operand * right,
4477 operand * result, iCode * ifx, int sign)
4479 int size, offset = 0;
4480 unsigned long lit = 0L;
4481 bool swap_sense = FALSE;
4483 /* if left & right are bit variables */
4484 if (AOP_TYPE (left) == AOP_CRY &&
4485 AOP_TYPE (right) == AOP_CRY)
4487 /* Cant happen on the Z80 */
4488 wassertl (0, "Tried to compare two bits");
4492 /* Do a long subtract of right from left. */
4493 size = max (AOP_SIZE (left), AOP_SIZE (right));
4495 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4497 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4498 // Pull left into DE and right into HL
4499 aopGet (AOP(left), LSB, FALSE);
4502 aopGet (AOP(right), LSB, FALSE);
4506 emit2 ("ld a,(de)");
4507 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4516 spillPair (PAIR_HL);
4520 if (AOP_TYPE (right) == AOP_LIT)
4522 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4523 /* optimize if(x < 0) or if(x >= 0) */
4528 /* No sign so it's always false */
4533 /* Just load in the top most bit */
4534 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4535 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4537 genIfxJump (ifx, "7");
4548 genIfxJump (ifx, swap_sense ? "c" : "nc");
4559 _moveA (aopGet (AOP (left), offset, FALSE));
4560 /* Subtract through, propagating the carry */
4561 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4567 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4571 /* Shift the sign bit up into carry */
4574 outBitCLong (result, swap_sense);
4578 /* if the result is used in the next
4579 ifx conditional branch then generate
4580 code a little differently */
4588 genIfxJump (ifx, swap_sense ? "nc" : "c");
4592 genIfxJump (ifx, swap_sense ? "p" : "m");
4597 genIfxJump (ifx, swap_sense ? "nc" : "c");
4604 /* Shift the sign bit up into carry */
4607 outBitCLong (result, swap_sense);
4609 /* leave the result in acc */
4613 /*-----------------------------------------------------------------*/
4614 /* genCmpGt :- greater than comparison */
4615 /*-----------------------------------------------------------------*/
4617 genCmpGt (iCode * ic, iCode * ifx)
4619 operand *left, *right, *result;
4620 sym_link *letype, *retype;
4623 left = IC_LEFT (ic);
4624 right = IC_RIGHT (ic);
4625 result = IC_RESULT (ic);
4627 letype = getSpec (operandType (left));
4628 retype = getSpec (operandType (right));
4629 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4630 /* assign the amsops */
4631 aopOp (left, ic, FALSE, FALSE);
4632 aopOp (right, ic, FALSE, FALSE);
4633 aopOp (result, ic, TRUE, FALSE);
4635 genCmp (right, left, result, ifx, sign);
4637 freeAsmop (left, NULL, ic);
4638 freeAsmop (right, NULL, ic);
4639 freeAsmop (result, NULL, ic);
4642 /*-----------------------------------------------------------------*/
4643 /* genCmpLt - less than comparisons */
4644 /*-----------------------------------------------------------------*/
4646 genCmpLt (iCode * ic, iCode * ifx)
4648 operand *left, *right, *result;
4649 sym_link *letype, *retype;
4652 left = IC_LEFT (ic);
4653 right = IC_RIGHT (ic);
4654 result = IC_RESULT (ic);
4656 letype = getSpec (operandType (left));
4657 retype = getSpec (operandType (right));
4658 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4660 /* assign the amsops */
4661 aopOp (left, ic, FALSE, FALSE);
4662 aopOp (right, ic, FALSE, FALSE);
4663 aopOp (result, ic, TRUE, FALSE);
4665 genCmp (left, right, result, ifx, sign);
4667 freeAsmop (left, NULL, ic);
4668 freeAsmop (right, NULL, ic);
4669 freeAsmop (result, NULL, ic);
4672 /*-----------------------------------------------------------------*/
4673 /* gencjneshort - compare and jump if not equal */
4674 /*-----------------------------------------------------------------*/
4676 gencjneshort (operand * left, operand * right, symbol * lbl)
4678 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4680 unsigned long lit = 0L;
4682 /* Swap the left and right if it makes the computation easier */
4683 if (AOP_TYPE (left) == AOP_LIT)
4690 if (AOP_TYPE (right) == AOP_LIT)
4692 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4695 /* if the right side is a literal then anything goes */
4696 if (AOP_TYPE (right) == AOP_LIT &&
4697 AOP_TYPE (left) != AOP_DIR)
4701 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4706 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4713 emit2 ("jp nz,!tlabel", lbl->key + 100);
4719 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4720 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4723 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4724 emit2 ("jp nz,!tlabel", lbl->key + 100);
4729 /* if the right side is in a register or in direct space or
4730 if the left is a pointer register & right is not */
4731 else if (AOP_TYPE (right) == AOP_REG ||
4732 AOP_TYPE (right) == AOP_DIR ||
4733 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4737 _moveA (aopGet (AOP (left), offset, FALSE));
4738 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4739 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4741 emit2 ("jp nz,!tlabel", lbl->key + 100);
4744 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4745 emit2 ("jp nz,!tlabel", lbl->key + 100);
4752 /* right is a pointer reg need both a & b */
4753 /* PENDING: is this required? */
4756 _moveA (aopGet (AOP (right), offset, FALSE));
4757 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4758 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4764 /*-----------------------------------------------------------------*/
4765 /* gencjne - compare and jump if not equal */
4766 /*-----------------------------------------------------------------*/
4768 gencjne (operand * left, operand * right, symbol * lbl)
4770 symbol *tlbl = newiTempLabel (NULL);
4772 gencjneshort (left, right, lbl);
4775 emit2 ("ld a,!one");
4776 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4777 emitLabel (lbl->key + 100);
4779 emitLabel (tlbl->key + 100);
4782 /*-----------------------------------------------------------------*/
4783 /* genCmpEq - generates code for equal to */
4784 /*-----------------------------------------------------------------*/
4786 genCmpEq (iCode * ic, iCode * ifx)
4788 operand *left, *right, *result;
4790 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4791 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4792 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4794 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4796 /* Swap operands if it makes the operation easier. ie if:
4797 1. Left is a literal.
4799 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4801 operand *t = IC_RIGHT (ic);
4802 IC_RIGHT (ic) = IC_LEFT (ic);
4806 if (ifx && !AOP_SIZE (result))
4809 /* if they are both bit variables */
4810 if (AOP_TYPE (left) == AOP_CRY &&
4811 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4813 wassertl (0, "Tried to compare two bits");
4817 tlbl = newiTempLabel (NULL);
4818 gencjneshort (left, right, tlbl);
4821 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4822 emitLabel (tlbl->key + 100);
4826 /* PENDING: do this better */
4827 symbol *lbl = newiTempLabel (NULL);
4828 emit2 ("!shortjp !tlabel", lbl->key + 100);
4829 emitLabel (tlbl->key + 100);
4830 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4831 emitLabel (lbl->key + 100);
4834 /* mark the icode as generated */
4839 /* if they are both bit variables */
4840 if (AOP_TYPE (left) == AOP_CRY &&
4841 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4843 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4849 gencjne (left, right, newiTempLabel (NULL));
4850 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4857 genIfxJump (ifx, "a");
4860 /* if the result is used in an arithmetic operation
4861 then put the result in place */
4862 if (AOP_TYPE (result) != AOP_CRY)
4867 /* leave the result in acc */
4871 freeAsmop (left, NULL, ic);
4872 freeAsmop (right, NULL, ic);
4873 freeAsmop (result, NULL, ic);
4876 /*-----------------------------------------------------------------*/
4877 /* ifxForOp - returns the icode containing the ifx for operand */
4878 /*-----------------------------------------------------------------*/
4880 ifxForOp (operand * op, iCode * ic)
4882 /* if true symbol then needs to be assigned */
4883 if (IS_TRUE_SYMOP (op))
4886 /* if this has register type condition and
4887 the next instruction is ifx with the same operand
4888 and live to of the operand is upto the ifx only then */
4890 ic->next->op == IFX &&
4891 IC_COND (ic->next)->key == op->key &&
4892 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4898 /*-----------------------------------------------------------------*/
4899 /* genAndOp - for && operation */
4900 /*-----------------------------------------------------------------*/
4902 genAndOp (iCode * ic)
4904 operand *left, *right, *result;
4907 /* note here that && operations that are in an if statement are
4908 taken away by backPatchLabels only those used in arthmetic
4909 operations remain */
4910 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4911 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4912 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4914 /* if both are bit variables */
4915 if (AOP_TYPE (left) == AOP_CRY &&
4916 AOP_TYPE (right) == AOP_CRY)
4918 wassertl (0, "Tried to and two bits");
4922 tlbl = newiTempLabel (NULL);
4924 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4926 emitLabel (tlbl->key + 100);
4930 freeAsmop (left, NULL, ic);
4931 freeAsmop (right, NULL, ic);
4932 freeAsmop (result, NULL, ic);
4935 /*-----------------------------------------------------------------*/
4936 /* genOrOp - for || operation */
4937 /*-----------------------------------------------------------------*/
4939 genOrOp (iCode * ic)
4941 operand *left, *right, *result;
4944 /* note here that || operations that are in an
4945 if statement are taken away by backPatchLabels
4946 only those used in arthmetic operations remain */
4947 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4948 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4949 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4951 /* if both are bit variables */
4952 if (AOP_TYPE (left) == AOP_CRY &&
4953 AOP_TYPE (right) == AOP_CRY)
4955 wassertl (0, "Tried to OR two bits");
4959 tlbl = newiTempLabel (NULL);
4961 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4963 emitLabel (tlbl->key + 100);
4967 freeAsmop (left, NULL, ic);
4968 freeAsmop (right, NULL, ic);
4969 freeAsmop (result, NULL, ic);
4972 /*-----------------------------------------------------------------*/
4973 /* isLiteralBit - test if lit == 2^n */
4974 /*-----------------------------------------------------------------*/
4976 isLiteralBit (unsigned long lit)
4978 unsigned long pw[32] =
4979 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4980 0x100L, 0x200L, 0x400L, 0x800L,
4981 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4982 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4983 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4984 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4985 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4988 for (idx = 0; idx < 32; idx++)
4994 /*-----------------------------------------------------------------*/
4995 /* jmpTrueOrFalse - */
4996 /*-----------------------------------------------------------------*/
4998 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5000 // ugly but optimized by peephole
5003 symbol *nlbl = newiTempLabel (NULL);
5004 emit2 ("jp !tlabel", nlbl->key + 100);
5005 emitLabel (tlbl->key + 100);
5006 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5007 emitLabel (nlbl->key + 100);
5011 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5012 emitLabel (tlbl->key + 100);
5017 /*-----------------------------------------------------------------*/
5018 /* genAnd - code for and */
5019 /*-----------------------------------------------------------------*/
5021 genAnd (iCode * ic, iCode * ifx)
5023 operand *left, *right, *result;
5024 int size, offset = 0;
5025 unsigned long lit = 0L;
5028 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5029 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5030 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5032 /* if left is a literal & right is not then exchange them */
5033 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5034 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5036 operand *tmp = right;
5041 /* if result = right then exchange them */
5042 if (sameRegs (AOP (result), AOP (right)))
5044 operand *tmp = right;
5049 /* if right is bit then exchange them */
5050 if (AOP_TYPE (right) == AOP_CRY &&
5051 AOP_TYPE (left) != AOP_CRY)
5053 operand *tmp = right;
5057 if (AOP_TYPE (right) == AOP_LIT)
5058 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5060 size = AOP_SIZE (result);
5062 if (AOP_TYPE (left) == AOP_CRY)
5064 wassertl (0, "Tried to perform an AND with a bit as an operand");
5068 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5069 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5070 if ((AOP_TYPE (right) == AOP_LIT) &&
5071 (AOP_TYPE (result) == AOP_CRY) &&
5072 (AOP_TYPE (left) != AOP_CRY))
5074 symbol *tlbl = newiTempLabel (NULL);
5075 int sizel = AOP_SIZE (left);
5078 /* PENDING: Test case for this. */
5083 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5085 _moveA (aopGet (AOP (left), offset, FALSE));
5086 if (bytelit != 0x0FFL)
5088 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5095 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5099 // bit = left & literal
5103 emit2 ("!tlabeldef", tlbl->key + 100);
5105 // if(left & literal)
5110 jmpTrueOrFalse (ifx, tlbl);
5118 /* if left is same as result */
5119 if (sameRegs (AOP (result), AOP (left)))
5121 for (; size--; offset++)
5123 if (AOP_TYPE (right) == AOP_LIT)
5125 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5130 aopPut (AOP (result), "!zero", offset);
5133 _moveA (aopGet (AOP (left), offset, FALSE));
5135 aopGet (AOP (right), offset, FALSE));
5136 aopPut (AOP (left), "a", offset);
5143 if (AOP_TYPE (left) == AOP_ACC)
5145 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5149 _moveA (aopGet (AOP (left), offset, FALSE));
5151 aopGet (AOP (right), offset, FALSE));
5152 aopPut (AOP (left), "a", offset);
5159 // left & result in different registers
5160 if (AOP_TYPE (result) == AOP_CRY)
5162 wassertl (0, "Tried to AND where the result is in carry");
5166 for (; (size--); offset++)
5169 // result = left & right
5170 if (AOP_TYPE (right) == AOP_LIT)
5172 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5174 aopPut (AOP (result),
5175 aopGet (AOP (left), offset, FALSE),
5179 else if (bytelit == 0)
5181 aopPut (AOP (result), "!zero", offset);
5185 // faster than result <- left, anl result,right
5186 // and better if result is SFR
5187 if (AOP_TYPE (left) == AOP_ACC)
5188 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5191 _moveA (aopGet (AOP (left), offset, FALSE));
5193 aopGet (AOP (right), offset, FALSE));
5195 aopPut (AOP (result), "a", offset);
5202 freeAsmop (left, NULL, ic);
5203 freeAsmop (right, NULL, ic);
5204 freeAsmop (result, NULL, ic);
5207 /*-----------------------------------------------------------------*/
5208 /* genOr - code for or */
5209 /*-----------------------------------------------------------------*/
5211 genOr (iCode * ic, iCode * ifx)
5213 operand *left, *right, *result;
5214 int size, offset = 0;
5215 unsigned long lit = 0L;
5218 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5219 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5220 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5222 /* if left is a literal & right is not then exchange them */
5223 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5224 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5226 operand *tmp = right;
5231 /* if result = right then exchange them */
5232 if (sameRegs (AOP (result), AOP (right)))
5234 operand *tmp = right;
5239 /* if right is bit then exchange them */
5240 if (AOP_TYPE (right) == AOP_CRY &&
5241 AOP_TYPE (left) != AOP_CRY)
5243 operand *tmp = right;
5247 if (AOP_TYPE (right) == AOP_LIT)
5248 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5250 size = AOP_SIZE (result);
5252 if (AOP_TYPE (left) == AOP_CRY)
5254 wassertl (0, "Tried to OR where left is a bit");
5258 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5259 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5260 if ((AOP_TYPE (right) == AOP_LIT) &&
5261 (AOP_TYPE (result) == AOP_CRY) &&
5262 (AOP_TYPE (left) != AOP_CRY))
5264 symbol *tlbl = newiTempLabel (NULL);
5265 int sizel = AOP_SIZE (left);
5269 wassertl (0, "Result is assigned to a bit");
5271 /* PENDING: Modeled after the AND code which is inefficent. */
5274 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5276 _moveA (aopGet (AOP (left), offset, FALSE));
5277 /* OR with any literal is the same as OR with itself. */
5279 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5285 jmpTrueOrFalse (ifx, tlbl);
5290 /* if left is same as result */
5291 if (sameRegs (AOP (result), AOP (left)))
5293 for (; size--; offset++)
5295 if (AOP_TYPE (right) == AOP_LIT)
5297 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5301 _moveA (aopGet (AOP (left), offset, FALSE));
5303 aopGet (AOP (right), offset, FALSE));
5304 aopPut (AOP (result), "a", offset);
5309 if (AOP_TYPE (left) == AOP_ACC)
5310 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5313 _moveA (aopGet (AOP (left), offset, FALSE));
5315 aopGet (AOP (right), offset, FALSE));
5316 aopPut (AOP (result), "a", offset);
5323 // left & result in different registers
5324 if (AOP_TYPE (result) == AOP_CRY)
5326 wassertl (0, "Result of OR is in a bit");
5329 for (; (size--); offset++)
5332 // result = left & right
5333 if (AOP_TYPE (right) == AOP_LIT)
5335 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5337 aopPut (AOP (result),
5338 aopGet (AOP (left), offset, FALSE),
5343 // faster than result <- left, anl result,right
5344 // and better if result is SFR
5345 if (AOP_TYPE (left) == AOP_ACC)
5346 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5349 _moveA (aopGet (AOP (left), offset, FALSE));
5351 aopGet (AOP (right), offset, FALSE));
5353 aopPut (AOP (result), "a", offset);
5354 /* PENDING: something weird is going on here. Add exception. */
5355 if (AOP_TYPE (result) == AOP_ACC)
5361 freeAsmop (left, NULL, ic);
5362 freeAsmop (right, NULL, ic);
5363 freeAsmop (result, NULL, ic);
5366 /*-----------------------------------------------------------------*/
5367 /* genXor - code for xclusive or */
5368 /*-----------------------------------------------------------------*/
5370 genXor (iCode * ic, iCode * ifx)
5372 operand *left, *right, *result;
5373 int size, offset = 0;
5374 unsigned long lit = 0L;
5376 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5377 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5378 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5380 /* if left is a literal & right is not then exchange them */
5381 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5382 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5384 operand *tmp = right;
5389 /* if result = right then exchange them */
5390 if (sameRegs (AOP (result), AOP (right)))
5392 operand *tmp = right;
5397 /* if right is bit then exchange them */
5398 if (AOP_TYPE (right) == AOP_CRY &&
5399 AOP_TYPE (left) != AOP_CRY)
5401 operand *tmp = right;
5405 if (AOP_TYPE (right) == AOP_LIT)
5406 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5408 size = AOP_SIZE (result);
5410 if (AOP_TYPE (left) == AOP_CRY)
5412 wassertl (0, "Tried to XOR a bit");
5416 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5417 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5418 if ((AOP_TYPE (right) == AOP_LIT) &&
5419 (AOP_TYPE (result) == AOP_CRY) &&
5420 (AOP_TYPE (left) != AOP_CRY))
5422 symbol *tlbl = newiTempLabel (NULL);
5423 int sizel = AOP_SIZE (left);
5427 /* PENDING: Test case for this. */
5428 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5432 _moveA (aopGet (AOP (left), offset, FALSE));
5433 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5434 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5439 jmpTrueOrFalse (ifx, tlbl);
5443 wassertl (0, "Result of XOR was destined for a bit");
5448 /* if left is same as result */
5449 if (sameRegs (AOP (result), AOP (left)))
5451 for (; size--; offset++)
5453 if (AOP_TYPE (right) == AOP_LIT)
5455 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5459 _moveA (aopGet (AOP (left), offset, FALSE));
5461 aopGet (AOP (right), offset, FALSE));
5462 aopPut (AOP (result), "a", offset);
5467 if (AOP_TYPE (left) == AOP_ACC)
5469 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5473 _moveA (aopGet (AOP (left), offset, FALSE));
5475 aopGet (AOP (right), offset, FALSE));
5476 aopPut (AOP (result), "a", offset);
5483 // left & result in different registers
5484 if (AOP_TYPE (result) == AOP_CRY)
5486 wassertl (0, "Result of XOR is in a bit");
5489 for (; (size--); offset++)
5492 // result = left & right
5493 if (AOP_TYPE (right) == AOP_LIT)
5495 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5497 aopPut (AOP (result),
5498 aopGet (AOP (left), offset, FALSE),
5503 // faster than result <- left, anl result,right
5504 // and better if result is SFR
5505 if (AOP_TYPE (left) == AOP_ACC)
5507 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5511 _moveA (aopGet (AOP (left), offset, FALSE));
5513 aopGet (AOP (right), offset, FALSE));
5515 aopPut (AOP (result), "a", offset);
5520 freeAsmop (left, NULL, ic);
5521 freeAsmop (right, NULL, ic);
5522 freeAsmop (result, NULL, ic);
5525 /*-----------------------------------------------------------------*/
5526 /* genInline - write the inline code out */
5527 /*-----------------------------------------------------------------*/
5529 genInline (iCode * ic)
5531 char *buffer, *bp, *bp1;
5533 _G.lines.isInline += (!options.asmpeep);
5535 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5536 strcpy (buffer, IC_INLINE (ic));
5538 /* emit each line as a code */
5563 _G.lines.isInline -= (!options.asmpeep);
5567 /*-----------------------------------------------------------------*/
5568 /* genRRC - rotate right with carry */
5569 /*-----------------------------------------------------------------*/
5576 /*-----------------------------------------------------------------*/
5577 /* genRLC - generate code for rotate left with carry */
5578 /*-----------------------------------------------------------------*/
5585 /*-----------------------------------------------------------------*/
5586 /* genGetHbit - generates code get highest order bit */
5587 /*-----------------------------------------------------------------*/
5589 genGetHbit (iCode * ic)
5591 operand *left, *result;
5592 left = IC_LEFT (ic);
5593 result = IC_RESULT (ic);
5595 aopOp (left, ic, FALSE, FALSE);
5596 aopOp (result, ic, FALSE, FALSE);
5598 /* get the highest order byte into a */
5599 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5601 if (AOP_TYPE (result) == AOP_CRY)
5609 emit2 ("and a,!one");
5614 freeAsmop (left, NULL, ic);
5615 freeAsmop (result, NULL, ic);
5619 emitRsh2 (asmop *aop, int size, int is_signed)
5625 const char *l = aopGet (aop, size, FALSE);
5628 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5638 /*-----------------------------------------------------------------*/
5639 /* shiftR2Left2Result - shift right two bytes from left to result */
5640 /*-----------------------------------------------------------------*/
5642 shiftR2Left2Result (operand * left, int offl,
5643 operand * result, int offr,
5644 int shCount, int is_signed)
5647 symbol *tlbl, *tlbl1;
5649 movLeft2Result (left, offl, result, offr, 0);
5650 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5652 /* if (AOP(result)->type == AOP_REG) { */
5654 tlbl = newiTempLabel (NULL);
5655 tlbl1 = newiTempLabel (NULL);
5657 /* Left is already in result - so now do the shift */
5662 emitRsh2 (AOP (result), size, is_signed);
5667 emit2 ("ld a,!immedbyte+1", shCount);
5668 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5669 emitLabel (tlbl->key + 100);
5671 emitRsh2 (AOP (result), size, is_signed);
5673 emitLabel (tlbl1->key + 100);
5675 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5679 /*-----------------------------------------------------------------*/
5680 /* shiftL2Left2Result - shift left two bytes from left to result */
5681 /*-----------------------------------------------------------------*/
5683 shiftL2Left2Result (operand * left, int offl,
5684 operand * result, int offr, int shCount)
5686 if (sameRegs (AOP (result), AOP (left)) &&
5687 ((offl + MSB16) == offr))
5693 /* Copy left into result */
5694 movLeft2Result (left, offl, result, offr, 0);
5695 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5698 if (getPairId (AOP (result)) == PAIR_HL)
5702 emit2 ("add hl,hl");
5709 symbol *tlbl, *tlbl1;
5712 tlbl = newiTempLabel (NULL);
5713 tlbl1 = newiTempLabel (NULL);
5715 if (AOP (result)->type == AOP_REG)
5719 for (offset = 0; offset < size; offset++)
5721 l = aopGet (AOP (result), offset, FALSE);
5725 emit2 ("sla %s", l);
5736 /* Left is already in result - so now do the shift */
5739 emit2 ("ld a,!immedbyte+1", shCount);
5740 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5741 emitLabel (tlbl->key + 100);
5746 l = aopGet (AOP (result), offset, FALSE);
5750 emit2 ("sla %s", l);
5761 emitLabel (tlbl1->key + 100);
5763 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5769 /*-----------------------------------------------------------------*/
5770 /* AccRol - rotate left accumulator by known count */
5771 /*-----------------------------------------------------------------*/
5773 AccRol (int shCount)
5775 shCount &= 0x0007; // shCount : 0..7
5852 /*-----------------------------------------------------------------*/
5853 /* AccLsh - left shift accumulator by known count */
5854 /*-----------------------------------------------------------------*/
5856 AccLsh (int shCount)
5858 static const unsigned char SLMask[] =
5860 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5869 else if (shCount == 2)
5876 /* rotate left accumulator */
5878 /* and kill the lower order bits */
5879 emit2 ("and a,!immedbyte", SLMask[shCount]);
5884 /*-----------------------------------------------------------------*/
5885 /* shiftL1Left2Result - shift left one byte from left to result */
5886 /*-----------------------------------------------------------------*/
5888 shiftL1Left2Result (operand * left, int offl,
5889 operand * result, int offr, int shCount)
5892 l = aopGet (AOP (left), offl, FALSE);
5894 /* shift left accumulator */
5896 aopPut (AOP (result), "a", offr);
5900 /*-----------------------------------------------------------------*/
5901 /* genlshTwo - left shift two bytes by known amount != 0 */
5902 /*-----------------------------------------------------------------*/
5904 genlshTwo (operand * result, operand * left, int shCount)
5906 int size = AOP_SIZE (result);
5908 wassert (size == 2);
5910 /* if shCount >= 8 */
5918 movLeft2Result (left, LSB, result, MSB16, 0);
5919 aopPut (AOP (result), "!zero", 0);
5920 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5924 movLeft2Result (left, LSB, result, MSB16, 0);
5925 aopPut (AOP (result), "!zero", 0);
5930 aopPut (AOP (result), "!zero", LSB);
5933 /* 1 <= shCount <= 7 */
5942 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5947 /*-----------------------------------------------------------------*/
5948 /* genlshOne - left shift a one byte quantity by known count */
5949 /*-----------------------------------------------------------------*/
5951 genlshOne (operand * result, operand * left, int shCount)
5953 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5956 /*-----------------------------------------------------------------*/
5957 /* genLeftShiftLiteral - left shifting by known count */
5958 /*-----------------------------------------------------------------*/
5960 genLeftShiftLiteral (operand * left,
5965 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5968 freeAsmop (right, NULL, ic);
5970 aopOp (left, ic, FALSE, FALSE);
5971 aopOp (result, ic, FALSE, FALSE);
5973 size = getSize (operandType (result));
5975 /* I suppose that the left size >= result size */
5981 else if (shCount >= (size * 8))
5985 aopPut (AOP (result), "!zero", size);
5993 genlshOne (result, left, shCount);
5996 genlshTwo (result, left, shCount);
5999 wassertl (0, "Shifting of longs is currently unsupported");
6005 freeAsmop (left, NULL, ic);
6006 freeAsmop (result, NULL, ic);
6009 /*-----------------------------------------------------------------*/
6010 /* genLeftShift - generates code for left shifting */
6011 /*-----------------------------------------------------------------*/
6013 genLeftShift (iCode * ic)
6017 symbol *tlbl, *tlbl1;
6018 operand *left, *right, *result;
6020 right = IC_RIGHT (ic);
6021 left = IC_LEFT (ic);
6022 result = IC_RESULT (ic);
6024 aopOp (right, ic, FALSE, FALSE);
6026 /* if the shift count is known then do it
6027 as efficiently as possible */
6028 if (AOP_TYPE (right) == AOP_LIT)
6030 genLeftShiftLiteral (left, right, result, ic);
6034 /* shift count is unknown then we have to form a loop get the loop
6035 count in B : Note: we take only the lower order byte since
6036 shifting more that 32 bits make no sense anyway, ( the largest
6037 size of an object can be only 32 bits ) */
6038 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6040 freeAsmop (right, NULL, ic);
6041 aopOp (left, ic, FALSE, FALSE);
6042 aopOp (result, ic, FALSE, FALSE);
6044 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6047 /* now move the left to the result if they are not the
6050 if (!sameRegs (AOP (left), AOP (result)))
6053 size = AOP_SIZE (result);
6057 l = aopGet (AOP (left), offset, FALSE);
6058 aopPut (AOP (result), l, offset);
6063 tlbl = newiTempLabel (NULL);
6064 size = AOP_SIZE (result);
6066 tlbl1 = newiTempLabel (NULL);
6068 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6071 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6072 emitLabel (tlbl->key + 100);
6073 l = aopGet (AOP (result), offset, FALSE);
6077 l = aopGet (AOP (result), offset, FALSE);
6081 emit2 ("sla %s", l);
6089 emitLabel (tlbl1->key + 100);
6091 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6093 freeAsmop (left, NULL, ic);
6094 freeAsmop (result, NULL, ic);
6097 /*-----------------------------------------------------------------*/
6098 /* genrshOne - left shift two bytes by known amount != 0 */
6099 /*-----------------------------------------------------------------*/
6101 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6104 int size = AOP_SIZE (result);
6107 wassert (size == 1);
6108 wassert (shCount < 8);
6110 l = aopGet (AOP (left), 0, FALSE);
6112 if (AOP (result)->type == AOP_REG)
6114 aopPut (AOP (result), l, 0);
6115 l = aopGet (AOP (result), 0, FALSE);
6118 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6126 emit2 ("%s a", is_signed ? "sra" : "srl");
6128 aopPut (AOP (result), "a", 0);
6132 /*-----------------------------------------------------------------*/
6133 /* AccRsh - right shift accumulator by known count */
6134 /*-----------------------------------------------------------------*/
6136 AccRsh (int shCount)
6138 static const unsigned char SRMask[] =
6140 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6145 /* rotate right accumulator */
6146 AccRol (8 - shCount);
6147 /* and kill the higher order bits */
6148 emit2 ("and a,!immedbyte", SRMask[shCount]);
6152 /*-----------------------------------------------------------------*/
6153 /* shiftR1Left2Result - shift right one byte from left to result */
6154 /*-----------------------------------------------------------------*/
6156 shiftR1Left2Result (operand * left, int offl,
6157 operand * result, int offr,
6158 int shCount, int sign)
6160 _moveA (aopGet (AOP (left), offl, FALSE));
6165 emit2 ("%s a", sign ? "sra" : "srl");
6172 aopPut (AOP (result), "a", offr);
6175 /*-----------------------------------------------------------------*/
6176 /* genrshTwo - right shift two bytes by known amount != 0 */
6177 /*-----------------------------------------------------------------*/
6179 genrshTwo (operand * result, operand * left,
6180 int shCount, int sign)
6182 /* if shCount >= 8 */
6188 shiftR1Left2Result (left, MSB16, result, LSB,
6193 movLeft2Result (left, MSB16, result, LSB, sign);
6197 /* Sign extend the result */
6198 _moveA(aopGet (AOP (result), 0, FALSE));
6202 aopPut (AOP (result), ACC_NAME, MSB16);
6206 aopPut (AOP (result), "!zero", 1);
6209 /* 1 <= shCount <= 7 */
6212 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6216 /*-----------------------------------------------------------------*/
6217 /* genRightShiftLiteral - left shifting by known count */
6218 /*-----------------------------------------------------------------*/
6220 genRightShiftLiteral (operand * left,
6226 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6229 freeAsmop (right, NULL, ic);
6231 aopOp (left, ic, FALSE, FALSE);
6232 aopOp (result, ic, FALSE, FALSE);
6234 size = getSize (operandType (result));
6236 /* I suppose that the left size >= result size */
6242 else if (shCount >= (size * 8)) {
6244 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6245 _moveA(aopGet (AOP (left), 0, FALSE));
6253 aopPut (AOP (result), s, size);
6260 genrshOne (result, left, shCount, sign);
6263 genrshTwo (result, left, shCount, sign);
6266 wassertl (0, "Asked to shift right a long which should be a function call");
6269 wassertl (0, "Entered default case in right shift delegate");
6272 freeAsmop (left, NULL, ic);
6273 freeAsmop (result, NULL, ic);
6276 /*-----------------------------------------------------------------*/
6277 /* genRightShift - generate code for right shifting */
6278 /*-----------------------------------------------------------------*/
6280 genRightShift (iCode * ic)
6282 operand *right, *left, *result;
6284 int size, offset, first = 1;
6288 symbol *tlbl, *tlbl1;
6290 /* if signed then we do it the hard way preserve the
6291 sign bit moving it inwards */
6292 retype = getSpec (operandType (IC_RESULT (ic)));
6294 is_signed = !SPEC_USIGN (retype);
6296 /* signed & unsigned types are treated the same : i.e. the
6297 signed is NOT propagated inwards : quoting from the
6298 ANSI - standard : "for E1 >> E2, is equivalent to division
6299 by 2**E2 if unsigned or if it has a non-negative value,
6300 otherwise the result is implementation defined ", MY definition
6301 is that the sign does not get propagated */
6303 right = IC_RIGHT (ic);
6304 left = IC_LEFT (ic);
6305 result = IC_RESULT (ic);
6307 aopOp (right, ic, FALSE, FALSE);
6309 /* if the shift count is known then do it
6310 as efficiently as possible */
6311 if (AOP_TYPE (right) == AOP_LIT)
6313 genRightShiftLiteral (left, right, result, ic, is_signed);
6317 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6319 freeAsmop (right, NULL, ic);
6321 aopOp (left, ic, FALSE, FALSE);
6322 aopOp (result, ic, FALSE, FALSE);
6324 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6327 /* now move the left to the result if they are not the
6329 if (!sameRegs (AOP (left), AOP (result)))
6332 size = AOP_SIZE (result);
6336 l = aopGet (AOP (left), offset, FALSE);
6337 aopPut (AOP (result), l, offset);
6342 tlbl = newiTempLabel (NULL);
6343 tlbl1 = newiTempLabel (NULL);
6344 size = AOP_SIZE (result);
6347 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6350 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6351 emitLabel (tlbl->key + 100);
6354 l = aopGet (AOP (result), offset--, FALSE);
6357 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6365 emitLabel (tlbl1->key + 100);
6367 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6369 freeAsmop (left, NULL, ic);
6370 freeAsmop (result, NULL, ic);
6374 /*-----------------------------------------------------------------*/
6375 /* genUnpackBits - generates code for unpacking bits */
6376 /*-----------------------------------------------------------------*/
6378 genUnpackBits (operand * result, int pair)
6380 int offset = 0; /* result byte offset */
6381 int rsize; /* result size */
6382 int rlen = 0; /* remaining bitfield length */
6383 sym_link *etype; /* bitfield type information */
6384 int blen; /* bitfield length */
6385 int bstr; /* bitfield starting bit within byte */
6387 emitDebug ("; genUnpackBits");
6389 etype = getSpec (operandType (result));
6390 rsize = getSize (operandType (result));
6391 blen = SPEC_BLEN (etype);
6392 bstr = SPEC_BSTR (etype);
6394 /* If the bitfield length is less than a byte */
6397 emit2 ("ld a,!*pair", _pairs[pair].name);
6399 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6400 aopPut (AOP (result), "a", offset++);
6404 /* TODO: what if pair == PAIR_DE ? */
6405 if (getPairId (AOP (result)) == PAIR_HL)
6407 wassertl (rsize == 2, "HL must be of size 2");
6408 emit2 ("ld a,!*hl");
6410 emit2 ("ld h,!*hl");
6413 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6415 spillPair (PAIR_HL);
6419 /* Bit field did not fit in a byte. Copy all
6420 but the partial byte at the end. */
6421 for (rlen=blen;rlen>=8;rlen-=8)
6423 emit2 ("ld a,!*pair", _pairs[pair].name);
6424 aopPut (AOP (result), "a", offset++);
6427 emit2 ("inc %s", _pairs[pair].name);
6428 _G.pairs[pair].offset++;
6432 /* Handle the partial byte at the end */
6435 emit2 ("ld a,!*pair", _pairs[pair].name);
6436 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6437 aopPut (AOP (result), "a", offset++);
6445 aopPut (AOP (result), "!zero", offset++);
6449 /*-----------------------------------------------------------------*/
6450 /* genGenPointerGet - get value from generic pointer space */
6451 /*-----------------------------------------------------------------*/
6453 genGenPointerGet (operand * left,
6454 operand * result, iCode * ic)
6457 sym_link *retype = getSpec (operandType (result));
6463 aopOp (left, ic, FALSE, FALSE);
6464 aopOp (result, ic, FALSE, FALSE);
6466 size = AOP_SIZE (result);
6468 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6471 if (isPtrPair (AOP (left)))
6473 tsprintf (buffer, sizeof(buffer),
6474 "!*pair", getPairName (AOP (left)));
6475 aopPut (AOP (result), buffer, 0);
6479 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6480 aopPut (AOP (result), "a", 0);
6482 freeAsmop (left, NULL, ic);
6486 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6493 tsprintf (at, sizeof(at), "!*iyx", offset);
6494 aopPut (AOP (result), at, offset);
6498 freeAsmop (left, NULL, ic);
6502 /* For now we always load into IY */
6503 /* if this is remateriazable */
6504 fetchPair (pair, AOP (left));
6506 /* if bit then unpack */
6507 if (IS_BITVAR (retype))
6509 genUnpackBits (result, pair);
6510 freeAsmop (left, NULL, ic);
6514 else if (getPairId (AOP (result)) == PAIR_HL)
6516 wassertl (size == 2, "HL must be of size 2");
6517 emit2 ("ld a,!*hl");
6519 emit2 ("ld h,!*hl");
6521 spillPair (PAIR_HL);
6523 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6525 size = AOP_SIZE (result);
6530 /* PENDING: make this better */
6531 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6533 aopPut (AOP (result), "!*hl", offset++);
6537 emit2 ("ld a,!*pair", _pairs[pair].name);
6538 aopPut (AOP (result), "a", offset++);
6542 emit2 ("inc %s", _pairs[pair].name);
6543 _G.pairs[pair].offset++;
6546 /* Fixup HL back down */
6547 for (size = AOP_SIZE (result)-1; size; size--)
6549 emit2 ("dec %s", _pairs[pair].name);
6554 size = AOP_SIZE (result);
6559 /* PENDING: make this better */
6561 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6563 aopPut (AOP (result), "!*hl", offset++);
6567 emit2 ("ld a,!*pair", _pairs[pair].name);
6568 aopPut (AOP (result), "a", offset++);
6572 emit2 ("inc %s", _pairs[pair].name);
6573 _G.pairs[pair].offset++;
6578 freeAsmop (left, NULL, ic);
6581 freeAsmop (result, NULL, ic);
6584 /*-----------------------------------------------------------------*/
6585 /* genPointerGet - generate code for pointer get */
6586 /*-----------------------------------------------------------------*/
6588 genPointerGet (iCode * ic)
6590 operand *left, *result;
6591 sym_link *type, *etype;
6593 left = IC_LEFT (ic);
6594 result = IC_RESULT (ic);
6596 /* depending on the type of pointer we need to
6597 move it to the correct pointer register */
6598 type = operandType (left);
6599 etype = getSpec (type);
6601 genGenPointerGet (left, result, ic);
6605 isRegOrLit (asmop * aop)
6607 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6613 /*-----------------------------------------------------------------*/
6614 /* genPackBits - generates code for packed bit storage */
6615 /*-----------------------------------------------------------------*/
6617 genPackBits (sym_link * etype,
6622 int offset = 0; /* source byte offset */
6623 int rlen = 0; /* remaining bitfield length */
6624 int blen; /* bitfield length */
6625 int bstr; /* bitfield starting bit within byte */
6626 int litval; /* source literal value (if AOP_LIT) */
6627 unsigned char mask; /* bitmask within current byte */
6628 int extraPair; /* a tempory register */
6629 bool needPopExtra=0; /* need to restore original value of temp reg */
6631 emitDebug ("; genPackBits","");
6633 blen = SPEC_BLEN (etype);
6634 bstr = SPEC_BSTR (etype);
6636 /* If the bitfield length is less than a byte */
6639 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6640 (unsigned char) (0xFF >> (8 - bstr)));
6642 if (AOP_TYPE (right) == AOP_LIT)
6644 /* Case with a bitfield length <8 and literal source
6646 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6648 litval &= (~mask) & 0xff;
6649 emit2 ("ld a,!*pair", _pairs[pair].name);
6650 if ((mask|litval)!=0xff)
6651 emit2 ("and a,!immedbyte", mask);
6653 emit2 ("or a,!immedbyte", litval);
6654 emit2 ("ld !*pair,a", _pairs[pair].name);
6659 /* Case with a bitfield length <8 and arbitrary source
6661 _moveA (aopGet (AOP (right), 0, FALSE));
6662 /* shift and mask source value */
6664 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6666 extraPair = getFreePairId(ic);
6667 if (extraPair == PAIR_INVALID)
6669 extraPair = PAIR_BC;
6670 if (getPairId (AOP (right)) != PAIR_BC
6671 || !isLastUse (ic, right))
6677 emit2 ("ld %s,a", _pairs[extraPair].l);
6678 emit2 ("ld a,!*pair", _pairs[pair].name);
6680 emit2 ("and a,!immedbyte", mask);
6681 emit2 ("or a,%s", _pairs[extraPair].l);
6682 emit2 ("ld !*pair,a", _pairs[pair].name);
6689 /* Bit length is greater than 7 bits. In this case, copy */
6690 /* all except the partial byte at the end */
6691 for (rlen=blen;rlen>=8;rlen-=8)
6693 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6694 emit2 ("ld !*pair,a", _pairs[pair].name);
6697 emit2 ("inc %s", _pairs[pair].name);
6698 _G.pairs[pair].offset++;
6702 /* If there was a partial byte at the end */
6705 mask = (((unsigned char) -1 << rlen) & 0xff);
6707 if (AOP_TYPE (right) == AOP_LIT)
6709 /* Case with partial byte and literal source
6711 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6712 litval >>= (blen-rlen);
6713 litval &= (~mask) & 0xff;
6714 emit2 ("ld a,!*pair", _pairs[pair].name);
6715 if ((mask|litval)!=0xff)
6716 emit2 ("and a,!immedbyte", mask);
6718 emit2 ("or a,!immedbyte", litval);
6722 /* Case with partial byte and arbitrary source
6724 _moveA (aopGet (AOP (right), offset++, FALSE));
6725 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6727 extraPair = getFreePairId(ic);
6728 if (extraPair == PAIR_INVALID)
6730 extraPair = getPairId (AOP (right));
6731 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6732 extraPair = PAIR_BC;
6734 if (getPairId (AOP (right)) != PAIR_BC
6735 || !isLastUse (ic, right))
6741 emit2 ("ld %s,a", _pairs[extraPair].l);
6742 emit2 ("ld a,!*pair", _pairs[pair].name);
6744 emit2 ("and a,!immedbyte", mask);
6745 emit2 ("or a,%s", _pairs[extraPair].l);
6750 emit2 ("ld !*pair,a", _pairs[pair].name);
6755 /*-----------------------------------------------------------------*/
6756 /* genGenPointerSet - stores the value into a pointer location */
6757 /*-----------------------------------------------------------------*/
6759 genGenPointerSet (operand * right,
6760 operand * result, iCode * ic)
6763 sym_link *retype = getSpec (operandType (right));
6764 sym_link *letype = getSpec (operandType (result));
6765 PAIR_ID pairId = PAIR_HL;
6768 aopOp (result, ic, FALSE, FALSE);
6769 aopOp (right, ic, FALSE, FALSE);
6774 size = AOP_SIZE (right);
6776 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6777 emitDebug("; isBitvar = %d", isBitvar);
6779 /* Handle the exceptions first */
6780 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6783 const char *l = aopGet (AOP (right), 0, FALSE);
6784 const char *pair = getPairName (AOP (result));
6785 if (canAssignToPtr (l) && isPtr (pair))
6787 emit2 ("ld !*pair,%s", pair, l);
6792 emit2 ("ld !*pair,a", pair);
6797 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6800 const char *l = aopGet (AOP (right), 0, FALSE);
6805 if (canAssignToPtr (l))
6807 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6811 _moveA (aopGet (AOP (right), offset, FALSE));
6812 emit2 ("ld !*iyx,a", offset);
6818 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6825 const char *l = aopGet (AOP (right), offset, FALSE);
6826 if (isRegOrLit (AOP (right)) && !IS_GB)
6828 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6833 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6837 emit2 ("inc %s", _pairs[PAIR_HL].name);
6838 _G.pairs[PAIR_HL].offset++;
6843 /* Fixup HL back down */
6844 for (size = AOP_SIZE (right)-1; size; size--)
6846 emit2 ("dec %s", _pairs[PAIR_HL].name);
6851 /* if the operand is already in dptr
6852 then we do nothing else we move the value to dptr */
6853 if (AOP_TYPE (result) != AOP_STR)
6855 fetchPair (pairId, AOP (result));
6857 /* so hl now contains the address */
6858 freeAsmop (result, NULL, ic);
6860 /* if bit then unpack */
6863 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6873 const char *l = aopGet (AOP (right), offset, FALSE);
6874 if (isRegOrLit (AOP (right)) && !IS_GB)
6876 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6881 emit2 ("ld !*pair,a", _pairs[pairId].name);
6885 emit2 ("inc %s", _pairs[pairId].name);
6886 _G.pairs[pairId].offset++;
6892 freeAsmop (right, NULL, ic);
6895 /*-----------------------------------------------------------------*/
6896 /* genPointerSet - stores the value into a pointer location */
6897 /*-----------------------------------------------------------------*/
6899 genPointerSet (iCode * ic)
6901 operand *right, *result;
6902 sym_link *type, *etype;
6904 right = IC_RIGHT (ic);
6905 result = IC_RESULT (ic);
6907 /* depending on the type of pointer we need to
6908 move it to the correct pointer register */
6909 type = operandType (result);
6910 etype = getSpec (type);
6912 genGenPointerSet (right, result, ic);
6915 /*-----------------------------------------------------------------*/
6916 /* genIfx - generate code for Ifx statement */
6917 /*-----------------------------------------------------------------*/
6919 genIfx (iCode * ic, iCode * popIc)
6921 operand *cond = IC_COND (ic);
6924 aopOp (cond, ic, FALSE, TRUE);
6926 /* get the value into acc */
6927 if (AOP_TYPE (cond) != AOP_CRY)
6931 /* the result is now in the accumulator */
6932 freeAsmop (cond, NULL, ic);
6934 /* if there was something to be popped then do it */
6938 /* if the condition is a bit variable */
6939 if (isbit && IS_ITEMP (cond) &&
6941 genIfxJump (ic, SPIL_LOC (cond)->rname);
6942 else if (isbit && !IS_ITEMP (cond))
6943 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6945 genIfxJump (ic, "a");
6950 /*-----------------------------------------------------------------*/
6951 /* genAddrOf - generates code for address of */
6952 /*-----------------------------------------------------------------*/
6954 genAddrOf (iCode * ic)
6956 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6958 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6960 /* if the operand is on the stack then we
6961 need to get the stack offset of this
6968 if (sym->stack <= 0)
6970 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6974 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6976 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6980 emit2 ("ld de,!hashedstr", sym->rname);
6981 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6989 /* if it has an offset then we need to compute it */
6991 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6993 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6994 emit2 ("add hl,sp");
6998 emit2 ("ld hl,!hashedstr", sym->rname);
7000 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7002 freeAsmop (IC_RESULT (ic), NULL, ic);
7005 /*-----------------------------------------------------------------*/
7006 /* genAssign - generate code for assignment */
7007 /*-----------------------------------------------------------------*/
7009 genAssign (iCode * ic)
7011 operand *result, *right;
7013 unsigned long lit = 0L;
7015 result = IC_RESULT (ic);
7016 right = IC_RIGHT (ic);
7018 /* Dont bother assigning if they are the same */
7019 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7021 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7025 aopOp (right, ic, FALSE, FALSE);
7026 aopOp (result, ic, TRUE, FALSE);
7028 /* if they are the same registers */
7029 if (sameRegs (AOP (right), AOP (result)))
7031 emitDebug ("; (registers are the same)");
7035 /* if the result is a bit */
7036 if (AOP_TYPE (result) == AOP_CRY)
7038 wassertl (0, "Tried to assign to a bit");
7042 size = AOP_SIZE (result);
7045 if (AOP_TYPE (right) == AOP_LIT)
7047 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7050 if (isPair (AOP (result)))
7052 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7054 else if ((size > 1) &&
7055 (AOP_TYPE (result) != AOP_REG) &&
7056 (AOP_TYPE (right) == AOP_LIT) &&
7057 !IS_FLOAT (operandType (right)) &&
7060 bool fXored = FALSE;
7062 /* Work from the top down.
7063 Done this way so that we can use the cached copy of 0
7064 in A for a fast clear */
7067 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7069 if (!fXored && size > 1)
7076 aopPut (AOP (result), "a", offset);
7080 aopPut (AOP (result), "!zero", offset);
7084 aopPut (AOP (result),
7085 aopGet (AOP (right), offset, FALSE),
7090 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7092 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7093 aopPut (AOP (result), "l", LSB);
7094 aopPut (AOP (result), "h", MSB16);
7096 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7098 /* Special case. Load into a and d, then load out. */
7099 _moveA (aopGet (AOP (right), 0, FALSE));
7100 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7101 aopPut (AOP (result), "a", 0);
7102 aopPut (AOP (result), "e", 1);
7104 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7106 /* Special case - simple memcpy */
7107 aopGet (AOP (right), LSB, FALSE);
7110 aopGet (AOP (result), LSB, FALSE);
7114 emit2 ("ld a,(de)");
7115 /* Peephole will optimise this. */
7116 emit2 ("ld (hl),a");
7124 spillPair (PAIR_HL);
7130 /* PENDING: do this check better */
7131 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7133 _moveA (aopGet (AOP (right), offset, FALSE));
7134 aopPut (AOP (result), "a", offset);
7137 aopPut (AOP (result),
7138 aopGet (AOP (right), offset, FALSE),
7145 freeAsmop (right, NULL, ic);
7146 freeAsmop (result, NULL, ic);
7149 /*-----------------------------------------------------------------*/
7150 /* genJumpTab - genrates code for jump table */
7151 /*-----------------------------------------------------------------*/
7153 genJumpTab (iCode * ic)
7158 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7159 /* get the condition into accumulator */
7160 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7163 emit2 ("ld e,%s", l);
7164 emit2 ("ld d,!zero");
7165 jtab = newiTempLabel (NULL);
7167 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7168 emit2 ("add hl,de");
7169 emit2 ("add hl,de");
7170 emit2 ("add hl,de");
7171 freeAsmop (IC_JTCOND (ic), NULL, ic);
7175 emitLabel (jtab->key + 100);
7176 /* now generate the jump labels */
7177 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7178 jtab = setNextItem (IC_JTLABELS (ic)))
7179 emit2 ("jp !tlabel", jtab->key + 100);
7182 /*-----------------------------------------------------------------*/
7183 /* genCast - gen code for casting */
7184 /*-----------------------------------------------------------------*/
7186 genCast (iCode * ic)
7188 operand *result = IC_RESULT (ic);
7189 sym_link *rtype = operandType (IC_RIGHT (ic));
7190 operand *right = IC_RIGHT (ic);
7193 /* if they are equivalent then do nothing */
7194 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7197 aopOp (right, ic, FALSE, FALSE);
7198 aopOp (result, ic, FALSE, FALSE);
7200 /* if the result is a bit */
7201 if (AOP_TYPE (result) == AOP_CRY)
7203 wassertl (0, "Tried to cast to a bit");
7206 /* if they are the same size : or less */
7207 if (AOP_SIZE (result) <= AOP_SIZE (right))
7210 /* if they are in the same place */
7211 if (sameRegs (AOP (right), AOP (result)))
7214 /* if they in different places then copy */
7215 size = AOP_SIZE (result);
7219 aopPut (AOP (result),
7220 aopGet (AOP (right), offset, FALSE),
7227 /* So we now know that the size of destination is greater
7228 than the size of the source */
7229 /* we move to result for the size of source */
7230 size = AOP_SIZE (right);
7234 aopPut (AOP (result),
7235 aopGet (AOP (right), offset, FALSE),
7240 /* now depending on the sign of the destination */
7241 size = AOP_SIZE (result) - AOP_SIZE (right);
7242 /* Unsigned or not an integral type - right fill with zeros */
7243 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7246 aopPut (AOP (result), "!zero", offset++);
7250 /* we need to extend the sign :{ */
7251 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7257 aopPut (AOP (result), "a", offset++);
7261 freeAsmop (right, NULL, ic);
7262 freeAsmop (result, NULL, ic);
7265 /*-----------------------------------------------------------------*/
7266 /* genReceive - generate code for a receive iCode */
7267 /*-----------------------------------------------------------------*/
7269 genReceive (iCode * ic)
7271 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7272 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7273 IS_TRUE_SYMOP (IC_RESULT (ic))))
7283 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7284 size = AOP_SIZE(IC_RESULT(ic));
7286 for (i = 0; i < size; i++) {
7287 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7291 freeAsmop (IC_RESULT (ic), NULL, ic);
7294 /*-----------------------------------------------------------------*/
7295 /* genDummyRead - generate code for dummy read of volatiles */
7296 /*-----------------------------------------------------------------*/
7298 genDummyRead (iCode * ic)
7304 if (op && IS_SYMOP (op))
7306 aopOp (op, ic, FALSE, FALSE);
7309 size = AOP_SIZE (op);
7314 _moveA (aopGet (AOP (op), offset, FALSE));
7318 freeAsmop (op, NULL, ic);
7322 if (op && IS_SYMOP (op))
7324 aopOp (op, ic, FALSE, FALSE);
7327 size = AOP_SIZE (op);
7332 _moveA (aopGet (AOP (op), offset, FALSE));
7336 freeAsmop (op, NULL, ic);
7342 /** Maximum number of bytes to emit per line. */
7346 /** Context for the byte output chunker. */
7349 unsigned char buffer[DBEMIT_MAX_RUN];
7354 /** Flushes a byte chunker by writing out all in the buffer and
7358 _dbFlush(DBEMITCTX *self)
7365 sprintf(line, ".db 0x%02X", self->buffer[0]);
7367 for (i = 1; i < self->pos; i++)
7369 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7376 /** Write out another byte, buffering until a decent line is
7380 _dbEmit(DBEMITCTX *self, int c)
7382 if (self->pos == DBEMIT_MAX_RUN)
7386 self->buffer[self->pos++] = c;
7389 /** Context for a simple run length encoder. */
7393 unsigned char buffer[128];
7395 /** runLen may be equivalent to pos. */
7401 RLE_CHANGE_COST = 4,
7405 /** Flush the buffer of a run length encoder by writing out the run or
7406 data that it currently contains.
7409 _rleCommit(RLECTX *self)
7415 memset(&db, 0, sizeof(db));
7417 emit2(".db %u", self->pos);
7419 for (i = 0; i < self->pos; i++)
7421 _dbEmit(&db, self->buffer[i]);
7430 Can get either a run or a block of random stuff.
7431 Only want to change state if a good run comes in or a run ends.
7432 Detecting run end is easy.
7435 Say initial state is in run, len zero, last zero. Then if you get a
7436 few zeros then something else then a short run will be output.
7437 Seems OK. While in run mode, keep counting. While in random mode,
7438 keep a count of the run. If run hits margin, output all up to run,
7439 restart, enter run mode.
7442 /** Add another byte into the run length encoder, flushing as
7443 required. The run length encoder uses the Amiga IFF style, where
7444 a block is prefixed by its run length. A positive length means
7445 the next n bytes pass straight through. A negative length means
7446 that the next byte is repeated -n times. A zero terminates the
7450 _rleAppend(RLECTX *self, unsigned c)
7454 if (c != self->last)
7456 /* The run has stopped. See if it is worthwhile writing it out
7457 as a run. Note that the random data comes in as runs of
7460 if (self->runLen > RLE_CHANGE_COST)
7462 /* Yes, worthwhile. */
7463 /* Commit whatever was in the buffer. */
7465 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7469 /* Not worthwhile. Append to the end of the random list. */
7470 for (i = 0; i < self->runLen; i++)
7472 if (self->pos >= RLE_MAX_BLOCK)
7477 self->buffer[self->pos++] = self->last;
7485 if (self->runLen >= RLE_MAX_BLOCK)
7487 /* Commit whatever was in the buffer. */
7490 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7498 _rleFlush(RLECTX *self)
7500 _rleAppend(self, -1);
7507 /** genArrayInit - Special code for initialising an array with constant
7511 genArrayInit (iCode * ic)
7515 int elementSize = 0, eIndex, i;
7516 unsigned val, lastVal;
7520 memset(&rle, 0, sizeof(rle));
7522 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7524 _saveRegsForCall(ic, 0);
7526 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7527 emit2 ("call __initrleblock");
7529 type = operandType(IC_LEFT(ic));
7531 if (type && type->next)
7533 if (IS_SPEC(type->next) || IS_PTR(type->next))
7535 elementSize = getSize(type->next);
7537 else if (IS_ARRAY(type->next) && type->next->next)
7539 elementSize = getSize(type->next->next);
7543 printTypeChainRaw (type, NULL);
7544 wassertl (0, "Can't determine element size in genArrayInit.");
7549 wassertl (0, "Can't determine element size in genArrayInit.");
7552 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7554 iLoop = IC_ARRAYILIST(ic);
7555 lastVal = (unsigned)-1;
7557 /* Feed all the bytes into the run length encoder which will handle
7559 This works well for mixed char data, and for random int and long
7566 for (i = 0; i < ix; i++)
7568 for (eIndex = 0; eIndex < elementSize; eIndex++)
7570 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7571 _rleAppend(&rle, val);
7575 iLoop = iLoop->next;
7579 /* Mark the end of the run. */
7582 _restoreRegsAfterCall();
7586 freeAsmop (IC_LEFT(ic), NULL, ic);
7590 _swap (PAIR_ID one, PAIR_ID two)
7592 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7598 emit2 ("ld a,%s", _pairs[one].l);
7599 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7600 emit2 ("ld %s,a", _pairs[two].l);
7601 emit2 ("ld a,%s", _pairs[one].h);
7602 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7603 emit2 ("ld %s,a", _pairs[two].h);
7607 /* The problem is that we may have all three pairs used and they may
7608 be needed in a different order.
7613 hl = hl => unity, fine
7617 hl = hl hl = hl, swap de <=> bc
7625 hl = bc de = de, swap bc <=> hl
7633 hl = de bc = bc, swap hl <=> de
7638 * Any pair = pair are done last
7639 * Any pair = iTemp are done last
7640 * Any swaps can be done any time
7648 So how do we detect the cases?
7649 How about a 3x3 matrix?
7653 x x x x (Fourth for iTemp/other)
7655 First determin which mode to use by counting the number of unity and
7658 Two - Assign the pair first, then the rest
7659 One - Swap the two, then the rest
7663 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7665 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7667 PAIR_BC, PAIR_HL, PAIR_DE
7669 int i, j, nunity = 0;
7670 memset (ids, PAIR_INVALID, sizeof (ids));
7673 wassert (nparams == 3);
7675 /* First save everything that needs to be saved. */
7676 _saveRegsForCall (ic, 0);
7678 /* Loading HL first means that DE is always fine. */
7679 for (i = 0; i < nparams; i++)
7681 aopOp (pparams[i], ic, FALSE, FALSE);
7682 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7685 /* Count the number of unity or iTemp assigns. */
7686 for (i = 0; i < 3; i++)
7688 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7696 /* Any order, fall through. */
7698 else if (nunity == 2)
7700 /* One is assigned. Pull it out and assign. */
7701 for (i = 0; i < 3; i++)
7703 for (j = 0; j < NUM_PAIRS; j++)
7705 if (ids[dest[i]][j] == TRUE)
7707 /* Found it. See if it's the right one. */
7708 if (j == PAIR_INVALID || j == dest[i])
7714 fetchPair(dest[i], AOP (pparams[i]));
7721 else if (nunity == 1)
7723 /* Find the pairs to swap. */
7724 for (i = 0; i < 3; i++)
7726 for (j = 0; j < NUM_PAIRS; j++)
7728 if (ids[dest[i]][j] == TRUE)
7730 if (j == PAIR_INVALID || j == dest[i])
7745 int next = getPairId (AOP (pparams[0]));
7746 emit2 ("push %s", _pairs[next].name);
7748 if (next == dest[1])
7750 fetchPair (dest[1], AOP (pparams[1]));
7751 fetchPair (dest[2], AOP (pparams[2]));
7755 fetchPair (dest[2], AOP (pparams[2]));
7756 fetchPair (dest[1], AOP (pparams[1]));
7758 emit2 ("pop %s", _pairs[dest[0]].name);
7761 /* Finally pull out all of the iTemps */
7762 for (i = 0; i < 3; i++)
7764 if (ids[dest[i]][PAIR_INVALID] == 1)
7766 fetchPair (dest[i], AOP (pparams[i]));
7772 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7778 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7782 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7784 setupForBuiltin3 (ic, nParams, pparams);
7786 label = newiTempLabel(NULL);
7788 emitLabel (label->key);
7789 emit2 ("ld a,(hl)");
7792 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7794 freeAsmop (from, NULL, ic->next);
7795 freeAsmop (to, NULL, ic);
7799 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7801 operand *from, *to, *count;
7804 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7809 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7811 setupForBuiltin3 (ic, nParams, pparams);
7815 freeAsmop (count, NULL, ic->next->next);
7816 freeAsmop (from, NULL, ic);
7818 _restoreRegsAfterCall();
7820 /* if we need assign a result value */
7821 if ((IS_ITEMP (IC_RESULT (ic)) &&
7822 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7823 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7824 IS_TRUE_SYMOP (IC_RESULT (ic)))
7826 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7827 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7828 freeAsmop (IC_RESULT (ic), NULL, ic);
7831 freeAsmop (to, NULL, ic->next);
7834 /*-----------------------------------------------------------------*/
7835 /* genBuiltIn - calls the appropriate function to generating code */
7836 /* for a built in function */
7837 /*-----------------------------------------------------------------*/
7838 static void genBuiltIn (iCode *ic)
7840 operand *bi_parms[MAX_BUILTIN_ARGS];
7845 /* get all the arguments for a built in function */
7846 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7848 /* which function is it */
7849 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7851 if (strcmp(bif->name,"__builtin_strcpy")==0)
7853 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7855 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7857 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7861 wassertl (0, "Unknown builtin function encountered");
7865 /*-----------------------------------------------------------------*/
7866 /* genZ80Code - generate code for Z80 based controllers */
7867 /*-----------------------------------------------------------------*/
7869 genZ80Code (iCode * lic)
7877 _fReturn = _gbz80_return;
7878 _fTmp = _gbz80_return;
7882 _fReturn = _z80_return;
7883 _fTmp = _z80_return;
7886 _G.lines.head = _G.lines.current = NULL;
7888 /* if debug information required */
7889 if (options.debug && currFunc)
7891 debugFile->writeFunction (currFunc, lic);
7894 for (ic = lic; ic; ic = ic->next)
7896 _G.current_iCode = ic;
7898 if (ic->lineno && cln != ic->lineno)
7902 debugFile->writeCLine (ic);
7904 if (!options.noCcodeInAsm) {
7905 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7906 printCLine(ic->filename, ic->lineno));
7910 if (options.iCodeInAsm) {
7911 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7913 /* if the result is marked as
7914 spilt and rematerializable or code for
7915 this has already been generated then
7917 if (resultRemat (ic) || ic->generated)
7920 /* depending on the operation */
7924 emitDebug ("; genNot");
7929 emitDebug ("; genCpl");
7934 emitDebug ("; genUminus");
7939 emitDebug ("; genIpush");
7944 /* IPOP happens only when trying to restore a
7945 spilt live range, if there is an ifx statement
7946 following this pop then the if statement might
7947 be using some of the registers being popped which
7948 would destory the contents of the register so
7949 we need to check for this condition and handle it */
7951 ic->next->op == IFX &&
7952 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7954 emitDebug ("; genIfx");
7955 genIfx (ic->next, ic);
7959 emitDebug ("; genIpop");
7965 emitDebug ("; genCall");
7970 emitDebug ("; genPcall");
7975 emitDebug ("; genFunction");
7980 emitDebug ("; genEndFunction");
7981 genEndFunction (ic);
7985 emitDebug ("; genRet");
7990 emitDebug ("; genLabel");
7995 emitDebug ("; genGoto");
8000 emitDebug ("; genPlus");
8005 emitDebug ("; genMinus");
8010 emitDebug ("; genMult");
8015 emitDebug ("; genDiv");
8020 emitDebug ("; genMod");
8025 emitDebug ("; genCmpGt");
8026 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8030 emitDebug ("; genCmpLt");
8031 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8038 /* note these two are xlated by algebraic equivalence
8039 during parsing SDCC.y */
8040 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8041 "got '>=' or '<=' shouldn't have come here");
8045 emitDebug ("; genCmpEq");
8046 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8050 emitDebug ("; genAndOp");
8055 emitDebug ("; genOrOp");
8060 emitDebug ("; genXor");
8061 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8065 emitDebug ("; genOr");
8066 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8070 emitDebug ("; genAnd");
8071 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8075 emitDebug ("; genInline");
8080 emitDebug ("; genRRC");
8085 emitDebug ("; genRLC");
8090 emitDebug ("; genGetHBIT");
8095 emitDebug ("; genLeftShift");
8100 emitDebug ("; genRightShift");
8104 case GET_VALUE_AT_ADDRESS:
8105 emitDebug ("; genPointerGet");
8111 if (POINTER_SET (ic))
8113 emitDebug ("; genAssign (pointer)");
8118 emitDebug ("; genAssign");
8124 emitDebug ("; genIfx");
8129 emitDebug ("; genAddrOf");
8134 emitDebug ("; genJumpTab");
8139 emitDebug ("; genCast");
8144 emitDebug ("; genReceive");
8149 if (ic->builtinSEND)
8151 emitDebug ("; genBuiltIn");
8156 emitDebug ("; addSet");
8157 addSet (&_G.sendSet, ic);
8162 emitDebug ("; genArrayInit");
8166 case DUMMY_READ_VOLATILE:
8167 emitDebug ("; genDummyRead");
8177 /* now we are ready to call the
8178 peep hole optimizer */
8179 if (!options.nopeep)
8180 peepHole (&_G.lines.head);
8182 /* This is unfortunate */
8183 /* now do the actual printing */
8185 FILE *fp = codeOutFile;
8186 if (isInHome () && codeOutFile == code->oFile)
8187 codeOutFile = home->oFile;
8188 printLine (_G.lines.head, codeOutFile);
8189 if (_G.flushStatics)
8192 _G.flushStatics = 0;
8197 freeTrace(&_G.lines.trace);
8198 freeTrace(&_G.trace.aops);
8204 _isPairUsed (iCode * ic, PAIR_ID pairId)
8210 if (bitVectBitValue (ic->rMask, D_IDX))
8212 if (bitVectBitValue (ic->rMask, E_IDX))
8222 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8225 value *val = aop->aopu.aop_lit;
8227 wassert (aop->type == AOP_LIT);
8228 wassert (!IS_FLOAT (val->type));
8230 v = (unsigned long) floatFromVal (val);
8238 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8239 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));