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 /* emit2 - writes the code into a file : for now it is simple */
447 /*-----------------------------------------------------------------*/
449 _emit2 (const char *inst, const char *fmt,...)
452 char lb[INITIAL_INLINEASM];
459 sprintf (lb, "%s\t", inst);
460 vsprintf (lb + (strlen (lb)), fmt, ap);
463 vsprintf (lb, fmt, ap);
465 while (isspace (*lbp))
470 _G.lines.current = (_G.lines.current ?
471 connectLine (_G.lines.current, _newLineNode (lb)) :
472 (_G.lines.head = _newLineNode (lb)));
474 _G.lines.current->isInline = _G.lines.isInline;
475 _G.lines.current->ic = _G.current_iCode;
480 _emitMove(const char *to, const char *from)
482 if (STRCASECMP(to, from) != 0)
484 emit2("ld %s,%s", to, from);
489 // Could leave this to the peephole, but sometimes the peephole is inhibited.
494 aopDump(const char *plabel, asmop *aop)
500 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
505 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
508 for (i=aop->size-1;i>=0;i--)
509 *rbp++ = *(aop->aopu.aop_reg[i]->name);
511 emitDebug("; reg = %s", regbuf);
514 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
517 /* No information. */
523 _moveA(const char *moveFrom)
525 // Let the peephole optimiser take care of redundent loads
526 _emitMove(ACC_NAME, moveFrom);
536 getPairName (asmop * aop)
538 if (aop->type == AOP_REG)
540 switch (aop->aopu.aop_reg[0]->rIdx)
553 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
556 for (i = 0; i < NUM_PAIRS; i++)
558 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
560 return _pairs[i].name;
564 wassertl (0, "Tried to get the pair name of something that isn't a pair");
569 getPairId (asmop * aop)
573 if (aop->type == AOP_REG)
575 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
579 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
583 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
588 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
591 for (i = 0; i < NUM_PAIRS; i++)
593 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
603 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
607 return (getPairId (aop) != PAIR_INVALID);
610 /** Returns TRUE if the registers used in aop cannot be split into high
613 isUnsplitable (asmop * aop)
615 switch (getPairId (aop))
627 isPtrPair (asmop * aop)
629 PAIR_ID pairId = getPairId (aop);
642 spillPair (PAIR_ID pairId)
644 _G.pairs[pairId].last_type = AOP_INVALID;
645 _G.pairs[pairId].base = NULL;
648 /* Given a register name, spill the pair (if any) the register is part of */
650 spillPairReg (const char *regname)
652 if (strlen(regname)==1)
672 /** Push a register pair onto the stack */
674 genPairPush (asmop * aop)
676 emit2 ("push %s", getPairName (aop));
680 _push (PAIR_ID pairId)
682 emit2 ("push %s", _pairs[pairId].name);
683 _G.stack.pushed += 2;
687 _pop (PAIR_ID pairId)
689 emit2 ("pop %s", _pairs[pairId].name);
690 _G.stack.pushed -= 2;
695 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
708 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
715 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
716 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
719 wassertl (0, "Tried to move a nonphysical pair");
721 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
722 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
723 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
727 /*-----------------------------------------------------------------*/
728 /* newAsmop - creates a new asmOp */
729 /*-----------------------------------------------------------------*/
731 newAsmop (short type)
735 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
740 /*-----------------------------------------------------------------*/
741 /* aopForSym - for a true symbol */
742 /*-----------------------------------------------------------------*/
744 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
751 wassert (sym->etype);
753 space = SPEC_OCLS (sym->etype);
755 /* if already has one */
761 /* Assign depending on the storage class */
762 if (sym->onStack || sym->iaccess)
764 /* The pointer that is used depends on how big the offset is.
765 Normally everything is AOP_STK, but for offsets of < -128 or
766 > 127 on the Z80 an extended stack pointer is used.
768 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
770 emitDebug ("; AOP_EXSTK for %s", sym->rname);
771 sym->aop = aop = newAsmop (AOP_EXSTK);
775 emitDebug ("; AOP_STK for %s", sym->rname);
776 sym->aop = aop = newAsmop (AOP_STK);
779 aop->size = getSize (sym->type);
780 aop->aopu.aop_stk = sym->stack;
784 /* special case for a function */
785 if (IS_FUNC (sym->type))
787 sym->aop = aop = newAsmop (AOP_IMMD);
788 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
793 if( IN_REGSP( space ))
794 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
797 /* if it is in direct space */
800 sym->aop = aop = newAsmop (AOP_SFR);
801 aop->aopu.aop_dir = sym->rname;
802 aop->size = getSize (sym->type);
803 emitDebug ("; AOP_SFR for %s", sym->rname);
808 { /*.p.t.20030716 adding SFR support to the Z80 port */
809 aop = newAsmop (AOP_SFR);
811 aop->aopu.aop_dir = sym->rname;
812 aop->size = getSize( sym->type );
813 aop->paged = FUNC_REGBANK(sym->type);
814 aop->bcInUse = isPairInUse( PAIR_BC, ic );
815 aop->deInUse = isPairInUse( PAIR_DE, ic );
816 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
822 /* only remaining is far space */
823 /* in which case DPTR gets the address */
826 emitDebug ("; AOP_HL for %s", sym->rname);
827 sym->aop = aop = newAsmop (AOP_HL);
831 sym->aop = aop = newAsmop (AOP_IY);
833 aop->size = getSize (sym->type);
834 aop->aopu.aop_dir = sym->rname;
836 /* if it is in code space */
837 if (IN_CODESPACE (space))
843 /*-----------------------------------------------------------------*/
844 /* aopForRemat - rematerialzes an object */
845 /*-----------------------------------------------------------------*/
847 aopForRemat (symbol * sym)
850 iCode *ic = sym->rematiCode;
851 asmop *aop = newAsmop (AOP_IMMD);
855 /* if plus or minus print the right hand side */
856 if (ic->op == '+' || ic->op == '-')
858 /* PENDING: for re-target */
859 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
862 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
865 /* we reached the end */
866 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
870 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
874 /*-----------------------------------------------------------------*/
875 /* regsInCommon - two operands have some registers in common */
876 /*-----------------------------------------------------------------*/
878 regsInCommon (operand * op1, operand * op2)
883 /* if they have registers in common */
884 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
887 sym1 = OP_SYMBOL (op1);
888 sym2 = OP_SYMBOL (op2);
890 if (sym1->nRegs == 0 || sym2->nRegs == 0)
893 for (i = 0; i < sym1->nRegs; i++)
899 for (j = 0; j < sym2->nRegs; j++)
904 if (sym2->regs[j] == sym1->regs[i])
912 /*-----------------------------------------------------------------*/
913 /* operandsEqu - equivalent */
914 /*-----------------------------------------------------------------*/
916 operandsEqu (operand * op1, operand * op2)
920 /* if they not symbols */
921 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
924 sym1 = OP_SYMBOL (op1);
925 sym2 = OP_SYMBOL (op2);
927 /* if both are itemps & one is spilt
928 and the other is not then false */
929 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
930 sym1->isspilt != sym2->isspilt)
933 /* if they are the same */
937 if (strcmp (sym1->rname, sym2->rname) == 0)
941 /* if left is a tmp & right is not */
942 if (IS_ITEMP (op1) &&
945 (sym1->usl.spillLoc == sym2))
948 if (IS_ITEMP (op2) &&
952 (sym2->usl.spillLoc == sym1))
958 /*-----------------------------------------------------------------*/
959 /* sameRegs - two asmops have the same registers */
960 /*-----------------------------------------------------------------*/
962 sameRegs (asmop * aop1, asmop * aop2)
966 if (aop1->type == AOP_SFR ||
967 aop2->type == AOP_SFR)
973 if (aop1->type != AOP_REG ||
974 aop2->type != AOP_REG)
977 if (aop1->size != aop2->size)
980 for (i = 0; i < aop1->size; i++)
981 if (aop1->aopu.aop_reg[i] !=
982 aop2->aopu.aop_reg[i])
988 /*-----------------------------------------------------------------*/
989 /* aopOp - allocates an asmop for an operand : */
990 /*-----------------------------------------------------------------*/
992 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1001 /* if this a literal */
1002 if (IS_OP_LITERAL (op))
1004 op->aop = aop = newAsmop (AOP_LIT);
1005 aop->aopu.aop_lit = op->operand.valOperand;
1006 aop->size = getSize (operandType (op));
1010 /* if already has a asmop then continue */
1013 if (op->aop->type == AOP_SFR)
1015 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1016 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1021 /* if the underlying symbol has a aop */
1022 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1024 op->aop = OP_SYMBOL (op)->aop;
1025 if (op->aop->type == AOP_SFR)
1027 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1028 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1033 /* if this is a true symbol */
1034 if (IS_TRUE_SYMOP (op))
1036 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1040 /* this is a temporary : this has
1046 e) can be a return use only */
1048 sym = OP_SYMBOL (op);
1050 /* if the type is a conditional */
1051 if (sym->regType == REG_CND)
1053 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1058 /* if it is spilt then two situations
1060 b) has a spill location */
1061 if (sym->isspilt || sym->nRegs == 0)
1063 /* rematerialize it NOW */
1066 sym->aop = op->aop = aop =
1068 aop->size = getSize (sym->type);
1075 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1076 aop->size = getSize (sym->type);
1077 for (i = 0; i < 4; i++)
1078 aop->aopu.aop_str[i] = _fReturn[i];
1084 if (sym->accuse == ACCUSE_A)
1086 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1087 aop->size = getSize (sym->type);
1088 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1090 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1092 else if (sym->accuse == ACCUSE_SCRATCH)
1094 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1095 aop->size = getSize (sym->type);
1096 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1097 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1098 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1100 else if (sym->accuse == ACCUSE_IY)
1102 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1103 aop->size = getSize (sym->type);
1104 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1105 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1106 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1110 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1115 if (sym->usl.spillLoc)
1117 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1119 /* force a new aop if sizes differ */
1120 sym->usl.spillLoc->aop = NULL;
1122 sym->aop = op->aop = aop =
1123 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1124 aop->size = getSize (sym->type);
1128 /* else must be a dummy iTemp */
1129 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1130 aop->size = getSize (sym->type);
1134 /* must be in a register */
1135 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1136 aop->size = sym->nRegs;
1137 for (i = 0; i < sym->nRegs; i++)
1138 aop->aopu.aop_reg[i] = sym->regs[i];
1141 /*-----------------------------------------------------------------*/
1142 /* freeAsmop - free up the asmop given to an operand */
1143 /*----------------------------------------------------------------*/
1145 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1162 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1164 _pop (aop->aopu.aop_pairId);
1167 if (getPairId (aop) == PAIR_HL)
1169 spillPair (PAIR_HL);
1173 /* all other cases just dealloc */
1179 OP_SYMBOL (op)->aop = NULL;
1180 /* if the symbol has a spill */
1182 SPIL_LOC (op)->aop = NULL;
1189 isLitWord (asmop * aop)
1191 /* if (aop->size != 2)
1204 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1206 /* depending on type */
1212 /* PENDING: for re-target */
1215 tsprintf (buffer, sizeof(buffer),
1216 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1218 else if (offset == 0)
1220 tsprintf (buffer, sizeof(buffer),
1221 "%s", aop->aopu.aop_immd);
1225 tsprintf (buffer, sizeof(buffer),
1226 "%s + %d", aop->aopu.aop_immd, offset);
1228 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1232 value *val = aop->aopu.aop_lit;
1233 /* if it is a float then it gets tricky */
1234 /* otherwise it is fairly simple */
1235 if (!IS_FLOAT (val->type))
1237 unsigned long v = (unsigned long) floatFromVal (val);
1243 else if (offset == 0)
1249 wassertl(0, "Encountered an invalid offset while fetching a literal");
1253 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1255 tsprintf (buffer, sizeof(buffer), "!constword", v);
1257 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1268 /* it is type float */
1269 fl.f = (float) floatFromVal (val);
1271 #ifdef WORDS_BIGENDIAN
1272 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1274 i = fl.c[offset] | (fl.c[offset+1]<<8);
1277 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1279 tsprintf (buffer, sizeof(buffer), "!constword", i);
1281 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1290 aopGetWord (asmop * aop, int offset)
1292 return aopGetLitWordLong (aop, offset, TRUE);
1296 isPtr (const char *s)
1298 if (!strcmp (s, "hl"))
1300 if (!strcmp (s, "ix"))
1302 if (!strcmp (s, "iy"))
1308 adjustPair (const char *pair, int *pold, int new)
1314 emit2 ("inc %s", pair);
1319 emit2 ("dec %s", pair);
1327 spillPair (PAIR_HL);
1328 spillPair (PAIR_IY);
1332 requiresHL (asmop * aop)
1348 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1350 const char *l, *base;
1351 const char *pair = _pairs[pairId].name;
1352 l = aopGetLitWordLong (left, offset, FALSE);
1353 base = aopGetLitWordLong (left, 0, FALSE);
1354 wassert (l && pair && base);
1358 if (pairId == PAIR_HL || pairId == PAIR_IY)
1360 if (_G.pairs[pairId].last_type == left->type)
1362 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1364 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1366 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1369 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1376 _G.pairs[pairId].last_type = left->type;
1377 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1378 _G.pairs[pairId].offset = offset;
1380 /* Both a lit on the right and a true symbol on the left */
1381 emit2 ("ld %s,!hashedstr", pair, l);
1385 makeFreePairId (iCode *ic, bool *pisUsed)
1391 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1395 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1413 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1415 /* if this is remateriazable */
1416 if (isLitWord (aop)) {
1417 fetchLitPair (pairId, aop, offset);
1421 if (getPairId (aop) == pairId)
1425 /* we need to get it byte by byte */
1426 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1427 aopGet (aop, offset, FALSE);
1428 switch (aop->size - offset) {
1430 emit2 ("ld l,!*hl");
1431 emit2 ("ld h,!immedbyte", 0);
1434 // PENDING: Requires that you are only fetching two bytes.
1437 emit2 ("ld h,!*hl");
1441 wassertl (0, "Attempted to fetch too much data into HL");
1445 else if (IS_Z80 && aop->type == AOP_IY) {
1446 /* Instead of fetching relative to IY, just grab directly
1447 from the address IY refers to */
1448 char *l = aopGetLitWordLong (aop, offset, FALSE);
1450 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1452 if (aop->size < 2) {
1453 emit2("ld %s,!zero", _pairs[pairId].h);
1456 else if (pairId == PAIR_IY)
1460 emit2 ("push %s", _pairs[getPairId(aop)].name);
1466 PAIR_ID id = makeFreePairId (ic, &isUsed);
1469 /* Can't load into parts, so load into HL then exchange. */
1470 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1471 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1472 emit2 ("push %s", _pairs[id].name);
1478 else if (isUnsplitable(aop))
1480 emit2("push %s", _pairs[getPairId(aop)].name);
1481 emit2("pop %s", _pairs[pairId].name);
1485 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1486 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1488 /* PENDING: check? */
1489 if (pairId == PAIR_HL)
1490 spillPair (PAIR_HL);
1495 fetchPair (PAIR_ID pairId, asmop * aop)
1497 fetchPairLong (pairId, aop, NULL, 0);
1501 fetchHL (asmop * aop)
1503 fetchPair (PAIR_HL, aop);
1507 setupPairFromSP (PAIR_ID id, int offset)
1509 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1511 if (_G.preserveCarry)
1517 if (offset < INT8MIN || offset > INT8MAX)
1519 emit2 ("ld hl,!immedword", offset);
1520 emit2 ("add hl,sp");
1524 emit2 ("!ldahlsp", offset);
1527 if (_G.preserveCarry)
1535 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1540 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1541 fetchLitPair (pairId, aop, 0);
1545 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1547 fetchLitPair (pairId, aop, offset);
1548 _G.pairs[pairId].offset = offset;
1552 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1553 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1556 int offset = aop->aopu.aop_stk + _G.stack.offset;
1558 if (_G.pairs[pairId].last_type == aop->type &&
1559 _G.pairs[pairId].offset == offset)
1565 /* PENDING: Do this better. */
1566 if (_G.preserveCarry)
1568 sprintf (buffer, "%d", offset + _G.stack.pushed);
1569 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1570 emit2 ("add %s,sp", _pairs[pairId].name);
1571 _G.pairs[pairId].last_type = aop->type;
1572 _G.pairs[pairId].offset = offset;
1573 if (_G.preserveCarry)
1581 /* Doesnt include _G.stack.pushed */
1582 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1584 if (aop->aopu.aop_stk > 0)
1586 abso += _G.stack.param_offset;
1588 assert (pairId == PAIR_HL);
1589 /* In some cases we can still inc or dec hl */
1590 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1592 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1596 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1598 _G.pairs[pairId].offset = abso;
1603 if (pairId != aop->aopu.aop_pairId)
1604 genMovePairPair(aop->aopu.aop_pairId, pairId);
1605 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1611 _G.pairs[pairId].last_type = aop->type;
1617 emit2 ("!tlabeldef", key);
1621 /*-----------------------------------------------------------------*/
1622 /* aopGet - for fetching value of the aop */
1623 /*-----------------------------------------------------------------*/
1625 aopGet (asmop * aop, int offset, bool bit16)
1627 // char *s = buffer;
1629 /* offset is greater than size then zero */
1630 /* PENDING: this seems a bit screwed in some pointer cases. */
1631 if (offset > (aop->size - 1) &&
1632 aop->type != AOP_LIT)
1634 tsprintf (buffer, sizeof(buffer), "!zero");
1635 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1638 /* depending on type */
1642 tsprintf (buffer, sizeof(buffer), "!zero");
1643 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1646 /* PENDING: re-target */
1648 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1653 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1656 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1659 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1662 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1665 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1669 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1670 SNPRINTF (buffer, sizeof(buffer), "a");
1672 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1678 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1679 SNPRINTF (buffer, sizeof(buffer), "a");
1681 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1684 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1687 if( aop->bcInUse ) emit2( "push bc" );
1689 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1690 emit2( "in a,(c)" );
1695 spillPair (PAIR_BC);
1697 else if( z80_opts.port_mode == 180 )
1698 { /* z180 in0/out0 mode */
1699 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1703 emit2( "in a,(%s)", aop->aopu.aop_dir );
1706 SNPRINTF (buffer, sizeof(buffer), "a");
1708 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1712 return aop->aopu.aop_reg[offset]->name;
1716 setupPair (PAIR_HL, aop, offset);
1717 tsprintf (buffer, sizeof(buffer), "!*hl");
1719 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1723 setupPair (PAIR_IY, aop, offset);
1724 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1726 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1730 setupPair (PAIR_IY, aop, offset);
1731 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1733 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1738 setupPair (PAIR_HL, aop, offset);
1739 tsprintf (buffer, sizeof(buffer), "!*hl");
1743 if (aop->aopu.aop_stk >= 0)
1744 offset += _G.stack.param_offset;
1745 tsprintf (buffer, sizeof(buffer),
1746 "!*ixx", aop->aopu.aop_stk + offset);
1749 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1752 wassertl (0, "Tried to fetch from a bit variable");
1761 tsprintf(buffer, sizeof(buffer), "!zero");
1762 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1766 wassert (offset < 2);
1767 return aop->aopu.aop_str[offset];
1770 return aopLiteral (aop->aopu.aop_lit, offset);
1774 unsigned long v = aop->aopu.aop_simplelit;
1777 tsprintf (buffer, sizeof(buffer),
1778 "!immedbyte", (unsigned int) v & 0xff);
1780 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1784 return aop->aopu.aop_str[offset];
1787 setupPair (aop->aopu.aop_pairId, aop, offset);
1788 if (aop->aopu.aop_pairId==PAIR_IX)
1789 SNPRINTF (buffer, sizeof(buffer),
1791 else if (aop->aopu.aop_pairId==PAIR_IY)
1792 SNPRINTF (buffer, sizeof(buffer),
1795 SNPRINTF (buffer, sizeof(buffer),
1796 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1798 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1803 wassertl (0, "aopget got unsupported aop->type");
1808 isRegString (const char *s)
1810 if (!strcmp (s, "b") ||
1822 isConstant (const char *s)
1824 /* This is a bit of a hack... */
1825 return (*s == '#' || *s == '$');
1829 canAssignToPtr (const char *s)
1831 if (isRegString (s))
1838 /*-----------------------------------------------------------------*/
1839 /* aopPut - puts a string for a aop */
1840 /*-----------------------------------------------------------------*/
1842 aopPut (asmop * aop, const char *s, int offset)
1846 if (aop->size && offset > (aop->size - 1))
1848 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1849 "aopPut got offset > aop->size");
1854 tsprintf(buffer2, sizeof(buffer2), s);
1857 /* will assign value to value */
1858 /* depending on where it is ofcourse */
1862 _moveA (s); /* in case s is volatile */
1868 if (strcmp (s, "a"))
1869 emit2 ("ld a,%s", s);
1870 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1877 if (strcmp (s, "a"))
1878 emit2 ("ld a,%s", s);
1879 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1882 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1885 if( aop->bcInUse ) emit2( "push bc" );
1887 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1889 if(( s[0] == '#' ) /* immediate number */
1890 ||( s[0] == '(' ) /* indirect register (ix or iy ??)*/
1891 ||( isdigit( s[0] )))/* indirect register with offset (ix or iy ??)*/
1893 emit2( "ld a,%s", s );
1894 emit2( "out (c),a" );
1898 emit2( "out (c),%s", s );
1904 spillPair (PAIR_BC);
1906 else if( z80_opts.port_mode == 180 )
1907 { /* z180 in0/out0 mode */
1908 emit2( "ld a,%s", s );
1909 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1913 emit2( "ld a,%s", s );
1914 emit2( "out (%s),a", aop->aopu.aop_dir );
1920 if (!strcmp (s, "!*hl"))
1921 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1924 aop->aopu.aop_reg[offset]->name, s);
1925 spillPairReg(aop->aopu.aop_reg[offset]->name);
1930 if (!canAssignToPtr (s))
1932 emit2 ("ld a,%s", s);
1933 setupPair (PAIR_IY, aop, offset);
1934 emit2 ("ld !*iyx,a", offset);
1938 setupPair (PAIR_IY, aop, offset);
1939 emit2 ("ld !*iyx,%s", offset, s);
1945 /* PENDING: for re-target */
1946 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1948 emit2 ("ld a,!*hl");
1951 setupPair (PAIR_HL, aop, offset);
1953 emit2 ("ld !*hl,%s", s);
1958 if (!canAssignToPtr (s))
1960 emit2 ("ld a,%s", s);
1961 setupPair (PAIR_IY, aop, offset);
1962 emit2 ("ld !*iyx,a", offset);
1966 setupPair (PAIR_IY, aop, offset);
1967 emit2 ("ld !*iyx,%s", offset, s);
1974 /* PENDING: re-target */
1975 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1977 emit2 ("ld a,!*hl");
1980 setupPair (PAIR_HL, aop, offset);
1981 if (!canAssignToPtr (s))
1983 emit2 ("ld a,%s", s);
1984 emit2 ("ld !*hl,a");
1987 emit2 ("ld !*hl,%s", s);
1991 if (aop->aopu.aop_stk >= 0)
1992 offset += _G.stack.param_offset;
1993 if (!canAssignToPtr (s))
1995 emit2 ("ld a,%s", s);
1996 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2000 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2006 /* if bit variable */
2007 if (!aop->aopu.aop_dir)
2009 emit2 ("ld a,!zero");
2014 /* In bit space but not in C - cant happen */
2015 wassertl (0, "Tried to write into a bit variable");
2021 if (strcmp (aop->aopu.aop_str[offset], s))
2023 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2025 spillPairReg(aop->aopu.aop_str[offset]);
2030 if (!offset && (strcmp (s, "acc") == 0))
2034 wassertl (0, "Tried to access past the end of A");
2038 if (strcmp (aop->aopu.aop_str[offset], s))
2040 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2041 spillPairReg(aop->aopu.aop_str[offset]);
2047 wassert (offset < 2);
2048 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2049 spillPairReg(aop->aopu.aop_str[offset]);
2053 setupPair (aop->aopu.aop_pairId, aop, offset);
2054 if (aop->aopu.aop_pairId==PAIR_IX)
2055 emit2 ("ld !*ixx,%s", 0, s);
2056 else if (aop->aopu.aop_pairId==PAIR_IY)
2057 emit2 ("ld !*ixy,%s", 0, s);
2059 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2063 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2064 "aopPut got unsupported aop->type");
2069 #define AOP(op) op->aop
2070 #define AOP_TYPE(op) AOP(op)->type
2071 #define AOP_SIZE(op) AOP(op)->size
2072 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2075 commitPair (asmop * aop, PAIR_ID id)
2077 /* PENDING: Verify this. */
2078 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2082 aopPut (aop, "a", 0);
2083 aopPut (aop, "d", 1);
2088 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2090 char *l = aopGetLitWordLong (aop, 0, FALSE);
2093 emit2 ("ld (%s),%s", l, _pairs[id].name);
2097 aopPut (aop, _pairs[id].l, 0);
2098 aopPut (aop, _pairs[id].h, 1);
2103 /*-----------------------------------------------------------------*/
2104 /* getDataSize - get the operand data size */
2105 /*-----------------------------------------------------------------*/
2107 getDataSize (operand * op)
2110 size = AOP_SIZE (op);
2114 wassertl (0, "Somehow got a three byte data pointer");
2119 /*-----------------------------------------------------------------*/
2120 /* movLeft2Result - move byte from left to result */
2121 /*-----------------------------------------------------------------*/
2123 movLeft2Result (operand * left, int offl,
2124 operand * result, int offr, int sign)
2128 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2130 l = aopGet (AOP (left), offl, FALSE);
2134 aopPut (AOP (result), l, offr);
2138 if (getDataSize (left) == offl + 1)
2140 emit2 ("ld a,%s", l);
2141 aopPut (AOP (result), "a", offr);
2148 movLeft2ResultLong (operand * left, int offl,
2149 operand * result, int offr, int sign,
2154 movLeft2Result (left, offl, result, offr, sign);
2158 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2159 wassertl (size == 2, "Only implemented for two bytes or one");
2161 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2163 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2164 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2166 spillPair (PAIR_HL);
2168 else if ( getPairId ( AOP (result)) == PAIR_IY)
2170 PAIR_ID id = getPairId (AOP (left));
2171 if (id != PAIR_INVALID)
2173 emit2("push %s", _pairs[id].name);
2184 movLeft2Result (left, offl, result, offr, sign);
2185 movLeft2Result (left, offl+1, result, offr+1, sign);
2190 /** Put Acc into a register set
2193 outAcc (operand * result)
2196 size = getDataSize (result);
2199 aopPut (AOP (result), "a", 0);
2202 /* unsigned or positive */
2205 aopPut (AOP (result), "!zero", offset++);
2210 /** Take the value in carry and put it into a register
2213 outBitCLong (operand * result, bool swap_sense)
2215 /* if the result is bit */
2216 if (AOP_TYPE (result) == AOP_CRY)
2218 wassertl (0, "Tried to write carry to a bit");
2222 emit2 ("ld a,!zero");
2225 emit2 ("xor a,!immedbyte", 1);
2231 outBitC (operand * result)
2233 outBitCLong (result, FALSE);
2236 /*-----------------------------------------------------------------*/
2237 /* toBoolean - emit code for orl a,operator(sizeop) */
2238 /*-----------------------------------------------------------------*/
2240 _toBoolean (operand * oper)
2242 int size = AOP_SIZE (oper);
2246 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2249 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2253 if (AOP (oper)->type != AOP_ACC)
2256 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2262 /*-----------------------------------------------------------------*/
2263 /* genNot - generate code for ! operation */
2264 /*-----------------------------------------------------------------*/
2269 /* assign asmOps to operand & result */
2270 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2271 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2273 /* if in bit space then a special case */
2274 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2276 wassertl (0, "Tried to negate a bit");
2279 _toBoolean (IC_LEFT (ic));
2284 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2285 emit2 ("sub a,!one");
2286 outBitC (IC_RESULT (ic));
2288 /* release the aops */
2289 freeAsmop (IC_LEFT (ic), NULL, ic);
2290 freeAsmop (IC_RESULT (ic), NULL, ic);
2293 /*-----------------------------------------------------------------*/
2294 /* genCpl - generate code for complement */
2295 /*-----------------------------------------------------------------*/
2303 /* assign asmOps to operand & result */
2304 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2305 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2307 /* if both are in bit space then
2309 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2310 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2312 wassertl (0, "Left and the result are in bit space");
2315 size = AOP_SIZE (IC_RESULT (ic));
2318 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2321 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2324 /* release the aops */
2325 freeAsmop (IC_LEFT (ic), NULL, ic);
2326 freeAsmop (IC_RESULT (ic), NULL, ic);
2330 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2337 store de into result
2342 store de into result
2344 const char *first = isAdd ? "add" : "sub";
2345 const char *later = isAdd ? "adc" : "sbc";
2347 wassertl (IS_GB, "Code is only relevent to the gbz80");
2348 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2350 fetchPair (PAIR_DE, left);
2353 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2356 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2359 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2360 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2362 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2363 aopGet (right, MSB24, FALSE);
2367 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2370 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2372 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2373 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2377 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2379 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2382 /*-----------------------------------------------------------------*/
2383 /* genUminusFloat - unary minus for floating points */
2384 /*-----------------------------------------------------------------*/
2386 genUminusFloat (operand * op, operand * result)
2388 int size, offset = 0;
2390 emitDebug("; genUminusFloat");
2392 /* for this we just need to flip the
2393 first it then copy the rest in place */
2394 size = AOP_SIZE (op) - 1;
2396 _moveA(aopGet (AOP (op), MSB32, FALSE));
2398 emit2("xor a,!immedbyte", 0x80);
2399 aopPut (AOP (result), "a", MSB32);
2403 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2408 /*-----------------------------------------------------------------*/
2409 /* genUminus - unary minus code generation */
2410 /*-----------------------------------------------------------------*/
2412 genUminus (iCode * ic)
2415 sym_link *optype, *rtype;
2418 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2419 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2421 /* if both in bit space then special
2423 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2424 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2426 wassertl (0, "Left and right are in bit space");
2430 optype = operandType (IC_LEFT (ic));
2431 rtype = operandType (IC_RESULT (ic));
2433 /* if float then do float stuff */
2434 if (IS_FLOAT (optype))
2436 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2440 /* otherwise subtract from zero */
2441 size = AOP_SIZE (IC_LEFT (ic));
2443 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2445 /* Create a new asmop with value zero */
2446 asmop *azero = newAsmop (AOP_SIMPLELIT);
2447 azero->aopu.aop_simplelit = 0;
2449 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2457 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2458 emit2 ("ld a,!zero");
2459 emit2 ("sbc a,%s", l);
2460 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2463 /* if any remaining bytes in the result */
2464 /* we just need to propagate the sign */
2465 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2470 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2474 /* release the aops */
2475 freeAsmop (IC_LEFT (ic), NULL, ic);
2476 freeAsmop (IC_RESULT (ic), NULL, ic);
2479 /*-----------------------------------------------------------------*/
2480 /* assignResultValue - */
2481 /*-----------------------------------------------------------------*/
2483 assignResultValue (operand * oper)
2485 int size = AOP_SIZE (oper);
2488 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2489 topInA = requiresHL (AOP (oper));
2491 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2493 /* We do it the hard way here. */
2495 aopPut (AOP (oper), _fReturn[0], 0);
2496 aopPut (AOP (oper), _fReturn[1], 1);
2498 aopPut (AOP (oper), _fReturn[0], 2);
2499 aopPut (AOP (oper), _fReturn[1], 3);
2505 aopPut (AOP (oper), _fReturn[size], size);
2510 /** Simple restore that doesn't take into account what is used in the
2514 _restoreRegsAfterCall(void)
2516 if (_G.stack.pushedDE)
2519 _G.stack.pushedDE = FALSE;
2521 if (_G.stack.pushedBC)
2524 _G.stack.pushedBC = FALSE;
2526 _G.saves.saved = FALSE;
2530 _saveRegsForCall(iCode *ic, int sendSetSize)
2533 o Stack parameters are pushed before this function enters
2534 o DE and BC may be used in this function.
2535 o HL and DE may be used to return the result.
2536 o HL and DE may be used to send variables.
2537 o DE and BC may be used to store the result value.
2538 o HL may be used in computing the sent value of DE
2539 o The iPushes for other parameters occur before any addSets
2541 Logic: (to be run inside the first iPush or if none, before sending)
2542 o Compute if DE and/or BC are in use over the call
2543 o Compute if DE is used in the send set
2544 o Compute if DE and/or BC are used to hold the result value
2545 o If (DE is used, or in the send set) and is not used in the result, push.
2546 o If BC is used and is not in the result, push
2548 o If DE is used in the send set, fetch
2549 o If HL is used in the send set, fetch
2553 if (_G.saves.saved == FALSE) {
2554 bool deInUse, bcInUse;
2556 bool bcInRet = FALSE, deInRet = FALSE;
2559 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2560 z80_rUmaskForOp (IC_RESULT(ic)));
2562 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2563 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2565 deSending = (sendSetSize > 1);
2567 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2569 if (bcInUse && bcInRet == FALSE) {
2571 _G.stack.pushedBC = TRUE;
2573 if (deInUse && deInRet == FALSE) {
2575 _G.stack.pushedDE = TRUE;
2578 _G.saves.saved = TRUE;
2581 /* Already saved. */
2585 /*-----------------------------------------------------------------*/
2586 /* genIpush - genrate code for pushing this gets a little complex */
2587 /*-----------------------------------------------------------------*/
2589 genIpush (iCode * ic)
2591 int size, offset = 0;
2594 /* if this is not a parm push : ie. it is spill push
2595 and spill push is always done on the local stack */
2598 wassertl(0, "Encountered an unsupported spill push.");
2602 if (_G.saves.saved == FALSE) {
2603 /* Caller saves, and this is the first iPush. */
2604 /* Scan ahead until we find the function that we are pushing parameters to.
2605 Count the number of addSets on the way to figure out what registers
2606 are used in the send set.
2609 iCode *walk = ic->next;
2612 if (walk->op == SEND) {
2615 else if (walk->op == CALL || walk->op == PCALL) {
2624 _saveRegsForCall(walk, nAddSets);
2627 /* Already saved by another iPush. */
2630 /* then do the push */
2631 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2633 size = AOP_SIZE (IC_LEFT (ic));
2635 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2637 _G.stack.pushed += 2;
2638 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2644 fetchHL (AOP (IC_LEFT (ic)));
2646 spillPair (PAIR_HL);
2647 _G.stack.pushed += 2;
2652 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2654 spillPair (PAIR_HL);
2655 _G.stack.pushed += 2;
2656 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2658 spillPair (PAIR_HL);
2659 _G.stack.pushed += 2;
2665 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2667 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2669 emit2 ("ld a,(%s)", l);
2673 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2674 emit2 ("ld a,%s", l);
2682 freeAsmop (IC_LEFT (ic), NULL, ic);
2685 /*-----------------------------------------------------------------*/
2686 /* genIpop - recover the registers: can happen only for spilling */
2687 /*-----------------------------------------------------------------*/
2689 genIpop (iCode * ic)
2694 /* if the temp was not pushed then */
2695 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2698 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2699 size = AOP_SIZE (IC_LEFT (ic));
2700 offset = (size - 1);
2701 if (isPair (AOP (IC_LEFT (ic))))
2703 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2711 spillPair (PAIR_HL);
2712 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2716 freeAsmop (IC_LEFT (ic), NULL, ic);
2719 /* This is quite unfortunate */
2721 setArea (int inHome)
2724 static int lastArea = 0;
2726 if (_G.in_home != inHome) {
2728 const char *sz = port->mem.code_name;
2729 port->mem.code_name = "HOME";
2730 emit2("!area", CODE_NAME);
2731 port->mem.code_name = sz;
2734 emit2("!area", CODE_NAME); */
2735 _G.in_home = inHome;
2746 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2750 symbol *sym = OP_SYMBOL (op);
2752 if (sym->isspilt || sym->nRegs == 0)
2755 aopOp (op, ic, FALSE, FALSE);
2758 if (aop->type == AOP_REG)
2761 for (i = 0; i < aop->size; i++)
2763 if (pairId == PAIR_DE)
2765 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2766 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2768 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2771 else if (pairId == PAIR_BC)
2773 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2774 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2776 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2786 freeAsmop (IC_LEFT (ic), NULL, ic);
2790 /** Emit the code for a call statement
2793 emitCall (iCode * ic, bool ispcall)
2795 bool bInRet, cInRet, dInRet, eInRet;
2796 sym_link *dtype = operandType (IC_LEFT (ic));
2798 /* if caller saves & we have not saved then */
2804 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2806 /* if send set is not empty then assign */
2811 int nSend = elementsInSet(_G.sendSet);
2812 bool swapped = FALSE;
2814 int _z80_sendOrder[] = {
2819 /* Check if the parameters are swapped. If so route through hl instead. */
2820 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2822 sic = setFirstItem(_G.sendSet);
2823 sic = setNextItem(_G.sendSet);
2825 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2826 /* The second send value is loaded from one the one that holds the first
2827 send, i.e. it is overwritten. */
2828 /* Cache the first in HL, and load the second from HL instead. */
2829 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2830 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2836 for (sic = setFirstItem (_G.sendSet); sic;
2837 sic = setNextItem (_G.sendSet))
2840 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2842 size = AOP_SIZE (IC_LEFT (sic));
2843 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2844 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2846 // PENDING: Mild hack
2847 if (swapped == TRUE && send == 1) {
2849 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2852 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2854 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2857 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2861 freeAsmop (IC_LEFT (sic), NULL, sic);
2868 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2870 werror (W_INDIR_BANKED);
2872 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2874 if (isLitWord (AOP (IC_LEFT (ic))))
2876 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2880 symbol *rlbl = newiTempLabel (NULL);
2881 spillPair (PAIR_HL);
2882 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2884 _G.stack.pushed += 2;
2886 fetchHL (AOP (IC_LEFT (ic)));
2888 emit2 ("!tlabeldef", (rlbl->key + 100));
2889 _G.stack.pushed -= 2;
2891 freeAsmop (IC_LEFT (ic), NULL, ic);
2895 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2896 OP_SYMBOL (IC_LEFT (ic))->rname :
2897 OP_SYMBOL (IC_LEFT (ic))->name;
2898 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2900 emit2 ("call banked_call");
2901 emit2 ("!dws", name);
2902 emit2 ("!dw !bankimmeds", name);
2907 emit2 ("call %s", name);
2912 /* Mark the regsiters as restored. */
2913 _G.saves.saved = FALSE;
2915 /* if we need assign a result value */
2916 if ((IS_ITEMP (IC_RESULT (ic)) &&
2917 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2918 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2919 IS_TRUE_SYMOP (IC_RESULT (ic)))
2922 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2924 assignResultValue (IC_RESULT (ic));
2926 freeAsmop (IC_RESULT (ic), NULL, ic);
2929 /* adjust the stack for parameters if required */
2932 int i = ic->parmBytes;
2934 _G.stack.pushed -= i;
2937 emit2 ("!ldaspsp", i);
2944 emit2 ("ld iy,!immedword", i);
2945 emit2 ("add iy,sp");
2966 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2967 bInRet = bitVectBitValue(result, B_IDX);
2968 cInRet = bitVectBitValue(result, C_IDX);
2969 dInRet = bitVectBitValue(result, D_IDX);
2970 eInRet = bitVectBitValue(result, E_IDX);
2980 if (_G.stack.pushedDE)
2982 if (dInRet && eInRet)
2984 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2988 /* Only restore E */
2995 /* Only restore D */
3003 _G.stack.pushedDE = FALSE;
3006 if (_G.stack.pushedBC)
3008 if (bInRet && cInRet)
3010 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3014 /* Only restore C */
3021 /* Only restore B */
3029 _G.stack.pushedBC = FALSE;
3033 /*-----------------------------------------------------------------*/
3034 /* genCall - generates a call statement */
3035 /*-----------------------------------------------------------------*/
3037 genCall (iCode * ic)
3039 emitCall (ic, FALSE);
3042 /*-----------------------------------------------------------------*/
3043 /* genPcall - generates a call by pointer statement */
3044 /*-----------------------------------------------------------------*/
3046 genPcall (iCode * ic)
3048 emitCall (ic, TRUE);
3051 /*-----------------------------------------------------------------*/
3052 /* resultRemat - result is rematerializable */
3053 /*-----------------------------------------------------------------*/
3055 resultRemat (iCode * ic)
3057 if (SKIP_IC (ic) || ic->op == IFX)
3060 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3062 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3063 if (sym->remat && !POINTER_SET (ic))
3070 extern set *publics;
3072 /*-----------------------------------------------------------------*/
3073 /* genFunction - generated code for function entry */
3074 /*-----------------------------------------------------------------*/
3076 genFunction (iCode * ic)
3080 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3083 bool bcInUse = FALSE;
3084 bool deInUse = FALSE;
3086 setArea (IFFUNC_NONBANKED (sym->type));
3088 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
3091 _G.receiveOffset = 0;
3093 /* Record the last function name for debugging. */
3094 _G.lastFunctionName = sym->rname;
3096 /* Create the function header */
3097 emit2 ("!functionheader", sym->name);
3098 sprintf (buffer, "%s_start", sym->rname);
3099 emit2 ("!labeldef", buffer);
3100 emit2 ("!functionlabeldef", sym->rname);
3102 if (options.profile)
3104 emit2 ("!profileenter");
3107 ftype = operandType (IC_LEFT (ic));
3109 /* if critical function then turn interrupts off */
3110 if (IFFUNC_ISCRITICAL (ftype))
3113 /* if this is an interrupt service routine then save all potentially used registers. */
3114 if (IFFUNC_ISISR (sym->type))
3119 /* PENDING: callee-save etc */
3121 _G.stack.param_offset = 0;
3123 if (z80_opts.calleeSavesBC)
3128 /* Detect which registers are used. */
3129 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3132 for (i = 0; i < sym->regsUsed->size; i++)
3134 if (bitVectBitValue (sym->regsUsed, i))
3148 /* Other systems use DE as a temporary. */
3159 _G.stack.param_offset += 2;
3162 _G.calleeSaves.pushedBC = bcInUse;
3167 _G.stack.param_offset += 2;
3170 _G.calleeSaves.pushedDE = deInUse;
3172 /* adjust the stack for the function */
3173 _G.stack.last = sym->stack;
3176 for (sym = setFirstItem (istack->syms); sym;
3177 sym = setNextItem (istack->syms))
3179 if (sym->_isparm && !IS_REGPARM (sym->etype))
3185 sym = OP_SYMBOL (IC_LEFT (ic));
3187 _G.omitFramePtr = options.ommitFramePtr;
3188 if (IS_Z80 && !stackParm && !sym->stack)
3190 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3191 /* the above !sym->stack condition can be removed. -- EEP */
3193 emit2 ("!ldaspsp", -sym->stack);
3194 _G.omitFramePtr = TRUE;
3196 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3197 emit2 ("!enterxl", sym->stack);
3198 else if (sym->stack)
3199 emit2 ("!enterx", sym->stack);
3200 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3203 _G.stack.offset = sym->stack;
3206 /*-----------------------------------------------------------------*/
3207 /* genEndFunction - generates epilogue for functions */
3208 /*-----------------------------------------------------------------*/
3210 genEndFunction (iCode * ic)
3212 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3214 if (IFFUNC_ISISR (sym->type))
3216 wassertl (0, "Tried to close an interrupt support function");
3220 if (IFFUNC_ISCRITICAL (sym->type))
3223 /* PENDING: calleeSave */
3225 if (IS_Z80 && _G.omitFramePtr)
3227 if (_G.stack.offset)
3228 emit2 ("!ldaspsp", _G.stack.offset);
3230 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3232 emit2 ("!leavexl", _G.stack.offset);
3234 else if (_G.stack.offset)
3236 emit2 ("!leavex", _G.stack.offset);
3238 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3243 if (_G.calleeSaves.pushedDE)
3246 _G.calleeSaves.pushedDE = FALSE;
3249 if (_G.calleeSaves.pushedBC)
3252 _G.calleeSaves.pushedBC = FALSE;
3255 if (options.profile)
3257 emit2 ("!profileexit");
3261 if (options.debug && currFunc)
3263 _G.lines.isDebug = 1;
3264 sprintf (buffer, "C$%s$%d$%d$%d",
3265 FileBaseName (ic->filename), currFunc->lastLine,
3266 ic->level, ic->block);
3267 emit2 ("!labeldef", buffer);
3268 if (IS_STATIC (currFunc->etype))
3269 sprintf (buffer, "XF%s$%s$0$0", moduleName, currFunc->name);
3271 sprintf (buffer, "XG$%s$0$0", currFunc->name);
3272 emit2 ("!labeldef", buffer);
3273 _G.lines.isDebug = 0;
3276 /* Both banked and non-banked just ret */
3279 sprintf (buffer, "%s_end", sym->rname);
3280 emit2 ("!labeldef", buffer);
3282 _G.flushStatics = 1;
3283 _G.stack.pushed = 0;
3284 _G.stack.offset = 0;
3287 /*-----------------------------------------------------------------*/
3288 /* genRet - generate code for return statement */
3289 /*-----------------------------------------------------------------*/
3294 /* Errk. This is a hack until I can figure out how
3295 to cause dehl to spill on a call */
3296 int size, offset = 0;
3298 /* if we have no return value then
3299 just generate the "ret" */
3303 /* we have something to return then
3304 move the return value into place */
3305 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3306 size = AOP_SIZE (IC_LEFT (ic));
3308 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3311 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3315 emit2 ("ld de,%s", l);
3319 emit2 ("ld hl,%s", l);
3325 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3329 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3331 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3332 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3338 l = aopGet (AOP (IC_LEFT (ic)), offset,
3340 if (strcmp (_fReturn[offset], l))
3341 emit2 ("ld %s,%s", _fReturn[offset], l);
3346 freeAsmop (IC_LEFT (ic), NULL, ic);
3349 /* generate a jump to the return label
3350 if the next is not the return statement */
3351 if (!(ic->next && ic->next->op == LABEL &&
3352 IC_LABEL (ic->next) == returnLabel))
3354 emit2 ("jp !tlabel", returnLabel->key + 100);
3357 /*-----------------------------------------------------------------*/
3358 /* genLabel - generates a label */
3359 /*-----------------------------------------------------------------*/
3361 genLabel (iCode * ic)
3363 /* special case never generate */
3364 if (IC_LABEL (ic) == entryLabel)
3367 emitLabel (IC_LABEL (ic)->key + 100);
3370 /*-----------------------------------------------------------------*/
3371 /* genGoto - generates a ljmp */
3372 /*-----------------------------------------------------------------*/
3374 genGoto (iCode * ic)
3376 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3379 /*-----------------------------------------------------------------*/
3380 /* genPlusIncr :- does addition with increment if possible */
3381 /*-----------------------------------------------------------------*/
3383 genPlusIncr (iCode * ic)
3385 unsigned int icount;
3386 unsigned int size = getDataSize (IC_RESULT (ic));
3387 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3389 /* will try to generate an increment */
3390 /* if the right side is not a literal
3392 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3395 emitDebug ("; genPlusIncr");
3397 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3399 /* If result is a pair */
3400 if (resultId != PAIR_INVALID)
3402 if (isLitWord (AOP (IC_LEFT (ic))))
3404 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3407 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3409 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3411 PAIR_ID freep = getFreePairId (ic);
3412 if (freep != PAIR_INVALID)
3414 fetchPair (freep, AOP (IC_RIGHT (ic)));
3415 emit2 ("add hl,%s", _pairs[freep].name);
3421 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3422 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3429 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3433 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3437 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3442 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3444 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3445 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3449 /* if the literal value of the right hand side
3450 is greater than 4 then it is not worth it */
3454 /* if increment 16 bits in register */
3455 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3461 symbol *tlbl = NULL;
3462 tlbl = newiTempLabel (NULL);
3465 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3468 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3471 emitLabel (tlbl->key + 100);
3475 /* if the sizes are greater than 1 then we cannot */
3476 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3477 AOP_SIZE (IC_LEFT (ic)) > 1)
3480 /* If the result is in a register then we can load then increment.
3482 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3484 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3487 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3492 /* we can if the aops of the left & result match or
3493 if they are in registers and the registers are the
3495 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3499 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3507 /*-----------------------------------------------------------------*/
3508 /* outBitAcc - output a bit in acc */
3509 /*-----------------------------------------------------------------*/
3511 outBitAcc (operand * result)
3513 symbol *tlbl = newiTempLabel (NULL);
3514 /* if the result is a bit */
3515 if (AOP_TYPE (result) == AOP_CRY)
3517 wassertl (0, "Tried to write A into a bit");
3521 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3522 emit2 ("ld a,!one");
3523 emitLabel (tlbl->key + 100);
3529 couldDestroyCarry (asmop *aop)
3533 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3542 shiftIntoPair (int idx, asmop *aop)
3544 PAIR_ID id = PAIR_INVALID;
3546 wassertl (IS_Z80, "Only implemented for the Z80");
3547 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3559 wassertl (0, "Internal error - hit default case");
3562 emitDebug ("; Shift into pair idx %u", idx);
3566 setupPair (PAIR_HL, aop, 0);
3570 setupPair (PAIR_IY, aop, 0);
3572 emit2 ("pop %s", _pairs[id].name);
3575 aop->type = AOP_PAIRPTR;
3576 aop->aopu.aop_pairId = id;
3577 _G.pairs[id].offset = 0;
3578 _G.pairs[id].last_type = aop->type;
3582 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3584 wassert (left && right);
3588 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3590 shiftIntoPair (0, right);
3591 /* check result again, in case right == result */
3592 if (couldDestroyCarry (result))
3593 shiftIntoPair (1, result);
3595 else if (couldDestroyCarry (right))
3597 if (getPairId (result) == PAIR_HL)
3598 _G.preserveCarry = TRUE;
3600 shiftIntoPair (0, right);
3602 else if (couldDestroyCarry (result))
3604 shiftIntoPair (0, result);
3613 /*-----------------------------------------------------------------*/
3614 /* genPlus - generates code for addition */
3615 /*-----------------------------------------------------------------*/
3617 genPlus (iCode * ic)
3619 int size, offset = 0;
3621 /* special cases :- */
3623 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3624 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3625 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3627 /* Swap the left and right operands if:
3629 if literal, literal on the right or
3630 if left requires ACC or right is already
3633 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3634 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3635 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3637 operand *t = IC_RIGHT (ic);
3638 IC_RIGHT (ic) = IC_LEFT (ic);
3642 /* if both left & right are in bit
3644 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3645 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3648 wassertl (0, "Tried to add two bits");
3651 /* if left in bit space & right literal */
3652 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3653 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3655 /* Can happen I guess */
3656 wassertl (0, "Tried to add a bit to a literal");
3659 /* if I can do an increment instead
3660 of add then GOOD for ME */
3661 if (genPlusIncr (ic) == TRUE)
3664 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3666 size = getDataSize (IC_RESULT (ic));
3668 /* Special case when left and right are constant */
3669 if (isPair (AOP (IC_RESULT (ic))))
3672 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3673 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3675 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3681 sprintf (buffer, "#(%s + %s)", left, right);
3682 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3687 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3689 /* Fetch into HL then do the add */
3690 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3691 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3693 spillPair (PAIR_HL);
3695 if (left == PAIR_HL && right != PAIR_INVALID)
3697 emit2 ("add hl,%s", _pairs[right].name);
3700 else if (right == PAIR_HL && left != PAIR_INVALID)
3702 emit2 ("add hl,%s", _pairs[left].name);
3705 else if (right != PAIR_INVALID && right != PAIR_HL)
3707 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3708 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3711 else if (left != PAIR_INVALID && left != PAIR_HL)
3713 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3714 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3723 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3725 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3726 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3728 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3733 ld hl,sp+n trashes C so we cant afford to do it during an
3734 add with stack based varibles. Worst case is:
3747 So you cant afford to load up hl if either left, right, or result
3748 is on the stack (*sigh*) The alt is:
3756 Combinations in here are:
3757 * If left or right are in bc then the loss is small - trap later
3758 * If the result is in bc then the loss is also small
3762 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3763 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3764 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3766 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3767 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3768 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3769 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3771 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3773 /* Swap left and right */
3774 operand *t = IC_RIGHT (ic);
3775 IC_RIGHT (ic) = IC_LEFT (ic);
3778 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3780 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3781 emit2 ("add hl,bc");
3785 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3786 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3787 emit2 ("add hl,de");
3789 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3795 /* Be paranoid on the GB with 4 byte variables due to how C
3796 can be trashed by lda hl,n(sp).
3798 _gbz80_emitAddSubLong (ic, TRUE);
3803 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3807 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3809 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3812 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3815 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3819 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3822 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3825 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3827 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3831 _G.preserveCarry = FALSE;
3832 freeAsmop (IC_LEFT (ic), NULL, ic);
3833 freeAsmop (IC_RIGHT (ic), NULL, ic);
3834 freeAsmop (IC_RESULT (ic), NULL, ic);
3838 /*-----------------------------------------------------------------*/
3839 /* genMinusDec :- does subtraction with deccrement if possible */
3840 /*-----------------------------------------------------------------*/
3842 genMinusDec (iCode * ic)
3844 unsigned int icount;
3845 unsigned int size = getDataSize (IC_RESULT (ic));
3847 /* will try to generate an increment */
3848 /* if the right side is not a literal we cannot */
3849 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3852 /* if the literal value of the right hand side
3853 is greater than 4 then it is not worth it */
3854 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3857 size = getDataSize (IC_RESULT (ic));
3859 /* if decrement 16 bits in register */
3860 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3861 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3864 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3868 /* If result is a pair */
3869 if (isPair (AOP (IC_RESULT (ic))))
3871 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3873 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3877 /* if increment 16 bits in register */
3878 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3882 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3885 emit2 ("dec %s", _getTempPairName());
3888 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3894 /* if the sizes are greater than 1 then we cannot */
3895 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3896 AOP_SIZE (IC_LEFT (ic)) > 1)
3899 /* we can if the aops of the left & result match or if they are in
3900 registers and the registers are the same */
3901 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3904 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3911 /*-----------------------------------------------------------------*/
3912 /* genMinus - generates code for subtraction */
3913 /*-----------------------------------------------------------------*/
3915 genMinus (iCode * ic)
3917 int size, offset = 0;
3918 unsigned long lit = 0L;
3920 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3921 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3922 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3924 /* special cases :- */
3925 /* if both left & right are in bit space */
3926 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3927 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3929 wassertl (0, "Tried to subtract two bits");
3933 /* if I can do an decrement instead of subtract then GOOD for ME */
3934 if (genMinusDec (ic) == TRUE)
3937 size = getDataSize (IC_RESULT (ic));
3939 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3944 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3948 /* Same logic as genPlus */
3951 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3952 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3953 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3955 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3956 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3957 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3958 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3960 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3961 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3963 if (left == PAIR_INVALID && right == PAIR_INVALID)
3968 else if (right == PAIR_INVALID)
3970 else if (left == PAIR_INVALID)
3973 fetchPair (left, AOP (IC_LEFT (ic)));
3974 /* Order is important. Right may be HL */
3975 fetchPair (right, AOP (IC_RIGHT (ic)));
3977 emit2 ("ld a,%s", _pairs[left].l);
3978 emit2 ("sub a,%s", _pairs[right].l);
3980 emit2 ("ld a,%s", _pairs[left].h);
3981 emit2 ("sbc a,%s", _pairs[right].h);
3983 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3985 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3987 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3993 /* Be paranoid on the GB with 4 byte variables due to how C
3994 can be trashed by lda hl,n(sp).
3996 _gbz80_emitAddSubLong (ic, FALSE);
4001 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
4003 /* if literal, add a,#-lit, else normal subb */
4006 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4007 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4011 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4014 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4018 /* first add without previous c */
4020 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4022 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4024 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4027 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4028 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4029 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4031 wassertl (0, "Tried to subtract on a long pointer");
4035 _G.preserveCarry = FALSE;
4036 freeAsmop (IC_LEFT (ic), NULL, ic);
4037 freeAsmop (IC_RIGHT (ic), NULL, ic);
4038 freeAsmop (IC_RESULT (ic), NULL, ic);
4041 /*-----------------------------------------------------------------*/
4042 /* genMult - generates code for multiplication */
4043 /*-----------------------------------------------------------------*/
4045 genMult (iCode * ic)
4049 /* If true then the final operation should be a subtract */
4050 bool active = FALSE;
4052 /* Shouldn't occur - all done through function calls */
4053 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4054 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4055 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
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));
4093 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4098 /* Fully unroled version of mul.s. Not the most efficient.
4100 for (count = 0; count < 16; count++)
4102 if (count != 0 && active)
4104 emit2 ("add hl,hl");
4108 if (active == FALSE)
4115 emit2 ("add hl,de");
4124 if (IS_Z80 && _G.stack.pushedDE)
4127 _G.stack.pushedDE = FALSE;
4130 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4132 freeAsmop (IC_LEFT (ic), NULL, ic);
4133 freeAsmop (IC_RIGHT (ic), NULL, ic);
4134 freeAsmop (IC_RESULT (ic), NULL, ic);
4137 /*-----------------------------------------------------------------*/
4138 /* genDiv - generates code for division */
4139 /*-----------------------------------------------------------------*/
4143 /* Shouldn't occur - all done through function calls */
4144 wassertl (0, "Division is handled through support function calls");
4147 /*-----------------------------------------------------------------*/
4148 /* genMod - generates code for division */
4149 /*-----------------------------------------------------------------*/
4153 /* Shouldn't occur - all done through function calls */
4157 /*-----------------------------------------------------------------*/
4158 /* genIfxJump :- will create a jump depending on the ifx */
4159 /*-----------------------------------------------------------------*/
4161 genIfxJump (iCode * ic, char *jval)
4166 /* if true label then we jump if condition
4170 jlbl = IC_TRUE (ic);
4171 if (!strcmp (jval, "a"))
4175 else if (!strcmp (jval, "c"))
4179 else if (!strcmp (jval, "nc"))
4183 else if (!strcmp (jval, "m"))
4187 else if (!strcmp (jval, "p"))
4193 /* The buffer contains the bit on A that we should test */
4199 /* false label is present */
4200 jlbl = IC_FALSE (ic);
4201 if (!strcmp (jval, "a"))
4205 else if (!strcmp (jval, "c"))
4209 else if (!strcmp (jval, "nc"))
4213 else if (!strcmp (jval, "m"))
4217 else if (!strcmp (jval, "p"))
4223 /* The buffer contains the bit on A that we should test */
4227 /* Z80 can do a conditional long jump */
4228 if (!strcmp (jval, "a"))
4232 else if (!strcmp (jval, "c"))
4235 else if (!strcmp (jval, "nc"))
4238 else if (!strcmp (jval, "m"))
4241 else if (!strcmp (jval, "p"))
4246 emit2 ("bit %s,a", jval);
4248 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4250 /* mark the icode as generated */
4256 _getPairIdName (PAIR_ID id)
4258 return _pairs[id].name;
4263 /* if unsigned char cmp with lit, just compare */
4265 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4267 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4270 emit2 ("xor a,!immedbyte", 0x80);
4271 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4274 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4276 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4278 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4279 // Pull left into DE and right into HL
4280 aopGet (AOP(left), LSB, FALSE);
4283 aopGet (AOP(right), LSB, FALSE);
4287 if (size == 0 && sign)
4289 // Highest byte when signed needs the bits flipped
4292 emit2 ("ld a,(de)");
4293 emit2 ("xor !immedbyte", 0x80);
4295 emit2 ("ld a,(hl)");
4296 emit2 ("xor !immedbyte", 0x80);
4300 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4304 emit2 ("ld a,(de)");
4305 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4315 spillPair (PAIR_HL);
4317 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4319 setupPair (PAIR_HL, AOP (left), 0);
4320 aopGet (AOP(right), LSB, FALSE);
4324 if (size == 0 && sign)
4326 // Highest byte when signed needs the bits flipped
4329 emit2 ("ld a,(hl)");
4330 emit2 ("xor !immedbyte", 0x80);
4332 emit2 ("ld a,%d(iy)", offset);
4333 emit2 ("xor !immedbyte", 0x80);
4337 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4341 emit2 ("ld a,(hl)");
4342 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4351 spillPair (PAIR_HL);
4352 spillPair (PAIR_IY);
4356 if (AOP_TYPE (right) == AOP_LIT)
4358 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4359 /* optimize if(x < 0) or if(x >= 0) */
4364 /* No sign so it's always false */
4369 /* Just load in the top most bit */
4370 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4371 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4373 genIfxJump (ifx, "7");
4385 /* First setup h and l contaning the top most bytes XORed */
4386 bool fDidXor = FALSE;
4387 if (AOP_TYPE (left) == AOP_LIT)
4389 unsigned long lit = (unsigned long)
4390 floatFromVal (AOP (left)->aopu.aop_lit);
4391 emit2 ("ld %s,!immedbyte", _fTmp[0],
4392 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4396 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4397 emit2 ("xor a,!immedbyte", 0x80);
4398 emit2 ("ld %s,a", _fTmp[0]);
4401 if (AOP_TYPE (right) == AOP_LIT)
4403 unsigned long lit = (unsigned long)
4404 floatFromVal (AOP (right)->aopu.aop_lit);
4405 emit2 ("ld %s,!immedbyte", _fTmp[1],
4406 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4410 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4411 emit2 ("xor a,!immedbyte", 0x80);
4412 emit2 ("ld %s,a", _fTmp[1]);
4418 /* Do a long subtract */
4421 _moveA (aopGet (AOP (left), offset, FALSE));
4423 if (sign && size == 0)
4425 emit2 ("ld a,%s", _fTmp[0]);
4426 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4430 /* Subtract through, propagating the carry */
4431 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4439 /** Generic compare for > or <
4442 genCmp (operand * left, operand * right,
4443 operand * result, iCode * ifx, int sign)
4445 int size, offset = 0;
4446 unsigned long lit = 0L;
4447 bool swap_sense = FALSE;
4449 /* if left & right are bit variables */
4450 if (AOP_TYPE (left) == AOP_CRY &&
4451 AOP_TYPE (right) == AOP_CRY)
4453 /* Cant happen on the Z80 */
4454 wassertl (0, "Tried to compare two bits");
4458 /* Do a long subtract of right from left. */
4459 size = max (AOP_SIZE (left), AOP_SIZE (right));
4461 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4463 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4464 // Pull left into DE and right into HL
4465 aopGet (AOP(left), LSB, FALSE);
4468 aopGet (AOP(right), LSB, FALSE);
4472 emit2 ("ld a,(de)");
4473 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4482 spillPair (PAIR_HL);
4486 if (AOP_TYPE (right) == AOP_LIT)
4488 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4489 /* optimize if(x < 0) or if(x >= 0) */
4494 /* No sign so it's always false */
4499 /* Just load in the top most bit */
4500 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4501 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4503 genIfxJump (ifx, "7");
4514 genIfxJump (ifx, swap_sense ? "c" : "nc");
4525 _moveA (aopGet (AOP (left), offset, FALSE));
4526 /* Subtract through, propagating the carry */
4527 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4533 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4537 /* Shift the sign bit up into carry */
4540 outBitCLong (result, swap_sense);
4544 /* if the result is used in the next
4545 ifx conditional branch then generate
4546 code a little differently */
4554 genIfxJump (ifx, swap_sense ? "nc" : "c");
4558 genIfxJump (ifx, swap_sense ? "p" : "m");
4563 genIfxJump (ifx, swap_sense ? "nc" : "c");
4570 /* Shift the sign bit up into carry */
4573 outBitCLong (result, swap_sense);
4575 /* leave the result in acc */
4579 /*-----------------------------------------------------------------*/
4580 /* genCmpGt :- greater than comparison */
4581 /*-----------------------------------------------------------------*/
4583 genCmpGt (iCode * ic, iCode * ifx)
4585 operand *left, *right, *result;
4586 sym_link *letype, *retype;
4589 left = IC_LEFT (ic);
4590 right = IC_RIGHT (ic);
4591 result = IC_RESULT (ic);
4593 letype = getSpec (operandType (left));
4594 retype = getSpec (operandType (right));
4595 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4596 /* assign the amsops */
4597 aopOp (left, ic, FALSE, FALSE);
4598 aopOp (right, ic, FALSE, FALSE);
4599 aopOp (result, ic, TRUE, FALSE);
4601 genCmp (right, left, result, ifx, sign);
4603 freeAsmop (left, NULL, ic);
4604 freeAsmop (right, NULL, ic);
4605 freeAsmop (result, NULL, ic);
4608 /*-----------------------------------------------------------------*/
4609 /* genCmpLt - less than comparisons */
4610 /*-----------------------------------------------------------------*/
4612 genCmpLt (iCode * ic, iCode * ifx)
4614 operand *left, *right, *result;
4615 sym_link *letype, *retype;
4618 left = IC_LEFT (ic);
4619 right = IC_RIGHT (ic);
4620 result = IC_RESULT (ic);
4622 letype = getSpec (operandType (left));
4623 retype = getSpec (operandType (right));
4624 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4626 /* assign the amsops */
4627 aopOp (left, ic, FALSE, FALSE);
4628 aopOp (right, ic, FALSE, FALSE);
4629 aopOp (result, ic, TRUE, FALSE);
4631 genCmp (left, right, result, ifx, sign);
4633 freeAsmop (left, NULL, ic);
4634 freeAsmop (right, NULL, ic);
4635 freeAsmop (result, NULL, ic);
4638 /*-----------------------------------------------------------------*/
4639 /* gencjneshort - compare and jump if not equal */
4640 /*-----------------------------------------------------------------*/
4642 gencjneshort (operand * left, operand * right, symbol * lbl)
4644 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4646 unsigned long lit = 0L;
4648 /* Swap the left and right if it makes the computation easier */
4649 if (AOP_TYPE (left) == AOP_LIT)
4656 if (AOP_TYPE (right) == AOP_LIT)
4658 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4661 /* if the right side is a literal then anything goes */
4662 if (AOP_TYPE (right) == AOP_LIT &&
4663 AOP_TYPE (left) != AOP_DIR)
4667 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4672 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4679 emit2 ("jp nz,!tlabel", lbl->key + 100);
4685 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4686 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4689 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4690 emit2 ("jp nz,!tlabel", lbl->key + 100);
4695 /* if the right side is in a register or in direct space or
4696 if the left is a pointer register & right is not */
4697 else if (AOP_TYPE (right) == AOP_REG ||
4698 AOP_TYPE (right) == AOP_DIR ||
4699 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4703 _moveA (aopGet (AOP (left), offset, FALSE));
4704 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4705 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4707 emit2 ("jp nz,!tlabel", lbl->key + 100);
4710 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4711 emit2 ("jp nz,!tlabel", lbl->key + 100);
4718 /* right is a pointer reg need both a & b */
4719 /* PENDING: is this required? */
4722 _moveA (aopGet (AOP (right), offset, FALSE));
4723 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4724 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4730 /*-----------------------------------------------------------------*/
4731 /* gencjne - compare and jump if not equal */
4732 /*-----------------------------------------------------------------*/
4734 gencjne (operand * left, operand * right, symbol * lbl)
4736 symbol *tlbl = newiTempLabel (NULL);
4738 gencjneshort (left, right, lbl);
4741 emit2 ("ld a,!one");
4742 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4743 emitLabel (lbl->key + 100);
4745 emitLabel (tlbl->key + 100);
4748 /*-----------------------------------------------------------------*/
4749 /* genCmpEq - generates code for equal to */
4750 /*-----------------------------------------------------------------*/
4752 genCmpEq (iCode * ic, iCode * ifx)
4754 operand *left, *right, *result;
4756 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4757 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4758 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4760 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4762 /* Swap operands if it makes the operation easier. ie if:
4763 1. Left is a literal.
4765 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4767 operand *t = IC_RIGHT (ic);
4768 IC_RIGHT (ic) = IC_LEFT (ic);
4772 if (ifx && !AOP_SIZE (result))
4775 /* if they are both bit variables */
4776 if (AOP_TYPE (left) == AOP_CRY &&
4777 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4779 wassertl (0, "Tried to compare two bits");
4783 tlbl = newiTempLabel (NULL);
4784 gencjneshort (left, right, tlbl);
4787 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4788 emitLabel (tlbl->key + 100);
4792 /* PENDING: do this better */
4793 symbol *lbl = newiTempLabel (NULL);
4794 emit2 ("!shortjp !tlabel", lbl->key + 100);
4795 emitLabel (tlbl->key + 100);
4796 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4797 emitLabel (lbl->key + 100);
4800 /* mark the icode as generated */
4805 /* if they are both bit variables */
4806 if (AOP_TYPE (left) == AOP_CRY &&
4807 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4809 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4815 gencjne (left, right, newiTempLabel (NULL));
4816 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4823 genIfxJump (ifx, "a");
4826 /* if the result is used in an arithmetic operation
4827 then put the result in place */
4828 if (AOP_TYPE (result) != AOP_CRY)
4833 /* leave the result in acc */
4837 freeAsmop (left, NULL, ic);
4838 freeAsmop (right, NULL, ic);
4839 freeAsmop (result, NULL, ic);
4842 /*-----------------------------------------------------------------*/
4843 /* ifxForOp - returns the icode containing the ifx for operand */
4844 /*-----------------------------------------------------------------*/
4846 ifxForOp (operand * op, iCode * ic)
4848 /* if true symbol then needs to be assigned */
4849 if (IS_TRUE_SYMOP (op))
4852 /* if this has register type condition and
4853 the next instruction is ifx with the same operand
4854 and live to of the operand is upto the ifx only then */
4856 ic->next->op == IFX &&
4857 IC_COND (ic->next)->key == op->key &&
4858 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4864 /*-----------------------------------------------------------------*/
4865 /* genAndOp - for && operation */
4866 /*-----------------------------------------------------------------*/
4868 genAndOp (iCode * ic)
4870 operand *left, *right, *result;
4873 /* note here that && operations that are in an if statement are
4874 taken away by backPatchLabels only those used in arthmetic
4875 operations remain */
4876 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4877 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4878 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4880 /* if both are bit variables */
4881 if (AOP_TYPE (left) == AOP_CRY &&
4882 AOP_TYPE (right) == AOP_CRY)
4884 wassertl (0, "Tried to and two bits");
4888 tlbl = newiTempLabel (NULL);
4890 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4892 emitLabel (tlbl->key + 100);
4896 freeAsmop (left, NULL, ic);
4897 freeAsmop (right, NULL, ic);
4898 freeAsmop (result, NULL, ic);
4901 /*-----------------------------------------------------------------*/
4902 /* genOrOp - for || operation */
4903 /*-----------------------------------------------------------------*/
4905 genOrOp (iCode * ic)
4907 operand *left, *right, *result;
4910 /* note here that || operations that are in an
4911 if statement are taken away by backPatchLabels
4912 only those used in arthmetic operations remain */
4913 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4914 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4915 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4917 /* if both are bit variables */
4918 if (AOP_TYPE (left) == AOP_CRY &&
4919 AOP_TYPE (right) == AOP_CRY)
4921 wassertl (0, "Tried to OR two bits");
4925 tlbl = newiTempLabel (NULL);
4927 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4929 emitLabel (tlbl->key + 100);
4933 freeAsmop (left, NULL, ic);
4934 freeAsmop (right, NULL, ic);
4935 freeAsmop (result, NULL, ic);
4938 /*-----------------------------------------------------------------*/
4939 /* isLiteralBit - test if lit == 2^n */
4940 /*-----------------------------------------------------------------*/
4942 isLiteralBit (unsigned long lit)
4944 unsigned long pw[32] =
4945 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4946 0x100L, 0x200L, 0x400L, 0x800L,
4947 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4948 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4949 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4950 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4951 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4954 for (idx = 0; idx < 32; idx++)
4960 /*-----------------------------------------------------------------*/
4961 /* jmpTrueOrFalse - */
4962 /*-----------------------------------------------------------------*/
4964 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4966 // ugly but optimized by peephole
4969 symbol *nlbl = newiTempLabel (NULL);
4970 emit2 ("jp !tlabel", nlbl->key + 100);
4971 emitLabel (tlbl->key + 100);
4972 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4973 emitLabel (nlbl->key + 100);
4977 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4978 emitLabel (tlbl->key + 100);
4983 /*-----------------------------------------------------------------*/
4984 /* genAnd - code for and */
4985 /*-----------------------------------------------------------------*/
4987 genAnd (iCode * ic, iCode * ifx)
4989 operand *left, *right, *result;
4990 int size, offset = 0;
4991 unsigned long lit = 0L;
4994 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4995 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4996 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4998 /* if left is a literal & right is not then exchange them */
4999 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5000 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5002 operand *tmp = right;
5007 /* if result = right then exchange them */
5008 if (sameRegs (AOP (result), AOP (right)))
5010 operand *tmp = right;
5015 /* if right is bit then exchange them */
5016 if (AOP_TYPE (right) == AOP_CRY &&
5017 AOP_TYPE (left) != AOP_CRY)
5019 operand *tmp = right;
5023 if (AOP_TYPE (right) == AOP_LIT)
5024 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5026 size = AOP_SIZE (result);
5028 if (AOP_TYPE (left) == AOP_CRY)
5030 wassertl (0, "Tried to perform an AND with a bit as an operand");
5034 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5035 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5036 if ((AOP_TYPE (right) == AOP_LIT) &&
5037 (AOP_TYPE (result) == AOP_CRY) &&
5038 (AOP_TYPE (left) != AOP_CRY))
5040 symbol *tlbl = newiTempLabel (NULL);
5041 int sizel = AOP_SIZE (left);
5044 /* PENDING: Test case for this. */
5049 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5051 _moveA (aopGet (AOP (left), offset, FALSE));
5052 if (bytelit != 0x0FFL)
5054 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5061 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5065 // bit = left & literal
5069 emit2 ("!tlabeldef", tlbl->key + 100);
5071 // if(left & literal)
5076 jmpTrueOrFalse (ifx, tlbl);
5084 /* if left is same as result */
5085 if (sameRegs (AOP (result), AOP (left)))
5087 for (; size--; offset++)
5089 if (AOP_TYPE (right) == AOP_LIT)
5091 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5096 aopPut (AOP (result), "!zero", offset);
5099 _moveA (aopGet (AOP (left), offset, FALSE));
5101 aopGet (AOP (right), offset, FALSE));
5102 aopPut (AOP (left), "a", offset);
5109 if (AOP_TYPE (left) == AOP_ACC)
5111 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5115 _moveA (aopGet (AOP (left), offset, FALSE));
5117 aopGet (AOP (right), offset, FALSE));
5118 aopPut (AOP (left), "a", offset);
5125 // left & result in different registers
5126 if (AOP_TYPE (result) == AOP_CRY)
5128 wassertl (0, "Tried to AND where the result is in carry");
5132 for (; (size--); offset++)
5135 // result = left & right
5136 if (AOP_TYPE (right) == AOP_LIT)
5138 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5140 aopPut (AOP (result),
5141 aopGet (AOP (left), offset, FALSE),
5145 else if (bytelit == 0)
5147 aopPut (AOP (result), "!zero", offset);
5151 // faster than result <- left, anl result,right
5152 // and better if result is SFR
5153 if (AOP_TYPE (left) == AOP_ACC)
5154 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5157 _moveA (aopGet (AOP (left), offset, FALSE));
5159 aopGet (AOP (right), offset, FALSE));
5161 aopPut (AOP (result), "a", offset);
5168 freeAsmop (left, NULL, ic);
5169 freeAsmop (right, NULL, ic);
5170 freeAsmop (result, NULL, ic);
5173 /*-----------------------------------------------------------------*/
5174 /* genOr - code for or */
5175 /*-----------------------------------------------------------------*/
5177 genOr (iCode * ic, iCode * ifx)
5179 operand *left, *right, *result;
5180 int size, offset = 0;
5181 unsigned long lit = 0L;
5184 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5185 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5186 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5188 /* if left is a literal & right is not then exchange them */
5189 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5190 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5192 operand *tmp = right;
5197 /* if result = right then exchange them */
5198 if (sameRegs (AOP (result), AOP (right)))
5200 operand *tmp = right;
5205 /* if right is bit then exchange them */
5206 if (AOP_TYPE (right) == AOP_CRY &&
5207 AOP_TYPE (left) != AOP_CRY)
5209 operand *tmp = right;
5213 if (AOP_TYPE (right) == AOP_LIT)
5214 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5216 size = AOP_SIZE (result);
5218 if (AOP_TYPE (left) == AOP_CRY)
5220 wassertl (0, "Tried to OR where left is a bit");
5224 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5225 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5226 if ((AOP_TYPE (right) == AOP_LIT) &&
5227 (AOP_TYPE (result) == AOP_CRY) &&
5228 (AOP_TYPE (left) != AOP_CRY))
5230 symbol *tlbl = newiTempLabel (NULL);
5231 int sizel = AOP_SIZE (left);
5235 wassertl (0, "Result is assigned to a bit");
5237 /* PENDING: Modeled after the AND code which is inefficent. */
5240 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5242 _moveA (aopGet (AOP (left), offset, FALSE));
5243 /* OR with any literal is the same as OR with itself. */
5245 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5251 jmpTrueOrFalse (ifx, tlbl);
5256 /* if left is same as result */
5257 if (sameRegs (AOP (result), AOP (left)))
5259 for (; size--; offset++)
5261 if (AOP_TYPE (right) == AOP_LIT)
5263 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5267 _moveA (aopGet (AOP (left), offset, FALSE));
5269 aopGet (AOP (right), offset, FALSE));
5270 aopPut (AOP (result), "a", offset);
5275 if (AOP_TYPE (left) == AOP_ACC)
5276 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5279 _moveA (aopGet (AOP (left), offset, FALSE));
5281 aopGet (AOP (right), offset, FALSE));
5282 aopPut (AOP (result), "a", offset);
5289 // left & result in different registers
5290 if (AOP_TYPE (result) == AOP_CRY)
5292 wassertl (0, "Result of OR is in a bit");
5295 for (; (size--); offset++)
5298 // result = left & right
5299 if (AOP_TYPE (right) == AOP_LIT)
5301 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5303 aopPut (AOP (result),
5304 aopGet (AOP (left), offset, FALSE),
5309 // faster than result <- left, anl result,right
5310 // and better if result is SFR
5311 if (AOP_TYPE (left) == AOP_ACC)
5312 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5315 _moveA (aopGet (AOP (left), offset, FALSE));
5317 aopGet (AOP (right), offset, FALSE));
5319 aopPut (AOP (result), "a", offset);
5320 /* PENDING: something weird is going on here. Add exception. */
5321 if (AOP_TYPE (result) == AOP_ACC)
5327 freeAsmop (left, NULL, ic);
5328 freeAsmop (right, NULL, ic);
5329 freeAsmop (result, NULL, ic);
5332 /*-----------------------------------------------------------------*/
5333 /* genXor - code for xclusive or */
5334 /*-----------------------------------------------------------------*/
5336 genXor (iCode * ic, iCode * ifx)
5338 operand *left, *right, *result;
5339 int size, offset = 0;
5340 unsigned long lit = 0L;
5342 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5343 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5344 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5346 /* if left is a literal & right is not then exchange them */
5347 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5348 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5350 operand *tmp = right;
5355 /* if result = right then exchange them */
5356 if (sameRegs (AOP (result), AOP (right)))
5358 operand *tmp = right;
5363 /* if right is bit then exchange them */
5364 if (AOP_TYPE (right) == AOP_CRY &&
5365 AOP_TYPE (left) != AOP_CRY)
5367 operand *tmp = right;
5371 if (AOP_TYPE (right) == AOP_LIT)
5372 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5374 size = AOP_SIZE (result);
5376 if (AOP_TYPE (left) == AOP_CRY)
5378 wassertl (0, "Tried to XOR a bit");
5382 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5383 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5384 if ((AOP_TYPE (right) == AOP_LIT) &&
5385 (AOP_TYPE (result) == AOP_CRY) &&
5386 (AOP_TYPE (left) != AOP_CRY))
5388 symbol *tlbl = newiTempLabel (NULL);
5389 int sizel = AOP_SIZE (left);
5393 /* PENDING: Test case for this. */
5394 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5398 _moveA (aopGet (AOP (left), offset, FALSE));
5399 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5400 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5405 jmpTrueOrFalse (ifx, tlbl);
5409 wassertl (0, "Result of XOR was destined for a bit");
5414 /* if left is same as result */
5415 if (sameRegs (AOP (result), AOP (left)))
5417 for (; size--; offset++)
5419 if (AOP_TYPE (right) == AOP_LIT)
5421 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5425 _moveA (aopGet (AOP (left), offset, FALSE));
5427 aopGet (AOP (right), offset, FALSE));
5428 aopPut (AOP (result), "a", offset);
5433 if (AOP_TYPE (left) == AOP_ACC)
5435 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5439 _moveA (aopGet (AOP (left), offset, FALSE));
5441 aopGet (AOP (right), offset, FALSE));
5442 aopPut (AOP (result), "a", offset);
5449 // left & result in different registers
5450 if (AOP_TYPE (result) == AOP_CRY)
5452 wassertl (0, "Result of XOR is in a bit");
5455 for (; (size--); offset++)
5458 // result = left & right
5459 if (AOP_TYPE (right) == AOP_LIT)
5461 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5463 aopPut (AOP (result),
5464 aopGet (AOP (left), offset, FALSE),
5469 // faster than result <- left, anl result,right
5470 // and better if result is SFR
5471 if (AOP_TYPE (left) == AOP_ACC)
5473 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5477 _moveA (aopGet (AOP (left), offset, FALSE));
5479 aopGet (AOP (right), offset, FALSE));
5481 aopPut (AOP (result), "a", offset);
5486 freeAsmop (left, NULL, ic);
5487 freeAsmop (right, NULL, ic);
5488 freeAsmop (result, NULL, ic);
5491 /*-----------------------------------------------------------------*/
5492 /* genInline - write the inline code out */
5493 /*-----------------------------------------------------------------*/
5495 genInline (iCode * ic)
5497 char *buffer, *bp, *bp1;
5499 _G.lines.isInline += (!options.asmpeep);
5501 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5502 strcpy (buffer, IC_INLINE (ic));
5504 /* emit each line as a code */
5529 _G.lines.isInline -= (!options.asmpeep);
5533 /*-----------------------------------------------------------------*/
5534 /* genRRC - rotate right with carry */
5535 /*-----------------------------------------------------------------*/
5542 /*-----------------------------------------------------------------*/
5543 /* genRLC - generate code for rotate left with carry */
5544 /*-----------------------------------------------------------------*/
5551 /*-----------------------------------------------------------------*/
5552 /* genGetHbit - generates code get highest order bit */
5553 /*-----------------------------------------------------------------*/
5555 genGetHbit (iCode * ic)
5557 operand *left, *result;
5558 left = IC_LEFT (ic);
5559 result = IC_RESULT (ic);
5561 aopOp (left, ic, FALSE, FALSE);
5562 aopOp (result, ic, FALSE, FALSE);
5564 /* get the highest order byte into a */
5565 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5567 if (AOP_TYPE (result) == AOP_CRY)
5575 emit2 ("and a,!one");
5580 freeAsmop (left, NULL, ic);
5581 freeAsmop (result, NULL, ic);
5585 emitRsh2 (asmop *aop, int size, int is_signed)
5591 const char *l = aopGet (aop, size, FALSE);
5594 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5604 /*-----------------------------------------------------------------*/
5605 /* shiftR2Left2Result - shift right two bytes from left to result */
5606 /*-----------------------------------------------------------------*/
5608 shiftR2Left2Result (operand * left, int offl,
5609 operand * result, int offr,
5610 int shCount, int is_signed)
5613 symbol *tlbl, *tlbl1;
5615 movLeft2Result (left, offl, result, offr, 0);
5616 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5618 /* if (AOP(result)->type == AOP_REG) { */
5620 tlbl = newiTempLabel (NULL);
5621 tlbl1 = newiTempLabel (NULL);
5623 /* Left is already in result - so now do the shift */
5628 emitRsh2 (AOP (result), size, is_signed);
5633 emit2 ("ld a,!immedbyte+1", shCount);
5634 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5635 emitLabel (tlbl->key + 100);
5637 emitRsh2 (AOP (result), size, is_signed);
5639 emitLabel (tlbl1->key + 100);
5641 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5645 /*-----------------------------------------------------------------*/
5646 /* shiftL2Left2Result - shift left two bytes from left to result */
5647 /*-----------------------------------------------------------------*/
5649 shiftL2Left2Result (operand * left, int offl,
5650 operand * result, int offr, int shCount)
5652 if (sameRegs (AOP (result), AOP (left)) &&
5653 ((offl + MSB16) == offr))
5659 /* Copy left into result */
5660 movLeft2Result (left, offl, result, offr, 0);
5661 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5664 if (getPairId (AOP (result)) == PAIR_HL)
5668 emit2 ("add hl,hl");
5675 symbol *tlbl, *tlbl1;
5678 tlbl = newiTempLabel (NULL);
5679 tlbl1 = newiTempLabel (NULL);
5681 if (AOP (result)->type == AOP_REG)
5685 for (offset = 0; offset < size; offset++)
5687 l = aopGet (AOP (result), offset, FALSE);
5691 emit2 ("sla %s", l);
5702 /* Left is already in result - so now do the shift */
5705 emit2 ("ld a,!immedbyte+1", shCount);
5706 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5707 emitLabel (tlbl->key + 100);
5712 l = aopGet (AOP (result), offset, FALSE);
5716 emit2 ("sla %s", l);
5727 emitLabel (tlbl1->key + 100);
5729 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5735 /*-----------------------------------------------------------------*/
5736 /* AccRol - rotate left accumulator by known count */
5737 /*-----------------------------------------------------------------*/
5739 AccRol (int shCount)
5741 shCount &= 0x0007; // shCount : 0..7
5818 /*-----------------------------------------------------------------*/
5819 /* AccLsh - left shift accumulator by known count */
5820 /*-----------------------------------------------------------------*/
5822 AccLsh (int shCount)
5824 static const unsigned char SLMask[] =
5826 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5835 else if (shCount == 2)
5842 /* rotate left accumulator */
5844 /* and kill the lower order bits */
5845 emit2 ("and a,!immedbyte", SLMask[shCount]);
5850 /*-----------------------------------------------------------------*/
5851 /* shiftL1Left2Result - shift left one byte from left to result */
5852 /*-----------------------------------------------------------------*/
5854 shiftL1Left2Result (operand * left, int offl,
5855 operand * result, int offr, int shCount)
5858 l = aopGet (AOP (left), offl, FALSE);
5860 /* shift left accumulator */
5862 aopPut (AOP (result), "a", offr);
5866 /*-----------------------------------------------------------------*/
5867 /* genlshTwo - left shift two bytes by known amount != 0 */
5868 /*-----------------------------------------------------------------*/
5870 genlshTwo (operand * result, operand * left, int shCount)
5872 int size = AOP_SIZE (result);
5874 wassert (size == 2);
5876 /* if shCount >= 8 */
5884 movLeft2Result (left, LSB, result, MSB16, 0);
5885 aopPut (AOP (result), "!zero", 0);
5886 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5890 movLeft2Result (left, LSB, result, MSB16, 0);
5891 aopPut (AOP (result), "!zero", 0);
5896 aopPut (AOP (result), "!zero", LSB);
5899 /* 1 <= shCount <= 7 */
5908 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5913 /*-----------------------------------------------------------------*/
5914 /* genlshOne - left shift a one byte quantity by known count */
5915 /*-----------------------------------------------------------------*/
5917 genlshOne (operand * result, operand * left, int shCount)
5919 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5922 /*-----------------------------------------------------------------*/
5923 /* genLeftShiftLiteral - left shifting by known count */
5924 /*-----------------------------------------------------------------*/
5926 genLeftShiftLiteral (operand * left,
5931 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5934 freeAsmop (right, NULL, ic);
5936 aopOp (left, ic, FALSE, FALSE);
5937 aopOp (result, ic, FALSE, FALSE);
5939 size = getSize (operandType (result));
5941 /* I suppose that the left size >= result size */
5947 else if (shCount >= (size * 8))
5951 aopPut (AOP (result), "!zero", size);
5959 genlshOne (result, left, shCount);
5962 genlshTwo (result, left, shCount);
5965 wassertl (0, "Shifting of longs is currently unsupported");
5971 freeAsmop (left, NULL, ic);
5972 freeAsmop (result, NULL, ic);
5975 /*-----------------------------------------------------------------*/
5976 /* genLeftShift - generates code for left shifting */
5977 /*-----------------------------------------------------------------*/
5979 genLeftShift (iCode * ic)
5983 symbol *tlbl, *tlbl1;
5984 operand *left, *right, *result;
5986 right = IC_RIGHT (ic);
5987 left = IC_LEFT (ic);
5988 result = IC_RESULT (ic);
5990 aopOp (right, ic, FALSE, FALSE);
5992 /* if the shift count is known then do it
5993 as efficiently as possible */
5994 if (AOP_TYPE (right) == AOP_LIT)
5996 genLeftShiftLiteral (left, right, result, ic);
6000 /* shift count is unknown then we have to form a loop get the loop
6001 count in B : Note: we take only the lower order byte since
6002 shifting more that 32 bits make no sense anyway, ( the largest
6003 size of an object can be only 32 bits ) */
6004 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6006 freeAsmop (right, NULL, ic);
6007 aopOp (left, ic, FALSE, FALSE);
6008 aopOp (result, ic, FALSE, FALSE);
6010 /* now move the left to the result if they are not the
6013 if (!sameRegs (AOP (left), AOP (result)))
6016 size = AOP_SIZE (result);
6020 l = aopGet (AOP (left), offset, FALSE);
6021 aopPut (AOP (result), l, offset);
6026 tlbl = newiTempLabel (NULL);
6027 size = AOP_SIZE (result);
6029 tlbl1 = newiTempLabel (NULL);
6031 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6032 emitLabel (tlbl->key + 100);
6033 l = aopGet (AOP (result), offset, FALSE);
6037 l = aopGet (AOP (result), offset, FALSE);
6041 emit2 ("sla %s", l);
6049 emitLabel (tlbl1->key + 100);
6051 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6053 freeAsmop (left, NULL, ic);
6054 freeAsmop (result, NULL, ic);
6057 /*-----------------------------------------------------------------*/
6058 /* genrshOne - left shift two bytes by known amount != 0 */
6059 /*-----------------------------------------------------------------*/
6061 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6064 int size = AOP_SIZE (result);
6067 wassert (size == 1);
6068 wassert (shCount < 8);
6070 l = aopGet (AOP (left), 0, FALSE);
6072 if (AOP (result)->type == AOP_REG)
6074 aopPut (AOP (result), l, 0);
6075 l = aopGet (AOP (result), 0, FALSE);
6078 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6086 emit2 ("%s a", is_signed ? "sra" : "srl");
6088 aopPut (AOP (result), "a", 0);
6092 /*-----------------------------------------------------------------*/
6093 /* AccRsh - right shift accumulator by known count */
6094 /*-----------------------------------------------------------------*/
6096 AccRsh (int shCount)
6098 static const unsigned char SRMask[] =
6100 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6105 /* rotate right accumulator */
6106 AccRol (8 - shCount);
6107 /* and kill the higher order bits */
6108 emit2 ("and a,!immedbyte", SRMask[shCount]);
6112 /*-----------------------------------------------------------------*/
6113 /* shiftR1Left2Result - shift right one byte from left to result */
6114 /*-----------------------------------------------------------------*/
6116 shiftR1Left2Result (operand * left, int offl,
6117 operand * result, int offr,
6118 int shCount, int sign)
6120 _moveA (aopGet (AOP (left), offl, FALSE));
6125 emit2 ("%s a", sign ? "sra" : "srl");
6132 aopPut (AOP (result), "a", offr);
6135 /*-----------------------------------------------------------------*/
6136 /* genrshTwo - right shift two bytes by known amount != 0 */
6137 /*-----------------------------------------------------------------*/
6139 genrshTwo (operand * result, operand * left,
6140 int shCount, int sign)
6142 /* if shCount >= 8 */
6148 shiftR1Left2Result (left, MSB16, result, LSB,
6153 movLeft2Result (left, MSB16, result, LSB, sign);
6157 /* Sign extend the result */
6158 _moveA(aopGet (AOP (result), 0, FALSE));
6162 aopPut (AOP (result), ACC_NAME, MSB16);
6166 aopPut (AOP (result), "!zero", 1);
6169 /* 1 <= shCount <= 7 */
6172 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6176 /*-----------------------------------------------------------------*/
6177 /* genRightShiftLiteral - left shifting by known count */
6178 /*-----------------------------------------------------------------*/
6180 genRightShiftLiteral (operand * left,
6186 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6189 freeAsmop (right, NULL, ic);
6191 aopOp (left, ic, FALSE, FALSE);
6192 aopOp (result, ic, FALSE, FALSE);
6194 size = getSize (operandType (result));
6196 /* I suppose that the left size >= result size */
6202 else if (shCount >= (size * 8)) {
6204 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6205 _moveA(aopGet (AOP (left), 0, FALSE));
6213 aopPut (AOP (result), s, size);
6220 genrshOne (result, left, shCount, sign);
6223 genrshTwo (result, left, shCount, sign);
6226 wassertl (0, "Asked to shift right a long which should be a function call");
6229 wassertl (0, "Entered default case in right shift delegate");
6232 freeAsmop (left, NULL, ic);
6233 freeAsmop (result, NULL, ic);
6236 /*-----------------------------------------------------------------*/
6237 /* genRightShift - generate code for right shifting */
6238 /*-----------------------------------------------------------------*/
6240 genRightShift (iCode * ic)
6242 operand *right, *left, *result;
6244 int size, offset, first = 1;
6248 symbol *tlbl, *tlbl1;
6250 /* if signed then we do it the hard way preserve the
6251 sign bit moving it inwards */
6252 retype = getSpec (operandType (IC_RESULT (ic)));
6254 is_signed = !SPEC_USIGN (retype);
6256 /* signed & unsigned types are treated the same : i.e. the
6257 signed is NOT propagated inwards : quoting from the
6258 ANSI - standard : "for E1 >> E2, is equivalent to division
6259 by 2**E2 if unsigned or if it has a non-negative value,
6260 otherwise the result is implementation defined ", MY definition
6261 is that the sign does not get propagated */
6263 right = IC_RIGHT (ic);
6264 left = IC_LEFT (ic);
6265 result = IC_RESULT (ic);
6267 aopOp (right, ic, FALSE, FALSE);
6269 /* if the shift count is known then do it
6270 as efficiently as possible */
6271 if (AOP_TYPE (right) == AOP_LIT)
6273 genRightShiftLiteral (left, right, result, ic, is_signed);
6277 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6279 freeAsmop (right, NULL, ic);
6281 aopOp (left, ic, FALSE, FALSE);
6282 aopOp (result, ic, FALSE, FALSE);
6284 /* now move the left to the result if they are not the
6286 if (!sameRegs (AOP (left), AOP (result)))
6289 size = AOP_SIZE (result);
6293 l = aopGet (AOP (left), offset, FALSE);
6294 aopPut (AOP (result), l, offset);
6299 tlbl = newiTempLabel (NULL);
6300 tlbl1 = newiTempLabel (NULL);
6301 size = AOP_SIZE (result);
6304 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6305 emitLabel (tlbl->key + 100);
6308 l = aopGet (AOP (result), offset--, FALSE);
6311 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6319 emitLabel (tlbl1->key + 100);
6321 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6323 freeAsmop (left, NULL, ic);
6324 freeAsmop (result, NULL, ic);
6328 /*-----------------------------------------------------------------*/
6329 /* genUnpackBits - generates code for unpacking bits */
6330 /*-----------------------------------------------------------------*/
6332 genUnpackBits (operand * result, int pair)
6334 int offset = 0; /* result byte offset */
6335 int rsize; /* result size */
6336 int rlen = 0; /* remaining bitfield length */
6337 sym_link *etype; /* bitfield type information */
6338 int blen; /* bitfield length */
6339 int bstr; /* bitfield starting bit within byte */
6341 emitDebug ("; genUnpackBits");
6343 etype = getSpec (operandType (result));
6344 rsize = getSize (operandType (result));
6345 blen = SPEC_BLEN (etype);
6346 bstr = SPEC_BSTR (etype);
6348 /* If the bitfield length is less than a byte */
6351 emit2 ("ld a,!*pair", _pairs[pair].name);
6353 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6354 aopPut (AOP (result), "a", offset++);
6358 /* TODO: what if pair == PAIR_DE ? */
6359 if (getPairId (AOP (result)) == PAIR_HL)
6361 wassertl (rsize == 2, "HL must be of size 2");
6362 emit2 ("ld a,!*hl");
6364 emit2 ("ld h,!*hl");
6367 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6369 spillPair (PAIR_HL);
6373 /* Bit field did not fit in a byte. Copy all
6374 but the partial byte at the end. */
6375 for (rlen=blen;rlen>=8;rlen-=8)
6377 emit2 ("ld a,!*pair", _pairs[pair].name);
6378 aopPut (AOP (result), "a", offset++);
6381 emit2 ("inc %s", _pairs[pair].name);
6382 _G.pairs[pair].offset++;
6386 /* Handle the partial byte at the end */
6389 emit2 ("ld a,!*pair", _pairs[pair].name);
6390 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6391 aopPut (AOP (result), "a", offset++);
6399 aopPut (AOP (result), "!zero", offset++);
6403 /*-----------------------------------------------------------------*/
6404 /* genGenPointerGet - get value from generic pointer space */
6405 /*-----------------------------------------------------------------*/
6407 genGenPointerGet (operand * left,
6408 operand * result, iCode * ic)
6411 sym_link *retype = getSpec (operandType (result));
6417 aopOp (left, ic, FALSE, FALSE);
6418 aopOp (result, ic, FALSE, FALSE);
6420 size = AOP_SIZE (result);
6422 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6425 if (isPtrPair (AOP (left)))
6427 tsprintf (buffer, sizeof(buffer),
6428 "!*pair", getPairName (AOP (left)));
6429 aopPut (AOP (result), buffer, 0);
6433 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6434 aopPut (AOP (result), "a", 0);
6436 freeAsmop (left, NULL, ic);
6440 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6447 tsprintf (at, sizeof(at), "!*iyx", offset);
6448 aopPut (AOP (result), at, offset);
6452 freeAsmop (left, NULL, ic);
6456 /* For now we always load into IY */
6457 /* if this is remateriazable */
6458 fetchPair (pair, AOP (left));
6460 /* if bit then unpack */
6461 if (IS_BITVAR (retype))
6463 genUnpackBits (result, pair);
6464 freeAsmop (left, NULL, ic);
6468 else if (getPairId (AOP (result)) == PAIR_HL)
6470 wassertl (size == 2, "HL must be of size 2");
6471 emit2 ("ld a,!*hl");
6473 emit2 ("ld h,!*hl");
6475 spillPair (PAIR_HL);
6477 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6479 size = AOP_SIZE (result);
6484 /* PENDING: make this better */
6485 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6487 aopPut (AOP (result), "!*hl", offset++);
6491 emit2 ("ld a,!*pair", _pairs[pair].name);
6492 aopPut (AOP (result), "a", offset++);
6496 emit2 ("inc %s", _pairs[pair].name);
6497 _G.pairs[pair].offset++;
6500 /* Fixup HL back down */
6501 for (size = AOP_SIZE (result)-1; size; size--)
6503 emit2 ("dec %s", _pairs[pair].name);
6508 size = AOP_SIZE (result);
6513 /* PENDING: make this better */
6515 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6517 aopPut (AOP (result), "!*hl", offset++);
6521 emit2 ("ld a,!*pair", _pairs[pair].name);
6522 aopPut (AOP (result), "a", offset++);
6526 emit2 ("inc %s", _pairs[pair].name);
6527 _G.pairs[pair].offset++;
6532 freeAsmop (left, NULL, ic);
6535 freeAsmop (result, NULL, ic);
6538 /*-----------------------------------------------------------------*/
6539 /* genPointerGet - generate code for pointer get */
6540 /*-----------------------------------------------------------------*/
6542 genPointerGet (iCode * ic)
6544 operand *left, *result;
6545 sym_link *type, *etype;
6547 left = IC_LEFT (ic);
6548 result = IC_RESULT (ic);
6550 /* depending on the type of pointer we need to
6551 move it to the correct pointer register */
6552 type = operandType (left);
6553 etype = getSpec (type);
6555 genGenPointerGet (left, result, ic);
6559 isRegOrLit (asmop * aop)
6561 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6567 /*-----------------------------------------------------------------*/
6568 /* genPackBits - generates code for packed bit storage */
6569 /*-----------------------------------------------------------------*/
6571 genPackBits (sym_link * etype,
6576 int offset = 0; /* source byte offset */
6577 int rlen = 0; /* remaining bitfield length */
6578 int blen; /* bitfield length */
6579 int bstr; /* bitfield starting bit within byte */
6580 int litval; /* source literal value (if AOP_LIT) */
6581 unsigned char mask; /* bitmask within current byte */
6582 int extraPair; /* a tempory register */
6583 bool needPopExtra=0; /* need to restore original value of temp reg */
6585 emitDebug ("; genPackBits","");
6587 blen = SPEC_BLEN (etype);
6588 bstr = SPEC_BSTR (etype);
6590 /* If the bitfield length is less than a byte */
6593 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6594 (unsigned char) (0xFF >> (8 - bstr)));
6596 if (AOP_TYPE (right) == AOP_LIT)
6598 /* Case with a bitfield length <8 and literal source
6600 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6602 litval &= (~mask) & 0xff;
6603 emit2 ("ld a,!*pair", _pairs[pair].name);
6604 if ((mask|litval)!=0xff)
6605 emit2 ("and a,!immedbyte", mask);
6607 emit2 ("or a,!immedbyte", litval);
6608 emit2 ("ld !*pair,a", _pairs[pair].name);
6613 /* Case with a bitfield length <8 and arbitrary source
6615 _moveA (aopGet (AOP (right), 0, FALSE));
6616 /* shift and mask source value */
6618 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6620 extraPair = getFreePairId(ic);
6621 if (extraPair == PAIR_INVALID)
6623 extraPair = PAIR_BC;
6624 if (getPairId (AOP (right)) != PAIR_BC
6625 || !isLastUse (ic, right))
6631 emit2 ("ld %s,a", _pairs[extraPair].l);
6632 emit2 ("ld a,!*pair", _pairs[pair].name);
6634 emit2 ("and a,!immedbyte", mask);
6635 emit2 ("or a,%s", _pairs[extraPair].l);
6636 emit2 ("ld !*pair,a", _pairs[pair].name);
6643 /* Bit length is greater than 7 bits. In this case, copy */
6644 /* all except the partial byte at the end */
6645 for (rlen=blen;rlen>=8;rlen-=8)
6647 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6648 emit2 ("ld !*pair,a", _pairs[pair].name);
6651 emit2 ("inc %s", _pairs[pair].name);
6652 _G.pairs[pair].offset++;
6656 /* If there was a partial byte at the end */
6659 mask = (((unsigned char) -1 << rlen) & 0xff);
6661 if (AOP_TYPE (right) == AOP_LIT)
6663 /* Case with partial byte and literal source
6665 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6666 litval >>= (blen-rlen);
6667 litval &= (~mask) & 0xff;
6668 emit2 ("ld a,!*pair", _pairs[pair].name);
6669 if ((mask|litval)!=0xff)
6670 emit2 ("and a,!immedbyte", mask);
6672 emit2 ("or a,!immedbyte", litval);
6676 /* Case with partial byte and arbitrary source
6678 _moveA (aopGet (AOP (right), offset++, FALSE));
6679 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6681 extraPair = getFreePairId(ic);
6682 if (extraPair == PAIR_INVALID)
6684 extraPair = getPairId (AOP (right));
6685 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6686 extraPair = PAIR_BC;
6688 if (getPairId (AOP (right)) != PAIR_BC
6689 || !isLastUse (ic, right))
6695 emit2 ("ld %s,a", _pairs[extraPair].l);
6696 emit2 ("ld a,!*pair", _pairs[pair].name);
6698 emit2 ("and a,!immedbyte", mask);
6699 emit2 ("or a,%s", _pairs[extraPair].l);
6704 emit2 ("ld !*pair,a", _pairs[pair].name);
6709 /*-----------------------------------------------------------------*/
6710 /* genGenPointerSet - stores the value into a pointer location */
6711 /*-----------------------------------------------------------------*/
6713 genGenPointerSet (operand * right,
6714 operand * result, iCode * ic)
6717 sym_link *retype = getSpec (operandType (right));
6718 sym_link *letype = getSpec (operandType (result));
6719 PAIR_ID pairId = PAIR_HL;
6722 aopOp (result, ic, FALSE, FALSE);
6723 aopOp (right, ic, FALSE, FALSE);
6728 size = AOP_SIZE (right);
6730 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6731 emitDebug("; isBitvar = %d", isBitvar);
6733 /* Handle the exceptions first */
6734 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6737 const char *l = aopGet (AOP (right), 0, FALSE);
6738 const char *pair = getPairName (AOP (result));
6739 if (canAssignToPtr (l) && isPtr (pair))
6741 emit2 ("ld !*pair,%s", pair, l);
6746 emit2 ("ld !*pair,a", pair);
6751 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6754 const char *l = aopGet (AOP (right), 0, FALSE);
6759 if (canAssignToPtr (l))
6761 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6765 _moveA (aopGet (AOP (right), offset, FALSE));
6766 emit2 ("ld !*iyx,a", offset);
6772 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6779 const char *l = aopGet (AOP (right), offset, FALSE);
6780 if (isRegOrLit (AOP (right)) && !IS_GB)
6782 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6787 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6791 emit2 ("inc %s", _pairs[PAIR_HL].name);
6792 _G.pairs[PAIR_HL].offset++;
6797 /* Fixup HL back down */
6798 for (size = AOP_SIZE (right)-1; size; size--)
6800 emit2 ("dec %s", _pairs[PAIR_HL].name);
6805 /* if the operand is already in dptr
6806 then we do nothing else we move the value to dptr */
6807 if (AOP_TYPE (result) != AOP_STR)
6809 fetchPair (pairId, AOP (result));
6811 /* so hl know contains the address */
6812 freeAsmop (result, NULL, ic);
6814 /* if bit then unpack */
6817 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6827 const char *l = aopGet (AOP (right), offset, FALSE);
6828 if (isRegOrLit (AOP (right)) && !IS_GB)
6830 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6835 emit2 ("ld !*pair,a", _pairs[pairId].name);
6839 emit2 ("inc %s", _pairs[pairId].name);
6840 _G.pairs[pairId].offset++;
6846 freeAsmop (right, NULL, ic);
6849 /*-----------------------------------------------------------------*/
6850 /* genPointerSet - stores the value into a pointer location */
6851 /*-----------------------------------------------------------------*/
6853 genPointerSet (iCode * ic)
6855 operand *right, *result;
6856 sym_link *type, *etype;
6858 right = IC_RIGHT (ic);
6859 result = IC_RESULT (ic);
6861 /* depending on the type of pointer we need to
6862 move it to the correct pointer register */
6863 type = operandType (result);
6864 etype = getSpec (type);
6866 genGenPointerSet (right, result, ic);
6869 /*-----------------------------------------------------------------*/
6870 /* genIfx - generate code for Ifx statement */
6871 /*-----------------------------------------------------------------*/
6873 genIfx (iCode * ic, iCode * popIc)
6875 operand *cond = IC_COND (ic);
6878 aopOp (cond, ic, FALSE, TRUE);
6880 /* get the value into acc */
6881 if (AOP_TYPE (cond) != AOP_CRY)
6885 /* the result is now in the accumulator */
6886 freeAsmop (cond, NULL, ic);
6888 /* if there was something to be popped then do it */
6892 /* if the condition is a bit variable */
6893 if (isbit && IS_ITEMP (cond) &&
6895 genIfxJump (ic, SPIL_LOC (cond)->rname);
6896 else if (isbit && !IS_ITEMP (cond))
6897 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6899 genIfxJump (ic, "a");
6904 /*-----------------------------------------------------------------*/
6905 /* genAddrOf - generates code for address of */
6906 /*-----------------------------------------------------------------*/
6908 genAddrOf (iCode * ic)
6910 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6912 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6914 /* if the operand is on the stack then we
6915 need to get the stack offset of this
6922 if (sym->stack <= 0)
6924 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6928 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6930 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6934 emit2 ("ld de,!hashedstr", sym->rname);
6935 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6943 /* if it has an offset then we need to compute it */
6945 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6947 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6948 emit2 ("add hl,sp");
6952 emit2 ("ld hl,!hashedstr", sym->rname);
6954 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6956 freeAsmop (IC_RESULT (ic), NULL, ic);
6959 /*-----------------------------------------------------------------*/
6960 /* genAssign - generate code for assignment */
6961 /*-----------------------------------------------------------------*/
6963 genAssign (iCode * ic)
6965 operand *result, *right;
6967 unsigned long lit = 0L;
6969 result = IC_RESULT (ic);
6970 right = IC_RIGHT (ic);
6972 /* Dont bother assigning if they are the same */
6973 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6975 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6979 aopOp (right, ic, FALSE, FALSE);
6980 aopOp (result, ic, TRUE, FALSE);
6982 /* if they are the same registers */
6983 if (sameRegs (AOP (right), AOP (result)))
6985 emitDebug ("; (registers are the same)");
6989 /* if the result is a bit */
6990 if (AOP_TYPE (result) == AOP_CRY)
6992 wassertl (0, "Tried to assign to a bit");
6996 size = AOP_SIZE (result);
6999 if (AOP_TYPE (right) == AOP_LIT)
7001 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7004 if (isPair (AOP (result)))
7006 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7008 else if ((size > 1) &&
7009 (AOP_TYPE (result) != AOP_REG) &&
7010 (AOP_TYPE (right) == AOP_LIT) &&
7011 !IS_FLOAT (operandType (right)) &&
7014 bool fXored = FALSE;
7016 /* Work from the top down.
7017 Done this way so that we can use the cached copy of 0
7018 in A for a fast clear */
7021 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7023 if (!fXored && size > 1)
7030 aopPut (AOP (result), "a", offset);
7034 aopPut (AOP (result), "!zero", offset);
7038 aopPut (AOP (result),
7039 aopGet (AOP (right), offset, FALSE),
7044 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7046 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7047 aopPut (AOP (result), "l", LSB);
7048 aopPut (AOP (result), "h", MSB16);
7050 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7052 /* Special case. Load into a and d, then load out. */
7053 _moveA (aopGet (AOP (right), 0, FALSE));
7054 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7055 aopPut (AOP (result), "a", 0);
7056 aopPut (AOP (result), "e", 1);
7058 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7060 /* Special case - simple memcpy */
7061 aopGet (AOP (right), LSB, FALSE);
7064 aopGet (AOP (result), LSB, FALSE);
7068 emit2 ("ld a,(de)");
7069 /* Peephole will optimise this. */
7070 emit2 ("ld (hl),a");
7078 spillPair (PAIR_HL);
7084 /* PENDING: do this check better */
7085 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7087 _moveA (aopGet (AOP (right), offset, FALSE));
7088 aopPut (AOP (result), "a", offset);
7091 aopPut (AOP (result),
7092 aopGet (AOP (right), offset, FALSE),
7099 freeAsmop (right, NULL, ic);
7100 freeAsmop (result, NULL, ic);
7103 /*-----------------------------------------------------------------*/
7104 /* genJumpTab - genrates code for jump table */
7105 /*-----------------------------------------------------------------*/
7107 genJumpTab (iCode * ic)
7112 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7113 /* get the condition into accumulator */
7114 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7117 emit2 ("ld e,%s", l);
7118 emit2 ("ld d,!zero");
7119 jtab = newiTempLabel (NULL);
7121 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7122 emit2 ("add hl,de");
7123 emit2 ("add hl,de");
7124 emit2 ("add hl,de");
7125 freeAsmop (IC_JTCOND (ic), NULL, ic);
7129 emitLabel (jtab->key + 100);
7130 /* now generate the jump labels */
7131 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7132 jtab = setNextItem (IC_JTLABELS (ic)))
7133 emit2 ("jp !tlabel", jtab->key + 100);
7136 /*-----------------------------------------------------------------*/
7137 /* genCast - gen code for casting */
7138 /*-----------------------------------------------------------------*/
7140 genCast (iCode * ic)
7142 operand *result = IC_RESULT (ic);
7143 sym_link *rtype = operandType (IC_RIGHT (ic));
7144 operand *right = IC_RIGHT (ic);
7147 /* if they are equivalent then do nothing */
7148 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7151 aopOp (right, ic, FALSE, FALSE);
7152 aopOp (result, ic, FALSE, FALSE);
7154 /* if the result is a bit */
7155 if (AOP_TYPE (result) == AOP_CRY)
7157 wassertl (0, "Tried to cast to a bit");
7160 /* if they are the same size : or less */
7161 if (AOP_SIZE (result) <= AOP_SIZE (right))
7164 /* if they are in the same place */
7165 if (sameRegs (AOP (right), AOP (result)))
7168 /* if they in different places then copy */
7169 size = AOP_SIZE (result);
7173 aopPut (AOP (result),
7174 aopGet (AOP (right), offset, FALSE),
7181 /* So we now know that the size of destination is greater
7182 than the size of the source */
7183 /* we move to result for the size of source */
7184 size = AOP_SIZE (right);
7188 aopPut (AOP (result),
7189 aopGet (AOP (right), offset, FALSE),
7194 /* now depending on the sign of the destination */
7195 size = AOP_SIZE (result) - AOP_SIZE (right);
7196 /* Unsigned or not an integral type - right fill with zeros */
7197 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7200 aopPut (AOP (result), "!zero", offset++);
7204 /* we need to extend the sign :{ */
7205 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7211 aopPut (AOP (result), "a", offset++);
7215 freeAsmop (right, NULL, ic);
7216 freeAsmop (result, NULL, ic);
7219 /*-----------------------------------------------------------------*/
7220 /* genReceive - generate code for a receive iCode */
7221 /*-----------------------------------------------------------------*/
7223 genReceive (iCode * ic)
7225 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7226 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7227 IS_TRUE_SYMOP (IC_RESULT (ic))))
7237 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7238 size = AOP_SIZE(IC_RESULT(ic));
7240 for (i = 0; i < size; i++) {
7241 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7245 freeAsmop (IC_RESULT (ic), NULL, ic);
7248 /*-----------------------------------------------------------------*/
7249 /* genDummyRead - generate code for dummy read of volatiles */
7250 /*-----------------------------------------------------------------*/
7252 genDummyRead (iCode * ic)
7258 if (op && IS_SYMOP (op))
7260 aopOp (op, ic, FALSE, FALSE);
7263 size = AOP_SIZE (op);
7268 _moveA (aopGet (AOP (op), offset, FALSE));
7272 freeAsmop (op, NULL, ic);
7276 if (op && IS_SYMOP (op))
7278 aopOp (op, ic, FALSE, FALSE);
7281 size = AOP_SIZE (op);
7286 _moveA (aopGet (AOP (op), offset, FALSE));
7290 freeAsmop (op, NULL, ic);
7296 /** Maximum number of bytes to emit per line. */
7300 /** Context for the byte output chunker. */
7303 unsigned char buffer[DBEMIT_MAX_RUN];
7308 /** Flushes a byte chunker by writing out all in the buffer and
7312 _dbFlush(DBEMITCTX *self)
7319 sprintf(line, ".db 0x%02X", self->buffer[0]);
7321 for (i = 1; i < self->pos; i++)
7323 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7330 /** Write out another byte, buffering until a decent line is
7334 _dbEmit(DBEMITCTX *self, int c)
7336 if (self->pos == DBEMIT_MAX_RUN)
7340 self->buffer[self->pos++] = c;
7343 /** Context for a simple run length encoder. */
7347 unsigned char buffer[128];
7349 /** runLen may be equivalent to pos. */
7355 RLE_CHANGE_COST = 4,
7359 /** Flush the buffer of a run length encoder by writing out the run or
7360 data that it currently contains.
7363 _rleCommit(RLECTX *self)
7369 memset(&db, 0, sizeof(db));
7371 emit2(".db %u", self->pos);
7373 for (i = 0; i < self->pos; i++)
7375 _dbEmit(&db, self->buffer[i]);
7384 Can get either a run or a block of random stuff.
7385 Only want to change state if a good run comes in or a run ends.
7386 Detecting run end is easy.
7389 Say initial state is in run, len zero, last zero. Then if you get a
7390 few zeros then something else then a short run will be output.
7391 Seems OK. While in run mode, keep counting. While in random mode,
7392 keep a count of the run. If run hits margin, output all up to run,
7393 restart, enter run mode.
7396 /** Add another byte into the run length encoder, flushing as
7397 required. The run length encoder uses the Amiga IFF style, where
7398 a block is prefixed by its run length. A positive length means
7399 the next n bytes pass straight through. A negative length means
7400 that the next byte is repeated -n times. A zero terminates the
7404 _rleAppend(RLECTX *self, int c)
7408 if (c != self->last)
7410 /* The run has stopped. See if it is worthwhile writing it out
7411 as a run. Note that the random data comes in as runs of
7414 if (self->runLen > RLE_CHANGE_COST)
7416 /* Yes, worthwhile. */
7417 /* Commit whatever was in the buffer. */
7419 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7423 /* Not worthwhile. Append to the end of the random list. */
7424 for (i = 0; i < self->runLen; i++)
7426 if (self->pos >= RLE_MAX_BLOCK)
7431 self->buffer[self->pos++] = self->last;
7439 if (self->runLen >= RLE_MAX_BLOCK)
7441 /* Commit whatever was in the buffer. */
7444 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7452 _rleFlush(RLECTX *self)
7454 _rleAppend(self, -1);
7461 /** genArrayInit - Special code for initialising an array with constant
7465 genArrayInit (iCode * ic)
7469 int elementSize = 0, eIndex, i;
7470 unsigned val, lastVal;
7474 memset(&rle, 0, sizeof(rle));
7476 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7478 _saveRegsForCall(ic, 0);
7480 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7481 emit2 ("call __initrleblock");
7483 type = operandType(IC_LEFT(ic));
7485 if (type && type->next)
7487 elementSize = getSize(type->next);
7491 wassertl (0, "Can't determine element size in genArrayInit.");
7494 iLoop = IC_ARRAYILIST(ic);
7495 lastVal = (unsigned)-1;
7497 /* Feed all the bytes into the run length encoder which will handle
7499 This works well for mixed char data, and for random int and long
7508 for (i = 0; i < ix; i++)
7510 for (eIndex = 0; eIndex < elementSize; eIndex++)
7512 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7513 _rleAppend(&rle, val);
7518 iLoop = iLoop->next;
7522 /* Mark the end of the run. */
7525 _restoreRegsAfterCall();
7529 freeAsmop (IC_LEFT(ic), NULL, ic);
7533 _swap (PAIR_ID one, PAIR_ID two)
7535 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7541 emit2 ("ld a,%s", _pairs[one].l);
7542 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7543 emit2 ("ld %s,a", _pairs[two].l);
7544 emit2 ("ld a,%s", _pairs[one].h);
7545 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7546 emit2 ("ld %s,a", _pairs[two].h);
7550 /* The problem is that we may have all three pairs used and they may
7551 be needed in a different order.
7556 hl = hl => unity, fine
7560 hl = hl hl = hl, swap de <=> bc
7568 hl = bc de = de, swap bc <=> hl
7576 hl = de bc = bc, swap hl <=> de
7581 * Any pair = pair are done last
7582 * Any pair = iTemp are done last
7583 * Any swaps can be done any time
7591 So how do we detect the cases?
7592 How about a 3x3 matrix?
7596 x x x x (Fourth for iTemp/other)
7598 First determin which mode to use by counting the number of unity and
7601 Two - Assign the pair first, then the rest
7602 One - Swap the two, then the rest
7606 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7608 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7610 PAIR_BC, PAIR_HL, PAIR_DE
7612 int i, j, nunity = 0;
7613 memset (ids, PAIR_INVALID, sizeof (ids));
7616 wassert (nparams == 3);
7618 /* First save everything that needs to be saved. */
7619 _saveRegsForCall (ic, 0);
7621 /* Loading HL first means that DE is always fine. */
7622 for (i = 0; i < nparams; i++)
7624 aopOp (pparams[i], ic, FALSE, FALSE);
7625 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7628 /* Count the number of unity or iTemp assigns. */
7629 for (i = 0; i < 3; i++)
7631 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7639 /* Any order, fall through. */
7641 else if (nunity == 2)
7643 /* One is assigned. Pull it out and assign. */
7644 for (i = 0; i < 3; i++)
7646 for (j = 0; j < NUM_PAIRS; j++)
7648 if (ids[dest[i]][j] == TRUE)
7650 /* Found it. See if it's the right one. */
7651 if (j == PAIR_INVALID || j == dest[i])
7657 fetchPair(dest[i], AOP (pparams[i]));
7664 else if (nunity == 1)
7666 /* Find the pairs to swap. */
7667 for (i = 0; i < 3; i++)
7669 for (j = 0; j < NUM_PAIRS; j++)
7671 if (ids[dest[i]][j] == TRUE)
7673 if (j == PAIR_INVALID || j == dest[i])
7688 int next = getPairId (AOP (pparams[0]));
7689 emit2 ("push %s", _pairs[next].name);
7691 if (next == dest[1])
7693 fetchPair (dest[1], AOP (pparams[1]));
7694 fetchPair (dest[2], AOP (pparams[2]));
7698 fetchPair (dest[2], AOP (pparams[2]));
7699 fetchPair (dest[1], AOP (pparams[1]));
7701 emit2 ("pop %s", _pairs[dest[0]].name);
7704 /* Finally pull out all of the iTemps */
7705 for (i = 0; i < 3; i++)
7707 if (ids[dest[i]][PAIR_INVALID] == 1)
7709 fetchPair (dest[i], AOP (pparams[i]));
7715 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7721 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7725 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7727 setupForBuiltin3 (ic, nParams, pparams);
7729 label = newiTempLabel(NULL);
7731 emitLabel (label->key);
7732 emit2 ("ld a,(hl)");
7735 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7737 freeAsmop (from, NULL, ic->next);
7738 freeAsmop (to, NULL, ic);
7742 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7744 operand *from, *to, *count;
7747 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7752 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7754 setupForBuiltin3 (ic, nParams, pparams);
7758 freeAsmop (count, NULL, ic->next->next);
7759 freeAsmop (from, NULL, ic);
7761 _restoreRegsAfterCall();
7763 /* if we need assign a result value */
7764 if ((IS_ITEMP (IC_RESULT (ic)) &&
7765 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7766 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7767 IS_TRUE_SYMOP (IC_RESULT (ic)))
7769 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7770 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7771 freeAsmop (IC_RESULT (ic), NULL, ic);
7774 freeAsmop (to, NULL, ic->next);
7777 /*-----------------------------------------------------------------*/
7778 /* genBuiltIn - calls the appropriate function to generating code */
7779 /* for a built in function */
7780 /*-----------------------------------------------------------------*/
7781 static void genBuiltIn (iCode *ic)
7783 operand *bi_parms[MAX_BUILTIN_ARGS];
7788 /* get all the arguments for a built in function */
7789 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7791 /* which function is it */
7792 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7794 if (strcmp(bif->name,"__builtin_strcpy")==0)
7796 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7798 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7800 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7804 wassertl (0, "Unknown builtin function encountered");
7808 /*-----------------------------------------------------------------*/
7809 /* genZ80Code - generate code for Z80 based controllers */
7810 /*-----------------------------------------------------------------*/
7812 genZ80Code (iCode * lic)
7820 _fReturn = _gbz80_return;
7821 _fTmp = _gbz80_return;
7825 _fReturn = _z80_return;
7826 _fTmp = _z80_return;
7829 _G.lines.head = _G.lines.current = NULL;
7831 /* if debug information required */
7832 if (options.debug && currFunc)
7834 debugFile->writeFunction(currFunc);
7835 _G.lines.isDebug = 1;
7836 if (IS_STATIC (currFunc->etype))
7837 sprintf (buffer, "F%s$%s$0$0", moduleName, currFunc->name);
7839 sprintf (buffer, "G$%s$0$0", currFunc->name);
7840 emit2 ("!labeldef", buffer);
7841 _G.lines.isDebug = 0;
7844 for (ic = lic; ic; ic = ic->next)
7846 _G.current_iCode = ic;
7848 if (ic->lineno && cln != ic->lineno)
7852 _G.lines.isDebug = 1;
7853 sprintf (buffer, "C$%s$%d$%d$%d",
7854 FileBaseName (ic->filename), ic->lineno,
7855 ic->level, ic->block);
7856 emit2 ("%s !equ .", buffer);
7857 emit2 ("!global", buffer);
7858 _G.lines.isDebug = 0;
7860 if (!options.noCcodeInAsm) {
7861 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7862 printCLine(ic->filename, ic->lineno));
7866 if (options.iCodeInAsm) {
7867 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7869 /* if the result is marked as
7870 spilt and rematerializable or code for
7871 this has already been generated then
7873 if (resultRemat (ic) || ic->generated)
7876 /* depending on the operation */
7880 emitDebug ("; genNot");
7885 emitDebug ("; genCpl");
7890 emitDebug ("; genUminus");
7895 emitDebug ("; genIpush");
7900 /* IPOP happens only when trying to restore a
7901 spilt live range, if there is an ifx statement
7902 following this pop then the if statement might
7903 be using some of the registers being popped which
7904 would destory the contents of the register so
7905 we need to check for this condition and handle it */
7907 ic->next->op == IFX &&
7908 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7910 emitDebug ("; genIfx");
7911 genIfx (ic->next, ic);
7915 emitDebug ("; genIpop");
7921 emitDebug ("; genCall");
7926 emitDebug ("; genPcall");
7931 emitDebug ("; genFunction");
7936 emitDebug ("; genEndFunction");
7937 genEndFunction (ic);
7941 emitDebug ("; genRet");
7946 emitDebug ("; genLabel");
7951 emitDebug ("; genGoto");
7956 emitDebug ("; genPlus");
7961 emitDebug ("; genMinus");
7966 emitDebug ("; genMult");
7971 emitDebug ("; genDiv");
7976 emitDebug ("; genMod");
7981 emitDebug ("; genCmpGt");
7982 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7986 emitDebug ("; genCmpLt");
7987 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7994 /* note these two are xlated by algebraic equivalence
7995 during parsing SDCC.y */
7996 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7997 "got '>=' or '<=' shouldn't have come here");
8001 emitDebug ("; genCmpEq");
8002 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8006 emitDebug ("; genAndOp");
8011 emitDebug ("; genOrOp");
8016 emitDebug ("; genXor");
8017 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8021 emitDebug ("; genOr");
8022 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8026 emitDebug ("; genAnd");
8027 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8031 emitDebug ("; genInline");
8036 emitDebug ("; genRRC");
8041 emitDebug ("; genRLC");
8046 emitDebug ("; genGetHBIT");
8051 emitDebug ("; genLeftShift");
8056 emitDebug ("; genRightShift");
8060 case GET_VALUE_AT_ADDRESS:
8061 emitDebug ("; genPointerGet");
8067 if (POINTER_SET (ic))
8069 emitDebug ("; genAssign (pointer)");
8074 emitDebug ("; genAssign");
8080 emitDebug ("; genIfx");
8085 emitDebug ("; genAddrOf");
8090 emitDebug ("; genJumpTab");
8095 emitDebug ("; genCast");
8100 emitDebug ("; genReceive");
8105 if (ic->builtinSEND)
8107 emitDebug ("; genBuiltIn");
8112 emitDebug ("; addSet");
8113 addSet (&_G.sendSet, ic);
8118 emitDebug ("; genArrayInit");
8122 case DUMMY_READ_VOLATILE:
8123 emitDebug ("; genDummyRead");
8133 /* now we are ready to call the
8134 peep hole optimizer */
8135 if (!options.nopeep)
8136 peepHole (&_G.lines.head);
8138 /* This is unfortunate */
8139 /* now do the actual printing */
8141 FILE *fp = codeOutFile;
8142 if (isInHome () && codeOutFile == code->oFile)
8143 codeOutFile = home->oFile;
8144 printLine (_G.lines.head, codeOutFile);
8145 if (_G.flushStatics)
8148 _G.flushStatics = 0;
8153 freeTrace(&_G.lines.trace);
8154 freeTrace(&_G.trace.aops);
8160 _isPairUsed (iCode * ic, PAIR_ID pairId)
8166 if (bitVectBitValue (ic->rMask, D_IDX))
8168 if (bitVectBitValue (ic->rMask, E_IDX))
8178 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8181 value *val = aop->aopu.aop_lit;
8183 wassert (aop->type == AOP_LIT);
8184 wassert (!IS_FLOAT (val->type));
8186 v = (unsigned long) floatFromVal (val);
8194 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8195 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));