1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
90 #if defined(__BORLANDC__) || defined(_MSC_VER)
91 #define STRCASECMP stricmp
93 #define STRCASECMP strcasecmp
97 #include "SDCCglobl.h"
98 #include "SDCCpeeph.h"
100 #include "SDCCglue.h"
101 #include "newalloc.h"
103 /* This is the down and dirty file with all kinds of kludgy & hacky
104 stuff. This is what it is all about CODE GENERATION for a specific MCU.
105 Some of the routines may be reusable, will have to see */
107 /* Z80 calling convention description.
108 Parameters are passed right to left. As the stack grows downwards,
109 the parameters are arranged in left to right in memory.
110 Parameters may be passed in the HL and DE registers with one
112 PENDING: What if the parameter is a long?
113 Everything is caller saves. i.e. the caller must save any registers
114 that it wants to preserve over the call.
115 GB: The return value is returned in DEHL. DE is normally used as a
116 working register pair. Caller saves allows it to be used for a
118 va args functions do not use register parameters. All arguments
119 are passed on the stack.
120 IX is used as an index register to the top of the local variable
121 area. ix-0 is the top most local variable.
126 /* Set to enable debugging trace statements in the output assembly code. */
130 static char *_z80_return[] =
131 {"l", "h", "e", "d"};
132 static char *_gbz80_return[] =
133 {"e", "d", "l", "h"};
134 static char *_fReceive[] =
135 { "c", "b", "e", "d" };
137 static char **_fReturn;
140 extern FILE *codeOutFile;
148 /** Enum covering all the possible register pairs.
167 } _pairs[NUM_PAIRS] = {
168 { "??1", "?2", "?3" },
173 { "iy", "iyl", "iyh" },
174 { "ix", "ixl", "ixh" }
178 #define ACC_NAME _pairs[PAIR_AF].h
188 /** Code generator persistent data.
192 /** Used to optimised setting up of a pair by remebering what it
193 contains and adjusting instead of reloading where possible.
222 const char *lastFunctionName;
223 iCode *current_iCode;
230 /** TRUE if the registers have already been saved. */
249 static const char *aopGet (asmop * aop, int offset, bool bit16);
251 static const char *aopNames[] = {
272 isLastUse (iCode *ic, operand *op)
274 bitVect *uses = bitVectCopy (OP_USES (op));
276 while (!bitVectIsZero (uses))
278 if (bitVectFirstBit (uses) == ic->key)
280 if (bitVectnBitsOn (uses) == 1)
289 bitVectUnSetBit (uses, bitVectFirstBit (uses));
309 _getTempPairName(void)
311 return _pairs[_getTempPairId()].name;
315 isPairInUse (PAIR_ID id, iCode *ic)
319 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
321 else if (id == PAIR_BC)
323 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
327 wassertl (0, "Only implemented for DE and BC");
333 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
337 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
341 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
345 wassertl (0, "Only implemented for DE");
351 getFreePairId (iCode *ic)
353 if (!isPairInUse (PAIR_BC, ic))
357 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
370 /* Clean up the line so that it is 'prettier' */
371 if (strchr (buf, ':'))
373 /* Is a label - cant do anything */
376 /* Change the first (and probably only) ' ' to a tab so
391 _newLineNode (char *line)
395 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
396 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
402 _vemit2 (const char *szFormat, va_list ap)
404 char buffer[INITIAL_INLINEASM];
406 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
409 _G.lines.current = (_G.lines.current ?
410 connectLine (_G.lines.current, _newLineNode (buffer)) :
411 (_G.lines.head = _newLineNode (buffer)));
413 _G.lines.current->isInline = _G.lines.isInline;
414 _G.lines.current->isDebug = _G.lines.isDebug;
415 _G.lines.current->ic = _G.current_iCode;
419 emit2 (const char *szFormat,...)
423 va_start (ap, szFormat);
425 _vemit2 (szFormat, ap);
431 emitDebug (const char *szFormat,...)
437 va_start (ap, szFormat);
439 _vemit2 (szFormat, ap);
445 /*-----------------------------------------------------------------*/
446 /* z80_emitDebuggerSymbol - associate the current code location */
447 /* with a debugger symbol */
448 /*-----------------------------------------------------------------*/
450 z80_emitDebuggerSymbol (char * debugSym)
452 _G.lines.isDebug = 1;
453 emit2 ("%s !equ .", debugSym);
454 emit2 ("!global", debugSym);
455 _G.lines.isDebug = 0;
458 /*-----------------------------------------------------------------*/
459 /* emit2 - writes the code into a file : for now it is simple */
460 /*-----------------------------------------------------------------*/
462 _emit2 (const char *inst, const char *fmt,...)
465 char lb[INITIAL_INLINEASM];
472 sprintf (lb, "%s\t", inst);
473 vsprintf (lb + (strlen (lb)), fmt, ap);
476 vsprintf (lb, fmt, ap);
478 while (isspace (*lbp))
483 _G.lines.current = (_G.lines.current ?
484 connectLine (_G.lines.current, _newLineNode (lb)) :
485 (_G.lines.head = _newLineNode (lb)));
487 _G.lines.current->isInline = _G.lines.isInline;
488 _G.lines.current->ic = _G.current_iCode;
493 _emitMove(const char *to, const char *from)
495 if (STRCASECMP(to, from) != 0)
497 emit2("ld %s,%s", to, from);
502 // Could leave this to the peephole, but sometimes the peephole is inhibited.
507 aopDump(const char *plabel, asmop *aop)
513 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
518 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
521 for (i=aop->size-1;i>=0;i--)
522 *rbp++ = *(aop->aopu.aop_reg[i]->name);
524 emitDebug("; reg = %s", regbuf);
527 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
530 /* No information. */
536 _moveA(const char *moveFrom)
538 // Let the peephole optimiser take care of redundent loads
539 _emitMove(ACC_NAME, moveFrom);
549 getPairName (asmop * aop)
551 if (aop->type == AOP_REG)
553 switch (aop->aopu.aop_reg[0]->rIdx)
566 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
569 for (i = 0; i < NUM_PAIRS; i++)
571 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
573 return _pairs[i].name;
577 wassertl (0, "Tried to get the pair name of something that isn't a pair");
582 getPairId (asmop * aop)
586 if (aop->type == AOP_REG)
588 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
592 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
596 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
601 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
604 for (i = 0; i < NUM_PAIRS; i++)
606 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
616 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
620 return (getPairId (aop) != PAIR_INVALID);
623 /** Returns TRUE if the registers used in aop cannot be split into high
626 isUnsplitable (asmop * aop)
628 switch (getPairId (aop))
640 isPtrPair (asmop * aop)
642 PAIR_ID pairId = getPairId (aop);
655 spillPair (PAIR_ID pairId)
657 _G.pairs[pairId].last_type = AOP_INVALID;
658 _G.pairs[pairId].base = NULL;
661 /* Given a register name, spill the pair (if any) the register is part of */
663 spillPairReg (const char *regname)
665 if (strlen(regname)==1)
685 /** Push a register pair onto the stack */
687 genPairPush (asmop * aop)
689 emit2 ("push %s", getPairName (aop));
693 _push (PAIR_ID pairId)
695 emit2 ("push %s", _pairs[pairId].name);
696 _G.stack.pushed += 2;
700 _pop (PAIR_ID pairId)
702 emit2 ("pop %s", _pairs[pairId].name);
703 _G.stack.pushed -= 2;
708 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
721 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
728 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
729 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
732 wassertl (0, "Tried to move a nonphysical pair");
734 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
735 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
736 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
740 /*-----------------------------------------------------------------*/
741 /* newAsmop - creates a new asmOp */
742 /*-----------------------------------------------------------------*/
744 newAsmop (short type)
748 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
753 /*-----------------------------------------------------------------*/
754 /* aopForSym - for a true symbol */
755 /*-----------------------------------------------------------------*/
757 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
764 wassert (sym->etype);
766 space = SPEC_OCLS (sym->etype);
768 /* if already has one */
774 /* Assign depending on the storage class */
775 if (sym->onStack || sym->iaccess)
777 /* The pointer that is used depends on how big the offset is.
778 Normally everything is AOP_STK, but for offsets of < -128 or
779 > 127 on the Z80 an extended stack pointer is used.
781 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
783 emitDebug ("; AOP_EXSTK for %s", sym->rname);
784 sym->aop = aop = newAsmop (AOP_EXSTK);
788 emitDebug ("; AOP_STK for %s", sym->rname);
789 sym->aop = aop = newAsmop (AOP_STK);
792 aop->size = getSize (sym->type);
793 aop->aopu.aop_stk = sym->stack;
797 /* special case for a function */
798 if (IS_FUNC (sym->type))
800 sym->aop = aop = newAsmop (AOP_IMMD);
801 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
806 if( IN_REGSP( space ))
807 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
810 /* if it is in direct space */
813 sym->aop = aop = newAsmop (AOP_SFR);
814 aop->aopu.aop_dir = sym->rname;
815 aop->size = getSize (sym->type);
816 emitDebug ("; AOP_SFR for %s", sym->rname);
821 { /*.p.t.20030716 adding SFR support to the Z80 port */
822 aop = newAsmop (AOP_SFR);
824 aop->aopu.aop_dir = sym->rname;
825 aop->size = getSize( sym->type );
826 aop->paged = FUNC_REGBANK(sym->type);
827 aop->bcInUse = isPairInUse( PAIR_BC, ic );
828 aop->deInUse = isPairInUse( PAIR_DE, ic );
829 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
835 /* only remaining is far space */
836 /* in which case DPTR gets the address */
839 emitDebug ("; AOP_HL for %s", sym->rname);
840 sym->aop = aop = newAsmop (AOP_HL);
844 sym->aop = aop = newAsmop (AOP_IY);
846 aop->size = getSize (sym->type);
847 aop->aopu.aop_dir = sym->rname;
849 /* if it is in code space */
850 if (IN_CODESPACE (space))
856 /*-----------------------------------------------------------------*/
857 /* aopForRemat - rematerialzes an object */
858 /*-----------------------------------------------------------------*/
860 aopForRemat (symbol * sym)
863 iCode *ic = sym->rematiCode;
864 asmop *aop = newAsmop (AOP_IMMD);
868 /* if plus or minus print the right hand side */
869 if (ic->op == '+' || ic->op == '-')
871 /* PENDING: for re-target */
872 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
875 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
878 /* we reached the end */
879 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
883 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
887 /*-----------------------------------------------------------------*/
888 /* regsInCommon - two operands have some registers in common */
889 /*-----------------------------------------------------------------*/
891 regsInCommon (operand * op1, operand * op2)
896 /* if they have registers in common */
897 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
900 sym1 = OP_SYMBOL (op1);
901 sym2 = OP_SYMBOL (op2);
903 if (sym1->nRegs == 0 || sym2->nRegs == 0)
906 for (i = 0; i < sym1->nRegs; i++)
912 for (j = 0; j < sym2->nRegs; j++)
917 if (sym2->regs[j] == sym1->regs[i])
925 /*-----------------------------------------------------------------*/
926 /* operandsEqu - equivalent */
927 /*-----------------------------------------------------------------*/
929 operandsEqu (operand * op1, operand * op2)
933 /* if they not symbols */
934 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
937 sym1 = OP_SYMBOL (op1);
938 sym2 = OP_SYMBOL (op2);
940 /* if both are itemps & one is spilt
941 and the other is not then false */
942 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
943 sym1->isspilt != sym2->isspilt)
946 /* if they are the same */
950 if (strcmp (sym1->rname, sym2->rname) == 0)
954 /* if left is a tmp & right is not */
955 if (IS_ITEMP (op1) &&
958 (sym1->usl.spillLoc == sym2))
961 if (IS_ITEMP (op2) &&
965 (sym2->usl.spillLoc == sym1))
971 /*-----------------------------------------------------------------*/
972 /* sameRegs - two asmops have the same registers */
973 /*-----------------------------------------------------------------*/
975 sameRegs (asmop * aop1, asmop * aop2)
979 if (aop1->type == AOP_SFR ||
980 aop2->type == AOP_SFR)
986 if (aop1->type != AOP_REG ||
987 aop2->type != AOP_REG)
990 if (aop1->size != aop2->size)
993 for (i = 0; i < aop1->size; i++)
994 if (aop1->aopu.aop_reg[i] !=
995 aop2->aopu.aop_reg[i])
1001 /*-----------------------------------------------------------------*/
1002 /* aopOp - allocates an asmop for an operand : */
1003 /*-----------------------------------------------------------------*/
1005 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1014 /* if this a literal */
1015 if (IS_OP_LITERAL (op))
1017 op->aop = aop = newAsmop (AOP_LIT);
1018 aop->aopu.aop_lit = op->operand.valOperand;
1019 aop->size = getSize (operandType (op));
1023 /* if already has a asmop then continue */
1026 if (op->aop->type == AOP_SFR)
1028 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1029 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1034 /* if the underlying symbol has a aop */
1035 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1037 op->aop = OP_SYMBOL (op)->aop;
1038 if (op->aop->type == AOP_SFR)
1040 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1041 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1046 /* if this is a true symbol */
1047 if (IS_TRUE_SYMOP (op))
1049 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1053 /* this is a temporary : this has
1059 e) can be a return use only */
1061 sym = OP_SYMBOL (op);
1063 /* if the type is a conditional */
1064 if (sym->regType == REG_CND)
1066 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1071 /* if it is spilt then two situations
1073 b) has a spill location */
1074 if (sym->isspilt || sym->nRegs == 0)
1076 /* rematerialize it NOW */
1079 sym->aop = op->aop = aop =
1081 aop->size = getSize (sym->type);
1088 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1089 aop->size = getSize (sym->type);
1090 for (i = 0; i < 4; i++)
1091 aop->aopu.aop_str[i] = _fReturn[i];
1097 if (sym->accuse == ACCUSE_A)
1099 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1100 aop->size = getSize (sym->type);
1101 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1103 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1105 else if (sym->accuse == ACCUSE_SCRATCH)
1107 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1108 aop->size = getSize (sym->type);
1109 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1110 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1111 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1113 else if (sym->accuse == ACCUSE_IY)
1115 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1116 aop->size = getSize (sym->type);
1117 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1118 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1119 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1123 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1128 if (sym->usl.spillLoc)
1130 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1132 /* force a new aop if sizes differ */
1133 sym->usl.spillLoc->aop = NULL;
1135 sym->aop = op->aop = aop =
1136 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1137 aop->size = getSize (sym->type);
1141 /* else must be a dummy iTemp */
1142 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1143 aop->size = getSize (sym->type);
1147 /* must be in a register */
1148 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1149 aop->size = sym->nRegs;
1150 for (i = 0; i < sym->nRegs; i++)
1151 aop->aopu.aop_reg[i] = sym->regs[i];
1154 /*-----------------------------------------------------------------*/
1155 /* freeAsmop - free up the asmop given to an operand */
1156 /*----------------------------------------------------------------*/
1158 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1175 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1177 _pop (aop->aopu.aop_pairId);
1180 if (getPairId (aop) == PAIR_HL)
1182 spillPair (PAIR_HL);
1186 /* all other cases just dealloc */
1192 OP_SYMBOL (op)->aop = NULL;
1193 /* if the symbol has a spill */
1195 SPIL_LOC (op)->aop = NULL;
1202 isLitWord (asmop * aop)
1204 /* if (aop->size != 2)
1217 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1219 /* depending on type */
1225 /* PENDING: for re-target */
1228 tsprintf (buffer, sizeof(buffer),
1229 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1231 else if (offset == 0)
1233 tsprintf (buffer, sizeof(buffer),
1234 "%s", aop->aopu.aop_immd);
1238 tsprintf (buffer, sizeof(buffer),
1239 "%s + %d", aop->aopu.aop_immd, offset);
1241 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1245 value *val = aop->aopu.aop_lit;
1246 /* if it is a float then it gets tricky */
1247 /* otherwise it is fairly simple */
1248 if (!IS_FLOAT (val->type))
1250 unsigned long v = (unsigned long) floatFromVal (val);
1256 else if (offset == 0)
1262 wassertl(0, "Encountered an invalid offset while fetching a literal");
1266 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1268 tsprintf (buffer, sizeof(buffer), "!constword", v);
1270 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1281 /* it is type float */
1282 fl.f = (float) floatFromVal (val);
1284 #ifdef WORDS_BIGENDIAN
1285 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1287 i = fl.c[offset] | (fl.c[offset+1]<<8);
1290 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1292 tsprintf (buffer, sizeof(buffer), "!constword", i);
1294 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1303 aopGetWord (asmop * aop, int offset)
1305 return aopGetLitWordLong (aop, offset, TRUE);
1309 isPtr (const char *s)
1311 if (!strcmp (s, "hl"))
1313 if (!strcmp (s, "ix"))
1315 if (!strcmp (s, "iy"))
1321 adjustPair (const char *pair, int *pold, int new)
1327 emit2 ("inc %s", pair);
1332 emit2 ("dec %s", pair);
1340 spillPair (PAIR_HL);
1341 spillPair (PAIR_IY);
1345 requiresHL (asmop * aop)
1361 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1363 const char *l, *base;
1364 const char *pair = _pairs[pairId].name;
1365 l = aopGetLitWordLong (left, offset, FALSE);
1366 base = aopGetLitWordLong (left, 0, FALSE);
1367 wassert (l && pair && base);
1371 if (pairId == PAIR_HL || pairId == PAIR_IY)
1373 if (_G.pairs[pairId].last_type == left->type)
1375 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1377 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1379 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1382 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1389 _G.pairs[pairId].last_type = left->type;
1390 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1391 _G.pairs[pairId].offset = offset;
1393 /* Both a lit on the right and a true symbol on the left */
1394 emit2 ("ld %s,!hashedstr", pair, l);
1398 makeFreePairId (iCode *ic, bool *pisUsed)
1404 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1408 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1426 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1428 /* if this is remateriazable */
1429 if (isLitWord (aop)) {
1430 fetchLitPair (pairId, aop, offset);
1434 if (getPairId (aop) == pairId)
1438 /* we need to get it byte by byte */
1439 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1440 aopGet (aop, offset, FALSE);
1441 switch (aop->size - offset) {
1443 emit2 ("ld l,!*hl");
1444 emit2 ("ld h,!immedbyte", 0);
1447 // PENDING: Requires that you are only fetching two bytes.
1450 emit2 ("ld h,!*hl");
1454 wassertl (0, "Attempted to fetch too much data into HL");
1458 else if (IS_Z80 && aop->type == AOP_IY) {
1459 /* Instead of fetching relative to IY, just grab directly
1460 from the address IY refers to */
1461 char *l = aopGetLitWordLong (aop, offset, FALSE);
1463 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1465 if (aop->size < 2) {
1466 emit2("ld %s,!zero", _pairs[pairId].h);
1469 else if (pairId == PAIR_IY)
1473 emit2 ("push %s", _pairs[getPairId(aop)].name);
1479 PAIR_ID id = makeFreePairId (ic, &isUsed);
1482 /* Can't load into parts, so load into HL then exchange. */
1483 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1484 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1485 emit2 ("push %s", _pairs[id].name);
1491 else if (isUnsplitable(aop))
1493 emit2("push %s", _pairs[getPairId(aop)].name);
1494 emit2("pop %s", _pairs[pairId].name);
1498 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1499 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1501 /* PENDING: check? */
1502 if (pairId == PAIR_HL)
1503 spillPair (PAIR_HL);
1508 fetchPair (PAIR_ID pairId, asmop * aop)
1510 fetchPairLong (pairId, aop, NULL, 0);
1514 fetchHL (asmop * aop)
1516 fetchPair (PAIR_HL, aop);
1520 setupPairFromSP (PAIR_ID id, int offset)
1522 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1524 if (_G.preserveCarry)
1530 if (offset < INT8MIN || offset > INT8MAX)
1532 emit2 ("ld hl,!immedword", offset);
1533 emit2 ("add hl,sp");
1537 emit2 ("!ldahlsp", offset);
1540 if (_G.preserveCarry)
1548 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1553 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1554 fetchLitPair (pairId, aop, 0);
1558 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1560 fetchLitPair (pairId, aop, offset);
1561 _G.pairs[pairId].offset = offset;
1565 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1566 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1569 int offset = aop->aopu.aop_stk + _G.stack.offset;
1571 if (_G.pairs[pairId].last_type == aop->type &&
1572 _G.pairs[pairId].offset == offset)
1578 /* PENDING: Do this better. */
1579 if (_G.preserveCarry)
1581 sprintf (buffer, "%d", offset + _G.stack.pushed);
1582 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1583 emit2 ("add %s,sp", _pairs[pairId].name);
1584 _G.pairs[pairId].last_type = aop->type;
1585 _G.pairs[pairId].offset = offset;
1586 if (_G.preserveCarry)
1594 /* Doesnt include _G.stack.pushed */
1595 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1597 if (aop->aopu.aop_stk > 0)
1599 abso += _G.stack.param_offset;
1601 assert (pairId == PAIR_HL);
1602 /* In some cases we can still inc or dec hl */
1603 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1605 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1609 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1611 _G.pairs[pairId].offset = abso;
1616 if (pairId != aop->aopu.aop_pairId)
1617 genMovePairPair(aop->aopu.aop_pairId, pairId);
1618 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1624 _G.pairs[pairId].last_type = aop->type;
1630 emit2 ("!tlabeldef", key);
1634 /*-----------------------------------------------------------------*/
1635 /* aopGet - for fetching value of the aop */
1636 /*-----------------------------------------------------------------*/
1638 aopGet (asmop * aop, int offset, bool bit16)
1640 // char *s = buffer;
1642 /* offset is greater than size then zero */
1643 /* PENDING: this seems a bit screwed in some pointer cases. */
1644 if (offset > (aop->size - 1) &&
1645 aop->type != AOP_LIT)
1647 tsprintf (buffer, sizeof(buffer), "!zero");
1648 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1651 /* depending on type */
1655 tsprintf (buffer, sizeof(buffer), "!zero");
1656 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1659 /* PENDING: re-target */
1661 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1666 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1669 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1672 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1675 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1678 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1682 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1683 SNPRINTF (buffer, sizeof(buffer), "a");
1685 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1691 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1692 SNPRINTF (buffer, sizeof(buffer), "a");
1694 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1697 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1700 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1701 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1702 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1704 else if( z80_opts.port_mode == 180 )
1705 { /* z180 in0/out0 mode */
1706 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1710 emit2( "in a,(%s)", aop->aopu.aop_dir );
1713 SNPRINTF (buffer, sizeof(buffer), "a");
1715 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1719 return aop->aopu.aop_reg[offset]->name;
1723 setupPair (PAIR_HL, aop, offset);
1724 tsprintf (buffer, sizeof(buffer), "!*hl");
1726 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1730 setupPair (PAIR_IY, aop, offset);
1731 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1733 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1737 setupPair (PAIR_IY, aop, offset);
1738 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1740 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1745 setupPair (PAIR_HL, aop, offset);
1746 tsprintf (buffer, sizeof(buffer), "!*hl");
1750 if (aop->aopu.aop_stk >= 0)
1751 offset += _G.stack.param_offset;
1752 tsprintf (buffer, sizeof(buffer),
1753 "!*ixx", aop->aopu.aop_stk + offset);
1756 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1759 wassertl (0, "Tried to fetch from a bit variable");
1768 tsprintf(buffer, sizeof(buffer), "!zero");
1769 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1773 wassert (offset < 2);
1774 return aop->aopu.aop_str[offset];
1777 return aopLiteral (aop->aopu.aop_lit, offset);
1781 unsigned long v = aop->aopu.aop_simplelit;
1784 tsprintf (buffer, sizeof(buffer),
1785 "!immedbyte", (unsigned int) v & 0xff);
1787 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1791 return aop->aopu.aop_str[offset];
1794 setupPair (aop->aopu.aop_pairId, aop, offset);
1795 if (aop->aopu.aop_pairId==PAIR_IX)
1796 SNPRINTF (buffer, sizeof(buffer),
1798 else if (aop->aopu.aop_pairId==PAIR_IY)
1799 SNPRINTF (buffer, sizeof(buffer),
1802 SNPRINTF (buffer, sizeof(buffer),
1803 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1805 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1810 wassertl (0, "aopget got unsupported aop->type");
1815 isRegString (const char *s)
1817 if (!strcmp (s, "b") ||
1829 isConstant (const char *s)
1831 /* This is a bit of a hack... */
1832 return (*s == '#' || *s == '$');
1836 canAssignToPtr (const char *s)
1838 if (isRegString (s))
1845 /*-----------------------------------------------------------------*/
1846 /* aopPut - puts a string for a aop */
1847 /*-----------------------------------------------------------------*/
1849 aopPut (asmop * aop, const char *s, int offset)
1853 if (aop->size && offset > (aop->size - 1))
1855 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1856 "aopPut got offset > aop->size");
1861 tsprintf(buffer2, sizeof(buffer2), s);
1864 /* will assign value to value */
1865 /* depending on where it is ofcourse */
1869 _moveA (s); /* in case s is volatile */
1875 if (strcmp (s, "a"))
1876 emit2 ("ld a,%s", s);
1877 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1884 if (strcmp (s, "a"))
1885 emit2 ("ld a,%s", s);
1886 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1889 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1892 if( aop->bcInUse ) emit2( "push bc" );
1894 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1896 if(( s[0] == '#' ) /* immediate number */
1897 ||( s[0] == '(' ) /* indirect register (ix or iy ??)*/
1898 ||( isdigit( s[0] )))/* indirect register with offset (ix or iy ??)*/
1900 emit2( "ld a,%s", s );
1901 emit2( "out (c),a" );
1905 emit2( "out (c),%s", s );
1911 spillPair (PAIR_BC);
1913 else if( z80_opts.port_mode == 180 )
1914 { /* z180 in0/out0 mode */
1915 emit2( "ld a,%s", s );
1916 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1920 emit2( "ld a,%s", s );
1921 emit2( "out (%s),a", aop->aopu.aop_dir );
1927 if (!strcmp (s, "!*hl"))
1928 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1931 aop->aopu.aop_reg[offset]->name, s);
1932 spillPairReg(aop->aopu.aop_reg[offset]->name);
1937 if (!canAssignToPtr (s))
1939 emit2 ("ld a,%s", s);
1940 setupPair (PAIR_IY, aop, offset);
1941 emit2 ("ld !*iyx,a", offset);
1945 setupPair (PAIR_IY, aop, offset);
1946 emit2 ("ld !*iyx,%s", offset, s);
1952 /* PENDING: for re-target */
1953 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1955 emit2 ("ld a,!*hl");
1958 setupPair (PAIR_HL, aop, offset);
1960 emit2 ("ld !*hl,%s", s);
1965 if (!canAssignToPtr (s))
1967 emit2 ("ld a,%s", s);
1968 setupPair (PAIR_IY, aop, offset);
1969 emit2 ("ld !*iyx,a", offset);
1973 setupPair (PAIR_IY, aop, offset);
1974 emit2 ("ld !*iyx,%s", offset, s);
1981 /* PENDING: re-target */
1982 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1984 emit2 ("ld a,!*hl");
1987 setupPair (PAIR_HL, aop, offset);
1988 if (!canAssignToPtr (s))
1990 emit2 ("ld a,%s", s);
1991 emit2 ("ld !*hl,a");
1994 emit2 ("ld !*hl,%s", s);
1998 if (aop->aopu.aop_stk >= 0)
1999 offset += _G.stack.param_offset;
2000 if (!canAssignToPtr (s))
2002 emit2 ("ld a,%s", s);
2003 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2007 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2013 /* if bit variable */
2014 if (!aop->aopu.aop_dir)
2016 emit2 ("ld a,!zero");
2021 /* In bit space but not in C - cant happen */
2022 wassertl (0, "Tried to write into a bit variable");
2028 if (strcmp (aop->aopu.aop_str[offset], s))
2030 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2032 spillPairReg(aop->aopu.aop_str[offset]);
2037 if (!offset && (strcmp (s, "acc") == 0))
2041 wassertl (0, "Tried to access past the end of A");
2045 if (strcmp (aop->aopu.aop_str[offset], s))
2047 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2048 spillPairReg(aop->aopu.aop_str[offset]);
2054 wassert (offset < 2);
2055 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2056 spillPairReg(aop->aopu.aop_str[offset]);
2060 setupPair (aop->aopu.aop_pairId, aop, offset);
2061 if (aop->aopu.aop_pairId==PAIR_IX)
2062 emit2 ("ld !*ixx,%s", 0, s);
2063 else if (aop->aopu.aop_pairId==PAIR_IY)
2064 emit2 ("ld !*ixy,%s", 0, s);
2066 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2070 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2071 "aopPut got unsupported aop->type");
2076 #define AOP(op) op->aop
2077 #define AOP_TYPE(op) AOP(op)->type
2078 #define AOP_SIZE(op) AOP(op)->size
2079 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2082 commitPair (asmop * aop, PAIR_ID id)
2084 /* PENDING: Verify this. */
2085 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2089 aopPut (aop, "a", 0);
2090 aopPut (aop, "d", 1);
2095 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2097 char *l = aopGetLitWordLong (aop, 0, FALSE);
2100 emit2 ("ld (%s),%s", l, _pairs[id].name);
2104 aopPut (aop, _pairs[id].l, 0);
2105 aopPut (aop, _pairs[id].h, 1);
2110 /*-----------------------------------------------------------------*/
2111 /* getDataSize - get the operand data size */
2112 /*-----------------------------------------------------------------*/
2114 getDataSize (operand * op)
2117 size = AOP_SIZE (op);
2121 wassertl (0, "Somehow got a three byte data pointer");
2126 /*-----------------------------------------------------------------*/
2127 /* movLeft2Result - move byte from left to result */
2128 /*-----------------------------------------------------------------*/
2130 movLeft2Result (operand * left, int offl,
2131 operand * result, int offr, int sign)
2135 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2137 l = aopGet (AOP (left), offl, FALSE);
2141 aopPut (AOP (result), l, offr);
2145 if (getDataSize (left) == offl + 1)
2147 emit2 ("ld a,%s", l);
2148 aopPut (AOP (result), "a", offr);
2155 movLeft2ResultLong (operand * left, int offl,
2156 operand * result, int offr, int sign,
2161 movLeft2Result (left, offl, result, offr, sign);
2165 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2166 wassertl (size == 2, "Only implemented for two bytes or one");
2168 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2170 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2171 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2173 spillPair (PAIR_HL);
2175 else if ( getPairId ( AOP (result)) == PAIR_IY)
2177 PAIR_ID id = getPairId (AOP (left));
2178 if (id != PAIR_INVALID)
2180 emit2("push %s", _pairs[id].name);
2191 movLeft2Result (left, offl, result, offr, sign);
2192 movLeft2Result (left, offl+1, result, offr+1, sign);
2197 /** Put Acc into a register set
2200 outAcc (operand * result)
2203 size = getDataSize (result);
2206 aopPut (AOP (result), "a", 0);
2209 /* unsigned or positive */
2212 aopPut (AOP (result), "!zero", offset++);
2217 /** Take the value in carry and put it into a register
2220 outBitCLong (operand * result, bool swap_sense)
2222 /* if the result is bit */
2223 if (AOP_TYPE (result) == AOP_CRY)
2225 wassertl (0, "Tried to write carry to a bit");
2229 emit2 ("ld a,!zero");
2232 emit2 ("xor a,!immedbyte", 1);
2238 outBitC (operand * result)
2240 outBitCLong (result, FALSE);
2243 /*-----------------------------------------------------------------*/
2244 /* toBoolean - emit code for orl a,operator(sizeop) */
2245 /*-----------------------------------------------------------------*/
2247 _toBoolean (operand * oper)
2249 int size = AOP_SIZE (oper);
2253 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2256 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2260 if (AOP (oper)->type != AOP_ACC)
2263 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2269 /*-----------------------------------------------------------------*/
2270 /* genNot - generate code for ! operation */
2271 /*-----------------------------------------------------------------*/
2276 /* assign asmOps to operand & result */
2277 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2278 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2280 /* if in bit space then a special case */
2281 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2283 wassertl (0, "Tried to negate a bit");
2286 _toBoolean (IC_LEFT (ic));
2291 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2292 emit2 ("sub a,!one");
2293 outBitC (IC_RESULT (ic));
2295 /* release the aops */
2296 freeAsmop (IC_LEFT (ic), NULL, ic);
2297 freeAsmop (IC_RESULT (ic), NULL, ic);
2300 /*-----------------------------------------------------------------*/
2301 /* genCpl - generate code for complement */
2302 /*-----------------------------------------------------------------*/
2310 /* assign asmOps to operand & result */
2311 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2312 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2314 /* if both are in bit space then
2316 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2317 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2319 wassertl (0, "Left and the result are in bit space");
2322 size = AOP_SIZE (IC_RESULT (ic));
2325 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2328 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2331 /* release the aops */
2332 freeAsmop (IC_LEFT (ic), NULL, ic);
2333 freeAsmop (IC_RESULT (ic), NULL, ic);
2337 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2344 store de into result
2349 store de into result
2351 const char *first = isAdd ? "add" : "sub";
2352 const char *later = isAdd ? "adc" : "sbc";
2354 wassertl (IS_GB, "Code is only relevent to the gbz80");
2355 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2357 fetchPair (PAIR_DE, left);
2360 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2363 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2366 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2367 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2369 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2370 aopGet (right, MSB24, FALSE);
2374 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2377 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2379 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2380 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2384 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2386 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2389 /*-----------------------------------------------------------------*/
2390 /* genUminusFloat - unary minus for floating points */
2391 /*-----------------------------------------------------------------*/
2393 genUminusFloat (operand * op, operand * result)
2395 int size, offset = 0;
2397 emitDebug("; genUminusFloat");
2399 /* for this we just need to flip the
2400 first it then copy the rest in place */
2401 size = AOP_SIZE (op) - 1;
2403 _moveA(aopGet (AOP (op), MSB32, FALSE));
2405 emit2("xor a,!immedbyte", 0x80);
2406 aopPut (AOP (result), "a", MSB32);
2410 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2415 /*-----------------------------------------------------------------*/
2416 /* genUminus - unary minus code generation */
2417 /*-----------------------------------------------------------------*/
2419 genUminus (iCode * ic)
2422 sym_link *optype, *rtype;
2425 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2426 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2428 /* if both in bit space then special
2430 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2431 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2433 wassertl (0, "Left and right are in bit space");
2437 optype = operandType (IC_LEFT (ic));
2438 rtype = operandType (IC_RESULT (ic));
2440 /* if float then do float stuff */
2441 if (IS_FLOAT (optype))
2443 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2447 /* otherwise subtract from zero */
2448 size = AOP_SIZE (IC_LEFT (ic));
2450 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2452 /* Create a new asmop with value zero */
2453 asmop *azero = newAsmop (AOP_SIMPLELIT);
2454 azero->aopu.aop_simplelit = 0;
2456 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2464 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2465 emit2 ("ld a,!zero");
2466 emit2 ("sbc a,%s", l);
2467 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2470 /* if any remaining bytes in the result */
2471 /* we just need to propagate the sign */
2472 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2477 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2481 /* release the aops */
2482 freeAsmop (IC_LEFT (ic), NULL, ic);
2483 freeAsmop (IC_RESULT (ic), NULL, ic);
2486 /*-----------------------------------------------------------------*/
2487 /* assignResultValue - */
2488 /*-----------------------------------------------------------------*/
2490 assignResultValue (operand * oper)
2492 int size = AOP_SIZE (oper);
2495 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2496 topInA = requiresHL (AOP (oper));
2498 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2500 /* We do it the hard way here. */
2502 aopPut (AOP (oper), _fReturn[0], 0);
2503 aopPut (AOP (oper), _fReturn[1], 1);
2505 aopPut (AOP (oper), _fReturn[0], 2);
2506 aopPut (AOP (oper), _fReturn[1], 3);
2512 aopPut (AOP (oper), _fReturn[size], size);
2517 /** Simple restore that doesn't take into account what is used in the
2521 _restoreRegsAfterCall(void)
2523 if (_G.stack.pushedDE)
2526 _G.stack.pushedDE = FALSE;
2528 if (_G.stack.pushedBC)
2531 _G.stack.pushedBC = FALSE;
2533 _G.saves.saved = FALSE;
2537 _saveRegsForCall(iCode *ic, int sendSetSize)
2540 o Stack parameters are pushed before this function enters
2541 o DE and BC may be used in this function.
2542 o HL and DE may be used to return the result.
2543 o HL and DE may be used to send variables.
2544 o DE and BC may be used to store the result value.
2545 o HL may be used in computing the sent value of DE
2546 o The iPushes for other parameters occur before any addSets
2548 Logic: (to be run inside the first iPush or if none, before sending)
2549 o Compute if DE and/or BC are in use over the call
2550 o Compute if DE is used in the send set
2551 o Compute if DE and/or BC are used to hold the result value
2552 o If (DE is used, or in the send set) and is not used in the result, push.
2553 o If BC is used and is not in the result, push
2555 o If DE is used in the send set, fetch
2556 o If HL is used in the send set, fetch
2560 if (_G.saves.saved == FALSE) {
2561 bool deInUse, bcInUse;
2563 bool bcInRet = FALSE, deInRet = FALSE;
2566 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2567 z80_rUmaskForOp (IC_RESULT(ic)));
2569 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2570 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2572 deSending = (sendSetSize > 1);
2574 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2576 if (bcInUse && bcInRet == FALSE) {
2578 _G.stack.pushedBC = TRUE;
2580 if (deInUse && deInRet == FALSE) {
2582 _G.stack.pushedDE = TRUE;
2585 _G.saves.saved = TRUE;
2588 /* Already saved. */
2592 /*-----------------------------------------------------------------*/
2593 /* genIpush - genrate code for pushing this gets a little complex */
2594 /*-----------------------------------------------------------------*/
2596 genIpush (iCode * ic)
2598 int size, offset = 0;
2601 /* if this is not a parm push : ie. it is spill push
2602 and spill push is always done on the local stack */
2605 wassertl(0, "Encountered an unsupported spill push.");
2609 if (_G.saves.saved == FALSE) {
2610 /* Caller saves, and this is the first iPush. */
2611 /* Scan ahead until we find the function that we are pushing parameters to.
2612 Count the number of addSets on the way to figure out what registers
2613 are used in the send set.
2616 iCode *walk = ic->next;
2619 if (walk->op == SEND) {
2622 else if (walk->op == CALL || walk->op == PCALL) {
2631 _saveRegsForCall(walk, nAddSets);
2634 /* Already saved by another iPush. */
2637 /* then do the push */
2638 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2640 size = AOP_SIZE (IC_LEFT (ic));
2642 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2644 _G.stack.pushed += 2;
2645 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2651 fetchHL (AOP (IC_LEFT (ic)));
2653 spillPair (PAIR_HL);
2654 _G.stack.pushed += 2;
2659 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2661 spillPair (PAIR_HL);
2662 _G.stack.pushed += 2;
2663 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2665 spillPair (PAIR_HL);
2666 _G.stack.pushed += 2;
2672 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2674 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2676 emit2 ("ld a,(%s)", l);
2680 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2681 emit2 ("ld a,%s", l);
2689 freeAsmop (IC_LEFT (ic), NULL, ic);
2692 /*-----------------------------------------------------------------*/
2693 /* genIpop - recover the registers: can happen only for spilling */
2694 /*-----------------------------------------------------------------*/
2696 genIpop (iCode * ic)
2701 /* if the temp was not pushed then */
2702 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2705 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2706 size = AOP_SIZE (IC_LEFT (ic));
2707 offset = (size - 1);
2708 if (isPair (AOP (IC_LEFT (ic))))
2710 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2718 spillPair (PAIR_HL);
2719 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2723 freeAsmop (IC_LEFT (ic), NULL, ic);
2726 /* This is quite unfortunate */
2728 setArea (int inHome)
2731 static int lastArea = 0;
2733 if (_G.in_home != inHome) {
2735 const char *sz = port->mem.code_name;
2736 port->mem.code_name = "HOME";
2737 emit2("!area", CODE_NAME);
2738 port->mem.code_name = sz;
2741 emit2("!area", CODE_NAME); */
2742 _G.in_home = inHome;
2753 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2757 symbol *sym = OP_SYMBOL (op);
2759 if (sym->isspilt || sym->nRegs == 0)
2762 aopOp (op, ic, FALSE, FALSE);
2765 if (aop->type == AOP_REG)
2768 for (i = 0; i < aop->size; i++)
2770 if (pairId == PAIR_DE)
2772 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2773 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2775 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2778 else if (pairId == PAIR_BC)
2780 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2781 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2783 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2793 freeAsmop (IC_LEFT (ic), NULL, ic);
2797 /** Emit the code for a call statement
2800 emitCall (iCode * ic, bool ispcall)
2802 bool bInRet, cInRet, dInRet, eInRet;
2803 sym_link *dtype = operandType (IC_LEFT (ic));
2805 /* if caller saves & we have not saved then */
2811 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2813 /* if send set is not empty then assign */
2818 int nSend = elementsInSet(_G.sendSet);
2819 bool swapped = FALSE;
2821 int _z80_sendOrder[] = {
2826 /* Check if the parameters are swapped. If so route through hl instead. */
2827 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2829 sic = setFirstItem(_G.sendSet);
2830 sic = setNextItem(_G.sendSet);
2832 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2833 /* The second send value is loaded from one the one that holds the first
2834 send, i.e. it is overwritten. */
2835 /* Cache the first in HL, and load the second from HL instead. */
2836 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2837 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2843 for (sic = setFirstItem (_G.sendSet); sic;
2844 sic = setNextItem (_G.sendSet))
2847 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2849 size = AOP_SIZE (IC_LEFT (sic));
2850 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2851 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2853 // PENDING: Mild hack
2854 if (swapped == TRUE && send == 1) {
2856 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2859 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2861 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2864 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2868 freeAsmop (IC_LEFT (sic), NULL, sic);
2875 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2877 werror (W_INDIR_BANKED);
2879 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2881 if (isLitWord (AOP (IC_LEFT (ic))))
2883 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2887 symbol *rlbl = newiTempLabel (NULL);
2888 spillPair (PAIR_HL);
2889 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2891 _G.stack.pushed += 2;
2893 fetchHL (AOP (IC_LEFT (ic)));
2895 emit2 ("!tlabeldef", (rlbl->key + 100));
2896 _G.stack.pushed -= 2;
2898 freeAsmop (IC_LEFT (ic), NULL, ic);
2902 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2903 OP_SYMBOL (IC_LEFT (ic))->rname :
2904 OP_SYMBOL (IC_LEFT (ic))->name;
2905 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2907 emit2 ("call banked_call");
2908 emit2 ("!dws", name);
2909 emit2 ("!dw !bankimmeds", name);
2914 emit2 ("call %s", name);
2919 /* Mark the regsiters as restored. */
2920 _G.saves.saved = FALSE;
2922 /* if we need assign a result value */
2923 if ((IS_ITEMP (IC_RESULT (ic)) &&
2924 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2925 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2926 IS_TRUE_SYMOP (IC_RESULT (ic)))
2929 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2931 assignResultValue (IC_RESULT (ic));
2933 freeAsmop (IC_RESULT (ic), NULL, ic);
2936 /* adjust the stack for parameters if required */
2939 int i = ic->parmBytes;
2941 _G.stack.pushed -= i;
2944 emit2 ("!ldaspsp", i);
2951 emit2 ("ld iy,!immedword", i);
2952 emit2 ("add iy,sp");
2973 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2974 bInRet = bitVectBitValue(result, B_IDX);
2975 cInRet = bitVectBitValue(result, C_IDX);
2976 dInRet = bitVectBitValue(result, D_IDX);
2977 eInRet = bitVectBitValue(result, E_IDX);
2987 if (_G.stack.pushedDE)
2989 if (dInRet && eInRet)
2991 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2995 /* Only restore E */
3002 /* Only restore D */
3010 _G.stack.pushedDE = FALSE;
3013 if (_G.stack.pushedBC)
3015 if (bInRet && cInRet)
3017 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3021 /* Only restore C */
3028 /* Only restore B */
3036 _G.stack.pushedBC = FALSE;
3040 /*-----------------------------------------------------------------*/
3041 /* genCall - generates a call statement */
3042 /*-----------------------------------------------------------------*/
3044 genCall (iCode * ic)
3046 emitCall (ic, FALSE);
3049 /*-----------------------------------------------------------------*/
3050 /* genPcall - generates a call by pointer statement */
3051 /*-----------------------------------------------------------------*/
3053 genPcall (iCode * ic)
3055 emitCall (ic, TRUE);
3058 /*-----------------------------------------------------------------*/
3059 /* resultRemat - result is rematerializable */
3060 /*-----------------------------------------------------------------*/
3062 resultRemat (iCode * ic)
3064 if (SKIP_IC (ic) || ic->op == IFX)
3067 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3069 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3070 if (sym->remat && !POINTER_SET (ic))
3077 extern set *publics;
3079 /*-----------------------------------------------------------------*/
3080 /* genFunction - generated code for function entry */
3081 /*-----------------------------------------------------------------*/
3083 genFunction (iCode * ic)
3087 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3090 bool bcInUse = FALSE;
3091 bool deInUse = FALSE;
3093 setArea (IFFUNC_NONBANKED (sym->type));
3095 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
3098 _G.receiveOffset = 0;
3100 /* Record the last function name for debugging. */
3101 _G.lastFunctionName = sym->rname;
3103 /* Create the function header */
3104 emit2 ("!functionheader", sym->name);
3105 sprintf (buffer, "%s_start", sym->rname);
3106 emit2 ("!labeldef", buffer);
3107 emit2 ("!functionlabeldef", sym->rname);
3109 if (options.profile)
3111 emit2 ("!profileenter");
3114 ftype = operandType (IC_LEFT (ic));
3116 /* if critical function then turn interrupts off */
3117 if (IFFUNC_ISCRITICAL (ftype))
3120 /* if this is an interrupt service routine then save all potentially used registers. */
3121 if (IFFUNC_ISISR (sym->type))
3126 /* PENDING: callee-save etc */
3128 _G.stack.param_offset = 0;
3130 if (z80_opts.calleeSavesBC)
3135 /* Detect which registers are used. */
3136 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3139 for (i = 0; i < sym->regsUsed->size; i++)
3141 if (bitVectBitValue (sym->regsUsed, i))
3155 /* Other systems use DE as a temporary. */
3166 _G.stack.param_offset += 2;
3169 _G.calleeSaves.pushedBC = bcInUse;
3174 _G.stack.param_offset += 2;
3177 _G.calleeSaves.pushedDE = deInUse;
3179 /* adjust the stack for the function */
3180 _G.stack.last = sym->stack;
3183 for (sym = setFirstItem (istack->syms); sym;
3184 sym = setNextItem (istack->syms))
3186 if (sym->_isparm && !IS_REGPARM (sym->etype))
3192 sym = OP_SYMBOL (IC_LEFT (ic));
3194 _G.omitFramePtr = options.ommitFramePtr;
3195 if (IS_Z80 && !stackParm && !sym->stack)
3197 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3198 /* the above !sym->stack condition can be removed. -- EEP */
3200 emit2 ("!ldaspsp", -sym->stack);
3201 _G.omitFramePtr = TRUE;
3203 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3204 emit2 ("!enterxl", sym->stack);
3205 else if (sym->stack)
3206 emit2 ("!enterx", sym->stack);
3207 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3210 _G.stack.offset = sym->stack;
3213 /*-----------------------------------------------------------------*/
3214 /* genEndFunction - generates epilogue for functions */
3215 /*-----------------------------------------------------------------*/
3217 genEndFunction (iCode * ic)
3219 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3221 if (IFFUNC_ISISR (sym->type))
3223 wassertl (0, "Tried to close an interrupt support function");
3227 if (IFFUNC_ISCRITICAL (sym->type))
3230 /* PENDING: calleeSave */
3232 if (IS_Z80 && _G.omitFramePtr)
3234 if (_G.stack.offset)
3235 emit2 ("!ldaspsp", _G.stack.offset);
3237 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3239 emit2 ("!leavexl", _G.stack.offset);
3241 else if (_G.stack.offset)
3243 emit2 ("!leavex", _G.stack.offset);
3245 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3250 if (_G.calleeSaves.pushedDE)
3253 _G.calleeSaves.pushedDE = FALSE;
3256 if (_G.calleeSaves.pushedBC)
3259 _G.calleeSaves.pushedBC = FALSE;
3262 if (options.profile)
3264 emit2 ("!profileexit");
3268 if (options.debug && currFunc)
3270 debugFile->writeEndFunction (currFunc, ic, 1);
3273 /* Both banked and non-banked just ret */
3276 sprintf (buffer, "%s_end", sym->rname);
3277 emit2 ("!labeldef", buffer);
3279 _G.flushStatics = 1;
3280 _G.stack.pushed = 0;
3281 _G.stack.offset = 0;
3284 /*-----------------------------------------------------------------*/
3285 /* genRet - generate code for return statement */
3286 /*-----------------------------------------------------------------*/
3291 /* Errk. This is a hack until I can figure out how
3292 to cause dehl to spill on a call */
3293 int size, offset = 0;
3295 /* if we have no return value then
3296 just generate the "ret" */
3300 /* we have something to return then
3301 move the return value into place */
3302 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3303 size = AOP_SIZE (IC_LEFT (ic));
3305 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3308 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3312 emit2 ("ld de,%s", l);
3316 emit2 ("ld hl,%s", l);
3322 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3326 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3328 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3329 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3335 l = aopGet (AOP (IC_LEFT (ic)), offset,
3337 if (strcmp (_fReturn[offset], l))
3338 emit2 ("ld %s,%s", _fReturn[offset], l);
3343 freeAsmop (IC_LEFT (ic), NULL, ic);
3346 /* generate a jump to the return label
3347 if the next is not the return statement */
3348 if (!(ic->next && ic->next->op == LABEL &&
3349 IC_LABEL (ic->next) == returnLabel))
3351 emit2 ("jp !tlabel", returnLabel->key + 100);
3354 /*-----------------------------------------------------------------*/
3355 /* genLabel - generates a label */
3356 /*-----------------------------------------------------------------*/
3358 genLabel (iCode * ic)
3360 /* special case never generate */
3361 if (IC_LABEL (ic) == entryLabel)
3364 emitLabel (IC_LABEL (ic)->key + 100);
3367 /*-----------------------------------------------------------------*/
3368 /* genGoto - generates a ljmp */
3369 /*-----------------------------------------------------------------*/
3371 genGoto (iCode * ic)
3373 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3376 /*-----------------------------------------------------------------*/
3377 /* genPlusIncr :- does addition with increment if possible */
3378 /*-----------------------------------------------------------------*/
3380 genPlusIncr (iCode * ic)
3382 unsigned int icount;
3383 unsigned int size = getDataSize (IC_RESULT (ic));
3384 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3386 /* will try to generate an increment */
3387 /* if the right side is not a literal
3389 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3392 emitDebug ("; genPlusIncr");
3394 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3396 /* If result is a pair */
3397 if (resultId != PAIR_INVALID)
3399 if (isLitWord (AOP (IC_LEFT (ic))))
3401 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3404 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3406 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3408 PAIR_ID freep = getFreePairId (ic);
3409 if (freep != PAIR_INVALID)
3411 fetchPair (freep, AOP (IC_RIGHT (ic)));
3412 emit2 ("add hl,%s", _pairs[freep].name);
3418 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3419 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3426 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3430 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3434 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3439 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3441 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3442 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3446 /* if the literal value of the right hand side
3447 is greater than 4 then it is not worth it */
3451 /* if increment 16 bits in register */
3452 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3458 symbol *tlbl = NULL;
3459 tlbl = newiTempLabel (NULL);
3462 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3465 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3468 emitLabel (tlbl->key + 100);
3472 /* if the sizes are greater than 1 then we cannot */
3473 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3474 AOP_SIZE (IC_LEFT (ic)) > 1)
3477 /* If the result is in a register then we can load then increment.
3479 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3481 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3484 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3489 /* we can if the aops of the left & result match or
3490 if they are in registers and the registers are the
3492 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3496 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3504 /*-----------------------------------------------------------------*/
3505 /* outBitAcc - output a bit in acc */
3506 /*-----------------------------------------------------------------*/
3508 outBitAcc (operand * result)
3510 symbol *tlbl = newiTempLabel (NULL);
3511 /* if the result is a bit */
3512 if (AOP_TYPE (result) == AOP_CRY)
3514 wassertl (0, "Tried to write A into a bit");
3518 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3519 emit2 ("ld a,!one");
3520 emitLabel (tlbl->key + 100);
3526 couldDestroyCarry (asmop *aop)
3530 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3539 shiftIntoPair (int idx, asmop *aop)
3541 PAIR_ID id = PAIR_INVALID;
3543 wassertl (IS_Z80, "Only implemented for the Z80");
3544 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3556 wassertl (0, "Internal error - hit default case");
3559 emitDebug ("; Shift into pair idx %u", idx);
3563 setupPair (PAIR_HL, aop, 0);
3567 setupPair (PAIR_IY, aop, 0);
3569 emit2 ("pop %s", _pairs[id].name);
3572 aop->type = AOP_PAIRPTR;
3573 aop->aopu.aop_pairId = id;
3574 _G.pairs[id].offset = 0;
3575 _G.pairs[id].last_type = aop->type;
3579 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3581 wassert (left && right);
3585 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3587 shiftIntoPair (0, right);
3588 /* check result again, in case right == result */
3589 if (couldDestroyCarry (result))
3590 shiftIntoPair (1, result);
3592 else if (couldDestroyCarry (right))
3594 if (getPairId (result) == PAIR_HL)
3595 _G.preserveCarry = TRUE;
3597 shiftIntoPair (0, right);
3599 else if (couldDestroyCarry (result))
3601 shiftIntoPair (0, result);
3610 /*-----------------------------------------------------------------*/
3611 /* genPlus - generates code for addition */
3612 /*-----------------------------------------------------------------*/
3614 genPlus (iCode * ic)
3616 int size, offset = 0;
3618 /* special cases :- */
3620 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3621 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3622 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3624 /* Swap the left and right operands if:
3626 if literal, literal on the right or
3627 if left requires ACC or right is already
3630 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3631 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3632 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3634 operand *t = IC_RIGHT (ic);
3635 IC_RIGHT (ic) = IC_LEFT (ic);
3639 /* if both left & right are in bit
3641 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3642 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3645 wassertl (0, "Tried to add two bits");
3648 /* if left in bit space & right literal */
3649 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3650 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3652 /* Can happen I guess */
3653 wassertl (0, "Tried to add a bit to a literal");
3656 /* if I can do an increment instead
3657 of add then GOOD for ME */
3658 if (genPlusIncr (ic) == TRUE)
3661 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3663 size = getDataSize (IC_RESULT (ic));
3665 /* Special case when left and right are constant */
3666 if (isPair (AOP (IC_RESULT (ic))))
3669 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3670 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3672 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3678 sprintf (buffer, "#(%s + %s)", left, right);
3679 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3684 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3686 /* Fetch into HL then do the add */
3687 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3688 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3690 spillPair (PAIR_HL);
3692 if (left == PAIR_HL && right != PAIR_INVALID)
3694 emit2 ("add hl,%s", _pairs[right].name);
3697 else if (right == PAIR_HL && left != PAIR_INVALID)
3699 emit2 ("add hl,%s", _pairs[left].name);
3702 else if (right != PAIR_INVALID && right != PAIR_HL)
3704 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3705 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3708 else if (left != PAIR_INVALID && left != PAIR_HL)
3710 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3711 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3720 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3722 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3723 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3725 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3730 ld hl,sp+n trashes C so we cant afford to do it during an
3731 add with stack based varibles. Worst case is:
3744 So you cant afford to load up hl if either left, right, or result
3745 is on the stack (*sigh*) The alt is:
3753 Combinations in here are:
3754 * If left or right are in bc then the loss is small - trap later
3755 * If the result is in bc then the loss is also small
3759 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3760 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3761 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3763 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3764 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3765 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3766 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3768 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3770 /* Swap left and right */
3771 operand *t = IC_RIGHT (ic);
3772 IC_RIGHT (ic) = IC_LEFT (ic);
3775 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3777 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3778 emit2 ("add hl,bc");
3782 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3783 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3784 emit2 ("add hl,de");
3786 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3792 /* Be paranoid on the GB with 4 byte variables due to how C
3793 can be trashed by lda hl,n(sp).
3795 _gbz80_emitAddSubLong (ic, TRUE);
3800 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3804 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3806 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3809 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3812 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3816 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3819 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3822 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3824 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3828 _G.preserveCarry = FALSE;
3829 freeAsmop (IC_LEFT (ic), NULL, ic);
3830 freeAsmop (IC_RIGHT (ic), NULL, ic);
3831 freeAsmop (IC_RESULT (ic), NULL, ic);
3835 /*-----------------------------------------------------------------*/
3836 /* genMinusDec :- does subtraction with deccrement if possible */
3837 /*-----------------------------------------------------------------*/
3839 genMinusDec (iCode * ic)
3841 unsigned int icount;
3842 unsigned int size = getDataSize (IC_RESULT (ic));
3844 /* will try to generate an increment */
3845 /* if the right side is not a literal we cannot */
3846 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3849 /* if the literal value of the right hand side
3850 is greater than 4 then it is not worth it */
3851 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3854 size = getDataSize (IC_RESULT (ic));
3856 /* if decrement 16 bits in register */
3857 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3858 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3861 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3865 /* If result is a pair */
3866 if (isPair (AOP (IC_RESULT (ic))))
3868 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3870 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3874 /* if increment 16 bits in register */
3875 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3879 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3882 emit2 ("dec %s", _getTempPairName());
3885 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3891 /* if the sizes are greater than 1 then we cannot */
3892 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3893 AOP_SIZE (IC_LEFT (ic)) > 1)
3896 /* we can if the aops of the left & result match or if they are in
3897 registers and the registers are the same */
3898 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3901 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3908 /*-----------------------------------------------------------------*/
3909 /* genMinus - generates code for subtraction */
3910 /*-----------------------------------------------------------------*/
3912 genMinus (iCode * ic)
3914 int size, offset = 0;
3915 unsigned long lit = 0L;
3917 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3918 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3919 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3921 /* special cases :- */
3922 /* if both left & right are in bit space */
3923 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3924 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3926 wassertl (0, "Tried to subtract two bits");
3930 /* if I can do an decrement instead of subtract then GOOD for ME */
3931 if (genMinusDec (ic) == TRUE)
3934 size = getDataSize (IC_RESULT (ic));
3936 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3941 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3945 /* Same logic as genPlus */
3948 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3949 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3950 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3952 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3953 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3954 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3955 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3957 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3958 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3960 if (left == PAIR_INVALID && right == PAIR_INVALID)
3965 else if (right == PAIR_INVALID)
3967 else if (left == PAIR_INVALID)
3970 fetchPair (left, AOP (IC_LEFT (ic)));
3971 /* Order is important. Right may be HL */
3972 fetchPair (right, AOP (IC_RIGHT (ic)));
3974 emit2 ("ld a,%s", _pairs[left].l);
3975 emit2 ("sub a,%s", _pairs[right].l);
3977 emit2 ("ld a,%s", _pairs[left].h);
3978 emit2 ("sbc a,%s", _pairs[right].h);
3980 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3982 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3984 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3990 /* Be paranoid on the GB with 4 byte variables due to how C
3991 can be trashed by lda hl,n(sp).
3993 _gbz80_emitAddSubLong (ic, FALSE);
3998 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
4000 /* if literal, add a,#-lit, else normal subb */
4003 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4004 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4008 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4011 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4015 /* first add without previous c */
4017 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4019 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4021 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4024 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4025 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4026 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4028 wassertl (0, "Tried to subtract on a long pointer");
4032 _G.preserveCarry = FALSE;
4033 freeAsmop (IC_LEFT (ic), NULL, ic);
4034 freeAsmop (IC_RIGHT (ic), NULL, ic);
4035 freeAsmop (IC_RESULT (ic), NULL, ic);
4038 /*-----------------------------------------------------------------*/
4039 /* genMult - generates code for multiplication */
4040 /*-----------------------------------------------------------------*/
4042 genMult (iCode * ic)
4046 /* If true then the final operation should be a subtract */
4047 bool active = FALSE;
4050 /* Shouldn't occur - all done through function calls */
4051 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4052 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4053 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4055 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4057 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4058 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4059 AOP_SIZE (IC_RESULT (ic)) > 2)
4061 wassertl (0, "Multiplication is handled through support function calls");
4064 /* Swap left and right such that right is a literal */
4065 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4067 operand *t = IC_RIGHT (ic);
4068 IC_RIGHT (ic) = IC_LEFT (ic);
4072 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4074 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4075 // wassertl (val > 0, "Multiply must be positive");
4076 wassertl (val != 1, "Can't multiply by 1");
4078 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4080 _G.stack.pushedDE = TRUE;
4083 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4085 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4096 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4101 /* Fully unroled version of mul.s. Not the most efficient.
4103 for (count = 0; count < 16; count++)
4105 if (count != 0 && active)
4107 emit2 ("add hl,hl");
4111 if (active == FALSE)
4119 emit2 ("add hl,de");
4128 if (IS_Z80 && _G.stack.pushedDE)
4131 _G.stack.pushedDE = FALSE;
4135 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4137 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4139 freeAsmop (IC_LEFT (ic), NULL, ic);
4140 freeAsmop (IC_RIGHT (ic), NULL, ic);
4141 freeAsmop (IC_RESULT (ic), NULL, ic);
4144 /*-----------------------------------------------------------------*/
4145 /* genDiv - generates code for division */
4146 /*-----------------------------------------------------------------*/
4150 /* Shouldn't occur - all done through function calls */
4151 wassertl (0, "Division is handled through support function calls");
4154 /*-----------------------------------------------------------------*/
4155 /* genMod - generates code for division */
4156 /*-----------------------------------------------------------------*/
4160 /* Shouldn't occur - all done through function calls */
4164 /*-----------------------------------------------------------------*/
4165 /* genIfxJump :- will create a jump depending on the ifx */
4166 /*-----------------------------------------------------------------*/
4168 genIfxJump (iCode * ic, char *jval)
4173 /* if true label then we jump if condition
4177 jlbl = IC_TRUE (ic);
4178 if (!strcmp (jval, "a"))
4182 else if (!strcmp (jval, "c"))
4186 else if (!strcmp (jval, "nc"))
4190 else if (!strcmp (jval, "m"))
4194 else if (!strcmp (jval, "p"))
4200 /* The buffer contains the bit on A that we should test */
4206 /* false label is present */
4207 jlbl = IC_FALSE (ic);
4208 if (!strcmp (jval, "a"))
4212 else if (!strcmp (jval, "c"))
4216 else if (!strcmp (jval, "nc"))
4220 else if (!strcmp (jval, "m"))
4224 else if (!strcmp (jval, "p"))
4230 /* The buffer contains the bit on A that we should test */
4234 /* Z80 can do a conditional long jump */
4235 if (!strcmp (jval, "a"))
4239 else if (!strcmp (jval, "c"))
4242 else if (!strcmp (jval, "nc"))
4245 else if (!strcmp (jval, "m"))
4248 else if (!strcmp (jval, "p"))
4253 emit2 ("bit %s,a", jval);
4255 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4257 /* mark the icode as generated */
4263 _getPairIdName (PAIR_ID id)
4265 return _pairs[id].name;
4270 /* if unsigned char cmp with lit, just compare */
4272 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4274 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4277 emit2 ("xor a,!immedbyte", 0x80);
4278 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4281 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4283 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4285 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4286 // Pull left into DE and right into HL
4287 aopGet (AOP(left), LSB, FALSE);
4290 aopGet (AOP(right), LSB, FALSE);
4294 if (size == 0 && sign)
4296 // Highest byte when signed needs the bits flipped
4299 emit2 ("ld a,(de)");
4300 emit2 ("xor !immedbyte", 0x80);
4302 emit2 ("ld a,(hl)");
4303 emit2 ("xor !immedbyte", 0x80);
4307 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4311 emit2 ("ld a,(de)");
4312 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4322 spillPair (PAIR_HL);
4324 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4326 setupPair (PAIR_HL, AOP (left), 0);
4327 aopGet (AOP(right), LSB, FALSE);
4331 if (size == 0 && sign)
4333 // Highest byte when signed needs the bits flipped
4336 emit2 ("ld a,(hl)");
4337 emit2 ("xor !immedbyte", 0x80);
4339 emit2 ("ld a,%d(iy)", offset);
4340 emit2 ("xor !immedbyte", 0x80);
4344 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4348 emit2 ("ld a,(hl)");
4349 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4358 spillPair (PAIR_HL);
4359 spillPair (PAIR_IY);
4363 if (AOP_TYPE (right) == AOP_LIT)
4365 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4366 /* optimize if(x < 0) or if(x >= 0) */
4371 /* No sign so it's always false */
4376 /* Just load in the top most bit */
4377 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4378 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4380 genIfxJump (ifx, "7");
4392 /* First setup h and l contaning the top most bytes XORed */
4393 bool fDidXor = FALSE;
4394 if (AOP_TYPE (left) == AOP_LIT)
4396 unsigned long lit = (unsigned long)
4397 floatFromVal (AOP (left)->aopu.aop_lit);
4398 emit2 ("ld %s,!immedbyte", _fTmp[0],
4399 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4403 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4404 emit2 ("xor a,!immedbyte", 0x80);
4405 emit2 ("ld %s,a", _fTmp[0]);
4408 if (AOP_TYPE (right) == AOP_LIT)
4410 unsigned long lit = (unsigned long)
4411 floatFromVal (AOP (right)->aopu.aop_lit);
4412 emit2 ("ld %s,!immedbyte", _fTmp[1],
4413 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4417 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4418 emit2 ("xor a,!immedbyte", 0x80);
4419 emit2 ("ld %s,a", _fTmp[1]);
4425 /* Do a long subtract */
4428 _moveA (aopGet (AOP (left), offset, FALSE));
4430 if (sign && size == 0)
4432 emit2 ("ld a,%s", _fTmp[0]);
4433 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4437 /* Subtract through, propagating the carry */
4438 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4446 /** Generic compare for > or <
4449 genCmp (operand * left, operand * right,
4450 operand * result, iCode * ifx, int sign)
4452 int size, offset = 0;
4453 unsigned long lit = 0L;
4454 bool swap_sense = FALSE;
4456 /* if left & right are bit variables */
4457 if (AOP_TYPE (left) == AOP_CRY &&
4458 AOP_TYPE (right) == AOP_CRY)
4460 /* Cant happen on the Z80 */
4461 wassertl (0, "Tried to compare two bits");
4465 /* Do a long subtract of right from left. */
4466 size = max (AOP_SIZE (left), AOP_SIZE (right));
4468 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4470 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4471 // Pull left into DE and right into HL
4472 aopGet (AOP(left), LSB, FALSE);
4475 aopGet (AOP(right), LSB, FALSE);
4479 emit2 ("ld a,(de)");
4480 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4489 spillPair (PAIR_HL);
4493 if (AOP_TYPE (right) == AOP_LIT)
4495 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4496 /* optimize if(x < 0) or if(x >= 0) */
4501 /* No sign so it's always false */
4506 /* Just load in the top most bit */
4507 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4508 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4510 genIfxJump (ifx, "7");
4521 genIfxJump (ifx, swap_sense ? "c" : "nc");
4532 _moveA (aopGet (AOP (left), offset, FALSE));
4533 /* Subtract through, propagating the carry */
4534 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4540 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4544 /* Shift the sign bit up into carry */
4547 outBitCLong (result, swap_sense);
4551 /* if the result is used in the next
4552 ifx conditional branch then generate
4553 code a little differently */
4561 genIfxJump (ifx, swap_sense ? "nc" : "c");
4565 genIfxJump (ifx, swap_sense ? "p" : "m");
4570 genIfxJump (ifx, swap_sense ? "nc" : "c");
4577 /* Shift the sign bit up into carry */
4580 outBitCLong (result, swap_sense);
4582 /* leave the result in acc */
4586 /*-----------------------------------------------------------------*/
4587 /* genCmpGt :- greater than comparison */
4588 /*-----------------------------------------------------------------*/
4590 genCmpGt (iCode * ic, iCode * ifx)
4592 operand *left, *right, *result;
4593 sym_link *letype, *retype;
4596 left = IC_LEFT (ic);
4597 right = IC_RIGHT (ic);
4598 result = IC_RESULT (ic);
4600 letype = getSpec (operandType (left));
4601 retype = getSpec (operandType (right));
4602 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4603 /* assign the amsops */
4604 aopOp (left, ic, FALSE, FALSE);
4605 aopOp (right, ic, FALSE, FALSE);
4606 aopOp (result, ic, TRUE, FALSE);
4608 genCmp (right, left, result, ifx, sign);
4610 freeAsmop (left, NULL, ic);
4611 freeAsmop (right, NULL, ic);
4612 freeAsmop (result, NULL, ic);
4615 /*-----------------------------------------------------------------*/
4616 /* genCmpLt - less than comparisons */
4617 /*-----------------------------------------------------------------*/
4619 genCmpLt (iCode * ic, iCode * ifx)
4621 operand *left, *right, *result;
4622 sym_link *letype, *retype;
4625 left = IC_LEFT (ic);
4626 right = IC_RIGHT (ic);
4627 result = IC_RESULT (ic);
4629 letype = getSpec (operandType (left));
4630 retype = getSpec (operandType (right));
4631 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4633 /* assign the amsops */
4634 aopOp (left, ic, FALSE, FALSE);
4635 aopOp (right, ic, FALSE, FALSE);
4636 aopOp (result, ic, TRUE, FALSE);
4638 genCmp (left, right, result, ifx, sign);
4640 freeAsmop (left, NULL, ic);
4641 freeAsmop (right, NULL, ic);
4642 freeAsmop (result, NULL, ic);
4645 /*-----------------------------------------------------------------*/
4646 /* gencjneshort - compare and jump if not equal */
4647 /*-----------------------------------------------------------------*/
4649 gencjneshort (operand * left, operand * right, symbol * lbl)
4651 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4653 unsigned long lit = 0L;
4655 /* Swap the left and right if it makes the computation easier */
4656 if (AOP_TYPE (left) == AOP_LIT)
4663 if (AOP_TYPE (right) == AOP_LIT)
4665 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4668 /* if the right side is a literal then anything goes */
4669 if (AOP_TYPE (right) == AOP_LIT &&
4670 AOP_TYPE (left) != AOP_DIR)
4674 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4679 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4686 emit2 ("jp nz,!tlabel", lbl->key + 100);
4692 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4693 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4696 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4697 emit2 ("jp nz,!tlabel", lbl->key + 100);
4702 /* if the right side is in a register or in direct space or
4703 if the left is a pointer register & right is not */
4704 else if (AOP_TYPE (right) == AOP_REG ||
4705 AOP_TYPE (right) == AOP_DIR ||
4706 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4710 _moveA (aopGet (AOP (left), offset, FALSE));
4711 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4712 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4714 emit2 ("jp nz,!tlabel", lbl->key + 100);
4717 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4718 emit2 ("jp nz,!tlabel", lbl->key + 100);
4725 /* right is a pointer reg need both a & b */
4726 /* PENDING: is this required? */
4729 _moveA (aopGet (AOP (right), offset, FALSE));
4730 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4731 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4737 /*-----------------------------------------------------------------*/
4738 /* gencjne - compare and jump if not equal */
4739 /*-----------------------------------------------------------------*/
4741 gencjne (operand * left, operand * right, symbol * lbl)
4743 symbol *tlbl = newiTempLabel (NULL);
4745 gencjneshort (left, right, lbl);
4748 emit2 ("ld a,!one");
4749 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4750 emitLabel (lbl->key + 100);
4752 emitLabel (tlbl->key + 100);
4755 /*-----------------------------------------------------------------*/
4756 /* genCmpEq - generates code for equal to */
4757 /*-----------------------------------------------------------------*/
4759 genCmpEq (iCode * ic, iCode * ifx)
4761 operand *left, *right, *result;
4763 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4764 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4765 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4767 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4769 /* Swap operands if it makes the operation easier. ie if:
4770 1. Left is a literal.
4772 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4774 operand *t = IC_RIGHT (ic);
4775 IC_RIGHT (ic) = IC_LEFT (ic);
4779 if (ifx && !AOP_SIZE (result))
4782 /* if they are both bit variables */
4783 if (AOP_TYPE (left) == AOP_CRY &&
4784 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4786 wassertl (0, "Tried to compare two bits");
4790 tlbl = newiTempLabel (NULL);
4791 gencjneshort (left, right, tlbl);
4794 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4795 emitLabel (tlbl->key + 100);
4799 /* PENDING: do this better */
4800 symbol *lbl = newiTempLabel (NULL);
4801 emit2 ("!shortjp !tlabel", lbl->key + 100);
4802 emitLabel (tlbl->key + 100);
4803 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4804 emitLabel (lbl->key + 100);
4807 /* mark the icode as generated */
4812 /* if they are both bit variables */
4813 if (AOP_TYPE (left) == AOP_CRY &&
4814 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4816 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4822 gencjne (left, right, newiTempLabel (NULL));
4823 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4830 genIfxJump (ifx, "a");
4833 /* if the result is used in an arithmetic operation
4834 then put the result in place */
4835 if (AOP_TYPE (result) != AOP_CRY)
4840 /* leave the result in acc */
4844 freeAsmop (left, NULL, ic);
4845 freeAsmop (right, NULL, ic);
4846 freeAsmop (result, NULL, ic);
4849 /*-----------------------------------------------------------------*/
4850 /* ifxForOp - returns the icode containing the ifx for operand */
4851 /*-----------------------------------------------------------------*/
4853 ifxForOp (operand * op, iCode * ic)
4855 /* if true symbol then needs to be assigned */
4856 if (IS_TRUE_SYMOP (op))
4859 /* if this has register type condition and
4860 the next instruction is ifx with the same operand
4861 and live to of the operand is upto the ifx only then */
4863 ic->next->op == IFX &&
4864 IC_COND (ic->next)->key == op->key &&
4865 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4871 /*-----------------------------------------------------------------*/
4872 /* genAndOp - for && operation */
4873 /*-----------------------------------------------------------------*/
4875 genAndOp (iCode * ic)
4877 operand *left, *right, *result;
4880 /* note here that && operations that are in an if statement are
4881 taken away by backPatchLabels only those used in arthmetic
4882 operations remain */
4883 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4884 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4885 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4887 /* if both are bit variables */
4888 if (AOP_TYPE (left) == AOP_CRY &&
4889 AOP_TYPE (right) == AOP_CRY)
4891 wassertl (0, "Tried to and two bits");
4895 tlbl = newiTempLabel (NULL);
4897 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4899 emitLabel (tlbl->key + 100);
4903 freeAsmop (left, NULL, ic);
4904 freeAsmop (right, NULL, ic);
4905 freeAsmop (result, NULL, ic);
4908 /*-----------------------------------------------------------------*/
4909 /* genOrOp - for || operation */
4910 /*-----------------------------------------------------------------*/
4912 genOrOp (iCode * ic)
4914 operand *left, *right, *result;
4917 /* note here that || operations that are in an
4918 if statement are taken away by backPatchLabels
4919 only those used in arthmetic operations remain */
4920 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4921 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4922 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4924 /* if both are bit variables */
4925 if (AOP_TYPE (left) == AOP_CRY &&
4926 AOP_TYPE (right) == AOP_CRY)
4928 wassertl (0, "Tried to OR two bits");
4932 tlbl = newiTempLabel (NULL);
4934 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4936 emitLabel (tlbl->key + 100);
4940 freeAsmop (left, NULL, ic);
4941 freeAsmop (right, NULL, ic);
4942 freeAsmop (result, NULL, ic);
4945 /*-----------------------------------------------------------------*/
4946 /* isLiteralBit - test if lit == 2^n */
4947 /*-----------------------------------------------------------------*/
4949 isLiteralBit (unsigned long lit)
4951 unsigned long pw[32] =
4952 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4953 0x100L, 0x200L, 0x400L, 0x800L,
4954 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4955 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4956 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4957 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4958 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4961 for (idx = 0; idx < 32; idx++)
4967 /*-----------------------------------------------------------------*/
4968 /* jmpTrueOrFalse - */
4969 /*-----------------------------------------------------------------*/
4971 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4973 // ugly but optimized by peephole
4976 symbol *nlbl = newiTempLabel (NULL);
4977 emit2 ("jp !tlabel", nlbl->key + 100);
4978 emitLabel (tlbl->key + 100);
4979 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4980 emitLabel (nlbl->key + 100);
4984 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4985 emitLabel (tlbl->key + 100);
4990 /*-----------------------------------------------------------------*/
4991 /* genAnd - code for and */
4992 /*-----------------------------------------------------------------*/
4994 genAnd (iCode * ic, iCode * ifx)
4996 operand *left, *right, *result;
4997 int size, offset = 0;
4998 unsigned long lit = 0L;
5001 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5002 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5003 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5005 /* if left is a literal & right is not then exchange them */
5006 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5007 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5009 operand *tmp = right;
5014 /* if result = right then exchange them */
5015 if (sameRegs (AOP (result), AOP (right)))
5017 operand *tmp = right;
5022 /* if right is bit then exchange them */
5023 if (AOP_TYPE (right) == AOP_CRY &&
5024 AOP_TYPE (left) != AOP_CRY)
5026 operand *tmp = right;
5030 if (AOP_TYPE (right) == AOP_LIT)
5031 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5033 size = AOP_SIZE (result);
5035 if (AOP_TYPE (left) == AOP_CRY)
5037 wassertl (0, "Tried to perform an AND with a bit as an operand");
5041 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5042 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5043 if ((AOP_TYPE (right) == AOP_LIT) &&
5044 (AOP_TYPE (result) == AOP_CRY) &&
5045 (AOP_TYPE (left) != AOP_CRY))
5047 symbol *tlbl = newiTempLabel (NULL);
5048 int sizel = AOP_SIZE (left);
5051 /* PENDING: Test case for this. */
5056 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5058 _moveA (aopGet (AOP (left), offset, FALSE));
5059 if (bytelit != 0x0FFL)
5061 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5068 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5072 // bit = left & literal
5076 emit2 ("!tlabeldef", tlbl->key + 100);
5078 // if(left & literal)
5083 jmpTrueOrFalse (ifx, tlbl);
5091 /* if left is same as result */
5092 if (sameRegs (AOP (result), AOP (left)))
5094 for (; size--; offset++)
5096 if (AOP_TYPE (right) == AOP_LIT)
5098 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5103 aopPut (AOP (result), "!zero", offset);
5106 _moveA (aopGet (AOP (left), offset, FALSE));
5108 aopGet (AOP (right), offset, FALSE));
5109 aopPut (AOP (left), "a", offset);
5116 if (AOP_TYPE (left) == AOP_ACC)
5118 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5122 _moveA (aopGet (AOP (left), offset, FALSE));
5124 aopGet (AOP (right), offset, FALSE));
5125 aopPut (AOP (left), "a", offset);
5132 // left & result in different registers
5133 if (AOP_TYPE (result) == AOP_CRY)
5135 wassertl (0, "Tried to AND where the result is in carry");
5139 for (; (size--); offset++)
5142 // result = left & right
5143 if (AOP_TYPE (right) == AOP_LIT)
5145 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5147 aopPut (AOP (result),
5148 aopGet (AOP (left), offset, FALSE),
5152 else if (bytelit == 0)
5154 aopPut (AOP (result), "!zero", offset);
5158 // faster than result <- left, anl result,right
5159 // and better if result is SFR
5160 if (AOP_TYPE (left) == AOP_ACC)
5161 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5164 _moveA (aopGet (AOP (left), offset, FALSE));
5166 aopGet (AOP (right), offset, FALSE));
5168 aopPut (AOP (result), "a", offset);
5175 freeAsmop (left, NULL, ic);
5176 freeAsmop (right, NULL, ic);
5177 freeAsmop (result, NULL, ic);
5180 /*-----------------------------------------------------------------*/
5181 /* genOr - code for or */
5182 /*-----------------------------------------------------------------*/
5184 genOr (iCode * ic, iCode * ifx)
5186 operand *left, *right, *result;
5187 int size, offset = 0;
5188 unsigned long lit = 0L;
5191 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5192 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5193 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5195 /* if left is a literal & right is not then exchange them */
5196 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5197 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5199 operand *tmp = right;
5204 /* if result = right then exchange them */
5205 if (sameRegs (AOP (result), AOP (right)))
5207 operand *tmp = right;
5212 /* if right is bit then exchange them */
5213 if (AOP_TYPE (right) == AOP_CRY &&
5214 AOP_TYPE (left) != AOP_CRY)
5216 operand *tmp = right;
5220 if (AOP_TYPE (right) == AOP_LIT)
5221 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5223 size = AOP_SIZE (result);
5225 if (AOP_TYPE (left) == AOP_CRY)
5227 wassertl (0, "Tried to OR where left is a bit");
5231 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5232 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5233 if ((AOP_TYPE (right) == AOP_LIT) &&
5234 (AOP_TYPE (result) == AOP_CRY) &&
5235 (AOP_TYPE (left) != AOP_CRY))
5237 symbol *tlbl = newiTempLabel (NULL);
5238 int sizel = AOP_SIZE (left);
5242 wassertl (0, "Result is assigned to a bit");
5244 /* PENDING: Modeled after the AND code which is inefficent. */
5247 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5249 _moveA (aopGet (AOP (left), offset, FALSE));
5250 /* OR with any literal is the same as OR with itself. */
5252 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5258 jmpTrueOrFalse (ifx, tlbl);
5263 /* if left is same as result */
5264 if (sameRegs (AOP (result), AOP (left)))
5266 for (; size--; offset++)
5268 if (AOP_TYPE (right) == AOP_LIT)
5270 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5274 _moveA (aopGet (AOP (left), offset, FALSE));
5276 aopGet (AOP (right), offset, FALSE));
5277 aopPut (AOP (result), "a", offset);
5282 if (AOP_TYPE (left) == AOP_ACC)
5283 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5286 _moveA (aopGet (AOP (left), offset, FALSE));
5288 aopGet (AOP (right), offset, FALSE));
5289 aopPut (AOP (result), "a", offset);
5296 // left & result in different registers
5297 if (AOP_TYPE (result) == AOP_CRY)
5299 wassertl (0, "Result of OR is in a bit");
5302 for (; (size--); offset++)
5305 // result = left & right
5306 if (AOP_TYPE (right) == AOP_LIT)
5308 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5310 aopPut (AOP (result),
5311 aopGet (AOP (left), offset, FALSE),
5316 // faster than result <- left, anl result,right
5317 // and better if result is SFR
5318 if (AOP_TYPE (left) == AOP_ACC)
5319 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5322 _moveA (aopGet (AOP (left), offset, FALSE));
5324 aopGet (AOP (right), offset, FALSE));
5326 aopPut (AOP (result), "a", offset);
5327 /* PENDING: something weird is going on here. Add exception. */
5328 if (AOP_TYPE (result) == AOP_ACC)
5334 freeAsmop (left, NULL, ic);
5335 freeAsmop (right, NULL, ic);
5336 freeAsmop (result, NULL, ic);
5339 /*-----------------------------------------------------------------*/
5340 /* genXor - code for xclusive or */
5341 /*-----------------------------------------------------------------*/
5343 genXor (iCode * ic, iCode * ifx)
5345 operand *left, *right, *result;
5346 int size, offset = 0;
5347 unsigned long lit = 0L;
5349 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5350 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5351 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5353 /* if left is a literal & right is not then exchange them */
5354 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5355 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5357 operand *tmp = right;
5362 /* if result = right then exchange them */
5363 if (sameRegs (AOP (result), AOP (right)))
5365 operand *tmp = right;
5370 /* if right is bit then exchange them */
5371 if (AOP_TYPE (right) == AOP_CRY &&
5372 AOP_TYPE (left) != AOP_CRY)
5374 operand *tmp = right;
5378 if (AOP_TYPE (right) == AOP_LIT)
5379 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5381 size = AOP_SIZE (result);
5383 if (AOP_TYPE (left) == AOP_CRY)
5385 wassertl (0, "Tried to XOR a bit");
5389 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5390 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5391 if ((AOP_TYPE (right) == AOP_LIT) &&
5392 (AOP_TYPE (result) == AOP_CRY) &&
5393 (AOP_TYPE (left) != AOP_CRY))
5395 symbol *tlbl = newiTempLabel (NULL);
5396 int sizel = AOP_SIZE (left);
5400 /* PENDING: Test case for this. */
5401 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5405 _moveA (aopGet (AOP (left), offset, FALSE));
5406 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5407 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5412 jmpTrueOrFalse (ifx, tlbl);
5416 wassertl (0, "Result of XOR was destined for a bit");
5421 /* if left is same as result */
5422 if (sameRegs (AOP (result), AOP (left)))
5424 for (; size--; offset++)
5426 if (AOP_TYPE (right) == AOP_LIT)
5428 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5432 _moveA (aopGet (AOP (left), offset, FALSE));
5434 aopGet (AOP (right), offset, FALSE));
5435 aopPut (AOP (result), "a", offset);
5440 if (AOP_TYPE (left) == AOP_ACC)
5442 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5446 _moveA (aopGet (AOP (left), offset, FALSE));
5448 aopGet (AOP (right), offset, FALSE));
5449 aopPut (AOP (result), "a", offset);
5456 // left & result in different registers
5457 if (AOP_TYPE (result) == AOP_CRY)
5459 wassertl (0, "Result of XOR is in a bit");
5462 for (; (size--); offset++)
5465 // result = left & right
5466 if (AOP_TYPE (right) == AOP_LIT)
5468 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5470 aopPut (AOP (result),
5471 aopGet (AOP (left), offset, FALSE),
5476 // faster than result <- left, anl result,right
5477 // and better if result is SFR
5478 if (AOP_TYPE (left) == AOP_ACC)
5480 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5484 _moveA (aopGet (AOP (left), offset, FALSE));
5486 aopGet (AOP (right), offset, FALSE));
5488 aopPut (AOP (result), "a", offset);
5493 freeAsmop (left, NULL, ic);
5494 freeAsmop (right, NULL, ic);
5495 freeAsmop (result, NULL, ic);
5498 /*-----------------------------------------------------------------*/
5499 /* genInline - write the inline code out */
5500 /*-----------------------------------------------------------------*/
5502 genInline (iCode * ic)
5504 char *buffer, *bp, *bp1;
5506 _G.lines.isInline += (!options.asmpeep);
5508 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5509 strcpy (buffer, IC_INLINE (ic));
5511 /* emit each line as a code */
5536 _G.lines.isInline -= (!options.asmpeep);
5540 /*-----------------------------------------------------------------*/
5541 /* genRRC - rotate right with carry */
5542 /*-----------------------------------------------------------------*/
5549 /*-----------------------------------------------------------------*/
5550 /* genRLC - generate code for rotate left with carry */
5551 /*-----------------------------------------------------------------*/
5558 /*-----------------------------------------------------------------*/
5559 /* genGetHbit - generates code get highest order bit */
5560 /*-----------------------------------------------------------------*/
5562 genGetHbit (iCode * ic)
5564 operand *left, *result;
5565 left = IC_LEFT (ic);
5566 result = IC_RESULT (ic);
5568 aopOp (left, ic, FALSE, FALSE);
5569 aopOp (result, ic, FALSE, FALSE);
5571 /* get the highest order byte into a */
5572 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5574 if (AOP_TYPE (result) == AOP_CRY)
5582 emit2 ("and a,!one");
5587 freeAsmop (left, NULL, ic);
5588 freeAsmop (result, NULL, ic);
5592 emitRsh2 (asmop *aop, int size, int is_signed)
5598 const char *l = aopGet (aop, size, FALSE);
5601 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5611 /*-----------------------------------------------------------------*/
5612 /* shiftR2Left2Result - shift right two bytes from left to result */
5613 /*-----------------------------------------------------------------*/
5615 shiftR2Left2Result (operand * left, int offl,
5616 operand * result, int offr,
5617 int shCount, int is_signed)
5620 symbol *tlbl, *tlbl1;
5622 movLeft2Result (left, offl, result, offr, 0);
5623 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5625 /* if (AOP(result)->type == AOP_REG) { */
5627 tlbl = newiTempLabel (NULL);
5628 tlbl1 = newiTempLabel (NULL);
5630 /* Left is already in result - so now do the shift */
5635 emitRsh2 (AOP (result), size, is_signed);
5640 emit2 ("ld a,!immedbyte+1", shCount);
5641 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5642 emitLabel (tlbl->key + 100);
5644 emitRsh2 (AOP (result), size, is_signed);
5646 emitLabel (tlbl1->key + 100);
5648 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5652 /*-----------------------------------------------------------------*/
5653 /* shiftL2Left2Result - shift left two bytes from left to result */
5654 /*-----------------------------------------------------------------*/
5656 shiftL2Left2Result (operand * left, int offl,
5657 operand * result, int offr, int shCount)
5659 if (sameRegs (AOP (result), AOP (left)) &&
5660 ((offl + MSB16) == offr))
5666 /* Copy left into result */
5667 movLeft2Result (left, offl, result, offr, 0);
5668 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5671 if (getPairId (AOP (result)) == PAIR_HL)
5675 emit2 ("add hl,hl");
5682 symbol *tlbl, *tlbl1;
5685 tlbl = newiTempLabel (NULL);
5686 tlbl1 = newiTempLabel (NULL);
5688 if (AOP (result)->type == AOP_REG)
5692 for (offset = 0; offset < size; offset++)
5694 l = aopGet (AOP (result), offset, FALSE);
5698 emit2 ("sla %s", l);
5709 /* Left is already in result - so now do the shift */
5712 emit2 ("ld a,!immedbyte+1", shCount);
5713 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5714 emitLabel (tlbl->key + 100);
5719 l = aopGet (AOP (result), offset, FALSE);
5723 emit2 ("sla %s", l);
5734 emitLabel (tlbl1->key + 100);
5736 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5742 /*-----------------------------------------------------------------*/
5743 /* AccRol - rotate left accumulator by known count */
5744 /*-----------------------------------------------------------------*/
5746 AccRol (int shCount)
5748 shCount &= 0x0007; // shCount : 0..7
5825 /*-----------------------------------------------------------------*/
5826 /* AccLsh - left shift accumulator by known count */
5827 /*-----------------------------------------------------------------*/
5829 AccLsh (int shCount)
5831 static const unsigned char SLMask[] =
5833 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5842 else if (shCount == 2)
5849 /* rotate left accumulator */
5851 /* and kill the lower order bits */
5852 emit2 ("and a,!immedbyte", SLMask[shCount]);
5857 /*-----------------------------------------------------------------*/
5858 /* shiftL1Left2Result - shift left one byte from left to result */
5859 /*-----------------------------------------------------------------*/
5861 shiftL1Left2Result (operand * left, int offl,
5862 operand * result, int offr, int shCount)
5865 l = aopGet (AOP (left), offl, FALSE);
5867 /* shift left accumulator */
5869 aopPut (AOP (result), "a", offr);
5873 /*-----------------------------------------------------------------*/
5874 /* genlshTwo - left shift two bytes by known amount != 0 */
5875 /*-----------------------------------------------------------------*/
5877 genlshTwo (operand * result, operand * left, int shCount)
5879 int size = AOP_SIZE (result);
5881 wassert (size == 2);
5883 /* if shCount >= 8 */
5891 movLeft2Result (left, LSB, result, MSB16, 0);
5892 aopPut (AOP (result), "!zero", 0);
5893 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5897 movLeft2Result (left, LSB, result, MSB16, 0);
5898 aopPut (AOP (result), "!zero", 0);
5903 aopPut (AOP (result), "!zero", LSB);
5906 /* 1 <= shCount <= 7 */
5915 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5920 /*-----------------------------------------------------------------*/
5921 /* genlshOne - left shift a one byte quantity by known count */
5922 /*-----------------------------------------------------------------*/
5924 genlshOne (operand * result, operand * left, int shCount)
5926 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5929 /*-----------------------------------------------------------------*/
5930 /* genLeftShiftLiteral - left shifting by known count */
5931 /*-----------------------------------------------------------------*/
5933 genLeftShiftLiteral (operand * left,
5938 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5941 freeAsmop (right, NULL, ic);
5943 aopOp (left, ic, FALSE, FALSE);
5944 aopOp (result, ic, FALSE, FALSE);
5946 size = getSize (operandType (result));
5948 /* I suppose that the left size >= result size */
5954 else if (shCount >= (size * 8))
5958 aopPut (AOP (result), "!zero", size);
5966 genlshOne (result, left, shCount);
5969 genlshTwo (result, left, shCount);
5972 wassertl (0, "Shifting of longs is currently unsupported");
5978 freeAsmop (left, NULL, ic);
5979 freeAsmop (result, NULL, ic);
5982 /*-----------------------------------------------------------------*/
5983 /* genLeftShift - generates code for left shifting */
5984 /*-----------------------------------------------------------------*/
5986 genLeftShift (iCode * ic)
5990 symbol *tlbl, *tlbl1;
5991 operand *left, *right, *result;
5993 right = IC_RIGHT (ic);
5994 left = IC_LEFT (ic);
5995 result = IC_RESULT (ic);
5997 aopOp (right, ic, FALSE, FALSE);
5999 /* if the shift count is known then do it
6000 as efficiently as possible */
6001 if (AOP_TYPE (right) == AOP_LIT)
6003 genLeftShiftLiteral (left, right, result, ic);
6007 /* shift count is unknown then we have to form a loop get the loop
6008 count in B : Note: we take only the lower order byte since
6009 shifting more that 32 bits make no sense anyway, ( the largest
6010 size of an object can be only 32 bits ) */
6011 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6013 freeAsmop (right, NULL, ic);
6014 aopOp (left, ic, FALSE, FALSE);
6015 aopOp (result, ic, FALSE, FALSE);
6017 /* now move the left to the result if they are not the
6020 if (!sameRegs (AOP (left), AOP (result)))
6023 size = AOP_SIZE (result);
6027 l = aopGet (AOP (left), offset, FALSE);
6028 aopPut (AOP (result), l, offset);
6033 tlbl = newiTempLabel (NULL);
6034 size = AOP_SIZE (result);
6036 tlbl1 = newiTempLabel (NULL);
6038 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6039 emitLabel (tlbl->key + 100);
6040 l = aopGet (AOP (result), offset, FALSE);
6044 l = aopGet (AOP (result), offset, FALSE);
6048 emit2 ("sla %s", l);
6056 emitLabel (tlbl1->key + 100);
6058 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6060 freeAsmop (left, NULL, ic);
6061 freeAsmop (result, NULL, ic);
6064 /*-----------------------------------------------------------------*/
6065 /* genrshOne - left shift two bytes by known amount != 0 */
6066 /*-----------------------------------------------------------------*/
6068 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6071 int size = AOP_SIZE (result);
6074 wassert (size == 1);
6075 wassert (shCount < 8);
6077 l = aopGet (AOP (left), 0, FALSE);
6079 if (AOP (result)->type == AOP_REG)
6081 aopPut (AOP (result), l, 0);
6082 l = aopGet (AOP (result), 0, FALSE);
6085 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6093 emit2 ("%s a", is_signed ? "sra" : "srl");
6095 aopPut (AOP (result), "a", 0);
6099 /*-----------------------------------------------------------------*/
6100 /* AccRsh - right shift accumulator by known count */
6101 /*-----------------------------------------------------------------*/
6103 AccRsh (int shCount)
6105 static const unsigned char SRMask[] =
6107 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6112 /* rotate right accumulator */
6113 AccRol (8 - shCount);
6114 /* and kill the higher order bits */
6115 emit2 ("and a,!immedbyte", SRMask[shCount]);
6119 /*-----------------------------------------------------------------*/
6120 /* shiftR1Left2Result - shift right one byte from left to result */
6121 /*-----------------------------------------------------------------*/
6123 shiftR1Left2Result (operand * left, int offl,
6124 operand * result, int offr,
6125 int shCount, int sign)
6127 _moveA (aopGet (AOP (left), offl, FALSE));
6132 emit2 ("%s a", sign ? "sra" : "srl");
6139 aopPut (AOP (result), "a", offr);
6142 /*-----------------------------------------------------------------*/
6143 /* genrshTwo - right shift two bytes by known amount != 0 */
6144 /*-----------------------------------------------------------------*/
6146 genrshTwo (operand * result, operand * left,
6147 int shCount, int sign)
6149 /* if shCount >= 8 */
6155 shiftR1Left2Result (left, MSB16, result, LSB,
6160 movLeft2Result (left, MSB16, result, LSB, sign);
6164 /* Sign extend the result */
6165 _moveA(aopGet (AOP (result), 0, FALSE));
6169 aopPut (AOP (result), ACC_NAME, MSB16);
6173 aopPut (AOP (result), "!zero", 1);
6176 /* 1 <= shCount <= 7 */
6179 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6183 /*-----------------------------------------------------------------*/
6184 /* genRightShiftLiteral - left shifting by known count */
6185 /*-----------------------------------------------------------------*/
6187 genRightShiftLiteral (operand * left,
6193 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6196 freeAsmop (right, NULL, ic);
6198 aopOp (left, ic, FALSE, FALSE);
6199 aopOp (result, ic, FALSE, FALSE);
6201 size = getSize (operandType (result));
6203 /* I suppose that the left size >= result size */
6209 else if (shCount >= (size * 8)) {
6211 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6212 _moveA(aopGet (AOP (left), 0, FALSE));
6220 aopPut (AOP (result), s, size);
6227 genrshOne (result, left, shCount, sign);
6230 genrshTwo (result, left, shCount, sign);
6233 wassertl (0, "Asked to shift right a long which should be a function call");
6236 wassertl (0, "Entered default case in right shift delegate");
6239 freeAsmop (left, NULL, ic);
6240 freeAsmop (result, NULL, ic);
6243 /*-----------------------------------------------------------------*/
6244 /* genRightShift - generate code for right shifting */
6245 /*-----------------------------------------------------------------*/
6247 genRightShift (iCode * ic)
6249 operand *right, *left, *result;
6251 int size, offset, first = 1;
6255 symbol *tlbl, *tlbl1;
6257 /* if signed then we do it the hard way preserve the
6258 sign bit moving it inwards */
6259 retype = getSpec (operandType (IC_RESULT (ic)));
6261 is_signed = !SPEC_USIGN (retype);
6263 /* signed & unsigned types are treated the same : i.e. the
6264 signed is NOT propagated inwards : quoting from the
6265 ANSI - standard : "for E1 >> E2, is equivalent to division
6266 by 2**E2 if unsigned or if it has a non-negative value,
6267 otherwise the result is implementation defined ", MY definition
6268 is that the sign does not get propagated */
6270 right = IC_RIGHT (ic);
6271 left = IC_LEFT (ic);
6272 result = IC_RESULT (ic);
6274 aopOp (right, ic, FALSE, FALSE);
6276 /* if the shift count is known then do it
6277 as efficiently as possible */
6278 if (AOP_TYPE (right) == AOP_LIT)
6280 genRightShiftLiteral (left, right, result, ic, is_signed);
6284 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6286 freeAsmop (right, NULL, ic);
6288 aopOp (left, ic, FALSE, FALSE);
6289 aopOp (result, ic, FALSE, FALSE);
6291 /* now move the left to the result if they are not the
6293 if (!sameRegs (AOP (left), AOP (result)))
6296 size = AOP_SIZE (result);
6300 l = aopGet (AOP (left), offset, FALSE);
6301 aopPut (AOP (result), l, offset);
6306 tlbl = newiTempLabel (NULL);
6307 tlbl1 = newiTempLabel (NULL);
6308 size = AOP_SIZE (result);
6311 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6312 emitLabel (tlbl->key + 100);
6315 l = aopGet (AOP (result), offset--, FALSE);
6318 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6326 emitLabel (tlbl1->key + 100);
6328 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6330 freeAsmop (left, NULL, ic);
6331 freeAsmop (result, NULL, ic);
6335 /*-----------------------------------------------------------------*/
6336 /* genUnpackBits - generates code for unpacking bits */
6337 /*-----------------------------------------------------------------*/
6339 genUnpackBits (operand * result, int pair)
6341 int offset = 0; /* result byte offset */
6342 int rsize; /* result size */
6343 int rlen = 0; /* remaining bitfield length */
6344 sym_link *etype; /* bitfield type information */
6345 int blen; /* bitfield length */
6346 int bstr; /* bitfield starting bit within byte */
6348 emitDebug ("; genUnpackBits");
6350 etype = getSpec (operandType (result));
6351 rsize = getSize (operandType (result));
6352 blen = SPEC_BLEN (etype);
6353 bstr = SPEC_BSTR (etype);
6355 /* If the bitfield length is less than a byte */
6358 emit2 ("ld a,!*pair", _pairs[pair].name);
6360 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6361 aopPut (AOP (result), "a", offset++);
6365 /* TODO: what if pair == PAIR_DE ? */
6366 if (getPairId (AOP (result)) == PAIR_HL)
6368 wassertl (rsize == 2, "HL must be of size 2");
6369 emit2 ("ld a,!*hl");
6371 emit2 ("ld h,!*hl");
6374 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6376 spillPair (PAIR_HL);
6380 /* Bit field did not fit in a byte. Copy all
6381 but the partial byte at the end. */
6382 for (rlen=blen;rlen>=8;rlen-=8)
6384 emit2 ("ld a,!*pair", _pairs[pair].name);
6385 aopPut (AOP (result), "a", offset++);
6388 emit2 ("inc %s", _pairs[pair].name);
6389 _G.pairs[pair].offset++;
6393 /* Handle the partial byte at the end */
6396 emit2 ("ld a,!*pair", _pairs[pair].name);
6397 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6398 aopPut (AOP (result), "a", offset++);
6406 aopPut (AOP (result), "!zero", offset++);
6410 /*-----------------------------------------------------------------*/
6411 /* genGenPointerGet - get value from generic pointer space */
6412 /*-----------------------------------------------------------------*/
6414 genGenPointerGet (operand * left,
6415 operand * result, iCode * ic)
6418 sym_link *retype = getSpec (operandType (result));
6424 aopOp (left, ic, FALSE, FALSE);
6425 aopOp (result, ic, FALSE, FALSE);
6427 size = AOP_SIZE (result);
6429 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6432 if (isPtrPair (AOP (left)))
6434 tsprintf (buffer, sizeof(buffer),
6435 "!*pair", getPairName (AOP (left)));
6436 aopPut (AOP (result), buffer, 0);
6440 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6441 aopPut (AOP (result), "a", 0);
6443 freeAsmop (left, NULL, ic);
6447 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6454 tsprintf (at, sizeof(at), "!*iyx", offset);
6455 aopPut (AOP (result), at, offset);
6459 freeAsmop (left, NULL, ic);
6463 /* For now we always load into IY */
6464 /* if this is remateriazable */
6465 fetchPair (pair, AOP (left));
6467 /* if bit then unpack */
6468 if (IS_BITVAR (retype))
6470 genUnpackBits (result, pair);
6471 freeAsmop (left, NULL, ic);
6475 else if (getPairId (AOP (result)) == PAIR_HL)
6477 wassertl (size == 2, "HL must be of size 2");
6478 emit2 ("ld a,!*hl");
6480 emit2 ("ld h,!*hl");
6482 spillPair (PAIR_HL);
6484 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6486 size = AOP_SIZE (result);
6491 /* PENDING: make this better */
6492 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6494 aopPut (AOP (result), "!*hl", offset++);
6498 emit2 ("ld a,!*pair", _pairs[pair].name);
6499 aopPut (AOP (result), "a", offset++);
6503 emit2 ("inc %s", _pairs[pair].name);
6504 _G.pairs[pair].offset++;
6507 /* Fixup HL back down */
6508 for (size = AOP_SIZE (result)-1; size; size--)
6510 emit2 ("dec %s", _pairs[pair].name);
6515 size = AOP_SIZE (result);
6520 /* PENDING: make this better */
6522 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6524 aopPut (AOP (result), "!*hl", offset++);
6528 emit2 ("ld a,!*pair", _pairs[pair].name);
6529 aopPut (AOP (result), "a", offset++);
6533 emit2 ("inc %s", _pairs[pair].name);
6534 _G.pairs[pair].offset++;
6539 freeAsmop (left, NULL, ic);
6542 freeAsmop (result, NULL, ic);
6545 /*-----------------------------------------------------------------*/
6546 /* genPointerGet - generate code for pointer get */
6547 /*-----------------------------------------------------------------*/
6549 genPointerGet (iCode * ic)
6551 operand *left, *result;
6552 sym_link *type, *etype;
6554 left = IC_LEFT (ic);
6555 result = IC_RESULT (ic);
6557 /* depending on the type of pointer we need to
6558 move it to the correct pointer register */
6559 type = operandType (left);
6560 etype = getSpec (type);
6562 genGenPointerGet (left, result, ic);
6566 isRegOrLit (asmop * aop)
6568 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6574 /*-----------------------------------------------------------------*/
6575 /* genPackBits - generates code for packed bit storage */
6576 /*-----------------------------------------------------------------*/
6578 genPackBits (sym_link * etype,
6583 int offset = 0; /* source byte offset */
6584 int rlen = 0; /* remaining bitfield length */
6585 int blen; /* bitfield length */
6586 int bstr; /* bitfield starting bit within byte */
6587 int litval; /* source literal value (if AOP_LIT) */
6588 unsigned char mask; /* bitmask within current byte */
6589 int extraPair; /* a tempory register */
6590 bool needPopExtra=0; /* need to restore original value of temp reg */
6592 emitDebug ("; genPackBits","");
6594 blen = SPEC_BLEN (etype);
6595 bstr = SPEC_BSTR (etype);
6597 /* If the bitfield length is less than a byte */
6600 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6601 (unsigned char) (0xFF >> (8 - bstr)));
6603 if (AOP_TYPE (right) == AOP_LIT)
6605 /* Case with a bitfield length <8 and literal source
6607 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6609 litval &= (~mask) & 0xff;
6610 emit2 ("ld a,!*pair", _pairs[pair].name);
6611 if ((mask|litval)!=0xff)
6612 emit2 ("and a,!immedbyte", mask);
6614 emit2 ("or a,!immedbyte", litval);
6615 emit2 ("ld !*pair,a", _pairs[pair].name);
6620 /* Case with a bitfield length <8 and arbitrary source
6622 _moveA (aopGet (AOP (right), 0, FALSE));
6623 /* shift and mask source value */
6625 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6627 extraPair = getFreePairId(ic);
6628 if (extraPair == PAIR_INVALID)
6630 extraPair = PAIR_BC;
6631 if (getPairId (AOP (right)) != PAIR_BC
6632 || !isLastUse (ic, right))
6638 emit2 ("ld %s,a", _pairs[extraPair].l);
6639 emit2 ("ld a,!*pair", _pairs[pair].name);
6641 emit2 ("and a,!immedbyte", mask);
6642 emit2 ("or a,%s", _pairs[extraPair].l);
6643 emit2 ("ld !*pair,a", _pairs[pair].name);
6650 /* Bit length is greater than 7 bits. In this case, copy */
6651 /* all except the partial byte at the end */
6652 for (rlen=blen;rlen>=8;rlen-=8)
6654 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6655 emit2 ("ld !*pair,a", _pairs[pair].name);
6658 emit2 ("inc %s", _pairs[pair].name);
6659 _G.pairs[pair].offset++;
6663 /* If there was a partial byte at the end */
6666 mask = (((unsigned char) -1 << rlen) & 0xff);
6668 if (AOP_TYPE (right) == AOP_LIT)
6670 /* Case with partial byte and literal source
6672 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6673 litval >>= (blen-rlen);
6674 litval &= (~mask) & 0xff;
6675 emit2 ("ld a,!*pair", _pairs[pair].name);
6676 if ((mask|litval)!=0xff)
6677 emit2 ("and a,!immedbyte", mask);
6679 emit2 ("or a,!immedbyte", litval);
6683 /* Case with partial byte and arbitrary source
6685 _moveA (aopGet (AOP (right), offset++, FALSE));
6686 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6688 extraPair = getFreePairId(ic);
6689 if (extraPair == PAIR_INVALID)
6691 extraPair = getPairId (AOP (right));
6692 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6693 extraPair = PAIR_BC;
6695 if (getPairId (AOP (right)) != PAIR_BC
6696 || !isLastUse (ic, right))
6702 emit2 ("ld %s,a", _pairs[extraPair].l);
6703 emit2 ("ld a,!*pair", _pairs[pair].name);
6705 emit2 ("and a,!immedbyte", mask);
6706 emit2 ("or a,%s", _pairs[extraPair].l);
6711 emit2 ("ld !*pair,a", _pairs[pair].name);
6716 /*-----------------------------------------------------------------*/
6717 /* genGenPointerSet - stores the value into a pointer location */
6718 /*-----------------------------------------------------------------*/
6720 genGenPointerSet (operand * right,
6721 operand * result, iCode * ic)
6724 sym_link *retype = getSpec (operandType (right));
6725 sym_link *letype = getSpec (operandType (result));
6726 PAIR_ID pairId = PAIR_HL;
6729 aopOp (result, ic, FALSE, FALSE);
6730 aopOp (right, ic, FALSE, FALSE);
6735 size = AOP_SIZE (right);
6737 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6738 emitDebug("; isBitvar = %d", isBitvar);
6740 /* Handle the exceptions first */
6741 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6744 const char *l = aopGet (AOP (right), 0, FALSE);
6745 const char *pair = getPairName (AOP (result));
6746 if (canAssignToPtr (l) && isPtr (pair))
6748 emit2 ("ld !*pair,%s", pair, l);
6753 emit2 ("ld !*pair,a", pair);
6758 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6761 const char *l = aopGet (AOP (right), 0, FALSE);
6766 if (canAssignToPtr (l))
6768 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6772 _moveA (aopGet (AOP (right), offset, FALSE));
6773 emit2 ("ld !*iyx,a", offset);
6779 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6786 const char *l = aopGet (AOP (right), offset, FALSE);
6787 if (isRegOrLit (AOP (right)) && !IS_GB)
6789 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6794 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6798 emit2 ("inc %s", _pairs[PAIR_HL].name);
6799 _G.pairs[PAIR_HL].offset++;
6804 /* Fixup HL back down */
6805 for (size = AOP_SIZE (right)-1; size; size--)
6807 emit2 ("dec %s", _pairs[PAIR_HL].name);
6812 /* if the operand is already in dptr
6813 then we do nothing else we move the value to dptr */
6814 if (AOP_TYPE (result) != AOP_STR)
6816 fetchPair (pairId, AOP (result));
6818 /* so hl now contains the address */
6819 freeAsmop (result, NULL, ic);
6821 /* if bit then unpack */
6824 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6834 const char *l = aopGet (AOP (right), offset, FALSE);
6835 if (isRegOrLit (AOP (right)) && !IS_GB)
6837 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6842 emit2 ("ld !*pair,a", _pairs[pairId].name);
6846 emit2 ("inc %s", _pairs[pairId].name);
6847 _G.pairs[pairId].offset++;
6853 freeAsmop (right, NULL, ic);
6856 /*-----------------------------------------------------------------*/
6857 /* genPointerSet - stores the value into a pointer location */
6858 /*-----------------------------------------------------------------*/
6860 genPointerSet (iCode * ic)
6862 operand *right, *result;
6863 sym_link *type, *etype;
6865 right = IC_RIGHT (ic);
6866 result = IC_RESULT (ic);
6868 /* depending on the type of pointer we need to
6869 move it to the correct pointer register */
6870 type = operandType (result);
6871 etype = getSpec (type);
6873 genGenPointerSet (right, result, ic);
6876 /*-----------------------------------------------------------------*/
6877 /* genIfx - generate code for Ifx statement */
6878 /*-----------------------------------------------------------------*/
6880 genIfx (iCode * ic, iCode * popIc)
6882 operand *cond = IC_COND (ic);
6885 aopOp (cond, ic, FALSE, TRUE);
6887 /* get the value into acc */
6888 if (AOP_TYPE (cond) != AOP_CRY)
6892 /* the result is now in the accumulator */
6893 freeAsmop (cond, NULL, ic);
6895 /* if there was something to be popped then do it */
6899 /* if the condition is a bit variable */
6900 if (isbit && IS_ITEMP (cond) &&
6902 genIfxJump (ic, SPIL_LOC (cond)->rname);
6903 else if (isbit && !IS_ITEMP (cond))
6904 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6906 genIfxJump (ic, "a");
6911 /*-----------------------------------------------------------------*/
6912 /* genAddrOf - generates code for address of */
6913 /*-----------------------------------------------------------------*/
6915 genAddrOf (iCode * ic)
6917 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6919 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6921 /* if the operand is on the stack then we
6922 need to get the stack offset of this
6929 if (sym->stack <= 0)
6931 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6935 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6937 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6941 emit2 ("ld de,!hashedstr", sym->rname);
6942 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6950 /* if it has an offset then we need to compute it */
6952 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6954 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6955 emit2 ("add hl,sp");
6959 emit2 ("ld hl,!hashedstr", sym->rname);
6961 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6963 freeAsmop (IC_RESULT (ic), NULL, ic);
6966 /*-----------------------------------------------------------------*/
6967 /* genAssign - generate code for assignment */
6968 /*-----------------------------------------------------------------*/
6970 genAssign (iCode * ic)
6972 operand *result, *right;
6974 unsigned long lit = 0L;
6976 result = IC_RESULT (ic);
6977 right = IC_RIGHT (ic);
6979 /* Dont bother assigning if they are the same */
6980 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6982 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6986 aopOp (right, ic, FALSE, FALSE);
6987 aopOp (result, ic, TRUE, FALSE);
6989 /* if they are the same registers */
6990 if (sameRegs (AOP (right), AOP (result)))
6992 emitDebug ("; (registers are the same)");
6996 /* if the result is a bit */
6997 if (AOP_TYPE (result) == AOP_CRY)
6999 wassertl (0, "Tried to assign to a bit");
7003 size = AOP_SIZE (result);
7006 if (AOP_TYPE (right) == AOP_LIT)
7008 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7011 if (isPair (AOP (result)))
7013 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7015 else if ((size > 1) &&
7016 (AOP_TYPE (result) != AOP_REG) &&
7017 (AOP_TYPE (right) == AOP_LIT) &&
7018 !IS_FLOAT (operandType (right)) &&
7021 bool fXored = FALSE;
7023 /* Work from the top down.
7024 Done this way so that we can use the cached copy of 0
7025 in A for a fast clear */
7028 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7030 if (!fXored && size > 1)
7037 aopPut (AOP (result), "a", offset);
7041 aopPut (AOP (result), "!zero", offset);
7045 aopPut (AOP (result),
7046 aopGet (AOP (right), offset, FALSE),
7051 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7053 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7054 aopPut (AOP (result), "l", LSB);
7055 aopPut (AOP (result), "h", MSB16);
7057 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7059 /* Special case. Load into a and d, then load out. */
7060 _moveA (aopGet (AOP (right), 0, FALSE));
7061 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7062 aopPut (AOP (result), "a", 0);
7063 aopPut (AOP (result), "e", 1);
7065 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7067 /* Special case - simple memcpy */
7068 aopGet (AOP (right), LSB, FALSE);
7071 aopGet (AOP (result), LSB, FALSE);
7075 emit2 ("ld a,(de)");
7076 /* Peephole will optimise this. */
7077 emit2 ("ld (hl),a");
7085 spillPair (PAIR_HL);
7091 /* PENDING: do this check better */
7092 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7094 _moveA (aopGet (AOP (right), offset, FALSE));
7095 aopPut (AOP (result), "a", offset);
7098 aopPut (AOP (result),
7099 aopGet (AOP (right), offset, FALSE),
7106 freeAsmop (right, NULL, ic);
7107 freeAsmop (result, NULL, ic);
7110 /*-----------------------------------------------------------------*/
7111 /* genJumpTab - genrates code for jump table */
7112 /*-----------------------------------------------------------------*/
7114 genJumpTab (iCode * ic)
7119 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7120 /* get the condition into accumulator */
7121 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7124 emit2 ("ld e,%s", l);
7125 emit2 ("ld d,!zero");
7126 jtab = newiTempLabel (NULL);
7128 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7129 emit2 ("add hl,de");
7130 emit2 ("add hl,de");
7131 emit2 ("add hl,de");
7132 freeAsmop (IC_JTCOND (ic), NULL, ic);
7136 emitLabel (jtab->key + 100);
7137 /* now generate the jump labels */
7138 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7139 jtab = setNextItem (IC_JTLABELS (ic)))
7140 emit2 ("jp !tlabel", jtab->key + 100);
7143 /*-----------------------------------------------------------------*/
7144 /* genCast - gen code for casting */
7145 /*-----------------------------------------------------------------*/
7147 genCast (iCode * ic)
7149 operand *result = IC_RESULT (ic);
7150 sym_link *rtype = operandType (IC_RIGHT (ic));
7151 operand *right = IC_RIGHT (ic);
7154 /* if they are equivalent then do nothing */
7155 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7158 aopOp (right, ic, FALSE, FALSE);
7159 aopOp (result, ic, FALSE, FALSE);
7161 /* if the result is a bit */
7162 if (AOP_TYPE (result) == AOP_CRY)
7164 wassertl (0, "Tried to cast to a bit");
7167 /* if they are the same size : or less */
7168 if (AOP_SIZE (result) <= AOP_SIZE (right))
7171 /* if they are in the same place */
7172 if (sameRegs (AOP (right), AOP (result)))
7175 /* if they in different places then copy */
7176 size = AOP_SIZE (result);
7180 aopPut (AOP (result),
7181 aopGet (AOP (right), offset, FALSE),
7188 /* So we now know that the size of destination is greater
7189 than the size of the source */
7190 /* we move to result for the size of source */
7191 size = AOP_SIZE (right);
7195 aopPut (AOP (result),
7196 aopGet (AOP (right), offset, FALSE),
7201 /* now depending on the sign of the destination */
7202 size = AOP_SIZE (result) - AOP_SIZE (right);
7203 /* Unsigned or not an integral type - right fill with zeros */
7204 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7207 aopPut (AOP (result), "!zero", offset++);
7211 /* we need to extend the sign :{ */
7212 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7218 aopPut (AOP (result), "a", offset++);
7222 freeAsmop (right, NULL, ic);
7223 freeAsmop (result, NULL, ic);
7226 /*-----------------------------------------------------------------*/
7227 /* genReceive - generate code for a receive iCode */
7228 /*-----------------------------------------------------------------*/
7230 genReceive (iCode * ic)
7232 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7233 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7234 IS_TRUE_SYMOP (IC_RESULT (ic))))
7244 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7245 size = AOP_SIZE(IC_RESULT(ic));
7247 for (i = 0; i < size; i++) {
7248 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7252 freeAsmop (IC_RESULT (ic), NULL, ic);
7255 /*-----------------------------------------------------------------*/
7256 /* genDummyRead - generate code for dummy read of volatiles */
7257 /*-----------------------------------------------------------------*/
7259 genDummyRead (iCode * ic)
7265 if (op && IS_SYMOP (op))
7267 aopOp (op, ic, FALSE, FALSE);
7270 size = AOP_SIZE (op);
7275 _moveA (aopGet (AOP (op), offset, FALSE));
7279 freeAsmop (op, NULL, ic);
7283 if (op && IS_SYMOP (op))
7285 aopOp (op, ic, FALSE, FALSE);
7288 size = AOP_SIZE (op);
7293 _moveA (aopGet (AOP (op), offset, FALSE));
7297 freeAsmop (op, NULL, ic);
7303 /** Maximum number of bytes to emit per line. */
7307 /** Context for the byte output chunker. */
7310 unsigned char buffer[DBEMIT_MAX_RUN];
7315 /** Flushes a byte chunker by writing out all in the buffer and
7319 _dbFlush(DBEMITCTX *self)
7326 sprintf(line, ".db 0x%02X", self->buffer[0]);
7328 for (i = 1; i < self->pos; i++)
7330 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7337 /** Write out another byte, buffering until a decent line is
7341 _dbEmit(DBEMITCTX *self, int c)
7343 if (self->pos == DBEMIT_MAX_RUN)
7347 self->buffer[self->pos++] = c;
7350 /** Context for a simple run length encoder. */
7354 unsigned char buffer[128];
7356 /** runLen may be equivalent to pos. */
7362 RLE_CHANGE_COST = 4,
7366 /** Flush the buffer of a run length encoder by writing out the run or
7367 data that it currently contains.
7370 _rleCommit(RLECTX *self)
7376 memset(&db, 0, sizeof(db));
7378 emit2(".db %u", self->pos);
7380 for (i = 0; i < self->pos; i++)
7382 _dbEmit(&db, self->buffer[i]);
7391 Can get either a run or a block of random stuff.
7392 Only want to change state if a good run comes in or a run ends.
7393 Detecting run end is easy.
7396 Say initial state is in run, len zero, last zero. Then if you get a
7397 few zeros then something else then a short run will be output.
7398 Seems OK. While in run mode, keep counting. While in random mode,
7399 keep a count of the run. If run hits margin, output all up to run,
7400 restart, enter run mode.
7403 /** Add another byte into the run length encoder, flushing as
7404 required. The run length encoder uses the Amiga IFF style, where
7405 a block is prefixed by its run length. A positive length means
7406 the next n bytes pass straight through. A negative length means
7407 that the next byte is repeated -n times. A zero terminates the
7411 _rleAppend(RLECTX *self, int c)
7415 if (c != self->last)
7417 /* The run has stopped. See if it is worthwhile writing it out
7418 as a run. Note that the random data comes in as runs of
7421 if (self->runLen > RLE_CHANGE_COST)
7423 /* Yes, worthwhile. */
7424 /* Commit whatever was in the buffer. */
7426 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7430 /* Not worthwhile. Append to the end of the random list. */
7431 for (i = 0; i < self->runLen; i++)
7433 if (self->pos >= RLE_MAX_BLOCK)
7438 self->buffer[self->pos++] = self->last;
7446 if (self->runLen >= RLE_MAX_BLOCK)
7448 /* Commit whatever was in the buffer. */
7451 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7459 _rleFlush(RLECTX *self)
7461 _rleAppend(self, -1);
7468 /** genArrayInit - Special code for initialising an array with constant
7472 genArrayInit (iCode * ic)
7476 int elementSize = 0, eIndex, i;
7477 unsigned val, lastVal;
7481 memset(&rle, 0, sizeof(rle));
7483 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7485 _saveRegsForCall(ic, 0);
7487 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7488 emit2 ("call __initrleblock");
7490 type = operandType(IC_LEFT(ic));
7492 if (type && type->next)
7494 if (IS_SPEC(type->next))
7496 elementSize = getSize(type->next);
7498 else if (IS_ARRAY(type->next) && type->next->next)
7500 elementSize = getSize(type->next->next);
7504 wassertl (0, "Can't determine element size in genArrayInit.");
7509 wassertl (0, "Can't determine element size in genArrayInit.");
7512 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7514 iLoop = IC_ARRAYILIST(ic);
7515 lastVal = (unsigned)-1;
7517 /* Feed all the bytes into the run length encoder which will handle
7519 This works well for mixed char data, and for random int and long
7526 for (i = 0; i < ix; i++)
7528 for (eIndex = 0; eIndex < elementSize; eIndex++)
7530 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7531 _rleAppend(&rle, val);
7535 iLoop = iLoop->next;
7539 /* Mark the end of the run. */
7542 _restoreRegsAfterCall();
7546 freeAsmop (IC_LEFT(ic), NULL, ic);
7550 _swap (PAIR_ID one, PAIR_ID two)
7552 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7558 emit2 ("ld a,%s", _pairs[one].l);
7559 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7560 emit2 ("ld %s,a", _pairs[two].l);
7561 emit2 ("ld a,%s", _pairs[one].h);
7562 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7563 emit2 ("ld %s,a", _pairs[two].h);
7567 /* The problem is that we may have all three pairs used and they may
7568 be needed in a different order.
7573 hl = hl => unity, fine
7577 hl = hl hl = hl, swap de <=> bc
7585 hl = bc de = de, swap bc <=> hl
7593 hl = de bc = bc, swap hl <=> de
7598 * Any pair = pair are done last
7599 * Any pair = iTemp are done last
7600 * Any swaps can be done any time
7608 So how do we detect the cases?
7609 How about a 3x3 matrix?
7613 x x x x (Fourth for iTemp/other)
7615 First determin which mode to use by counting the number of unity and
7618 Two - Assign the pair first, then the rest
7619 One - Swap the two, then the rest
7623 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7625 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7627 PAIR_BC, PAIR_HL, PAIR_DE
7629 int i, j, nunity = 0;
7630 memset (ids, PAIR_INVALID, sizeof (ids));
7633 wassert (nparams == 3);
7635 /* First save everything that needs to be saved. */
7636 _saveRegsForCall (ic, 0);
7638 /* Loading HL first means that DE is always fine. */
7639 for (i = 0; i < nparams; i++)
7641 aopOp (pparams[i], ic, FALSE, FALSE);
7642 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7645 /* Count the number of unity or iTemp assigns. */
7646 for (i = 0; i < 3; i++)
7648 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7656 /* Any order, fall through. */
7658 else if (nunity == 2)
7660 /* One is assigned. Pull it out and assign. */
7661 for (i = 0; i < 3; i++)
7663 for (j = 0; j < NUM_PAIRS; j++)
7665 if (ids[dest[i]][j] == TRUE)
7667 /* Found it. See if it's the right one. */
7668 if (j == PAIR_INVALID || j == dest[i])
7674 fetchPair(dest[i], AOP (pparams[i]));
7681 else if (nunity == 1)
7683 /* Find the pairs to swap. */
7684 for (i = 0; i < 3; i++)
7686 for (j = 0; j < NUM_PAIRS; j++)
7688 if (ids[dest[i]][j] == TRUE)
7690 if (j == PAIR_INVALID || j == dest[i])
7705 int next = getPairId (AOP (pparams[0]));
7706 emit2 ("push %s", _pairs[next].name);
7708 if (next == dest[1])
7710 fetchPair (dest[1], AOP (pparams[1]));
7711 fetchPair (dest[2], AOP (pparams[2]));
7715 fetchPair (dest[2], AOP (pparams[2]));
7716 fetchPair (dest[1], AOP (pparams[1]));
7718 emit2 ("pop %s", _pairs[dest[0]].name);
7721 /* Finally pull out all of the iTemps */
7722 for (i = 0; i < 3; i++)
7724 if (ids[dest[i]][PAIR_INVALID] == 1)
7726 fetchPair (dest[i], AOP (pparams[i]));
7732 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7738 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7742 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7744 setupForBuiltin3 (ic, nParams, pparams);
7746 label = newiTempLabel(NULL);
7748 emitLabel (label->key);
7749 emit2 ("ld a,(hl)");
7752 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7754 freeAsmop (from, NULL, ic->next);
7755 freeAsmop (to, NULL, ic);
7759 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7761 operand *from, *to, *count;
7764 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7769 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7771 setupForBuiltin3 (ic, nParams, pparams);
7775 freeAsmop (count, NULL, ic->next->next);
7776 freeAsmop (from, NULL, ic);
7778 _restoreRegsAfterCall();
7780 /* if we need assign a result value */
7781 if ((IS_ITEMP (IC_RESULT (ic)) &&
7782 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7783 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7784 IS_TRUE_SYMOP (IC_RESULT (ic)))
7786 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7787 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7788 freeAsmop (IC_RESULT (ic), NULL, ic);
7791 freeAsmop (to, NULL, ic->next);
7794 /*-----------------------------------------------------------------*/
7795 /* genBuiltIn - calls the appropriate function to generating code */
7796 /* for a built in function */
7797 /*-----------------------------------------------------------------*/
7798 static void genBuiltIn (iCode *ic)
7800 operand *bi_parms[MAX_BUILTIN_ARGS];
7805 /* get all the arguments for a built in function */
7806 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7808 /* which function is it */
7809 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7811 if (strcmp(bif->name,"__builtin_strcpy")==0)
7813 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7815 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7817 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7821 wassertl (0, "Unknown builtin function encountered");
7825 /*-----------------------------------------------------------------*/
7826 /* genZ80Code - generate code for Z80 based controllers */
7827 /*-----------------------------------------------------------------*/
7829 genZ80Code (iCode * lic)
7837 _fReturn = _gbz80_return;
7838 _fTmp = _gbz80_return;
7842 _fReturn = _z80_return;
7843 _fTmp = _z80_return;
7846 _G.lines.head = _G.lines.current = NULL;
7848 /* if debug information required */
7849 if (options.debug && currFunc)
7851 debugFile->writeFunction (currFunc, lic);
7854 for (ic = lic; ic; ic = ic->next)
7856 _G.current_iCode = ic;
7858 if (ic->lineno && cln != ic->lineno)
7862 debugFile->writeCLine (ic);
7864 if (!options.noCcodeInAsm) {
7865 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7866 printCLine(ic->filename, ic->lineno));
7870 if (options.iCodeInAsm) {
7871 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7873 /* if the result is marked as
7874 spilt and rematerializable or code for
7875 this has already been generated then
7877 if (resultRemat (ic) || ic->generated)
7880 /* depending on the operation */
7884 emitDebug ("; genNot");
7889 emitDebug ("; genCpl");
7894 emitDebug ("; genUminus");
7899 emitDebug ("; genIpush");
7904 /* IPOP happens only when trying to restore a
7905 spilt live range, if there is an ifx statement
7906 following this pop then the if statement might
7907 be using some of the registers being popped which
7908 would destory the contents of the register so
7909 we need to check for this condition and handle it */
7911 ic->next->op == IFX &&
7912 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7914 emitDebug ("; genIfx");
7915 genIfx (ic->next, ic);
7919 emitDebug ("; genIpop");
7925 emitDebug ("; genCall");
7930 emitDebug ("; genPcall");
7935 emitDebug ("; genFunction");
7940 emitDebug ("; genEndFunction");
7941 genEndFunction (ic);
7945 emitDebug ("; genRet");
7950 emitDebug ("; genLabel");
7955 emitDebug ("; genGoto");
7960 emitDebug ("; genPlus");
7965 emitDebug ("; genMinus");
7970 emitDebug ("; genMult");
7975 emitDebug ("; genDiv");
7980 emitDebug ("; genMod");
7985 emitDebug ("; genCmpGt");
7986 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7990 emitDebug ("; genCmpLt");
7991 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7998 /* note these two are xlated by algebraic equivalence
7999 during parsing SDCC.y */
8000 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8001 "got '>=' or '<=' shouldn't have come here");
8005 emitDebug ("; genCmpEq");
8006 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8010 emitDebug ("; genAndOp");
8015 emitDebug ("; genOrOp");
8020 emitDebug ("; genXor");
8021 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8025 emitDebug ("; genOr");
8026 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8030 emitDebug ("; genAnd");
8031 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8035 emitDebug ("; genInline");
8040 emitDebug ("; genRRC");
8045 emitDebug ("; genRLC");
8050 emitDebug ("; genGetHBIT");
8055 emitDebug ("; genLeftShift");
8060 emitDebug ("; genRightShift");
8064 case GET_VALUE_AT_ADDRESS:
8065 emitDebug ("; genPointerGet");
8071 if (POINTER_SET (ic))
8073 emitDebug ("; genAssign (pointer)");
8078 emitDebug ("; genAssign");
8084 emitDebug ("; genIfx");
8089 emitDebug ("; genAddrOf");
8094 emitDebug ("; genJumpTab");
8099 emitDebug ("; genCast");
8104 emitDebug ("; genReceive");
8109 if (ic->builtinSEND)
8111 emitDebug ("; genBuiltIn");
8116 emitDebug ("; addSet");
8117 addSet (&_G.sendSet, ic);
8122 emitDebug ("; genArrayInit");
8126 case DUMMY_READ_VOLATILE:
8127 emitDebug ("; genDummyRead");
8137 /* now we are ready to call the
8138 peep hole optimizer */
8139 if (!options.nopeep)
8140 peepHole (&_G.lines.head);
8142 /* This is unfortunate */
8143 /* now do the actual printing */
8145 FILE *fp = codeOutFile;
8146 if (isInHome () && codeOutFile == code->oFile)
8147 codeOutFile = home->oFile;
8148 printLine (_G.lines.head, codeOutFile);
8149 if (_G.flushStatics)
8152 _G.flushStatics = 0;
8157 freeTrace(&_G.lines.trace);
8158 freeTrace(&_G.trace.aops);
8164 _isPairUsed (iCode * ic, PAIR_ID pairId)
8170 if (bitVectBitValue (ic->rMask, D_IDX))
8172 if (bitVectBitValue (ic->rMask, E_IDX))
8182 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8185 value *val = aop->aopu.aop_lit;
8187 wassert (aop->type == AOP_LIT);
8188 wassert (!IS_FLOAT (val->type));
8190 v = (unsigned long) floatFromVal (val);
8198 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8199 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));