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
3094 doesn't seem to get reset anywhere else.
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 ftype = operandType (IC_LEFT (ic));
3112 if (IFFUNC_ISNAKED(ftype))
3114 emitDebug("; naked function: no prologue.");
3118 /* if this is an interrupt service routine
3119 then save all potentially used registers. */
3120 if (IFFUNC_ISISR (sym->type))
3122 /* If critical function then turn interrupts off */
3123 /* except when no interrupt number is given then it implies the NMI handler */
3124 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3133 /* This is a non-ISR function.
3134 If critical function then turn interrupts off */
3135 if (IFFUNC_ISCRITICAL (sym->type))
3143 //get interrupt enable flag IFF2 into P/O
3152 if (options.profile)
3154 emit2 ("!profileenter");
3157 /* PENDING: callee-save etc */
3159 _G.stack.param_offset = 0;
3161 if (z80_opts.calleeSavesBC)
3166 /* Detect which registers are used. */
3167 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3170 for (i = 0; i < sym->regsUsed->size; i++)
3172 if (bitVectBitValue (sym->regsUsed, i))
3186 /* Other systems use DE as a temporary. */
3197 _G.stack.param_offset += 2;
3200 _G.calleeSaves.pushedBC = bcInUse;
3205 _G.stack.param_offset += 2;
3208 _G.calleeSaves.pushedDE = deInUse;
3210 /* adjust the stack for the function */
3211 _G.stack.last = sym->stack;
3214 for (sym = setFirstItem (istack->syms); sym;
3215 sym = setNextItem (istack->syms))
3217 if (sym->_isparm && !IS_REGPARM (sym->etype))
3223 sym = OP_SYMBOL (IC_LEFT (ic));
3225 _G.omitFramePtr = options.ommitFramePtr;
3226 if (IS_Z80 && !stackParm && !sym->stack)
3228 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3229 /* the above !sym->stack condition can be removed. -- EEP */
3231 emit2 ("!ldaspsp", -sym->stack);
3232 _G.omitFramePtr = TRUE;
3234 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3235 emit2 ("!enterxl", sym->stack);
3236 else if (sym->stack)
3237 emit2 ("!enterx", sym->stack);
3241 _G.stack.offset = sym->stack;
3244 /*-----------------------------------------------------------------*/
3245 /* genEndFunction - generates epilogue for functions */
3246 /*-----------------------------------------------------------------*/
3248 genEndFunction (iCode * ic)
3250 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3252 if (IFFUNC_ISNAKED(sym->type))
3254 emitDebug("; naked function: no epilogue.");
3258 /* PENDING: calleeSave */
3259 if (IS_Z80 && _G.omitFramePtr)
3261 if (_G.stack.offset)
3262 emit2 ("!ldaspsp", _G.stack.offset);
3264 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3266 emit2 ("!leavexl", _G.stack.offset);
3268 else if (_G.stack.offset)
3270 emit2 ("!leavex", _G.stack.offset);
3277 if (_G.calleeSaves.pushedDE)
3280 _G.calleeSaves.pushedDE = FALSE;
3283 if (_G.calleeSaves.pushedBC)
3286 _G.calleeSaves.pushedBC = FALSE;
3289 if (options.profile)
3291 emit2 ("!profileexit");
3294 /* if this is an interrupt service routine
3295 then save all potentially used registers. */
3296 if (IFFUNC_ISISR (sym->type))
3300 /* If critical function then turn interrupts back on */
3301 /* except when no interrupt number is given then it implies the NMI handler */
3302 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3309 /* This is a non-ISR function.
3310 If critical function then turn interrupts back on */
3311 if (IFFUNC_ISCRITICAL (sym->type))
3319 symbol *tlbl = newiTempLabel (NULL);
3322 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3323 //don't enable interrupts as they were off before
3324 emit2 ("jp po,!tlabel", tlbl->key + 100);
3326 emit2 ("!tlabeldef", (tlbl->key + 100));
3331 if (options.debug && currFunc)
3333 debugFile->writeEndFunction (currFunc, ic, 1);
3336 if (IFFUNC_ISISR (sym->type))
3338 /* "critical interrupt" is used to imply NMI handler */
3339 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3346 /* Both banked and non-banked just ret */
3350 if (!IS_STATIC(sym->etype))
3352 sprintf (buffer, "%s_end", sym->rname);
3353 emit2 ("!labeldef", buffer);
3356 _G.flushStatics = 1;
3357 _G.stack.pushed = 0;
3358 _G.stack.offset = 0;
3361 /*-----------------------------------------------------------------*/
3362 /* genRet - generate code for return statement */
3363 /*-----------------------------------------------------------------*/
3368 /* Errk. This is a hack until I can figure out how
3369 to cause dehl to spill on a call */
3370 int size, offset = 0;
3372 /* if we have no return value then
3373 just generate the "ret" */
3377 /* we have something to return then
3378 move the return value into place */
3379 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3380 size = AOP_SIZE (IC_LEFT (ic));
3382 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3385 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3389 emit2 ("ld de,%s", l);
3393 emit2 ("ld hl,%s", l);
3399 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3403 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3405 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3406 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3412 l = aopGet (AOP (IC_LEFT (ic)), offset,
3414 if (strcmp (_fReturn[offset], l))
3415 emit2 ("ld %s,%s", _fReturn[offset], l);
3420 freeAsmop (IC_LEFT (ic), NULL, ic);
3423 /* generate a jump to the return label
3424 if the next is not the return statement */
3425 if (!(ic->next && ic->next->op == LABEL &&
3426 IC_LABEL (ic->next) == returnLabel))
3428 emit2 ("jp !tlabel", returnLabel->key + 100);
3431 /*-----------------------------------------------------------------*/
3432 /* genLabel - generates a label */
3433 /*-----------------------------------------------------------------*/
3435 genLabel (iCode * ic)
3437 /* special case never generate */
3438 if (IC_LABEL (ic) == entryLabel)
3441 emitLabel (IC_LABEL (ic)->key + 100);
3444 /*-----------------------------------------------------------------*/
3445 /* genGoto - generates a ljmp */
3446 /*-----------------------------------------------------------------*/
3448 genGoto (iCode * ic)
3450 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3453 /*-----------------------------------------------------------------*/
3454 /* genPlusIncr :- does addition with increment if possible */
3455 /*-----------------------------------------------------------------*/
3457 genPlusIncr (iCode * ic)
3459 unsigned int icount;
3460 unsigned int size = getDataSize (IC_RESULT (ic));
3461 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3463 /* will try to generate an increment */
3464 /* if the right side is not a literal
3466 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3469 emitDebug ("; genPlusIncr");
3471 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3473 /* If result is a pair */
3474 if (resultId != PAIR_INVALID)
3476 if (isLitWord (AOP (IC_LEFT (ic))))
3478 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3481 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3483 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3485 PAIR_ID freep = getFreePairId (ic);
3486 if (freep != PAIR_INVALID)
3488 fetchPair (freep, AOP (IC_RIGHT (ic)));
3489 emit2 ("add hl,%s", _pairs[freep].name);
3495 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3496 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3503 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3507 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3511 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3516 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3518 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3519 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3523 /* if the literal value of the right hand side
3524 is greater than 4 then it is not worth it */
3528 /* if increment 16 bits in register */
3529 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3535 symbol *tlbl = NULL;
3536 tlbl = newiTempLabel (NULL);
3539 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3542 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3545 emitLabel (tlbl->key + 100);
3549 /* if the sizes are greater than 1 then we cannot */
3550 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3551 AOP_SIZE (IC_LEFT (ic)) > 1)
3554 /* If the result is in a register then we can load then increment.
3556 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3558 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3561 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3566 /* we can if the aops of the left & result match or
3567 if they are in registers and the registers are the
3569 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3573 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3581 /*-----------------------------------------------------------------*/
3582 /* outBitAcc - output a bit in acc */
3583 /*-----------------------------------------------------------------*/
3585 outBitAcc (operand * result)
3587 symbol *tlbl = newiTempLabel (NULL);
3588 /* if the result is a bit */
3589 if (AOP_TYPE (result) == AOP_CRY)
3591 wassertl (0, "Tried to write A into a bit");
3595 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3596 emit2 ("ld a,!one");
3597 emitLabel (tlbl->key + 100);
3603 couldDestroyCarry (asmop *aop)
3607 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3616 shiftIntoPair (int idx, asmop *aop)
3618 PAIR_ID id = PAIR_INVALID;
3620 wassertl (IS_Z80, "Only implemented for the Z80");
3621 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3633 wassertl (0, "Internal error - hit default case");
3636 emitDebug ("; Shift into pair idx %u", idx);
3640 setupPair (PAIR_HL, aop, 0);
3644 setupPair (PAIR_IY, aop, 0);
3646 emit2 ("pop %s", _pairs[id].name);
3649 aop->type = AOP_PAIRPTR;
3650 aop->aopu.aop_pairId = id;
3651 _G.pairs[id].offset = 0;
3652 _G.pairs[id].last_type = aop->type;
3656 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3658 wassert (left && right);
3662 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3664 shiftIntoPair (0, right);
3665 /* check result again, in case right == result */
3666 if (couldDestroyCarry (result))
3667 shiftIntoPair (1, result);
3669 else if (couldDestroyCarry (right))
3671 if (getPairId (result) == PAIR_HL)
3672 _G.preserveCarry = TRUE;
3674 shiftIntoPair (0, right);
3676 else if (couldDestroyCarry (result))
3678 shiftIntoPair (0, result);
3687 /*-----------------------------------------------------------------*/
3688 /* genPlus - generates code for addition */
3689 /*-----------------------------------------------------------------*/
3691 genPlus (iCode * ic)
3693 int size, offset = 0;
3695 /* special cases :- */
3697 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3698 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3699 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3701 /* Swap the left and right operands if:
3703 if literal, literal on the right or
3704 if left requires ACC or right is already
3707 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3708 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3709 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3711 operand *t = IC_RIGHT (ic);
3712 IC_RIGHT (ic) = IC_LEFT (ic);
3716 /* if both left & right are in bit
3718 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3719 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3722 wassertl (0, "Tried to add two bits");
3725 /* if left in bit space & right literal */
3726 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3727 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3729 /* Can happen I guess */
3730 wassertl (0, "Tried to add a bit to a literal");
3733 /* if I can do an increment instead
3734 of add then GOOD for ME */
3735 if (genPlusIncr (ic) == TRUE)
3738 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3740 size = getDataSize (IC_RESULT (ic));
3742 /* Special case when left and right are constant */
3743 if (isPair (AOP (IC_RESULT (ic))))
3746 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3747 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3749 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3755 sprintf (buffer, "#(%s + %s)", left, right);
3756 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3761 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3763 /* Fetch into HL then do the add */
3764 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3765 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3767 spillPair (PAIR_HL);
3769 if (left == PAIR_HL && right != PAIR_INVALID)
3771 emit2 ("add hl,%s", _pairs[right].name);
3774 else if (right == PAIR_HL && left != PAIR_INVALID)
3776 emit2 ("add hl,%s", _pairs[left].name);
3779 else if (right != PAIR_INVALID && right != PAIR_HL)
3781 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3782 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3785 else if (left != PAIR_INVALID && left != PAIR_HL)
3787 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3788 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3797 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3799 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3800 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3802 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3807 ld hl,sp+n trashes C so we cant afford to do it during an
3808 add with stack based varibles. Worst case is:
3821 So you cant afford to load up hl if either left, right, or result
3822 is on the stack (*sigh*) The alt is:
3830 Combinations in here are:
3831 * If left or right are in bc then the loss is small - trap later
3832 * If the result is in bc then the loss is also small
3836 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3837 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3838 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3840 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3841 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3842 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3843 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3845 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3847 /* Swap left and right */
3848 operand *t = IC_RIGHT (ic);
3849 IC_RIGHT (ic) = IC_LEFT (ic);
3852 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3854 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3855 emit2 ("add hl,bc");
3859 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3860 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3861 emit2 ("add hl,de");
3863 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3869 /* Be paranoid on the GB with 4 byte variables due to how C
3870 can be trashed by lda hl,n(sp).
3872 _gbz80_emitAddSubLong (ic, TRUE);
3877 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3881 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3883 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3886 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3889 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3893 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3896 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3899 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3901 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3905 _G.preserveCarry = FALSE;
3906 freeAsmop (IC_LEFT (ic), NULL, ic);
3907 freeAsmop (IC_RIGHT (ic), NULL, ic);
3908 freeAsmop (IC_RESULT (ic), NULL, ic);
3912 /*-----------------------------------------------------------------*/
3913 /* genMinusDec :- does subtraction with deccrement if possible */
3914 /*-----------------------------------------------------------------*/
3916 genMinusDec (iCode * ic)
3918 unsigned int icount;
3919 unsigned int size = getDataSize (IC_RESULT (ic));
3921 /* will try to generate an increment */
3922 /* if the right side is not a literal we cannot */
3923 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3926 /* if the literal value of the right hand side
3927 is greater than 4 then it is not worth it */
3928 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3931 size = getDataSize (IC_RESULT (ic));
3933 /* if decrement 16 bits in register */
3934 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3935 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3938 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3942 /* If result is a pair */
3943 if (isPair (AOP (IC_RESULT (ic))))
3945 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3947 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3951 /* if increment 16 bits in register */
3952 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3956 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3959 emit2 ("dec %s", _getTempPairName());
3962 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3968 /* if the sizes are greater than 1 then we cannot */
3969 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3970 AOP_SIZE (IC_LEFT (ic)) > 1)
3973 /* we can if the aops of the left & result match or if they are in
3974 registers and the registers are the same */
3975 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3978 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3985 /*-----------------------------------------------------------------*/
3986 /* genMinus - generates code for subtraction */
3987 /*-----------------------------------------------------------------*/
3989 genMinus (iCode * ic)
3991 int size, offset = 0;
3992 unsigned long lit = 0L;
3994 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3995 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3996 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3998 /* special cases :- */
3999 /* if both left & right are in bit space */
4000 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4001 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4003 wassertl (0, "Tried to subtract two bits");
4007 /* if I can do an decrement instead of subtract then GOOD for ME */
4008 if (genMinusDec (ic) == TRUE)
4011 size = getDataSize (IC_RESULT (ic));
4013 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4018 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4022 /* Same logic as genPlus */
4025 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4026 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4027 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4029 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4030 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4031 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4032 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4034 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4035 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4037 if (left == PAIR_INVALID && right == PAIR_INVALID)
4042 else if (right == PAIR_INVALID)
4044 else if (left == PAIR_INVALID)
4047 fetchPair (left, AOP (IC_LEFT (ic)));
4048 /* Order is important. Right may be HL */
4049 fetchPair (right, AOP (IC_RIGHT (ic)));
4051 emit2 ("ld a,%s", _pairs[left].l);
4052 emit2 ("sub a,%s", _pairs[right].l);
4054 emit2 ("ld a,%s", _pairs[left].h);
4055 emit2 ("sbc a,%s", _pairs[right].h);
4057 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4059 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4061 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4067 /* Be paranoid on the GB with 4 byte variables due to how C
4068 can be trashed by lda hl,n(sp).
4070 _gbz80_emitAddSubLong (ic, FALSE);
4075 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
4077 /* if literal, add a,#-lit, else normal subb */
4080 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4081 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4085 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4088 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4092 /* first add without previous c */
4094 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4096 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4098 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4101 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4102 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4103 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4105 wassertl (0, "Tried to subtract on a long pointer");
4109 _G.preserveCarry = FALSE;
4110 freeAsmop (IC_LEFT (ic), NULL, ic);
4111 freeAsmop (IC_RIGHT (ic), NULL, ic);
4112 freeAsmop (IC_RESULT (ic), NULL, ic);
4115 /*-----------------------------------------------------------------*/
4116 /* genMult - generates code for multiplication */
4117 /*-----------------------------------------------------------------*/
4119 genMult (iCode * ic)
4123 /* If true then the final operation should be a subtract */
4124 bool active = FALSE;
4127 /* Shouldn't occur - all done through function calls */
4128 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4129 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4130 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4132 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4134 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4135 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4136 AOP_SIZE (IC_RESULT (ic)) > 2)
4138 wassertl (0, "Multiplication is handled through support function calls");
4141 /* Swap left and right such that right is a literal */
4142 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4144 operand *t = IC_RIGHT (ic);
4145 IC_RIGHT (ic) = IC_LEFT (ic);
4149 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4151 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4152 // wassertl (val > 0, "Multiply must be positive");
4153 wassertl (val != 1, "Can't multiply by 1");
4155 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4157 _G.stack.pushedDE = TRUE;
4160 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4162 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4173 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4178 /* Fully unroled version of mul.s. Not the most efficient.
4180 for (count = 0; count < 16; count++)
4182 if (count != 0 && active)
4184 emit2 ("add hl,hl");
4188 if (active == FALSE)
4196 emit2 ("add hl,de");
4205 if (IS_Z80 && _G.stack.pushedDE)
4208 _G.stack.pushedDE = FALSE;
4212 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4214 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4216 freeAsmop (IC_LEFT (ic), NULL, ic);
4217 freeAsmop (IC_RIGHT (ic), NULL, ic);
4218 freeAsmop (IC_RESULT (ic), NULL, ic);
4221 /*-----------------------------------------------------------------*/
4222 /* genDiv - generates code for division */
4223 /*-----------------------------------------------------------------*/
4227 /* Shouldn't occur - all done through function calls */
4228 wassertl (0, "Division is handled through support function calls");
4231 /*-----------------------------------------------------------------*/
4232 /* genMod - generates code for division */
4233 /*-----------------------------------------------------------------*/
4237 /* Shouldn't occur - all done through function calls */
4241 /*-----------------------------------------------------------------*/
4242 /* genIfxJump :- will create a jump depending on the ifx */
4243 /*-----------------------------------------------------------------*/
4245 genIfxJump (iCode * ic, char *jval)
4250 /* if true label then we jump if condition
4254 jlbl = IC_TRUE (ic);
4255 if (!strcmp (jval, "a"))
4259 else if (!strcmp (jval, "c"))
4263 else if (!strcmp (jval, "nc"))
4267 else if (!strcmp (jval, "m"))
4271 else if (!strcmp (jval, "p"))
4277 /* The buffer contains the bit on A that we should test */
4283 /* false label is present */
4284 jlbl = IC_FALSE (ic);
4285 if (!strcmp (jval, "a"))
4289 else if (!strcmp (jval, "c"))
4293 else if (!strcmp (jval, "nc"))
4297 else if (!strcmp (jval, "m"))
4301 else if (!strcmp (jval, "p"))
4307 /* The buffer contains the bit on A that we should test */
4311 /* Z80 can do a conditional long jump */
4312 if (!strcmp (jval, "a"))
4316 else if (!strcmp (jval, "c"))
4319 else if (!strcmp (jval, "nc"))
4322 else if (!strcmp (jval, "m"))
4325 else if (!strcmp (jval, "p"))
4330 emit2 ("bit %s,a", jval);
4332 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4334 /* mark the icode as generated */
4340 _getPairIdName (PAIR_ID id)
4342 return _pairs[id].name;
4347 /* if unsigned char cmp with lit, just compare */
4349 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4351 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4354 emit2 ("xor a,!immedbyte", 0x80);
4355 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4358 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4360 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4362 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4363 // Pull left into DE and right into HL
4364 aopGet (AOP(left), LSB, FALSE);
4367 aopGet (AOP(right), LSB, FALSE);
4371 if (size == 0 && sign)
4373 // Highest byte when signed needs the bits flipped
4376 emit2 ("ld a,(de)");
4377 emit2 ("xor !immedbyte", 0x80);
4379 emit2 ("ld a,(hl)");
4380 emit2 ("xor !immedbyte", 0x80);
4384 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4388 emit2 ("ld a,(de)");
4389 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4399 spillPair (PAIR_HL);
4401 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4403 setupPair (PAIR_HL, AOP (left), 0);
4404 aopGet (AOP(right), LSB, FALSE);
4408 if (size == 0 && sign)
4410 // Highest byte when signed needs the bits flipped
4413 emit2 ("ld a,(hl)");
4414 emit2 ("xor !immedbyte", 0x80);
4416 emit2 ("ld a,%d(iy)", offset);
4417 emit2 ("xor !immedbyte", 0x80);
4421 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4425 emit2 ("ld a,(hl)");
4426 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4435 spillPair (PAIR_HL);
4436 spillPair (PAIR_IY);
4440 if (AOP_TYPE (right) == AOP_LIT)
4442 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4443 /* optimize if(x < 0) or if(x >= 0) */
4448 /* No sign so it's always false */
4453 /* Just load in the top most bit */
4454 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4455 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4457 genIfxJump (ifx, "7");
4469 /* First setup h and l contaning the top most bytes XORed */
4470 bool fDidXor = FALSE;
4471 if (AOP_TYPE (left) == AOP_LIT)
4473 unsigned long lit = (unsigned long)
4474 floatFromVal (AOP (left)->aopu.aop_lit);
4475 emit2 ("ld %s,!immedbyte", _fTmp[0],
4476 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4480 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4481 emit2 ("xor a,!immedbyte", 0x80);
4482 emit2 ("ld %s,a", _fTmp[0]);
4485 if (AOP_TYPE (right) == AOP_LIT)
4487 unsigned long lit = (unsigned long)
4488 floatFromVal (AOP (right)->aopu.aop_lit);
4489 emit2 ("ld %s,!immedbyte", _fTmp[1],
4490 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4494 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4495 emit2 ("xor a,!immedbyte", 0x80);
4496 emit2 ("ld %s,a", _fTmp[1]);
4502 /* Do a long subtract */
4505 _moveA (aopGet (AOP (left), offset, FALSE));
4507 if (sign && size == 0)
4509 emit2 ("ld a,%s", _fTmp[0]);
4510 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4514 /* Subtract through, propagating the carry */
4515 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4523 /** Generic compare for > or <
4526 genCmp (operand * left, operand * right,
4527 operand * result, iCode * ifx, int sign)
4529 int size, offset = 0;
4530 unsigned long lit = 0L;
4531 bool swap_sense = FALSE;
4533 /* if left & right are bit variables */
4534 if (AOP_TYPE (left) == AOP_CRY &&
4535 AOP_TYPE (right) == AOP_CRY)
4537 /* Cant happen on the Z80 */
4538 wassertl (0, "Tried to compare two bits");
4542 /* Do a long subtract of right from left. */
4543 size = max (AOP_SIZE (left), AOP_SIZE (right));
4545 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4547 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4548 // Pull left into DE and right into HL
4549 aopGet (AOP(left), LSB, FALSE);
4552 aopGet (AOP(right), LSB, FALSE);
4556 emit2 ("ld a,(de)");
4557 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4566 spillPair (PAIR_HL);
4570 if (AOP_TYPE (right) == AOP_LIT)
4572 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4573 /* optimize if(x < 0) or if(x >= 0) */
4578 /* No sign so it's always false */
4583 /* Just load in the top most bit */
4584 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4585 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4587 genIfxJump (ifx, "7");
4598 genIfxJump (ifx, swap_sense ? "c" : "nc");
4609 _moveA (aopGet (AOP (left), offset, FALSE));
4610 /* Subtract through, propagating the carry */
4611 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4617 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4621 /* Shift the sign bit up into carry */
4624 outBitCLong (result, swap_sense);
4628 /* if the result is used in the next
4629 ifx conditional branch then generate
4630 code a little differently */
4638 genIfxJump (ifx, swap_sense ? "nc" : "c");
4642 genIfxJump (ifx, swap_sense ? "p" : "m");
4647 genIfxJump (ifx, swap_sense ? "nc" : "c");
4654 /* Shift the sign bit up into carry */
4657 outBitCLong (result, swap_sense);
4659 /* leave the result in acc */
4663 /*-----------------------------------------------------------------*/
4664 /* genCmpGt :- greater than comparison */
4665 /*-----------------------------------------------------------------*/
4667 genCmpGt (iCode * ic, iCode * ifx)
4669 operand *left, *right, *result;
4670 sym_link *letype, *retype;
4673 left = IC_LEFT (ic);
4674 right = IC_RIGHT (ic);
4675 result = IC_RESULT (ic);
4677 letype = getSpec (operandType (left));
4678 retype = getSpec (operandType (right));
4679 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4680 /* assign the amsops */
4681 aopOp (left, ic, FALSE, FALSE);
4682 aopOp (right, ic, FALSE, FALSE);
4683 aopOp (result, ic, TRUE, FALSE);
4685 genCmp (right, left, result, ifx, sign);
4687 freeAsmop (left, NULL, ic);
4688 freeAsmop (right, NULL, ic);
4689 freeAsmop (result, NULL, ic);
4692 /*-----------------------------------------------------------------*/
4693 /* genCmpLt - less than comparisons */
4694 /*-----------------------------------------------------------------*/
4696 genCmpLt (iCode * ic, iCode * ifx)
4698 operand *left, *right, *result;
4699 sym_link *letype, *retype;
4702 left = IC_LEFT (ic);
4703 right = IC_RIGHT (ic);
4704 result = IC_RESULT (ic);
4706 letype = getSpec (operandType (left));
4707 retype = getSpec (operandType (right));
4708 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4710 /* assign the amsops */
4711 aopOp (left, ic, FALSE, FALSE);
4712 aopOp (right, ic, FALSE, FALSE);
4713 aopOp (result, ic, TRUE, FALSE);
4715 genCmp (left, right, result, ifx, sign);
4717 freeAsmop (left, NULL, ic);
4718 freeAsmop (right, NULL, ic);
4719 freeAsmop (result, NULL, ic);
4722 /*-----------------------------------------------------------------*/
4723 /* gencjneshort - compare and jump if not equal */
4724 /*-----------------------------------------------------------------*/
4726 gencjneshort (operand * left, operand * right, symbol * lbl)
4728 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4730 unsigned long lit = 0L;
4732 /* Swap the left and right if it makes the computation easier */
4733 if (AOP_TYPE (left) == AOP_LIT)
4740 if (AOP_TYPE (right) == AOP_LIT)
4742 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4745 /* if the right side is a literal then anything goes */
4746 if (AOP_TYPE (right) == AOP_LIT &&
4747 AOP_TYPE (left) != AOP_DIR)
4751 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4756 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4763 emit2 ("jp nz,!tlabel", lbl->key + 100);
4769 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4770 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4773 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4774 emit2 ("jp nz,!tlabel", lbl->key + 100);
4779 /* if the right side is in a register or in direct space or
4780 if the left is a pointer register & right is not */
4781 else if (AOP_TYPE (right) == AOP_REG ||
4782 AOP_TYPE (right) == AOP_DIR ||
4783 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4787 _moveA (aopGet (AOP (left), offset, FALSE));
4788 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4789 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4791 emit2 ("jp nz,!tlabel", lbl->key + 100);
4794 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4795 emit2 ("jp nz,!tlabel", lbl->key + 100);
4802 /* right is a pointer reg need both a & b */
4803 /* PENDING: is this required? */
4806 _moveA (aopGet (AOP (right), offset, FALSE));
4807 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4808 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4814 /*-----------------------------------------------------------------*/
4815 /* gencjne - compare and jump if not equal */
4816 /*-----------------------------------------------------------------*/
4818 gencjne (operand * left, operand * right, symbol * lbl)
4820 symbol *tlbl = newiTempLabel (NULL);
4822 gencjneshort (left, right, lbl);
4825 emit2 ("ld a,!one");
4826 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4827 emitLabel (lbl->key + 100);
4829 emitLabel (tlbl->key + 100);
4832 /*-----------------------------------------------------------------*/
4833 /* genCmpEq - generates code for equal to */
4834 /*-----------------------------------------------------------------*/
4836 genCmpEq (iCode * ic, iCode * ifx)
4838 operand *left, *right, *result;
4840 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4841 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4842 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4844 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4846 /* Swap operands if it makes the operation easier. ie if:
4847 1. Left is a literal.
4849 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4851 operand *t = IC_RIGHT (ic);
4852 IC_RIGHT (ic) = IC_LEFT (ic);
4856 if (ifx && !AOP_SIZE (result))
4859 /* if they are both bit variables */
4860 if (AOP_TYPE (left) == AOP_CRY &&
4861 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4863 wassertl (0, "Tried to compare two bits");
4867 tlbl = newiTempLabel (NULL);
4868 gencjneshort (left, right, tlbl);
4871 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4872 emitLabel (tlbl->key + 100);
4876 /* PENDING: do this better */
4877 symbol *lbl = newiTempLabel (NULL);
4878 emit2 ("!shortjp !tlabel", lbl->key + 100);
4879 emitLabel (tlbl->key + 100);
4880 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4881 emitLabel (lbl->key + 100);
4884 /* mark the icode as generated */
4889 /* if they are both bit variables */
4890 if (AOP_TYPE (left) == AOP_CRY &&
4891 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4893 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4899 gencjne (left, right, newiTempLabel (NULL));
4900 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4907 genIfxJump (ifx, "a");
4910 /* if the result is used in an arithmetic operation
4911 then put the result in place */
4912 if (AOP_TYPE (result) != AOP_CRY)
4917 /* leave the result in acc */
4921 freeAsmop (left, NULL, ic);
4922 freeAsmop (right, NULL, ic);
4923 freeAsmop (result, NULL, ic);
4926 /*-----------------------------------------------------------------*/
4927 /* ifxForOp - returns the icode containing the ifx for operand */
4928 /*-----------------------------------------------------------------*/
4930 ifxForOp (operand * op, iCode * ic)
4932 /* if true symbol then needs to be assigned */
4933 if (IS_TRUE_SYMOP (op))
4936 /* if this has register type condition and
4937 the next instruction is ifx with the same operand
4938 and live to of the operand is upto the ifx only then */
4940 ic->next->op == IFX &&
4941 IC_COND (ic->next)->key == op->key &&
4942 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4948 /*-----------------------------------------------------------------*/
4949 /* genAndOp - for && operation */
4950 /*-----------------------------------------------------------------*/
4952 genAndOp (iCode * ic)
4954 operand *left, *right, *result;
4957 /* note here that && operations that are in an if statement are
4958 taken away by backPatchLabels only those used in arthmetic
4959 operations remain */
4960 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4961 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4962 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4964 /* if both are bit variables */
4965 if (AOP_TYPE (left) == AOP_CRY &&
4966 AOP_TYPE (right) == AOP_CRY)
4968 wassertl (0, "Tried to and two bits");
4972 tlbl = newiTempLabel (NULL);
4974 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4976 emitLabel (tlbl->key + 100);
4980 freeAsmop (left, NULL, ic);
4981 freeAsmop (right, NULL, ic);
4982 freeAsmop (result, NULL, ic);
4985 /*-----------------------------------------------------------------*/
4986 /* genOrOp - for || operation */
4987 /*-----------------------------------------------------------------*/
4989 genOrOp (iCode * ic)
4991 operand *left, *right, *result;
4994 /* note here that || operations that are in an
4995 if statement are taken away by backPatchLabels
4996 only those used in arthmetic operations remain */
4997 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4998 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4999 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5001 /* if both are bit variables */
5002 if (AOP_TYPE (left) == AOP_CRY &&
5003 AOP_TYPE (right) == AOP_CRY)
5005 wassertl (0, "Tried to OR two bits");
5009 tlbl = newiTempLabel (NULL);
5011 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5013 emitLabel (tlbl->key + 100);
5017 freeAsmop (left, NULL, ic);
5018 freeAsmop (right, NULL, ic);
5019 freeAsmop (result, NULL, ic);
5022 /*-----------------------------------------------------------------*/
5023 /* isLiteralBit - test if lit == 2^n */
5024 /*-----------------------------------------------------------------*/
5026 isLiteralBit (unsigned long lit)
5028 unsigned long pw[32] =
5029 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5030 0x100L, 0x200L, 0x400L, 0x800L,
5031 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5032 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5033 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5034 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5035 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5038 for (idx = 0; idx < 32; idx++)
5044 /*-----------------------------------------------------------------*/
5045 /* jmpTrueOrFalse - */
5046 /*-----------------------------------------------------------------*/
5048 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5050 // ugly but optimized by peephole
5053 symbol *nlbl = newiTempLabel (NULL);
5054 emit2 ("jp !tlabel", nlbl->key + 100);
5055 emitLabel (tlbl->key + 100);
5056 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5057 emitLabel (nlbl->key + 100);
5061 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5062 emitLabel (tlbl->key + 100);
5067 /*-----------------------------------------------------------------*/
5068 /* genAnd - code for and */
5069 /*-----------------------------------------------------------------*/
5071 genAnd (iCode * ic, iCode * ifx)
5073 operand *left, *right, *result;
5074 int size, offset = 0;
5075 unsigned long lit = 0L;
5078 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5079 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5080 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5082 /* if left is a literal & right is not then exchange them */
5083 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5084 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5086 operand *tmp = right;
5091 /* if result = right then exchange them */
5092 if (sameRegs (AOP (result), AOP (right)))
5094 operand *tmp = right;
5099 /* if right is bit then exchange them */
5100 if (AOP_TYPE (right) == AOP_CRY &&
5101 AOP_TYPE (left) != AOP_CRY)
5103 operand *tmp = right;
5107 if (AOP_TYPE (right) == AOP_LIT)
5108 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5110 size = AOP_SIZE (result);
5112 if (AOP_TYPE (left) == AOP_CRY)
5114 wassertl (0, "Tried to perform an AND with a bit as an operand");
5118 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5119 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5120 if ((AOP_TYPE (right) == AOP_LIT) &&
5121 (AOP_TYPE (result) == AOP_CRY) &&
5122 (AOP_TYPE (left) != AOP_CRY))
5124 symbol *tlbl = newiTempLabel (NULL);
5125 int sizel = AOP_SIZE (left);
5128 /* PENDING: Test case for this. */
5133 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5135 _moveA (aopGet (AOP (left), offset, FALSE));
5136 if (bytelit != 0x0FFL)
5138 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5145 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5149 // bit = left & literal
5153 emit2 ("!tlabeldef", tlbl->key + 100);
5155 // if(left & literal)
5160 jmpTrueOrFalse (ifx, tlbl);
5168 /* if left is same as result */
5169 if (sameRegs (AOP (result), AOP (left)))
5171 for (; size--; offset++)
5173 if (AOP_TYPE (right) == AOP_LIT)
5175 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5180 aopPut (AOP (result), "!zero", offset);
5183 _moveA (aopGet (AOP (left), offset, FALSE));
5185 aopGet (AOP (right), offset, FALSE));
5186 aopPut (AOP (left), "a", offset);
5193 if (AOP_TYPE (left) == AOP_ACC)
5195 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5199 _moveA (aopGet (AOP (left), offset, FALSE));
5201 aopGet (AOP (right), offset, FALSE));
5202 aopPut (AOP (left), "a", offset);
5209 // left & result in different registers
5210 if (AOP_TYPE (result) == AOP_CRY)
5212 wassertl (0, "Tried to AND where the result is in carry");
5216 for (; (size--); offset++)
5219 // result = left & right
5220 if (AOP_TYPE (right) == AOP_LIT)
5222 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5224 aopPut (AOP (result),
5225 aopGet (AOP (left), offset, FALSE),
5229 else if (bytelit == 0)
5231 aopPut (AOP (result), "!zero", offset);
5235 // faster than result <- left, anl result,right
5236 // and better if result is SFR
5237 if (AOP_TYPE (left) == AOP_ACC)
5238 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5241 _moveA (aopGet (AOP (left), offset, FALSE));
5243 aopGet (AOP (right), offset, FALSE));
5245 aopPut (AOP (result), "a", offset);
5252 freeAsmop (left, NULL, ic);
5253 freeAsmop (right, NULL, ic);
5254 freeAsmop (result, NULL, ic);
5257 /*-----------------------------------------------------------------*/
5258 /* genOr - code for or */
5259 /*-----------------------------------------------------------------*/
5261 genOr (iCode * ic, iCode * ifx)
5263 operand *left, *right, *result;
5264 int size, offset = 0;
5265 unsigned long lit = 0L;
5268 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5269 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5270 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5272 /* if left is a literal & right is not then exchange them */
5273 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5274 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5276 operand *tmp = right;
5281 /* if result = right then exchange them */
5282 if (sameRegs (AOP (result), AOP (right)))
5284 operand *tmp = right;
5289 /* if right is bit then exchange them */
5290 if (AOP_TYPE (right) == AOP_CRY &&
5291 AOP_TYPE (left) != AOP_CRY)
5293 operand *tmp = right;
5297 if (AOP_TYPE (right) == AOP_LIT)
5298 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5300 size = AOP_SIZE (result);
5302 if (AOP_TYPE (left) == AOP_CRY)
5304 wassertl (0, "Tried to OR where left is a bit");
5308 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5309 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5310 if ((AOP_TYPE (right) == AOP_LIT) &&
5311 (AOP_TYPE (result) == AOP_CRY) &&
5312 (AOP_TYPE (left) != AOP_CRY))
5314 symbol *tlbl = newiTempLabel (NULL);
5315 int sizel = AOP_SIZE (left);
5319 wassertl (0, "Result is assigned to a bit");
5321 /* PENDING: Modeled after the AND code which is inefficient. */
5324 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5326 _moveA (aopGet (AOP (left), offset, FALSE));
5327 /* OR with any literal is the same as OR with itself. */
5329 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5335 jmpTrueOrFalse (ifx, tlbl);
5340 /* if left is same as result */
5341 if (sameRegs (AOP (result), AOP (left)))
5343 for (; size--; offset++)
5345 if (AOP_TYPE (right) == AOP_LIT)
5347 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5351 _moveA (aopGet (AOP (left), offset, FALSE));
5353 aopGet (AOP (right), offset, FALSE));
5354 aopPut (AOP (result), "a", offset);
5359 if (AOP_TYPE (left) == AOP_ACC)
5360 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5363 _moveA (aopGet (AOP (left), offset, FALSE));
5365 aopGet (AOP (right), offset, FALSE));
5366 aopPut (AOP (result), "a", offset);
5373 // left & result in different registers
5374 if (AOP_TYPE (result) == AOP_CRY)
5376 wassertl (0, "Result of OR is in a bit");
5379 for (; (size--); offset++)
5382 // result = left & right
5383 if (AOP_TYPE (right) == AOP_LIT)
5385 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5387 aopPut (AOP (result),
5388 aopGet (AOP (left), offset, FALSE),
5393 // faster than result <- left, anl result,right
5394 // and better if result is SFR
5395 if (AOP_TYPE (left) == AOP_ACC)
5396 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5399 _moveA (aopGet (AOP (left), offset, FALSE));
5401 aopGet (AOP (right), offset, FALSE));
5403 aopPut (AOP (result), "a", offset);
5404 /* PENDING: something weird is going on here. Add exception. */
5405 if (AOP_TYPE (result) == AOP_ACC)
5411 freeAsmop (left, NULL, ic);
5412 freeAsmop (right, NULL, ic);
5413 freeAsmop (result, NULL, ic);
5416 /*-----------------------------------------------------------------*/
5417 /* genXor - code for xclusive or */
5418 /*-----------------------------------------------------------------*/
5420 genXor (iCode * ic, iCode * ifx)
5422 operand *left, *right, *result;
5423 int size, offset = 0;
5424 unsigned long lit = 0L;
5426 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5427 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5428 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5430 /* if left is a literal & right is not then exchange them */
5431 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5432 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5434 operand *tmp = right;
5439 /* if result = right then exchange them */
5440 if (sameRegs (AOP (result), AOP (right)))
5442 operand *tmp = right;
5447 /* if right is bit then exchange them */
5448 if (AOP_TYPE (right) == AOP_CRY &&
5449 AOP_TYPE (left) != AOP_CRY)
5451 operand *tmp = right;
5455 if (AOP_TYPE (right) == AOP_LIT)
5456 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5458 size = AOP_SIZE (result);
5460 if (AOP_TYPE (left) == AOP_CRY)
5462 wassertl (0, "Tried to XOR a bit");
5466 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5467 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5468 if ((AOP_TYPE (right) == AOP_LIT) &&
5469 (AOP_TYPE (result) == AOP_CRY) &&
5470 (AOP_TYPE (left) != AOP_CRY))
5472 symbol *tlbl = newiTempLabel (NULL);
5473 int sizel = AOP_SIZE (left);
5477 /* PENDING: Test case for this. */
5478 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5482 _moveA (aopGet (AOP (left), offset, FALSE));
5483 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5484 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5489 jmpTrueOrFalse (ifx, tlbl);
5493 wassertl (0, "Result of XOR was destined for a bit");
5498 /* if left is same as result */
5499 if (sameRegs (AOP (result), AOP (left)))
5501 for (; size--; offset++)
5503 if (AOP_TYPE (right) == AOP_LIT)
5505 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5509 _moveA (aopGet (AOP (left), offset, FALSE));
5511 aopGet (AOP (right), offset, FALSE));
5512 aopPut (AOP (result), "a", offset);
5517 if (AOP_TYPE (left) == AOP_ACC)
5519 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5523 _moveA (aopGet (AOP (left), offset, FALSE));
5525 aopGet (AOP (right), offset, FALSE));
5526 aopPut (AOP (result), "a", offset);
5533 // left & result in different registers
5534 if (AOP_TYPE (result) == AOP_CRY)
5536 wassertl (0, "Result of XOR is in a bit");
5539 for (; (size--); offset++)
5542 // result = left & right
5543 if (AOP_TYPE (right) == AOP_LIT)
5545 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5547 aopPut (AOP (result),
5548 aopGet (AOP (left), offset, FALSE),
5553 // faster than result <- left, anl result,right
5554 // and better if result is SFR
5555 if (AOP_TYPE (left) == AOP_ACC)
5557 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5561 _moveA (aopGet (AOP (left), offset, FALSE));
5563 aopGet (AOP (right), offset, FALSE));
5565 aopPut (AOP (result), "a", offset);
5570 freeAsmop (left, NULL, ic);
5571 freeAsmop (right, NULL, ic);
5572 freeAsmop (result, NULL, ic);
5575 /*-----------------------------------------------------------------*/
5576 /* genInline - write the inline code out */
5577 /*-----------------------------------------------------------------*/
5579 genInline (iCode * ic)
5581 char *buffer, *bp, *bp1;
5583 _G.lines.isInline += (!options.asmpeep);
5585 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5586 strcpy (buffer, IC_INLINE (ic));
5588 /* emit each line as a code */
5613 _G.lines.isInline -= (!options.asmpeep);
5617 /*-----------------------------------------------------------------*/
5618 /* genRRC - rotate right with carry */
5619 /*-----------------------------------------------------------------*/
5626 /*-----------------------------------------------------------------*/
5627 /* genRLC - generate code for rotate left with carry */
5628 /*-----------------------------------------------------------------*/
5635 /*-----------------------------------------------------------------*/
5636 /* genGetHbit - generates code get highest order bit */
5637 /*-----------------------------------------------------------------*/
5639 genGetHbit (iCode * ic)
5641 operand *left, *result;
5642 left = IC_LEFT (ic);
5643 result = IC_RESULT (ic);
5645 aopOp (left, ic, FALSE, FALSE);
5646 aopOp (result, ic, FALSE, FALSE);
5648 /* get the highest order byte into a */
5649 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5651 if (AOP_TYPE (result) == AOP_CRY)
5659 emit2 ("and a,!one");
5664 freeAsmop (left, NULL, ic);
5665 freeAsmop (result, NULL, ic);
5669 emitRsh2 (asmop *aop, int size, int is_signed)
5675 const char *l = aopGet (aop, size, FALSE);
5678 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5688 /*-----------------------------------------------------------------*/
5689 /* shiftR2Left2Result - shift right two bytes from left to result */
5690 /*-----------------------------------------------------------------*/
5692 shiftR2Left2Result (operand * left, int offl,
5693 operand * result, int offr,
5694 int shCount, int is_signed)
5697 symbol *tlbl, *tlbl1;
5699 movLeft2Result (left, offl, result, offr, 0);
5700 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5702 /* if (AOP(result)->type == AOP_REG) { */
5704 tlbl = newiTempLabel (NULL);
5705 tlbl1 = newiTempLabel (NULL);
5707 /* Left is already in result - so now do the shift */
5712 emitRsh2 (AOP (result), size, is_signed);
5717 emit2 ("ld a,!immedbyte+1", shCount);
5718 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5719 emitLabel (tlbl->key + 100);
5721 emitRsh2 (AOP (result), size, is_signed);
5723 emitLabel (tlbl1->key + 100);
5725 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5729 /*-----------------------------------------------------------------*/
5730 /* shiftL2Left2Result - shift left two bytes from left to result */
5731 /*-----------------------------------------------------------------*/
5733 shiftL2Left2Result (operand * left, int offl,
5734 operand * result, int offr, int shCount)
5736 if (sameRegs (AOP (result), AOP (left)) &&
5737 ((offl + MSB16) == offr))
5743 /* Copy left into result */
5744 movLeft2Result (left, offl, result, offr, 0);
5745 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5748 if (getPairId (AOP (result)) == PAIR_HL)
5752 emit2 ("add hl,hl");
5759 symbol *tlbl, *tlbl1;
5762 tlbl = newiTempLabel (NULL);
5763 tlbl1 = newiTempLabel (NULL);
5765 if (AOP (result)->type == AOP_REG)
5769 for (offset = 0; offset < size; offset++)
5771 l = aopGet (AOP (result), offset, FALSE);
5775 emit2 ("sla %s", l);
5786 /* Left is already in result - so now do the shift */
5789 emit2 ("ld a,!immedbyte+1", shCount);
5790 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5791 emitLabel (tlbl->key + 100);
5796 l = aopGet (AOP (result), offset, FALSE);
5800 emit2 ("sla %s", l);
5811 emitLabel (tlbl1->key + 100);
5813 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5819 /*-----------------------------------------------------------------*/
5820 /* AccRol - rotate left accumulator by known count */
5821 /*-----------------------------------------------------------------*/
5823 AccRol (int shCount)
5825 shCount &= 0x0007; // shCount : 0..7
5902 /*-----------------------------------------------------------------*/
5903 /* AccLsh - left shift accumulator by known count */
5904 /*-----------------------------------------------------------------*/
5906 AccLsh (int shCount)
5908 static const unsigned char SLMask[] =
5910 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5919 else if (shCount == 2)
5926 /* rotate left accumulator */
5928 /* and kill the lower order bits */
5929 emit2 ("and a,!immedbyte", SLMask[shCount]);
5934 /*-----------------------------------------------------------------*/
5935 /* shiftL1Left2Result - shift left one byte from left to result */
5936 /*-----------------------------------------------------------------*/
5938 shiftL1Left2Result (operand * left, int offl,
5939 operand * result, int offr, int shCount)
5942 l = aopGet (AOP (left), offl, FALSE);
5944 /* shift left accumulator */
5946 aopPut (AOP (result), "a", offr);
5950 /*-----------------------------------------------------------------*/
5951 /* genlshTwo - left shift two bytes by known amount != 0 */
5952 /*-----------------------------------------------------------------*/
5954 genlshTwo (operand * result, operand * left, int shCount)
5956 int size = AOP_SIZE (result);
5958 wassert (size == 2);
5960 /* if shCount >= 8 */
5968 movLeft2Result (left, LSB, result, MSB16, 0);
5969 aopPut (AOP (result), "!zero", 0);
5970 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5974 movLeft2Result (left, LSB, result, MSB16, 0);
5975 aopPut (AOP (result), "!zero", 0);
5980 aopPut (AOP (result), "!zero", LSB);
5983 /* 1 <= shCount <= 7 */
5992 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5997 /*-----------------------------------------------------------------*/
5998 /* genlshOne - left shift a one byte quantity by known count */
5999 /*-----------------------------------------------------------------*/
6001 genlshOne (operand * result, operand * left, int shCount)
6003 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6006 /*-----------------------------------------------------------------*/
6007 /* genLeftShiftLiteral - left shifting by known count */
6008 /*-----------------------------------------------------------------*/
6010 genLeftShiftLiteral (operand * left,
6015 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6018 freeAsmop (right, NULL, ic);
6020 aopOp (left, ic, FALSE, FALSE);
6021 aopOp (result, ic, FALSE, FALSE);
6023 size = getSize (operandType (result));
6025 /* I suppose that the left size >= result size */
6031 else if (shCount >= (size * 8))
6035 aopPut (AOP (result), "!zero", size);
6043 genlshOne (result, left, shCount);
6046 genlshTwo (result, left, shCount);
6049 wassertl (0, "Shifting of longs is currently unsupported");
6055 freeAsmop (left, NULL, ic);
6056 freeAsmop (result, NULL, ic);
6059 /*-----------------------------------------------------------------*/
6060 /* genLeftShift - generates code for left shifting */
6061 /*-----------------------------------------------------------------*/
6063 genLeftShift (iCode * ic)
6067 symbol *tlbl, *tlbl1;
6068 operand *left, *right, *result;
6070 right = IC_RIGHT (ic);
6071 left = IC_LEFT (ic);
6072 result = IC_RESULT (ic);
6074 aopOp (right, ic, FALSE, FALSE);
6076 /* if the shift count is known then do it
6077 as efficiently as possible */
6078 if (AOP_TYPE (right) == AOP_LIT)
6080 genLeftShiftLiteral (left, right, result, ic);
6084 /* shift count is unknown then we have to form a loop get the loop
6085 count in B : Note: we take only the lower order byte since
6086 shifting more that 32 bits make no sense anyway, ( the largest
6087 size of an object can be only 32 bits ) */
6088 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6090 freeAsmop (right, NULL, ic);
6091 aopOp (left, ic, FALSE, FALSE);
6092 aopOp (result, ic, FALSE, FALSE);
6094 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6097 /* now move the left to the result if they are not the
6100 if (!sameRegs (AOP (left), AOP (result)))
6103 size = AOP_SIZE (result);
6107 l = aopGet (AOP (left), offset, FALSE);
6108 aopPut (AOP (result), l, offset);
6113 tlbl = newiTempLabel (NULL);
6114 size = AOP_SIZE (result);
6116 tlbl1 = newiTempLabel (NULL);
6118 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6121 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6122 emitLabel (tlbl->key + 100);
6123 l = aopGet (AOP (result), offset, FALSE);
6127 l = aopGet (AOP (result), offset, FALSE);
6131 emit2 ("sla %s", l);
6139 emitLabel (tlbl1->key + 100);
6141 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6143 freeAsmop (left, NULL, ic);
6144 freeAsmop (result, NULL, ic);
6147 /*-----------------------------------------------------------------*/
6148 /* genrshOne - left shift two bytes by known amount != 0 */
6149 /*-----------------------------------------------------------------*/
6151 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6154 int size = AOP_SIZE (result);
6157 wassert (size == 1);
6158 wassert (shCount < 8);
6160 l = aopGet (AOP (left), 0, FALSE);
6162 if (AOP (result)->type == AOP_REG)
6164 aopPut (AOP (result), l, 0);
6165 l = aopGet (AOP (result), 0, FALSE);
6168 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6176 emit2 ("%s a", is_signed ? "sra" : "srl");
6178 aopPut (AOP (result), "a", 0);
6182 /*-----------------------------------------------------------------*/
6183 /* AccRsh - right shift accumulator by known count */
6184 /*-----------------------------------------------------------------*/
6186 AccRsh (int shCount)
6188 static const unsigned char SRMask[] =
6190 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6195 /* rotate right accumulator */
6196 AccRol (8 - shCount);
6197 /* and kill the higher order bits */
6198 emit2 ("and a,!immedbyte", SRMask[shCount]);
6202 /*-----------------------------------------------------------------*/
6203 /* shiftR1Left2Result - shift right one byte from left to result */
6204 /*-----------------------------------------------------------------*/
6206 shiftR1Left2Result (operand * left, int offl,
6207 operand * result, int offr,
6208 int shCount, int sign)
6210 _moveA (aopGet (AOP (left), offl, FALSE));
6215 emit2 ("%s a", sign ? "sra" : "srl");
6222 aopPut (AOP (result), "a", offr);
6225 /*-----------------------------------------------------------------*/
6226 /* genrshTwo - right shift two bytes by known amount != 0 */
6227 /*-----------------------------------------------------------------*/
6229 genrshTwo (operand * result, operand * left,
6230 int shCount, int sign)
6232 /* if shCount >= 8 */
6238 shiftR1Left2Result (left, MSB16, result, LSB,
6243 movLeft2Result (left, MSB16, result, LSB, sign);
6247 /* Sign extend the result */
6248 _moveA(aopGet (AOP (result), 0, FALSE));
6252 aopPut (AOP (result), ACC_NAME, MSB16);
6256 aopPut (AOP (result), "!zero", 1);
6259 /* 1 <= shCount <= 7 */
6262 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6266 /*-----------------------------------------------------------------*/
6267 /* genRightShiftLiteral - left shifting by known count */
6268 /*-----------------------------------------------------------------*/
6270 genRightShiftLiteral (operand * left,
6276 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6279 freeAsmop (right, NULL, ic);
6281 aopOp (left, ic, FALSE, FALSE);
6282 aopOp (result, ic, FALSE, FALSE);
6284 size = getSize (operandType (result));
6286 /* I suppose that the left size >= result size */
6292 else if (shCount >= (size * 8)) {
6294 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6295 _moveA(aopGet (AOP (left), 0, FALSE));
6303 aopPut (AOP (result), s, size);
6310 genrshOne (result, left, shCount, sign);
6313 genrshTwo (result, left, shCount, sign);
6316 wassertl (0, "Asked to shift right a long which should be a function call");
6319 wassertl (0, "Entered default case in right shift delegate");
6322 freeAsmop (left, NULL, ic);
6323 freeAsmop (result, NULL, ic);
6326 /*-----------------------------------------------------------------*/
6327 /* genRightShift - generate code for right shifting */
6328 /*-----------------------------------------------------------------*/
6330 genRightShift (iCode * ic)
6332 operand *right, *left, *result;
6334 int size, offset, first = 1;
6338 symbol *tlbl, *tlbl1;
6340 /* if signed then we do it the hard way preserve the
6341 sign bit moving it inwards */
6342 retype = getSpec (operandType (IC_RESULT (ic)));
6344 is_signed = !SPEC_USIGN (retype);
6346 /* signed & unsigned types are treated the same : i.e. the
6347 signed is NOT propagated inwards : quoting from the
6348 ANSI - standard : "for E1 >> E2, is equivalent to division
6349 by 2**E2 if unsigned or if it has a non-negative value,
6350 otherwise the result is implementation defined ", MY definition
6351 is that the sign does not get propagated */
6353 right = IC_RIGHT (ic);
6354 left = IC_LEFT (ic);
6355 result = IC_RESULT (ic);
6357 aopOp (right, ic, FALSE, FALSE);
6359 /* if the shift count is known then do it
6360 as efficiently as possible */
6361 if (AOP_TYPE (right) == AOP_LIT)
6363 genRightShiftLiteral (left, right, result, ic, is_signed);
6367 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6369 freeAsmop (right, NULL, ic);
6371 aopOp (left, ic, FALSE, FALSE);
6372 aopOp (result, ic, FALSE, FALSE);
6374 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6377 /* now move the left to the result if they are not the
6379 if (!sameRegs (AOP (left), AOP (result)))
6382 size = AOP_SIZE (result);
6386 l = aopGet (AOP (left), offset, FALSE);
6387 aopPut (AOP (result), l, offset);
6392 tlbl = newiTempLabel (NULL);
6393 tlbl1 = newiTempLabel (NULL);
6394 size = AOP_SIZE (result);
6397 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6400 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6401 emitLabel (tlbl->key + 100);
6404 l = aopGet (AOP (result), offset--, FALSE);
6407 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6415 emitLabel (tlbl1->key + 100);
6417 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6419 freeAsmop (left, NULL, ic);
6420 freeAsmop (result, NULL, ic);
6424 /*-----------------------------------------------------------------*/
6425 /* genUnpackBits - generates code for unpacking bits */
6426 /*-----------------------------------------------------------------*/
6428 genUnpackBits (operand * result, int pair)
6430 int offset = 0; /* result byte offset */
6431 int rsize; /* result size */
6432 int rlen = 0; /* remaining bitfield length */
6433 sym_link *etype; /* bitfield type information */
6434 int blen; /* bitfield length */
6435 int bstr; /* bitfield starting bit within byte */
6437 emitDebug ("; genUnpackBits");
6439 etype = getSpec (operandType (result));
6440 rsize = getSize (operandType (result));
6441 blen = SPEC_BLEN (etype);
6442 bstr = SPEC_BSTR (etype);
6444 /* If the bitfield length is less than a byte */
6447 emit2 ("ld a,!*pair", _pairs[pair].name);
6449 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6450 if (!SPEC_USIGN (etype))
6452 /* signed bitfield */
6453 symbol *tlbl = newiTempLabel (NULL);
6455 emit2 ("bit %d,a", blen - 1);
6456 emit2 ("jp z,!tlabel", tlbl->key + 100);
6457 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6458 emitLabel (tlbl->key + 100);
6460 aopPut (AOP (result), "a", offset++);
6464 /* TODO: what if pair == PAIR_DE ? */
6465 if (getPairId (AOP (result)) == PAIR_HL)
6467 wassertl (rsize == 2, "HL must be of size 2");
6468 emit2 ("ld a,!*hl");
6470 emit2 ("ld h,!*hl");
6473 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6474 if (!SPEC_USIGN (etype))
6476 /* signed bitfield */
6477 symbol *tlbl = newiTempLabel (NULL);
6479 emit2 ("bit %d,a", blen - 1);
6480 emit2 ("jp z,!tlabel", tlbl->key + 100);
6481 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6482 emitLabel (tlbl->key + 100);
6485 spillPair (PAIR_HL);
6489 /* Bit field did not fit in a byte. Copy all
6490 but the partial byte at the end. */
6491 for (rlen=blen;rlen>=8;rlen-=8)
6493 emit2 ("ld a,!*pair", _pairs[pair].name);
6494 aopPut (AOP (result), "a", offset++);
6497 emit2 ("inc %s", _pairs[pair].name);
6498 _G.pairs[pair].offset++;
6502 /* Handle the partial byte at the end */
6505 emit2 ("ld a,!*pair", _pairs[pair].name);
6506 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6507 if (!SPEC_USIGN (etype))
6509 /* signed bitfield */
6510 symbol *tlbl = newiTempLabel (NULL);
6512 emit2 ("bit %d,a", rlen - 1);
6513 emit2 ("jp z,!tlabel", tlbl->key + 100);
6514 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6515 emitLabel (tlbl->key + 100);
6517 aopPut (AOP (result), "a", offset++);
6525 if (SPEC_USIGN (etype))
6529 /* signed bitfield: sign extension with 0x00 or 0xff */
6537 aopPut (AOP (result), source, offset++);
6541 /*-----------------------------------------------------------------*/
6542 /* genGenPointerGet - get value from generic pointer space */
6543 /*-----------------------------------------------------------------*/
6545 genGenPointerGet (operand * left,
6546 operand * result, iCode * ic)
6549 sym_link *retype = getSpec (operandType (result));
6555 aopOp (left, ic, FALSE, FALSE);
6556 aopOp (result, ic, FALSE, FALSE);
6558 size = AOP_SIZE (result);
6560 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6563 if (isPtrPair (AOP (left)))
6565 tsprintf (buffer, sizeof(buffer),
6566 "!*pair", getPairName (AOP (left)));
6567 aopPut (AOP (result), buffer, 0);
6571 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6572 aopPut (AOP (result), "a", 0);
6574 freeAsmop (left, NULL, ic);
6578 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6585 tsprintf (at, sizeof(at), "!*iyx", offset);
6586 aopPut (AOP (result), at, offset);
6590 freeAsmop (left, NULL, ic);
6594 /* For now we always load into IY */
6595 /* if this is remateriazable */
6596 fetchPair (pair, AOP (left));
6598 /* if bit then unpack */
6599 if (IS_BITVAR (retype))
6601 genUnpackBits (result, pair);
6602 freeAsmop (left, NULL, ic);
6606 else if (getPairId (AOP (result)) == PAIR_HL)
6608 wassertl (size == 2, "HL must be of size 2");
6609 emit2 ("ld a,!*hl");
6611 emit2 ("ld h,!*hl");
6613 spillPair (PAIR_HL);
6615 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6617 size = AOP_SIZE (result);
6622 /* PENDING: make this better */
6623 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6625 aopPut (AOP (result), "!*hl", offset++);
6629 emit2 ("ld a,!*pair", _pairs[pair].name);
6630 aopPut (AOP (result), "a", offset++);
6634 emit2 ("inc %s", _pairs[pair].name);
6635 _G.pairs[pair].offset++;
6638 /* Fixup HL back down */
6639 for (size = AOP_SIZE (result)-1; size; size--)
6641 emit2 ("dec %s", _pairs[pair].name);
6646 size = AOP_SIZE (result);
6651 /* PENDING: make this better */
6653 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6655 aopPut (AOP (result), "!*hl", offset++);
6659 emit2 ("ld a,!*pair", _pairs[pair].name);
6660 aopPut (AOP (result), "a", offset++);
6664 emit2 ("inc %s", _pairs[pair].name);
6665 _G.pairs[pair].offset++;
6670 freeAsmop (left, NULL, ic);
6673 freeAsmop (result, NULL, ic);
6676 /*-----------------------------------------------------------------*/
6677 /* genPointerGet - generate code for pointer get */
6678 /*-----------------------------------------------------------------*/
6680 genPointerGet (iCode * ic)
6682 operand *left, *result;
6683 sym_link *type, *etype;
6685 left = IC_LEFT (ic);
6686 result = IC_RESULT (ic);
6688 /* depending on the type of pointer we need to
6689 move it to the correct pointer register */
6690 type = operandType (left);
6691 etype = getSpec (type);
6693 genGenPointerGet (left, result, ic);
6697 isRegOrLit (asmop * aop)
6699 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6705 /*-----------------------------------------------------------------*/
6706 /* genPackBits - generates code for packed bit storage */
6707 /*-----------------------------------------------------------------*/
6709 genPackBits (sym_link * etype,
6714 int offset = 0; /* source byte offset */
6715 int rlen = 0; /* remaining bitfield length */
6716 int blen; /* bitfield length */
6717 int bstr; /* bitfield starting bit within byte */
6718 int litval; /* source literal value (if AOP_LIT) */
6719 unsigned char mask; /* bitmask within current byte */
6720 int extraPair; /* a tempory register */
6721 bool needPopExtra=0; /* need to restore original value of temp reg */
6723 emitDebug ("; genPackBits","");
6725 blen = SPEC_BLEN (etype);
6726 bstr = SPEC_BSTR (etype);
6728 /* If the bitfield length is less than a byte */
6731 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6732 (unsigned char) (0xFF >> (8 - bstr)));
6734 if (AOP_TYPE (right) == AOP_LIT)
6736 /* Case with a bitfield length <8 and literal source
6738 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6740 litval &= (~mask) & 0xff;
6741 emit2 ("ld a,!*pair", _pairs[pair].name);
6742 if ((mask|litval)!=0xff)
6743 emit2 ("and a,!immedbyte", mask);
6745 emit2 ("or a,!immedbyte", litval);
6746 emit2 ("ld !*pair,a", _pairs[pair].name);
6751 /* Case with a bitfield length <8 and arbitrary source
6753 _moveA (aopGet (AOP (right), 0, FALSE));
6754 /* shift and mask source value */
6756 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6758 extraPair = getFreePairId(ic);
6759 if (extraPair == PAIR_INVALID)
6761 extraPair = PAIR_BC;
6762 if (getPairId (AOP (right)) != PAIR_BC
6763 || !isLastUse (ic, right))
6769 emit2 ("ld %s,a", _pairs[extraPair].l);
6770 emit2 ("ld a,!*pair", _pairs[pair].name);
6772 emit2 ("and a,!immedbyte", mask);
6773 emit2 ("or a,%s", _pairs[extraPair].l);
6774 emit2 ("ld !*pair,a", _pairs[pair].name);
6781 /* Bit length is greater than 7 bits. In this case, copy */
6782 /* all except the partial byte at the end */
6783 for (rlen=blen;rlen>=8;rlen-=8)
6785 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6786 emit2 ("ld !*pair,a", _pairs[pair].name);
6789 emit2 ("inc %s", _pairs[pair].name);
6790 _G.pairs[pair].offset++;
6794 /* If there was a partial byte at the end */
6797 mask = (((unsigned char) -1 << rlen) & 0xff);
6799 if (AOP_TYPE (right) == AOP_LIT)
6801 /* Case with partial byte and literal source
6803 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6804 litval >>= (blen-rlen);
6805 litval &= (~mask) & 0xff;
6806 emit2 ("ld a,!*pair", _pairs[pair].name);
6807 if ((mask|litval)!=0xff)
6808 emit2 ("and a,!immedbyte", mask);
6810 emit2 ("or a,!immedbyte", litval);
6814 /* Case with partial byte and arbitrary source
6816 _moveA (aopGet (AOP (right), offset++, FALSE));
6817 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6819 extraPair = getFreePairId(ic);
6820 if (extraPair == PAIR_INVALID)
6822 extraPair = getPairId (AOP (right));
6823 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6824 extraPair = PAIR_BC;
6826 if (getPairId (AOP (right)) != PAIR_BC
6827 || !isLastUse (ic, right))
6833 emit2 ("ld %s,a", _pairs[extraPair].l);
6834 emit2 ("ld a,!*pair", _pairs[pair].name);
6836 emit2 ("and a,!immedbyte", mask);
6837 emit2 ("or a,%s", _pairs[extraPair].l);
6842 emit2 ("ld !*pair,a", _pairs[pair].name);
6847 /*-----------------------------------------------------------------*/
6848 /* genGenPointerSet - stores the value into a pointer location */
6849 /*-----------------------------------------------------------------*/
6851 genGenPointerSet (operand * right,
6852 operand * result, iCode * ic)
6855 sym_link *retype = getSpec (operandType (right));
6856 sym_link *letype = getSpec (operandType (result));
6857 PAIR_ID pairId = PAIR_HL;
6860 aopOp (result, ic, FALSE, FALSE);
6861 aopOp (right, ic, FALSE, FALSE);
6866 size = AOP_SIZE (right);
6868 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6869 emitDebug("; isBitvar = %d", isBitvar);
6871 /* Handle the exceptions first */
6872 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6875 const char *l = aopGet (AOP (right), 0, FALSE);
6876 const char *pair = getPairName (AOP (result));
6877 if (canAssignToPtr (l) && isPtr (pair))
6879 emit2 ("ld !*pair,%s", pair, l);
6884 emit2 ("ld !*pair,a", pair);
6889 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6892 const char *l = aopGet (AOP (right), 0, FALSE);
6897 if (canAssignToPtr (l))
6899 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6903 _moveA (aopGet (AOP (right), offset, FALSE));
6904 emit2 ("ld !*iyx,a", offset);
6910 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6917 const char *l = aopGet (AOP (right), offset, FALSE);
6918 if (isRegOrLit (AOP (right)) && !IS_GB)
6920 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6925 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6929 emit2 ("inc %s", _pairs[PAIR_HL].name);
6930 _G.pairs[PAIR_HL].offset++;
6935 /* Fixup HL back down */
6936 for (size = AOP_SIZE (right)-1; size; size--)
6938 emit2 ("dec %s", _pairs[PAIR_HL].name);
6943 /* if the operand is already in dptr
6944 then we do nothing else we move the value to dptr */
6945 if (AOP_TYPE (result) != AOP_STR)
6947 fetchPair (pairId, AOP (result));
6949 /* so hl now contains the address */
6950 freeAsmop (result, NULL, ic);
6952 /* if bit then unpack */
6955 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6965 const char *l = aopGet (AOP (right), offset, FALSE);
6966 if (isRegOrLit (AOP (right)) && !IS_GB)
6968 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6973 emit2 ("ld !*pair,a", _pairs[pairId].name);
6977 emit2 ("inc %s", _pairs[pairId].name);
6978 _G.pairs[pairId].offset++;
6984 freeAsmop (right, NULL, ic);
6987 /*-----------------------------------------------------------------*/
6988 /* genPointerSet - stores the value into a pointer location */
6989 /*-----------------------------------------------------------------*/
6991 genPointerSet (iCode * ic)
6993 operand *right, *result;
6994 sym_link *type, *etype;
6996 right = IC_RIGHT (ic);
6997 result = IC_RESULT (ic);
6999 /* depending on the type of pointer we need to
7000 move it to the correct pointer register */
7001 type = operandType (result);
7002 etype = getSpec (type);
7004 genGenPointerSet (right, result, ic);
7007 /*-----------------------------------------------------------------*/
7008 /* genIfx - generate code for Ifx statement */
7009 /*-----------------------------------------------------------------*/
7011 genIfx (iCode * ic, iCode * popIc)
7013 operand *cond = IC_COND (ic);
7016 aopOp (cond, ic, FALSE, TRUE);
7018 /* get the value into acc */
7019 if (AOP_TYPE (cond) != AOP_CRY)
7023 /* the result is now in the accumulator */
7024 freeAsmop (cond, NULL, ic);
7026 /* if there was something to be popped then do it */
7030 /* if the condition is a bit variable */
7031 if (isbit && IS_ITEMP (cond) &&
7033 genIfxJump (ic, SPIL_LOC (cond)->rname);
7034 else if (isbit && !IS_ITEMP (cond))
7035 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7037 genIfxJump (ic, "a");
7042 /*-----------------------------------------------------------------*/
7043 /* genAddrOf - generates code for address of */
7044 /*-----------------------------------------------------------------*/
7046 genAddrOf (iCode * ic)
7048 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7050 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7052 /* if the operand is on the stack then we
7053 need to get the stack offset of this
7060 if (sym->stack <= 0)
7062 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7066 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7068 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7072 emit2 ("ld de,!hashedstr", sym->rname);
7073 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7081 /* if it has an offset then we need to compute it */
7083 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7085 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7086 emit2 ("add hl,sp");
7090 emit2 ("ld hl,!hashedstr", sym->rname);
7092 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7094 freeAsmop (IC_RESULT (ic), NULL, ic);
7097 /*-----------------------------------------------------------------*/
7098 /* genAssign - generate code for assignment */
7099 /*-----------------------------------------------------------------*/
7101 genAssign (iCode * ic)
7103 operand *result, *right;
7105 unsigned long lit = 0L;
7107 result = IC_RESULT (ic);
7108 right = IC_RIGHT (ic);
7110 /* Dont bother assigning if they are the same */
7111 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7113 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7117 aopOp (right, ic, FALSE, FALSE);
7118 aopOp (result, ic, TRUE, FALSE);
7120 /* if they are the same registers */
7121 if (sameRegs (AOP (right), AOP (result)))
7123 emitDebug ("; (registers are the same)");
7127 /* if the result is a bit */
7128 if (AOP_TYPE (result) == AOP_CRY)
7130 wassertl (0, "Tried to assign to a bit");
7134 size = AOP_SIZE (result);
7137 if (AOP_TYPE (right) == AOP_LIT)
7139 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7142 if (isPair (AOP (result)))
7144 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7146 else if ((size > 1) &&
7147 (AOP_TYPE (result) != AOP_REG) &&
7148 (AOP_TYPE (right) == AOP_LIT) &&
7149 !IS_FLOAT (operandType (right)) &&
7152 bool fXored = FALSE;
7154 /* Work from the top down.
7155 Done this way so that we can use the cached copy of 0
7156 in A for a fast clear */
7159 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7161 if (!fXored && size > 1)
7168 aopPut (AOP (result), "a", offset);
7172 aopPut (AOP (result), "!zero", offset);
7176 aopPut (AOP (result),
7177 aopGet (AOP (right), offset, FALSE),
7182 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7184 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7185 aopPut (AOP (result), "l", LSB);
7186 aopPut (AOP (result), "h", MSB16);
7188 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7190 /* Special case. Load into a and d, then load out. */
7191 _moveA (aopGet (AOP (right), 0, FALSE));
7192 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7193 aopPut (AOP (result), "a", 0);
7194 aopPut (AOP (result), "e", 1);
7196 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7198 /* Special case - simple memcpy */
7199 aopGet (AOP (right), LSB, FALSE);
7202 aopGet (AOP (result), LSB, FALSE);
7206 emit2 ("ld a,(de)");
7207 /* Peephole will optimise this. */
7208 emit2 ("ld (hl),a");
7216 spillPair (PAIR_HL);
7222 /* PENDING: do this check better */
7223 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7225 _moveA (aopGet (AOP (right), offset, FALSE));
7226 aopPut (AOP (result), "a", offset);
7229 aopPut (AOP (result),
7230 aopGet (AOP (right), offset, FALSE),
7237 freeAsmop (right, NULL, ic);
7238 freeAsmop (result, NULL, ic);
7241 /*-----------------------------------------------------------------*/
7242 /* genJumpTab - genrates code for jump table */
7243 /*-----------------------------------------------------------------*/
7245 genJumpTab (iCode * ic)
7250 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7251 /* get the condition into accumulator */
7252 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7255 emit2 ("ld e,%s", l);
7256 emit2 ("ld d,!zero");
7257 jtab = newiTempLabel (NULL);
7259 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7260 emit2 ("add hl,de");
7261 emit2 ("add hl,de");
7262 emit2 ("add hl,de");
7263 freeAsmop (IC_JTCOND (ic), NULL, ic);
7267 emitLabel (jtab->key + 100);
7268 /* now generate the jump labels */
7269 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7270 jtab = setNextItem (IC_JTLABELS (ic)))
7271 emit2 ("jp !tlabel", jtab->key + 100);
7274 /*-----------------------------------------------------------------*/
7275 /* genCast - gen code for casting */
7276 /*-----------------------------------------------------------------*/
7278 genCast (iCode * ic)
7280 operand *result = IC_RESULT (ic);
7281 sym_link *rtype = operandType (IC_RIGHT (ic));
7282 operand *right = IC_RIGHT (ic);
7285 /* if they are equivalent then do nothing */
7286 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7289 aopOp (right, ic, FALSE, FALSE);
7290 aopOp (result, ic, FALSE, FALSE);
7292 /* if the result is a bit */
7293 if (AOP_TYPE (result) == AOP_CRY)
7295 wassertl (0, "Tried to cast to a bit");
7298 /* if they are the same size : or less */
7299 if (AOP_SIZE (result) <= AOP_SIZE (right))
7302 /* if they are in the same place */
7303 if (sameRegs (AOP (right), AOP (result)))
7306 /* if they in different places then copy */
7307 size = AOP_SIZE (result);
7311 aopPut (AOP (result),
7312 aopGet (AOP (right), offset, FALSE),
7319 /* So we now know that the size of destination is greater
7320 than the size of the source */
7321 /* we move to result for the size of source */
7322 size = AOP_SIZE (right);
7326 aopPut (AOP (result),
7327 aopGet (AOP (right), offset, FALSE),
7332 /* now depending on the sign of the destination */
7333 size = AOP_SIZE (result) - AOP_SIZE (right);
7334 /* Unsigned or not an integral type - right fill with zeros */
7335 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7338 aopPut (AOP (result), "!zero", offset++);
7342 /* we need to extend the sign :{ */
7343 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7349 aopPut (AOP (result), "a", offset++);
7353 freeAsmop (right, NULL, ic);
7354 freeAsmop (result, NULL, ic);
7357 /*-----------------------------------------------------------------*/
7358 /* genReceive - generate code for a receive iCode */
7359 /*-----------------------------------------------------------------*/
7361 genReceive (iCode * ic)
7363 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7364 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7365 IS_TRUE_SYMOP (IC_RESULT (ic))))
7375 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7376 size = AOP_SIZE(IC_RESULT(ic));
7378 for (i = 0; i < size; i++) {
7379 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7383 freeAsmop (IC_RESULT (ic), NULL, ic);
7386 /*-----------------------------------------------------------------*/
7387 /* genDummyRead - generate code for dummy read of volatiles */
7388 /*-----------------------------------------------------------------*/
7390 genDummyRead (iCode * ic)
7396 if (op && IS_SYMOP (op))
7398 aopOp (op, ic, FALSE, FALSE);
7401 size = AOP_SIZE (op);
7406 _moveA (aopGet (AOP (op), offset, FALSE));
7410 freeAsmop (op, NULL, ic);
7414 if (op && IS_SYMOP (op))
7416 aopOp (op, ic, FALSE, FALSE);
7419 size = AOP_SIZE (op);
7424 _moveA (aopGet (AOP (op), offset, FALSE));
7428 freeAsmop (op, NULL, ic);
7432 /*-----------------------------------------------------------------*/
7433 /* genCritical - generate code for start of a critical sequence */
7434 /*-----------------------------------------------------------------*/
7436 genCritical (iCode *ic)
7438 symbol *tlbl = newiTempLabel (NULL);
7444 else if (IC_RESULT (ic))
7446 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7447 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7448 //get interrupt enable flag IFF2 into P/O
7452 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7453 emit2 ("jp po,!tlabel", tlbl->key + 100);
7454 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7455 emit2 ("!tlabeldef", (tlbl->key + 100));
7456 freeAsmop (IC_RESULT (ic), NULL, ic);
7460 //get interrupt enable flag IFF2 into P/O
7469 /*-----------------------------------------------------------------*/
7470 /* genEndCritical - generate code for end of a critical sequence */
7471 /*-----------------------------------------------------------------*/
7473 genEndCritical (iCode *ic)
7475 symbol *tlbl = newiTempLabel (NULL);
7481 else if (IC_RIGHT (ic))
7483 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7484 _toBoolean (IC_RIGHT (ic));
7485 //don't enable interrupts if they were off before
7486 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
7488 emitLabel (tlbl->key + 100);
7489 freeAsmop (IC_RIGHT (ic), NULL, ic);
7495 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7496 //don't enable interrupts as they were off before
7497 emit2 ("jp po,!tlabel", tlbl->key + 100);
7499 emit2 ("!tlabeldef", (tlbl->key + 100));
7505 /** Maximum number of bytes to emit per line. */
7509 /** Context for the byte output chunker. */
7512 unsigned char buffer[DBEMIT_MAX_RUN];
7517 /** Flushes a byte chunker by writing out all in the buffer and
7521 _dbFlush(DBEMITCTX *self)
7528 sprintf(line, ".db 0x%02X", self->buffer[0]);
7530 for (i = 1; i < self->pos; i++)
7532 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7539 /** Write out another byte, buffering until a decent line is
7543 _dbEmit(DBEMITCTX *self, int c)
7545 if (self->pos == DBEMIT_MAX_RUN)
7549 self->buffer[self->pos++] = c;
7552 /** Context for a simple run length encoder. */
7556 unsigned char buffer[128];
7558 /** runLen may be equivalent to pos. */
7564 RLE_CHANGE_COST = 4,
7568 /** Flush the buffer of a run length encoder by writing out the run or
7569 data that it currently contains.
7572 _rleCommit(RLECTX *self)
7578 memset(&db, 0, sizeof(db));
7580 emit2(".db %u", self->pos);
7582 for (i = 0; i < self->pos; i++)
7584 _dbEmit(&db, self->buffer[i]);
7593 Can get either a run or a block of random stuff.
7594 Only want to change state if a good run comes in or a run ends.
7595 Detecting run end is easy.
7598 Say initial state is in run, len zero, last zero. Then if you get a
7599 few zeros then something else then a short run will be output.
7600 Seems OK. While in run mode, keep counting. While in random mode,
7601 keep a count of the run. If run hits margin, output all up to run,
7602 restart, enter run mode.
7605 /** Add another byte into the run length encoder, flushing as
7606 required. The run length encoder uses the Amiga IFF style, where
7607 a block is prefixed by its run length. A positive length means
7608 the next n bytes pass straight through. A negative length means
7609 that the next byte is repeated -n times. A zero terminates the
7613 _rleAppend(RLECTX *self, unsigned c)
7617 if (c != self->last)
7619 /* The run has stopped. See if it is worthwhile writing it out
7620 as a run. Note that the random data comes in as runs of
7623 if (self->runLen > RLE_CHANGE_COST)
7625 /* Yes, worthwhile. */
7626 /* Commit whatever was in the buffer. */
7628 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7632 /* Not worthwhile. Append to the end of the random list. */
7633 for (i = 0; i < self->runLen; i++)
7635 if (self->pos >= RLE_MAX_BLOCK)
7640 self->buffer[self->pos++] = self->last;
7648 if (self->runLen >= RLE_MAX_BLOCK)
7650 /* Commit whatever was in the buffer. */
7653 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7661 _rleFlush(RLECTX *self)
7663 _rleAppend(self, -1);
7670 /** genArrayInit - Special code for initialising an array with constant
7674 genArrayInit (iCode * ic)
7678 int elementSize = 0, eIndex, i;
7679 unsigned val, lastVal;
7683 memset(&rle, 0, sizeof(rle));
7685 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7687 _saveRegsForCall(ic, 0);
7689 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7690 emit2 ("call __initrleblock");
7692 type = operandType(IC_LEFT(ic));
7694 if (type && type->next)
7696 if (IS_SPEC(type->next) || IS_PTR(type->next))
7698 elementSize = getSize(type->next);
7700 else if (IS_ARRAY(type->next) && type->next->next)
7702 elementSize = getSize(type->next->next);
7706 printTypeChainRaw (type, NULL);
7707 wassertl (0, "Can't determine element size in genArrayInit.");
7712 wassertl (0, "Can't determine element size in genArrayInit.");
7715 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7717 iLoop = IC_ARRAYILIST(ic);
7718 lastVal = (unsigned)-1;
7720 /* Feed all the bytes into the run length encoder which will handle
7722 This works well for mixed char data, and for random int and long
7729 for (i = 0; i < ix; i++)
7731 for (eIndex = 0; eIndex < elementSize; eIndex++)
7733 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7734 _rleAppend(&rle, val);
7738 iLoop = iLoop->next;
7742 /* Mark the end of the run. */
7745 _restoreRegsAfterCall();
7749 freeAsmop (IC_LEFT(ic), NULL, ic);
7753 _swap (PAIR_ID one, PAIR_ID two)
7755 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7761 emit2 ("ld a,%s", _pairs[one].l);
7762 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7763 emit2 ("ld %s,a", _pairs[two].l);
7764 emit2 ("ld a,%s", _pairs[one].h);
7765 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7766 emit2 ("ld %s,a", _pairs[two].h);
7770 /* The problem is that we may have all three pairs used and they may
7771 be needed in a different order.
7776 hl = hl => unity, fine
7780 hl = hl hl = hl, swap de <=> bc
7788 hl = bc de = de, swap bc <=> hl
7796 hl = de bc = bc, swap hl <=> de
7801 * Any pair = pair are done last
7802 * Any pair = iTemp are done last
7803 * Any swaps can be done any time
7811 So how do we detect the cases?
7812 How about a 3x3 matrix?
7816 x x x x (Fourth for iTemp/other)
7818 First determin which mode to use by counting the number of unity and
7821 Two - Assign the pair first, then the rest
7822 One - Swap the two, then the rest
7826 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7828 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7830 PAIR_BC, PAIR_HL, PAIR_DE
7832 int i, j, nunity = 0;
7833 memset (ids, PAIR_INVALID, sizeof (ids));
7836 wassert (nparams == 3);
7838 /* First save everything that needs to be saved. */
7839 _saveRegsForCall (ic, 0);
7841 /* Loading HL first means that DE is always fine. */
7842 for (i = 0; i < nparams; i++)
7844 aopOp (pparams[i], ic, FALSE, FALSE);
7845 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7848 /* Count the number of unity or iTemp assigns. */
7849 for (i = 0; i < 3; i++)
7851 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7859 /* Any order, fall through. */
7861 else if (nunity == 2)
7863 /* One is assigned. Pull it out and assign. */
7864 for (i = 0; i < 3; i++)
7866 for (j = 0; j < NUM_PAIRS; j++)
7868 if (ids[dest[i]][j] == TRUE)
7870 /* Found it. See if it's the right one. */
7871 if (j == PAIR_INVALID || j == dest[i])
7877 fetchPair(dest[i], AOP (pparams[i]));
7884 else if (nunity == 1)
7886 /* Find the pairs to swap. */
7887 for (i = 0; i < 3; i++)
7889 for (j = 0; j < NUM_PAIRS; j++)
7891 if (ids[dest[i]][j] == TRUE)
7893 if (j == PAIR_INVALID || j == dest[i])
7908 int next = getPairId (AOP (pparams[0]));
7909 emit2 ("push %s", _pairs[next].name);
7911 if (next == dest[1])
7913 fetchPair (dest[1], AOP (pparams[1]));
7914 fetchPair (dest[2], AOP (pparams[2]));
7918 fetchPair (dest[2], AOP (pparams[2]));
7919 fetchPair (dest[1], AOP (pparams[1]));
7921 emit2 ("pop %s", _pairs[dest[0]].name);
7924 /* Finally pull out all of the iTemps */
7925 for (i = 0; i < 3; i++)
7927 if (ids[dest[i]][PAIR_INVALID] == 1)
7929 fetchPair (dest[i], AOP (pparams[i]));
7935 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7941 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7945 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7947 setupForBuiltin3 (ic, nParams, pparams);
7949 label = newiTempLabel(NULL);
7951 emitLabel (label->key);
7952 emit2 ("ld a,(hl)");
7955 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7957 freeAsmop (from, NULL, ic->next);
7958 freeAsmop (to, NULL, ic);
7962 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7964 operand *from, *to, *count;
7967 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7972 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7974 setupForBuiltin3 (ic, nParams, pparams);
7978 freeAsmop (count, NULL, ic->next->next);
7979 freeAsmop (from, NULL, ic);
7981 _restoreRegsAfterCall();
7983 /* if we need assign a result value */
7984 if ((IS_ITEMP (IC_RESULT (ic)) &&
7985 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7986 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7987 IS_TRUE_SYMOP (IC_RESULT (ic)))
7989 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7990 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7991 freeAsmop (IC_RESULT (ic), NULL, ic);
7994 freeAsmop (to, NULL, ic->next);
7997 /*-----------------------------------------------------------------*/
7998 /* genBuiltIn - calls the appropriate function to generating code */
7999 /* for a built in function */
8000 /*-----------------------------------------------------------------*/
8001 static void genBuiltIn (iCode *ic)
8003 operand *bi_parms[MAX_BUILTIN_ARGS];
8008 /* get all the arguments for a built in function */
8009 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8011 /* which function is it */
8012 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8014 if (strcmp(bif->name,"__builtin_strcpy")==0)
8016 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8018 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8020 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8024 wassertl (0, "Unknown builtin function encountered");
8028 /*-----------------------------------------------------------------*/
8029 /* genZ80Code - generate code for Z80 based controllers */
8030 /*-----------------------------------------------------------------*/
8032 genZ80Code (iCode * lic)
8040 _fReturn = _gbz80_return;
8041 _fTmp = _gbz80_return;
8045 _fReturn = _z80_return;
8046 _fTmp = _z80_return;
8049 _G.lines.head = _G.lines.current = NULL;
8051 /* if debug information required */
8052 if (options.debug && currFunc)
8054 debugFile->writeFunction (currFunc, lic);
8057 for (ic = lic; ic; ic = ic->next)
8059 _G.current_iCode = ic;
8061 if (ic->lineno && cln != ic->lineno)
8065 debugFile->writeCLine (ic);
8067 if (!options.noCcodeInAsm)
8069 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8070 printCLine(ic->filename, ic->lineno));
8074 if (options.iCodeInAsm)
8076 emit2 (";ic:%d: %s", ic->key, printILine(ic));
8078 /* if the result is marked as
8079 spilt and rematerializable or code for
8080 this has already been generated then
8082 if (resultRemat (ic) || ic->generated)
8085 /* depending on the operation */
8089 emitDebug ("; genNot");
8094 emitDebug ("; genCpl");
8099 emitDebug ("; genUminus");
8104 emitDebug ("; genIpush");
8109 /* IPOP happens only when trying to restore a
8110 spilt live range, if there is an ifx statement
8111 following this pop then the if statement might
8112 be using some of the registers being popped which
8113 would destory the contents of the register so
8114 we need to check for this condition and handle it */
8116 ic->next->op == IFX &&
8117 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8119 emitDebug ("; genIfx");
8120 genIfx (ic->next, ic);
8124 emitDebug ("; genIpop");
8130 emitDebug ("; genCall");
8135 emitDebug ("; genPcall");
8140 emitDebug ("; genFunction");
8145 emitDebug ("; genEndFunction");
8146 genEndFunction (ic);
8150 emitDebug ("; genRet");
8155 emitDebug ("; genLabel");
8160 emitDebug ("; genGoto");
8165 emitDebug ("; genPlus");
8170 emitDebug ("; genMinus");
8175 emitDebug ("; genMult");
8180 emitDebug ("; genDiv");
8185 emitDebug ("; genMod");
8190 emitDebug ("; genCmpGt");
8191 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8195 emitDebug ("; genCmpLt");
8196 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8203 /* note these two are xlated by algebraic equivalence
8204 during parsing SDCC.y */
8205 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8206 "got '>=' or '<=' shouldn't have come here");
8210 emitDebug ("; genCmpEq");
8211 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8215 emitDebug ("; genAndOp");
8220 emitDebug ("; genOrOp");
8225 emitDebug ("; genXor");
8226 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8230 emitDebug ("; genOr");
8231 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8235 emitDebug ("; genAnd");
8236 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8240 emitDebug ("; genInline");
8245 emitDebug ("; genRRC");
8250 emitDebug ("; genRLC");
8255 emitDebug ("; genGetHBIT");
8260 emitDebug ("; genLeftShift");
8265 emitDebug ("; genRightShift");
8269 case GET_VALUE_AT_ADDRESS:
8270 emitDebug ("; genPointerGet");
8276 if (POINTER_SET (ic))
8278 emitDebug ("; genAssign (pointer)");
8283 emitDebug ("; genAssign");
8289 emitDebug ("; genIfx");
8294 emitDebug ("; genAddrOf");
8299 emitDebug ("; genJumpTab");
8304 emitDebug ("; genCast");
8309 emitDebug ("; genReceive");
8314 if (ic->builtinSEND)
8316 emitDebug ("; genBuiltIn");
8321 emitDebug ("; addSet");
8322 addSet (&_G.sendSet, ic);
8327 emitDebug ("; genArrayInit");
8331 case DUMMY_READ_VOLATILE:
8332 emitDebug ("; genDummyRead");
8337 emitDebug ("; genCritical");
8342 emitDebug ("; genEndCritical");
8343 genEndCritical (ic);
8352 /* now we are ready to call the
8353 peep hole optimizer */
8354 if (!options.nopeep)
8355 peepHole (&_G.lines.head);
8357 /* This is unfortunate */
8358 /* now do the actual printing */
8360 FILE *fp = codeOutFile;
8361 if (isInHome () && codeOutFile == code->oFile)
8362 codeOutFile = home->oFile;
8363 printLine (_G.lines.head, codeOutFile);
8364 if (_G.flushStatics)
8367 _G.flushStatics = 0;
8372 freeTrace(&_G.lines.trace);
8373 freeTrace(&_G.trace.aops);
8379 _isPairUsed (iCode * ic, PAIR_ID pairId)
8385 if (bitVectBitValue (ic->rMask, D_IDX))
8387 if (bitVectBitValue (ic->rMask, E_IDX))
8397 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8400 value *val = aop->aopu.aop_lit;
8402 wassert (aop->type == AOP_LIT);
8403 wassert (!IS_FLOAT (val->type));
8405 v = (unsigned long) floatFromVal (val);
8413 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8414 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));