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 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1688 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1689 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1691 else if( z80_opts.port_mode == 180 )
1692 { /* z180 in0/out0 mode */
1693 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1697 emit2( "in a,(%s)", aop->aopu.aop_dir );
1700 SNPRINTF (buffer, sizeof(buffer), "a");
1702 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1706 return aop->aopu.aop_reg[offset]->name;
1710 setupPair (PAIR_HL, aop, offset);
1711 tsprintf (buffer, sizeof(buffer), "!*hl");
1713 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1717 setupPair (PAIR_IY, aop, offset);
1718 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1720 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1724 setupPair (PAIR_IY, aop, offset);
1725 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1727 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1732 setupPair (PAIR_HL, aop, offset);
1733 tsprintf (buffer, sizeof(buffer), "!*hl");
1737 if (aop->aopu.aop_stk >= 0)
1738 offset += _G.stack.param_offset;
1739 tsprintf (buffer, sizeof(buffer),
1740 "!*ixx", aop->aopu.aop_stk + offset);
1743 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1746 wassertl (0, "Tried to fetch from a bit variable");
1755 tsprintf(buffer, sizeof(buffer), "!zero");
1756 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1760 wassert (offset < 2);
1761 return aop->aopu.aop_str[offset];
1764 return aopLiteral (aop->aopu.aop_lit, offset);
1768 unsigned long v = aop->aopu.aop_simplelit;
1771 tsprintf (buffer, sizeof(buffer),
1772 "!immedbyte", (unsigned int) v & 0xff);
1774 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1778 return aop->aopu.aop_str[offset];
1781 setupPair (aop->aopu.aop_pairId, aop, offset);
1782 if (aop->aopu.aop_pairId==PAIR_IX)
1783 SNPRINTF (buffer, sizeof(buffer),
1785 else if (aop->aopu.aop_pairId==PAIR_IY)
1786 SNPRINTF (buffer, sizeof(buffer),
1789 SNPRINTF (buffer, sizeof(buffer),
1790 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1792 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1797 wassertl (0, "aopget got unsupported aop->type");
1802 isRegString (const char *s)
1804 if (!strcmp (s, "b") ||
1816 isConstant (const char *s)
1818 /* This is a bit of a hack... */
1819 return (*s == '#' || *s == '$');
1823 canAssignToPtr (const char *s)
1825 if (isRegString (s))
1832 /*-----------------------------------------------------------------*/
1833 /* aopPut - puts a string for a aop */
1834 /*-----------------------------------------------------------------*/
1836 aopPut (asmop * aop, const char *s, int offset)
1840 if (aop->size && offset > (aop->size - 1))
1842 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1843 "aopPut got offset > aop->size");
1848 tsprintf(buffer2, sizeof(buffer2), s);
1851 /* will assign value to value */
1852 /* depending on where it is ofcourse */
1856 _moveA (s); /* in case s is volatile */
1862 if (strcmp (s, "a"))
1863 emit2 ("ld a,%s", s);
1864 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1871 if (strcmp (s, "a"))
1872 emit2 ("ld a,%s", s);
1873 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1876 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1879 if( aop->bcInUse ) emit2( "push bc" );
1881 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1883 if(( s[0] == '#' ) /* immediate number */
1884 ||( s[0] == '(' ) /* indirect register (ix or iy ??)*/
1885 ||( isdigit( s[0] )))/* indirect register with offset (ix or iy ??)*/
1887 emit2( "ld a,%s", s );
1888 emit2( "out (c),a" );
1892 emit2( "out (c),%s", s );
1898 spillPair (PAIR_BC);
1900 else if( z80_opts.port_mode == 180 )
1901 { /* z180 in0/out0 mode */
1902 emit2( "ld a,%s", s );
1903 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1907 emit2( "ld a,%s", s );
1908 emit2( "out (%s),a", aop->aopu.aop_dir );
1914 if (!strcmp (s, "!*hl"))
1915 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1918 aop->aopu.aop_reg[offset]->name, s);
1919 spillPairReg(aop->aopu.aop_reg[offset]->name);
1924 if (!canAssignToPtr (s))
1926 emit2 ("ld a,%s", s);
1927 setupPair (PAIR_IY, aop, offset);
1928 emit2 ("ld !*iyx,a", offset);
1932 setupPair (PAIR_IY, aop, offset);
1933 emit2 ("ld !*iyx,%s", offset, s);
1939 /* PENDING: for re-target */
1940 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1942 emit2 ("ld a,!*hl");
1945 setupPair (PAIR_HL, aop, offset);
1947 emit2 ("ld !*hl,%s", s);
1952 if (!canAssignToPtr (s))
1954 emit2 ("ld a,%s", s);
1955 setupPair (PAIR_IY, aop, offset);
1956 emit2 ("ld !*iyx,a", offset);
1960 setupPair (PAIR_IY, aop, offset);
1961 emit2 ("ld !*iyx,%s", offset, s);
1968 /* PENDING: re-target */
1969 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1971 emit2 ("ld a,!*hl");
1974 setupPair (PAIR_HL, aop, offset);
1975 if (!canAssignToPtr (s))
1977 emit2 ("ld a,%s", s);
1978 emit2 ("ld !*hl,a");
1981 emit2 ("ld !*hl,%s", s);
1985 if (aop->aopu.aop_stk >= 0)
1986 offset += _G.stack.param_offset;
1987 if (!canAssignToPtr (s))
1989 emit2 ("ld a,%s", s);
1990 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1994 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2000 /* if bit variable */
2001 if (!aop->aopu.aop_dir)
2003 emit2 ("ld a,!zero");
2008 /* In bit space but not in C - cant happen */
2009 wassertl (0, "Tried to write into a bit variable");
2015 if (strcmp (aop->aopu.aop_str[offset], s))
2017 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2019 spillPairReg(aop->aopu.aop_str[offset]);
2024 if (!offset && (strcmp (s, "acc") == 0))
2028 wassertl (0, "Tried to access past the end of A");
2032 if (strcmp (aop->aopu.aop_str[offset], s))
2034 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2035 spillPairReg(aop->aopu.aop_str[offset]);
2041 wassert (offset < 2);
2042 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2043 spillPairReg(aop->aopu.aop_str[offset]);
2047 setupPair (aop->aopu.aop_pairId, aop, offset);
2048 if (aop->aopu.aop_pairId==PAIR_IX)
2049 emit2 ("ld !*ixx,%s", 0, s);
2050 else if (aop->aopu.aop_pairId==PAIR_IY)
2051 emit2 ("ld !*ixy,%s", 0, s);
2053 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2057 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2058 "aopPut got unsupported aop->type");
2063 #define AOP(op) op->aop
2064 #define AOP_TYPE(op) AOP(op)->type
2065 #define AOP_SIZE(op) AOP(op)->size
2066 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2069 commitPair (asmop * aop, PAIR_ID id)
2071 /* PENDING: Verify this. */
2072 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2076 aopPut (aop, "a", 0);
2077 aopPut (aop, "d", 1);
2082 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2084 char *l = aopGetLitWordLong (aop, 0, FALSE);
2087 emit2 ("ld (%s),%s", l, _pairs[id].name);
2091 aopPut (aop, _pairs[id].l, 0);
2092 aopPut (aop, _pairs[id].h, 1);
2097 /*-----------------------------------------------------------------*/
2098 /* getDataSize - get the operand data size */
2099 /*-----------------------------------------------------------------*/
2101 getDataSize (operand * op)
2104 size = AOP_SIZE (op);
2108 wassertl (0, "Somehow got a three byte data pointer");
2113 /*-----------------------------------------------------------------*/
2114 /* movLeft2Result - move byte from left to result */
2115 /*-----------------------------------------------------------------*/
2117 movLeft2Result (operand * left, int offl,
2118 operand * result, int offr, int sign)
2122 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2124 l = aopGet (AOP (left), offl, FALSE);
2128 aopPut (AOP (result), l, offr);
2132 if (getDataSize (left) == offl + 1)
2134 emit2 ("ld a,%s", l);
2135 aopPut (AOP (result), "a", offr);
2142 movLeft2ResultLong (operand * left, int offl,
2143 operand * result, int offr, int sign,
2148 movLeft2Result (left, offl, result, offr, sign);
2152 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2153 wassertl (size == 2, "Only implemented for two bytes or one");
2155 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2157 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2158 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2160 spillPair (PAIR_HL);
2162 else if ( getPairId ( AOP (result)) == PAIR_IY)
2164 PAIR_ID id = getPairId (AOP (left));
2165 if (id != PAIR_INVALID)
2167 emit2("push %s", _pairs[id].name);
2178 movLeft2Result (left, offl, result, offr, sign);
2179 movLeft2Result (left, offl+1, result, offr+1, sign);
2184 /** Put Acc into a register set
2187 outAcc (operand * result)
2190 size = getDataSize (result);
2193 aopPut (AOP (result), "a", 0);
2196 /* unsigned or positive */
2199 aopPut (AOP (result), "!zero", offset++);
2204 /** Take the value in carry and put it into a register
2207 outBitCLong (operand * result, bool swap_sense)
2209 /* if the result is bit */
2210 if (AOP_TYPE (result) == AOP_CRY)
2212 wassertl (0, "Tried to write carry to a bit");
2216 emit2 ("ld a,!zero");
2219 emit2 ("xor a,!immedbyte", 1);
2225 outBitC (operand * result)
2227 outBitCLong (result, FALSE);
2230 /*-----------------------------------------------------------------*/
2231 /* toBoolean - emit code for orl a,operator(sizeop) */
2232 /*-----------------------------------------------------------------*/
2234 _toBoolean (operand * oper)
2236 int size = AOP_SIZE (oper);
2240 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2243 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2247 if (AOP (oper)->type != AOP_ACC)
2250 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2256 /*-----------------------------------------------------------------*/
2257 /* genNot - generate code for ! operation */
2258 /*-----------------------------------------------------------------*/
2263 /* assign asmOps to operand & result */
2264 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2265 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2267 /* if in bit space then a special case */
2268 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2270 wassertl (0, "Tried to negate a bit");
2273 _toBoolean (IC_LEFT (ic));
2278 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2279 emit2 ("sub a,!one");
2280 outBitC (IC_RESULT (ic));
2282 /* release the aops */
2283 freeAsmop (IC_LEFT (ic), NULL, ic);
2284 freeAsmop (IC_RESULT (ic), NULL, ic);
2287 /*-----------------------------------------------------------------*/
2288 /* genCpl - generate code for complement */
2289 /*-----------------------------------------------------------------*/
2297 /* assign asmOps to operand & result */
2298 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2299 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2301 /* if both are in bit space then
2303 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2304 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2306 wassertl (0, "Left and the result are in bit space");
2309 size = AOP_SIZE (IC_RESULT (ic));
2312 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2315 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2318 /* release the aops */
2319 freeAsmop (IC_LEFT (ic), NULL, ic);
2320 freeAsmop (IC_RESULT (ic), NULL, ic);
2324 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2331 store de into result
2336 store de into result
2338 const char *first = isAdd ? "add" : "sub";
2339 const char *later = isAdd ? "adc" : "sbc";
2341 wassertl (IS_GB, "Code is only relevent to the gbz80");
2342 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2344 fetchPair (PAIR_DE, left);
2347 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2350 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2353 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2354 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2356 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2357 aopGet (right, MSB24, FALSE);
2361 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2364 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2366 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2367 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2371 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2373 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2376 /*-----------------------------------------------------------------*/
2377 /* genUminusFloat - unary minus for floating points */
2378 /*-----------------------------------------------------------------*/
2380 genUminusFloat (operand * op, operand * result)
2382 int size, offset = 0;
2384 emitDebug("; genUminusFloat");
2386 /* for this we just need to flip the
2387 first it then copy the rest in place */
2388 size = AOP_SIZE (op) - 1;
2390 _moveA(aopGet (AOP (op), MSB32, FALSE));
2392 emit2("xor a,!immedbyte", 0x80);
2393 aopPut (AOP (result), "a", MSB32);
2397 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2402 /*-----------------------------------------------------------------*/
2403 /* genUminus - unary minus code generation */
2404 /*-----------------------------------------------------------------*/
2406 genUminus (iCode * ic)
2409 sym_link *optype, *rtype;
2412 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2413 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2415 /* if both in bit space then special
2417 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2418 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2420 wassertl (0, "Left and right are in bit space");
2424 optype = operandType (IC_LEFT (ic));
2425 rtype = operandType (IC_RESULT (ic));
2427 /* if float then do float stuff */
2428 if (IS_FLOAT (optype))
2430 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2434 /* otherwise subtract from zero */
2435 size = AOP_SIZE (IC_LEFT (ic));
2437 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2439 /* Create a new asmop with value zero */
2440 asmop *azero = newAsmop (AOP_SIMPLELIT);
2441 azero->aopu.aop_simplelit = 0;
2443 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2451 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2452 emit2 ("ld a,!zero");
2453 emit2 ("sbc a,%s", l);
2454 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2457 /* if any remaining bytes in the result */
2458 /* we just need to propagate the sign */
2459 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2464 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2468 /* release the aops */
2469 freeAsmop (IC_LEFT (ic), NULL, ic);
2470 freeAsmop (IC_RESULT (ic), NULL, ic);
2473 /*-----------------------------------------------------------------*/
2474 /* assignResultValue - */
2475 /*-----------------------------------------------------------------*/
2477 assignResultValue (operand * oper)
2479 int size = AOP_SIZE (oper);
2482 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2483 topInA = requiresHL (AOP (oper));
2485 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2487 /* We do it the hard way here. */
2489 aopPut (AOP (oper), _fReturn[0], 0);
2490 aopPut (AOP (oper), _fReturn[1], 1);
2492 aopPut (AOP (oper), _fReturn[0], 2);
2493 aopPut (AOP (oper), _fReturn[1], 3);
2499 aopPut (AOP (oper), _fReturn[size], size);
2504 /** Simple restore that doesn't take into account what is used in the
2508 _restoreRegsAfterCall(void)
2510 if (_G.stack.pushedDE)
2513 _G.stack.pushedDE = FALSE;
2515 if (_G.stack.pushedBC)
2518 _G.stack.pushedBC = FALSE;
2520 _G.saves.saved = FALSE;
2524 _saveRegsForCall(iCode *ic, int sendSetSize)
2527 o Stack parameters are pushed before this function enters
2528 o DE and BC may be used in this function.
2529 o HL and DE may be used to return the result.
2530 o HL and DE may be used to send variables.
2531 o DE and BC may be used to store the result value.
2532 o HL may be used in computing the sent value of DE
2533 o The iPushes for other parameters occur before any addSets
2535 Logic: (to be run inside the first iPush or if none, before sending)
2536 o Compute if DE and/or BC are in use over the call
2537 o Compute if DE is used in the send set
2538 o Compute if DE and/or BC are used to hold the result value
2539 o If (DE is used, or in the send set) and is not used in the result, push.
2540 o If BC is used and is not in the result, push
2542 o If DE is used in the send set, fetch
2543 o If HL is used in the send set, fetch
2547 if (_G.saves.saved == FALSE) {
2548 bool deInUse, bcInUse;
2550 bool bcInRet = FALSE, deInRet = FALSE;
2553 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2554 z80_rUmaskForOp (IC_RESULT(ic)));
2556 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2557 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2559 deSending = (sendSetSize > 1);
2561 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2563 if (bcInUse && bcInRet == FALSE) {
2565 _G.stack.pushedBC = TRUE;
2567 if (deInUse && deInRet == FALSE) {
2569 _G.stack.pushedDE = TRUE;
2572 _G.saves.saved = TRUE;
2575 /* Already saved. */
2579 /*-----------------------------------------------------------------*/
2580 /* genIpush - genrate code for pushing this gets a little complex */
2581 /*-----------------------------------------------------------------*/
2583 genIpush (iCode * ic)
2585 int size, offset = 0;
2588 /* if this is not a parm push : ie. it is spill push
2589 and spill push is always done on the local stack */
2592 wassertl(0, "Encountered an unsupported spill push.");
2596 if (_G.saves.saved == FALSE) {
2597 /* Caller saves, and this is the first iPush. */
2598 /* Scan ahead until we find the function that we are pushing parameters to.
2599 Count the number of addSets on the way to figure out what registers
2600 are used in the send set.
2603 iCode *walk = ic->next;
2606 if (walk->op == SEND) {
2609 else if (walk->op == CALL || walk->op == PCALL) {
2618 _saveRegsForCall(walk, nAddSets);
2621 /* Already saved by another iPush. */
2624 /* then do the push */
2625 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2627 size = AOP_SIZE (IC_LEFT (ic));
2629 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2631 _G.stack.pushed += 2;
2632 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2638 fetchHL (AOP (IC_LEFT (ic)));
2640 spillPair (PAIR_HL);
2641 _G.stack.pushed += 2;
2646 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2648 spillPair (PAIR_HL);
2649 _G.stack.pushed += 2;
2650 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2652 spillPair (PAIR_HL);
2653 _G.stack.pushed += 2;
2659 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2661 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2663 emit2 ("ld a,(%s)", l);
2667 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2668 emit2 ("ld a,%s", l);
2676 freeAsmop (IC_LEFT (ic), NULL, ic);
2679 /*-----------------------------------------------------------------*/
2680 /* genIpop - recover the registers: can happen only for spilling */
2681 /*-----------------------------------------------------------------*/
2683 genIpop (iCode * ic)
2688 /* if the temp was not pushed then */
2689 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2692 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2693 size = AOP_SIZE (IC_LEFT (ic));
2694 offset = (size - 1);
2695 if (isPair (AOP (IC_LEFT (ic))))
2697 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2705 spillPair (PAIR_HL);
2706 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2710 freeAsmop (IC_LEFT (ic), NULL, ic);
2713 /* This is quite unfortunate */
2715 setArea (int inHome)
2718 static int lastArea = 0;
2720 if (_G.in_home != inHome) {
2722 const char *sz = port->mem.code_name;
2723 port->mem.code_name = "HOME";
2724 emit2("!area", CODE_NAME);
2725 port->mem.code_name = sz;
2728 emit2("!area", CODE_NAME); */
2729 _G.in_home = inHome;
2740 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2744 symbol *sym = OP_SYMBOL (op);
2746 if (sym->isspilt || sym->nRegs == 0)
2749 aopOp (op, ic, FALSE, FALSE);
2752 if (aop->type == AOP_REG)
2755 for (i = 0; i < aop->size; i++)
2757 if (pairId == PAIR_DE)
2759 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2760 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2762 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2765 else if (pairId == PAIR_BC)
2767 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2768 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2770 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2780 freeAsmop (IC_LEFT (ic), NULL, ic);
2784 /** Emit the code for a call statement
2787 emitCall (iCode * ic, bool ispcall)
2789 bool bInRet, cInRet, dInRet, eInRet;
2790 sym_link *dtype = operandType (IC_LEFT (ic));
2792 /* if caller saves & we have not saved then */
2798 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2800 /* if send set is not empty then assign */
2805 int nSend = elementsInSet(_G.sendSet);
2806 bool swapped = FALSE;
2808 int _z80_sendOrder[] = {
2813 /* Check if the parameters are swapped. If so route through hl instead. */
2814 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2816 sic = setFirstItem(_G.sendSet);
2817 sic = setNextItem(_G.sendSet);
2819 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2820 /* The second send value is loaded from one the one that holds the first
2821 send, i.e. it is overwritten. */
2822 /* Cache the first in HL, and load the second from HL instead. */
2823 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2824 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2830 for (sic = setFirstItem (_G.sendSet); sic;
2831 sic = setNextItem (_G.sendSet))
2834 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2836 size = AOP_SIZE (IC_LEFT (sic));
2837 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2838 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2840 // PENDING: Mild hack
2841 if (swapped == TRUE && send == 1) {
2843 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2846 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2848 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2851 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2855 freeAsmop (IC_LEFT (sic), NULL, sic);
2862 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2864 werror (W_INDIR_BANKED);
2866 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2868 if (isLitWord (AOP (IC_LEFT (ic))))
2870 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2874 symbol *rlbl = newiTempLabel (NULL);
2875 spillPair (PAIR_HL);
2876 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2878 _G.stack.pushed += 2;
2880 fetchHL (AOP (IC_LEFT (ic)));
2882 emit2 ("!tlabeldef", (rlbl->key + 100));
2883 _G.stack.pushed -= 2;
2885 freeAsmop (IC_LEFT (ic), NULL, ic);
2889 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2890 OP_SYMBOL (IC_LEFT (ic))->rname :
2891 OP_SYMBOL (IC_LEFT (ic))->name;
2892 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2894 emit2 ("call banked_call");
2895 emit2 ("!dws", name);
2896 emit2 ("!dw !bankimmeds", name);
2901 emit2 ("call %s", name);
2906 /* Mark the regsiters as restored. */
2907 _G.saves.saved = FALSE;
2909 /* if we need assign a result value */
2910 if ((IS_ITEMP (IC_RESULT (ic)) &&
2911 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2912 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2913 IS_TRUE_SYMOP (IC_RESULT (ic)))
2916 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2918 assignResultValue (IC_RESULT (ic));
2920 freeAsmop (IC_RESULT (ic), NULL, ic);
2923 /* adjust the stack for parameters if required */
2926 int i = ic->parmBytes;
2928 _G.stack.pushed -= i;
2931 emit2 ("!ldaspsp", i);
2938 emit2 ("ld iy,!immedword", i);
2939 emit2 ("add iy,sp");
2960 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2961 bInRet = bitVectBitValue(result, B_IDX);
2962 cInRet = bitVectBitValue(result, C_IDX);
2963 dInRet = bitVectBitValue(result, D_IDX);
2964 eInRet = bitVectBitValue(result, E_IDX);
2974 if (_G.stack.pushedDE)
2976 if (dInRet && eInRet)
2978 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2982 /* Only restore E */
2989 /* Only restore D */
2997 _G.stack.pushedDE = FALSE;
3000 if (_G.stack.pushedBC)
3002 if (bInRet && cInRet)
3004 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3008 /* Only restore C */
3015 /* Only restore B */
3023 _G.stack.pushedBC = FALSE;
3027 /*-----------------------------------------------------------------*/
3028 /* genCall - generates a call statement */
3029 /*-----------------------------------------------------------------*/
3031 genCall (iCode * ic)
3033 emitCall (ic, FALSE);
3036 /*-----------------------------------------------------------------*/
3037 /* genPcall - generates a call by pointer statement */
3038 /*-----------------------------------------------------------------*/
3040 genPcall (iCode * ic)
3042 emitCall (ic, TRUE);
3045 /*-----------------------------------------------------------------*/
3046 /* resultRemat - result is rematerializable */
3047 /*-----------------------------------------------------------------*/
3049 resultRemat (iCode * ic)
3051 if (SKIP_IC (ic) || ic->op == IFX)
3054 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3056 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3057 if (sym->remat && !POINTER_SET (ic))
3064 extern set *publics;
3066 /*-----------------------------------------------------------------*/
3067 /* genFunction - generated code for function entry */
3068 /*-----------------------------------------------------------------*/
3070 genFunction (iCode * ic)
3074 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3077 bool bcInUse = FALSE;
3078 bool deInUse = FALSE;
3080 setArea (IFFUNC_NONBANKED (sym->type));
3082 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
3085 _G.receiveOffset = 0;
3087 /* Record the last function name for debugging. */
3088 _G.lastFunctionName = sym->rname;
3090 /* Create the function header */
3091 emit2 ("!functionheader", sym->name);
3092 sprintf (buffer, "%s_start", sym->rname);
3093 emit2 ("!labeldef", buffer);
3094 emit2 ("!functionlabeldef", sym->rname);
3096 if (options.profile)
3098 emit2 ("!profileenter");
3101 ftype = operandType (IC_LEFT (ic));
3103 /* if critical function then turn interrupts off */
3104 if (IFFUNC_ISCRITICAL (ftype))
3107 /* if this is an interrupt service routine then save all potentially used registers. */
3108 if (IFFUNC_ISISR (sym->type))
3113 /* PENDING: callee-save etc */
3115 _G.stack.param_offset = 0;
3117 if (z80_opts.calleeSavesBC)
3122 /* Detect which registers are used. */
3123 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3126 for (i = 0; i < sym->regsUsed->size; i++)
3128 if (bitVectBitValue (sym->regsUsed, i))
3142 /* Other systems use DE as a temporary. */
3153 _G.stack.param_offset += 2;
3156 _G.calleeSaves.pushedBC = bcInUse;
3161 _G.stack.param_offset += 2;
3164 _G.calleeSaves.pushedDE = deInUse;
3166 /* adjust the stack for the function */
3167 _G.stack.last = sym->stack;
3170 for (sym = setFirstItem (istack->syms); sym;
3171 sym = setNextItem (istack->syms))
3173 if (sym->_isparm && !IS_REGPARM (sym->etype))
3179 sym = OP_SYMBOL (IC_LEFT (ic));
3181 _G.omitFramePtr = options.ommitFramePtr;
3182 if (IS_Z80 && !stackParm && !sym->stack)
3184 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3185 /* the above !sym->stack condition can be removed. -- EEP */
3187 emit2 ("!ldaspsp", -sym->stack);
3188 _G.omitFramePtr = TRUE;
3190 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3191 emit2 ("!enterxl", sym->stack);
3192 else if (sym->stack)
3193 emit2 ("!enterx", sym->stack);
3194 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3197 _G.stack.offset = sym->stack;
3200 /*-----------------------------------------------------------------*/
3201 /* genEndFunction - generates epilogue for functions */
3202 /*-----------------------------------------------------------------*/
3204 genEndFunction (iCode * ic)
3206 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3208 if (IFFUNC_ISISR (sym->type))
3210 wassertl (0, "Tried to close an interrupt support function");
3214 if (IFFUNC_ISCRITICAL (sym->type))
3217 /* PENDING: calleeSave */
3219 if (IS_Z80 && _G.omitFramePtr)
3221 if (_G.stack.offset)
3222 emit2 ("!ldaspsp", _G.stack.offset);
3224 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3226 emit2 ("!leavexl", _G.stack.offset);
3228 else if (_G.stack.offset)
3230 emit2 ("!leavex", _G.stack.offset);
3232 else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3237 if (_G.calleeSaves.pushedDE)
3240 _G.calleeSaves.pushedDE = FALSE;
3243 if (_G.calleeSaves.pushedBC)
3246 _G.calleeSaves.pushedBC = FALSE;
3249 if (options.profile)
3251 emit2 ("!profileexit");
3255 if (options.debug && currFunc)
3257 _G.lines.isDebug = 1;
3258 sprintf (buffer, "C$%s$%d$%d$%d",
3259 FileBaseName (ic->filename), currFunc->lastLine,
3260 ic->level, ic->block);
3261 emit2 ("!labeldef", buffer);
3262 if (IS_STATIC (currFunc->etype))
3263 sprintf (buffer, "XF%s$%s$0$0", moduleName, currFunc->name);
3265 sprintf (buffer, "XG$%s$0$0", currFunc->name);
3266 emit2 ("!labeldef", buffer);
3267 _G.lines.isDebug = 0;
3270 /* Both banked and non-banked just ret */
3273 sprintf (buffer, "%s_end", sym->rname);
3274 emit2 ("!labeldef", buffer);
3276 _G.flushStatics = 1;
3277 _G.stack.pushed = 0;
3278 _G.stack.offset = 0;
3281 /*-----------------------------------------------------------------*/
3282 /* genRet - generate code for return statement */
3283 /*-----------------------------------------------------------------*/
3288 /* Errk. This is a hack until I can figure out how
3289 to cause dehl to spill on a call */
3290 int size, offset = 0;
3292 /* if we have no return value then
3293 just generate the "ret" */
3297 /* we have something to return then
3298 move the return value into place */
3299 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3300 size = AOP_SIZE (IC_LEFT (ic));
3302 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3305 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3309 emit2 ("ld de,%s", l);
3313 emit2 ("ld hl,%s", l);
3319 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3323 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3325 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3326 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3332 l = aopGet (AOP (IC_LEFT (ic)), offset,
3334 if (strcmp (_fReturn[offset], l))
3335 emit2 ("ld %s,%s", _fReturn[offset], l);
3340 freeAsmop (IC_LEFT (ic), NULL, ic);
3343 /* generate a jump to the return label
3344 if the next is not the return statement */
3345 if (!(ic->next && ic->next->op == LABEL &&
3346 IC_LABEL (ic->next) == returnLabel))
3348 emit2 ("jp !tlabel", returnLabel->key + 100);
3351 /*-----------------------------------------------------------------*/
3352 /* genLabel - generates a label */
3353 /*-----------------------------------------------------------------*/
3355 genLabel (iCode * ic)
3357 /* special case never generate */
3358 if (IC_LABEL (ic) == entryLabel)
3361 emitLabel (IC_LABEL (ic)->key + 100);
3364 /*-----------------------------------------------------------------*/
3365 /* genGoto - generates a ljmp */
3366 /*-----------------------------------------------------------------*/
3368 genGoto (iCode * ic)
3370 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3373 /*-----------------------------------------------------------------*/
3374 /* genPlusIncr :- does addition with increment if possible */
3375 /*-----------------------------------------------------------------*/
3377 genPlusIncr (iCode * ic)
3379 unsigned int icount;
3380 unsigned int size = getDataSize (IC_RESULT (ic));
3381 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3383 /* will try to generate an increment */
3384 /* if the right side is not a literal
3386 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3389 emitDebug ("; genPlusIncr");
3391 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3393 /* If result is a pair */
3394 if (resultId != PAIR_INVALID)
3396 if (isLitWord (AOP (IC_LEFT (ic))))
3398 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3401 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3403 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3405 PAIR_ID freep = getFreePairId (ic);
3406 if (freep != PAIR_INVALID)
3408 fetchPair (freep, AOP (IC_RIGHT (ic)));
3409 emit2 ("add hl,%s", _pairs[freep].name);
3415 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3416 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3423 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3427 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3431 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3436 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3438 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3439 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3443 /* if the literal value of the right hand side
3444 is greater than 4 then it is not worth it */
3448 /* if increment 16 bits in register */
3449 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3455 symbol *tlbl = NULL;
3456 tlbl = newiTempLabel (NULL);
3459 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3462 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3465 emitLabel (tlbl->key + 100);
3469 /* if the sizes are greater than 1 then we cannot */
3470 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3471 AOP_SIZE (IC_LEFT (ic)) > 1)
3474 /* If the result is in a register then we can load then increment.
3476 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3478 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3481 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3486 /* we can if the aops of the left & result match or
3487 if they are in registers and the registers are the
3489 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3493 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3501 /*-----------------------------------------------------------------*/
3502 /* outBitAcc - output a bit in acc */
3503 /*-----------------------------------------------------------------*/
3505 outBitAcc (operand * result)
3507 symbol *tlbl = newiTempLabel (NULL);
3508 /* if the result is a bit */
3509 if (AOP_TYPE (result) == AOP_CRY)
3511 wassertl (0, "Tried to write A into a bit");
3515 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3516 emit2 ("ld a,!one");
3517 emitLabel (tlbl->key + 100);
3523 couldDestroyCarry (asmop *aop)
3527 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3536 shiftIntoPair (int idx, asmop *aop)
3538 PAIR_ID id = PAIR_INVALID;
3540 wassertl (IS_Z80, "Only implemented for the Z80");
3541 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3553 wassertl (0, "Internal error - hit default case");
3556 emitDebug ("; Shift into pair idx %u", idx);
3560 setupPair (PAIR_HL, aop, 0);
3564 setupPair (PAIR_IY, aop, 0);
3566 emit2 ("pop %s", _pairs[id].name);
3569 aop->type = AOP_PAIRPTR;
3570 aop->aopu.aop_pairId = id;
3571 _G.pairs[id].offset = 0;
3572 _G.pairs[id].last_type = aop->type;
3576 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3578 wassert (left && right);
3582 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3584 shiftIntoPair (0, right);
3585 /* check result again, in case right == result */
3586 if (couldDestroyCarry (result))
3587 shiftIntoPair (1, result);
3589 else if (couldDestroyCarry (right))
3591 if (getPairId (result) == PAIR_HL)
3592 _G.preserveCarry = TRUE;
3594 shiftIntoPair (0, right);
3596 else if (couldDestroyCarry (result))
3598 shiftIntoPair (0, result);
3607 /*-----------------------------------------------------------------*/
3608 /* genPlus - generates code for addition */
3609 /*-----------------------------------------------------------------*/
3611 genPlus (iCode * ic)
3613 int size, offset = 0;
3615 /* special cases :- */
3617 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3618 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3619 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3621 /* Swap the left and right operands if:
3623 if literal, literal on the right or
3624 if left requires ACC or right is already
3627 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3628 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3629 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3631 operand *t = IC_RIGHT (ic);
3632 IC_RIGHT (ic) = IC_LEFT (ic);
3636 /* if both left & right are in bit
3638 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3639 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3642 wassertl (0, "Tried to add two bits");
3645 /* if left in bit space & right literal */
3646 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3647 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3649 /* Can happen I guess */
3650 wassertl (0, "Tried to add a bit to a literal");
3653 /* if I can do an increment instead
3654 of add then GOOD for ME */
3655 if (genPlusIncr (ic) == TRUE)
3658 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3660 size = getDataSize (IC_RESULT (ic));
3662 /* Special case when left and right are constant */
3663 if (isPair (AOP (IC_RESULT (ic))))
3666 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3667 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3669 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3675 sprintf (buffer, "#(%s + %s)", left, right);
3676 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3681 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3683 /* Fetch into HL then do the add */
3684 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3685 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3687 spillPair (PAIR_HL);
3689 if (left == PAIR_HL && right != PAIR_INVALID)
3691 emit2 ("add hl,%s", _pairs[right].name);
3694 else if (right == PAIR_HL && left != PAIR_INVALID)
3696 emit2 ("add hl,%s", _pairs[left].name);
3699 else if (right != PAIR_INVALID && right != PAIR_HL)
3701 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3702 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3705 else if (left != PAIR_INVALID && left != PAIR_HL)
3707 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3708 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3717 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3719 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3720 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3722 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3727 ld hl,sp+n trashes C so we cant afford to do it during an
3728 add with stack based varibles. Worst case is:
3741 So you cant afford to load up hl if either left, right, or result
3742 is on the stack (*sigh*) The alt is:
3750 Combinations in here are:
3751 * If left or right are in bc then the loss is small - trap later
3752 * If the result is in bc then the loss is also small
3756 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3757 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3758 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3760 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3761 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3762 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3763 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3765 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3767 /* Swap left and right */
3768 operand *t = IC_RIGHT (ic);
3769 IC_RIGHT (ic) = IC_LEFT (ic);
3772 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3774 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3775 emit2 ("add hl,bc");
3779 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3780 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3781 emit2 ("add hl,de");
3783 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3789 /* Be paranoid on the GB with 4 byte variables due to how C
3790 can be trashed by lda hl,n(sp).
3792 _gbz80_emitAddSubLong (ic, TRUE);
3797 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3801 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3803 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3806 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3809 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3813 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3816 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3819 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3821 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3825 _G.preserveCarry = FALSE;
3826 freeAsmop (IC_LEFT (ic), NULL, ic);
3827 freeAsmop (IC_RIGHT (ic), NULL, ic);
3828 freeAsmop (IC_RESULT (ic), NULL, ic);
3832 /*-----------------------------------------------------------------*/
3833 /* genMinusDec :- does subtraction with deccrement if possible */
3834 /*-----------------------------------------------------------------*/
3836 genMinusDec (iCode * ic)
3838 unsigned int icount;
3839 unsigned int size = getDataSize (IC_RESULT (ic));
3841 /* will try to generate an increment */
3842 /* if the right side is not a literal we cannot */
3843 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3846 /* if the literal value of the right hand side
3847 is greater than 4 then it is not worth it */
3848 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3851 size = getDataSize (IC_RESULT (ic));
3853 /* if decrement 16 bits in register */
3854 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3855 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3858 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3862 /* If result is a pair */
3863 if (isPair (AOP (IC_RESULT (ic))))
3865 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3867 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3871 /* if increment 16 bits in register */
3872 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3876 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3879 emit2 ("dec %s", _getTempPairName());
3882 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3888 /* if the sizes are greater than 1 then we cannot */
3889 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3890 AOP_SIZE (IC_LEFT (ic)) > 1)
3893 /* we can if the aops of the left & result match or if they are in
3894 registers and the registers are the same */
3895 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3898 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3905 /*-----------------------------------------------------------------*/
3906 /* genMinus - generates code for subtraction */
3907 /*-----------------------------------------------------------------*/
3909 genMinus (iCode * ic)
3911 int size, offset = 0;
3912 unsigned long lit = 0L;
3914 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3915 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3916 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3918 /* special cases :- */
3919 /* if both left & right are in bit space */
3920 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3921 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3923 wassertl (0, "Tried to subtract two bits");
3927 /* if I can do an decrement instead of subtract then GOOD for ME */
3928 if (genMinusDec (ic) == TRUE)
3931 size = getDataSize (IC_RESULT (ic));
3933 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3938 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3942 /* Same logic as genPlus */
3945 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3946 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3947 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3949 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3950 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3951 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3952 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3954 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3955 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3957 if (left == PAIR_INVALID && right == PAIR_INVALID)
3962 else if (right == PAIR_INVALID)
3964 else if (left == PAIR_INVALID)
3967 fetchPair (left, AOP (IC_LEFT (ic)));
3968 /* Order is important. Right may be HL */
3969 fetchPair (right, AOP (IC_RIGHT (ic)));
3971 emit2 ("ld a,%s", _pairs[left].l);
3972 emit2 ("sub a,%s", _pairs[right].l);
3974 emit2 ("ld a,%s", _pairs[left].h);
3975 emit2 ("sbc a,%s", _pairs[right].h);
3977 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3979 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3981 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3987 /* Be paranoid on the GB with 4 byte variables due to how C
3988 can be trashed by lda hl,n(sp).
3990 _gbz80_emitAddSubLong (ic, FALSE);
3995 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3997 /* if literal, add a,#-lit, else normal subb */
4000 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4001 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4005 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4008 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4012 /* first add without previous c */
4014 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4016 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4018 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4021 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4022 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4023 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4025 wassertl (0, "Tried to subtract on a long pointer");
4029 _G.preserveCarry = FALSE;
4030 freeAsmop (IC_LEFT (ic), NULL, ic);
4031 freeAsmop (IC_RIGHT (ic), NULL, ic);
4032 freeAsmop (IC_RESULT (ic), NULL, ic);
4035 /*-----------------------------------------------------------------*/
4036 /* genMult - generates code for multiplication */
4037 /*-----------------------------------------------------------------*/
4039 genMult (iCode * ic)
4043 /* If true then the final operation should be a subtract */
4044 bool active = FALSE;
4047 /* Shouldn't occur - all done through function calls */
4048 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4049 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4050 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4052 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4054 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4055 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4056 AOP_SIZE (IC_RESULT (ic)) > 2)
4058 wassertl (0, "Multiplication is handled through support function calls");
4061 /* Swap left and right such that right is a literal */
4062 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4064 operand *t = IC_RIGHT (ic);
4065 IC_RIGHT (ic) = IC_LEFT (ic);
4069 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4071 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4072 // wassertl (val > 0, "Multiply must be positive");
4073 wassertl (val != 1, "Can't multiply by 1");
4075 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4077 _G.stack.pushedDE = TRUE;
4080 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4082 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)
4116 emit2 ("add hl,de");
4125 if (IS_Z80 && _G.stack.pushedDE)
4128 _G.stack.pushedDE = FALSE;
4132 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4134 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4136 freeAsmop (IC_LEFT (ic), NULL, ic);
4137 freeAsmop (IC_RIGHT (ic), NULL, ic);
4138 freeAsmop (IC_RESULT (ic), NULL, ic);
4141 /*-----------------------------------------------------------------*/
4142 /* genDiv - generates code for division */
4143 /*-----------------------------------------------------------------*/
4147 /* Shouldn't occur - all done through function calls */
4148 wassertl (0, "Division is handled through support function calls");
4151 /*-----------------------------------------------------------------*/
4152 /* genMod - generates code for division */
4153 /*-----------------------------------------------------------------*/
4157 /* Shouldn't occur - all done through function calls */
4161 /*-----------------------------------------------------------------*/
4162 /* genIfxJump :- will create a jump depending on the ifx */
4163 /*-----------------------------------------------------------------*/
4165 genIfxJump (iCode * ic, char *jval)
4170 /* if true label then we jump if condition
4174 jlbl = IC_TRUE (ic);
4175 if (!strcmp (jval, "a"))
4179 else if (!strcmp (jval, "c"))
4183 else if (!strcmp (jval, "nc"))
4187 else if (!strcmp (jval, "m"))
4191 else if (!strcmp (jval, "p"))
4197 /* The buffer contains the bit on A that we should test */
4203 /* false label is present */
4204 jlbl = IC_FALSE (ic);
4205 if (!strcmp (jval, "a"))
4209 else if (!strcmp (jval, "c"))
4213 else if (!strcmp (jval, "nc"))
4217 else if (!strcmp (jval, "m"))
4221 else if (!strcmp (jval, "p"))
4227 /* The buffer contains the bit on A that we should test */
4231 /* Z80 can do a conditional long jump */
4232 if (!strcmp (jval, "a"))
4236 else if (!strcmp (jval, "c"))
4239 else if (!strcmp (jval, "nc"))
4242 else if (!strcmp (jval, "m"))
4245 else if (!strcmp (jval, "p"))
4250 emit2 ("bit %s,a", jval);
4252 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4254 /* mark the icode as generated */
4260 _getPairIdName (PAIR_ID id)
4262 return _pairs[id].name;
4267 /* if unsigned char cmp with lit, just compare */
4269 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4271 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4274 emit2 ("xor a,!immedbyte", 0x80);
4275 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4278 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4280 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4282 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4283 // Pull left into DE and right into HL
4284 aopGet (AOP(left), LSB, FALSE);
4287 aopGet (AOP(right), LSB, FALSE);
4291 if (size == 0 && sign)
4293 // Highest byte when signed needs the bits flipped
4296 emit2 ("ld a,(de)");
4297 emit2 ("xor !immedbyte", 0x80);
4299 emit2 ("ld a,(hl)");
4300 emit2 ("xor !immedbyte", 0x80);
4304 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4308 emit2 ("ld a,(de)");
4309 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4319 spillPair (PAIR_HL);
4321 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4323 setupPair (PAIR_HL, AOP (left), 0);
4324 aopGet (AOP(right), LSB, FALSE);
4328 if (size == 0 && sign)
4330 // Highest byte when signed needs the bits flipped
4333 emit2 ("ld a,(hl)");
4334 emit2 ("xor !immedbyte", 0x80);
4336 emit2 ("ld a,%d(iy)", offset);
4337 emit2 ("xor !immedbyte", 0x80);
4341 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4345 emit2 ("ld a,(hl)");
4346 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4355 spillPair (PAIR_HL);
4356 spillPair (PAIR_IY);
4360 if (AOP_TYPE (right) == AOP_LIT)
4362 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4363 /* optimize if(x < 0) or if(x >= 0) */
4368 /* No sign so it's always false */
4373 /* Just load in the top most bit */
4374 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4375 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4377 genIfxJump (ifx, "7");
4389 /* First setup h and l contaning the top most bytes XORed */
4390 bool fDidXor = FALSE;
4391 if (AOP_TYPE (left) == AOP_LIT)
4393 unsigned long lit = (unsigned long)
4394 floatFromVal (AOP (left)->aopu.aop_lit);
4395 emit2 ("ld %s,!immedbyte", _fTmp[0],
4396 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4400 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4401 emit2 ("xor a,!immedbyte", 0x80);
4402 emit2 ("ld %s,a", _fTmp[0]);
4405 if (AOP_TYPE (right) == AOP_LIT)
4407 unsigned long lit = (unsigned long)
4408 floatFromVal (AOP (right)->aopu.aop_lit);
4409 emit2 ("ld %s,!immedbyte", _fTmp[1],
4410 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4414 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4415 emit2 ("xor a,!immedbyte", 0x80);
4416 emit2 ("ld %s,a", _fTmp[1]);
4422 /* Do a long subtract */
4425 _moveA (aopGet (AOP (left), offset, FALSE));
4427 if (sign && size == 0)
4429 emit2 ("ld a,%s", _fTmp[0]);
4430 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4434 /* Subtract through, propagating the carry */
4435 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4443 /** Generic compare for > or <
4446 genCmp (operand * left, operand * right,
4447 operand * result, iCode * ifx, int sign)
4449 int size, offset = 0;
4450 unsigned long lit = 0L;
4451 bool swap_sense = FALSE;
4453 /* if left & right are bit variables */
4454 if (AOP_TYPE (left) == AOP_CRY &&
4455 AOP_TYPE (right) == AOP_CRY)
4457 /* Cant happen on the Z80 */
4458 wassertl (0, "Tried to compare two bits");
4462 /* Do a long subtract of right from left. */
4463 size = max (AOP_SIZE (left), AOP_SIZE (right));
4465 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4467 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4468 // Pull left into DE and right into HL
4469 aopGet (AOP(left), LSB, FALSE);
4472 aopGet (AOP(right), LSB, FALSE);
4476 emit2 ("ld a,(de)");
4477 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4486 spillPair (PAIR_HL);
4490 if (AOP_TYPE (right) == AOP_LIT)
4492 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4493 /* optimize if(x < 0) or if(x >= 0) */
4498 /* No sign so it's always false */
4503 /* Just load in the top most bit */
4504 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4505 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4507 genIfxJump (ifx, "7");
4518 genIfxJump (ifx, swap_sense ? "c" : "nc");
4529 _moveA (aopGet (AOP (left), offset, FALSE));
4530 /* Subtract through, propagating the carry */
4531 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4537 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4541 /* Shift the sign bit up into carry */
4544 outBitCLong (result, swap_sense);
4548 /* if the result is used in the next
4549 ifx conditional branch then generate
4550 code a little differently */
4558 genIfxJump (ifx, swap_sense ? "nc" : "c");
4562 genIfxJump (ifx, swap_sense ? "p" : "m");
4567 genIfxJump (ifx, swap_sense ? "nc" : "c");
4574 /* Shift the sign bit up into carry */
4577 outBitCLong (result, swap_sense);
4579 /* leave the result in acc */
4583 /*-----------------------------------------------------------------*/
4584 /* genCmpGt :- greater than comparison */
4585 /*-----------------------------------------------------------------*/
4587 genCmpGt (iCode * ic, iCode * ifx)
4589 operand *left, *right, *result;
4590 sym_link *letype, *retype;
4593 left = IC_LEFT (ic);
4594 right = IC_RIGHT (ic);
4595 result = IC_RESULT (ic);
4597 letype = getSpec (operandType (left));
4598 retype = getSpec (operandType (right));
4599 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4600 /* assign the amsops */
4601 aopOp (left, ic, FALSE, FALSE);
4602 aopOp (right, ic, FALSE, FALSE);
4603 aopOp (result, ic, TRUE, FALSE);
4605 genCmp (right, left, result, ifx, sign);
4607 freeAsmop (left, NULL, ic);
4608 freeAsmop (right, NULL, ic);
4609 freeAsmop (result, NULL, ic);
4612 /*-----------------------------------------------------------------*/
4613 /* genCmpLt - less than comparisons */
4614 /*-----------------------------------------------------------------*/
4616 genCmpLt (iCode * ic, iCode * ifx)
4618 operand *left, *right, *result;
4619 sym_link *letype, *retype;
4622 left = IC_LEFT (ic);
4623 right = IC_RIGHT (ic);
4624 result = IC_RESULT (ic);
4626 letype = getSpec (operandType (left));
4627 retype = getSpec (operandType (right));
4628 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4630 /* assign the amsops */
4631 aopOp (left, ic, FALSE, FALSE);
4632 aopOp (right, ic, FALSE, FALSE);
4633 aopOp (result, ic, TRUE, FALSE);
4635 genCmp (left, right, result, ifx, sign);
4637 freeAsmop (left, NULL, ic);
4638 freeAsmop (right, NULL, ic);
4639 freeAsmop (result, NULL, ic);
4642 /*-----------------------------------------------------------------*/
4643 /* gencjneshort - compare and jump if not equal */
4644 /*-----------------------------------------------------------------*/
4646 gencjneshort (operand * left, operand * right, symbol * lbl)
4648 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4650 unsigned long lit = 0L;
4652 /* Swap the left and right if it makes the computation easier */
4653 if (AOP_TYPE (left) == AOP_LIT)
4660 if (AOP_TYPE (right) == AOP_LIT)
4662 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4665 /* if the right side is a literal then anything goes */
4666 if (AOP_TYPE (right) == AOP_LIT &&
4667 AOP_TYPE (left) != AOP_DIR)
4671 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4676 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4683 emit2 ("jp nz,!tlabel", lbl->key + 100);
4689 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4690 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4693 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4694 emit2 ("jp nz,!tlabel", lbl->key + 100);
4699 /* if the right side is in a register or in direct space or
4700 if the left is a pointer register & right is not */
4701 else if (AOP_TYPE (right) == AOP_REG ||
4702 AOP_TYPE (right) == AOP_DIR ||
4703 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4707 _moveA (aopGet (AOP (left), offset, FALSE));
4708 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4709 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4711 emit2 ("jp nz,!tlabel", lbl->key + 100);
4714 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4715 emit2 ("jp nz,!tlabel", lbl->key + 100);
4722 /* right is a pointer reg need both a & b */
4723 /* PENDING: is this required? */
4726 _moveA (aopGet (AOP (right), offset, FALSE));
4727 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4728 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4734 /*-----------------------------------------------------------------*/
4735 /* gencjne - compare and jump if not equal */
4736 /*-----------------------------------------------------------------*/
4738 gencjne (operand * left, operand * right, symbol * lbl)
4740 symbol *tlbl = newiTempLabel (NULL);
4742 gencjneshort (left, right, lbl);
4745 emit2 ("ld a,!one");
4746 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4747 emitLabel (lbl->key + 100);
4749 emitLabel (tlbl->key + 100);
4752 /*-----------------------------------------------------------------*/
4753 /* genCmpEq - generates code for equal to */
4754 /*-----------------------------------------------------------------*/
4756 genCmpEq (iCode * ic, iCode * ifx)
4758 operand *left, *right, *result;
4760 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4761 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4762 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4764 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4766 /* Swap operands if it makes the operation easier. ie if:
4767 1. Left is a literal.
4769 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4771 operand *t = IC_RIGHT (ic);
4772 IC_RIGHT (ic) = IC_LEFT (ic);
4776 if (ifx && !AOP_SIZE (result))
4779 /* if they are both bit variables */
4780 if (AOP_TYPE (left) == AOP_CRY &&
4781 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4783 wassertl (0, "Tried to compare two bits");
4787 tlbl = newiTempLabel (NULL);
4788 gencjneshort (left, right, tlbl);
4791 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4792 emitLabel (tlbl->key + 100);
4796 /* PENDING: do this better */
4797 symbol *lbl = newiTempLabel (NULL);
4798 emit2 ("!shortjp !tlabel", lbl->key + 100);
4799 emitLabel (tlbl->key + 100);
4800 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4801 emitLabel (lbl->key + 100);
4804 /* mark the icode as generated */
4809 /* if they are both bit variables */
4810 if (AOP_TYPE (left) == AOP_CRY &&
4811 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4813 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4819 gencjne (left, right, newiTempLabel (NULL));
4820 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4827 genIfxJump (ifx, "a");
4830 /* if the result is used in an arithmetic operation
4831 then put the result in place */
4832 if (AOP_TYPE (result) != AOP_CRY)
4837 /* leave the result in acc */
4841 freeAsmop (left, NULL, ic);
4842 freeAsmop (right, NULL, ic);
4843 freeAsmop (result, NULL, ic);
4846 /*-----------------------------------------------------------------*/
4847 /* ifxForOp - returns the icode containing the ifx for operand */
4848 /*-----------------------------------------------------------------*/
4850 ifxForOp (operand * op, iCode * ic)
4852 /* if true symbol then needs to be assigned */
4853 if (IS_TRUE_SYMOP (op))
4856 /* if this has register type condition and
4857 the next instruction is ifx with the same operand
4858 and live to of the operand is upto the ifx only then */
4860 ic->next->op == IFX &&
4861 IC_COND (ic->next)->key == op->key &&
4862 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4868 /*-----------------------------------------------------------------*/
4869 /* genAndOp - for && operation */
4870 /*-----------------------------------------------------------------*/
4872 genAndOp (iCode * ic)
4874 operand *left, *right, *result;
4877 /* note here that && operations that are in an if statement are
4878 taken away by backPatchLabels only those used in arthmetic
4879 operations remain */
4880 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4881 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4882 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4884 /* if both are bit variables */
4885 if (AOP_TYPE (left) == AOP_CRY &&
4886 AOP_TYPE (right) == AOP_CRY)
4888 wassertl (0, "Tried to and two bits");
4892 tlbl = newiTempLabel (NULL);
4894 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4896 emitLabel (tlbl->key + 100);
4900 freeAsmop (left, NULL, ic);
4901 freeAsmop (right, NULL, ic);
4902 freeAsmop (result, NULL, ic);
4905 /*-----------------------------------------------------------------*/
4906 /* genOrOp - for || operation */
4907 /*-----------------------------------------------------------------*/
4909 genOrOp (iCode * ic)
4911 operand *left, *right, *result;
4914 /* note here that || operations that are in an
4915 if statement are taken away by backPatchLabels
4916 only those used in arthmetic operations remain */
4917 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4918 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4919 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4921 /* if both are bit variables */
4922 if (AOP_TYPE (left) == AOP_CRY &&
4923 AOP_TYPE (right) == AOP_CRY)
4925 wassertl (0, "Tried to OR two bits");
4929 tlbl = newiTempLabel (NULL);
4931 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4933 emitLabel (tlbl->key + 100);
4937 freeAsmop (left, NULL, ic);
4938 freeAsmop (right, NULL, ic);
4939 freeAsmop (result, NULL, ic);
4942 /*-----------------------------------------------------------------*/
4943 /* isLiteralBit - test if lit == 2^n */
4944 /*-----------------------------------------------------------------*/
4946 isLiteralBit (unsigned long lit)
4948 unsigned long pw[32] =
4949 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4950 0x100L, 0x200L, 0x400L, 0x800L,
4951 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4952 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4953 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4954 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4955 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4958 for (idx = 0; idx < 32; idx++)
4964 /*-----------------------------------------------------------------*/
4965 /* jmpTrueOrFalse - */
4966 /*-----------------------------------------------------------------*/
4968 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4970 // ugly but optimized by peephole
4973 symbol *nlbl = newiTempLabel (NULL);
4974 emit2 ("jp !tlabel", nlbl->key + 100);
4975 emitLabel (tlbl->key + 100);
4976 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4977 emitLabel (nlbl->key + 100);
4981 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4982 emitLabel (tlbl->key + 100);
4987 /*-----------------------------------------------------------------*/
4988 /* genAnd - code for and */
4989 /*-----------------------------------------------------------------*/
4991 genAnd (iCode * ic, iCode * ifx)
4993 operand *left, *right, *result;
4994 int size, offset = 0;
4995 unsigned long lit = 0L;
4998 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4999 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5000 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5002 /* if left is a literal & right is not then exchange them */
5003 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5004 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5006 operand *tmp = right;
5011 /* if result = right then exchange them */
5012 if (sameRegs (AOP (result), AOP (right)))
5014 operand *tmp = right;
5019 /* if right is bit then exchange them */
5020 if (AOP_TYPE (right) == AOP_CRY &&
5021 AOP_TYPE (left) != AOP_CRY)
5023 operand *tmp = right;
5027 if (AOP_TYPE (right) == AOP_LIT)
5028 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5030 size = AOP_SIZE (result);
5032 if (AOP_TYPE (left) == AOP_CRY)
5034 wassertl (0, "Tried to perform an AND with a bit as an operand");
5038 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5039 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5040 if ((AOP_TYPE (right) == AOP_LIT) &&
5041 (AOP_TYPE (result) == AOP_CRY) &&
5042 (AOP_TYPE (left) != AOP_CRY))
5044 symbol *tlbl = newiTempLabel (NULL);
5045 int sizel = AOP_SIZE (left);
5048 /* PENDING: Test case for this. */
5053 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5055 _moveA (aopGet (AOP (left), offset, FALSE));
5056 if (bytelit != 0x0FFL)
5058 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5065 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5069 // bit = left & literal
5073 emit2 ("!tlabeldef", tlbl->key + 100);
5075 // if(left & literal)
5080 jmpTrueOrFalse (ifx, tlbl);
5088 /* if left is same as result */
5089 if (sameRegs (AOP (result), AOP (left)))
5091 for (; size--; offset++)
5093 if (AOP_TYPE (right) == AOP_LIT)
5095 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5100 aopPut (AOP (result), "!zero", offset);
5103 _moveA (aopGet (AOP (left), offset, FALSE));
5105 aopGet (AOP (right), offset, FALSE));
5106 aopPut (AOP (left), "a", offset);
5113 if (AOP_TYPE (left) == AOP_ACC)
5115 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5119 _moveA (aopGet (AOP (left), offset, FALSE));
5121 aopGet (AOP (right), offset, FALSE));
5122 aopPut (AOP (left), "a", offset);
5129 // left & result in different registers
5130 if (AOP_TYPE (result) == AOP_CRY)
5132 wassertl (0, "Tried to AND where the result is in carry");
5136 for (; (size--); offset++)
5139 // result = left & right
5140 if (AOP_TYPE (right) == AOP_LIT)
5142 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5144 aopPut (AOP (result),
5145 aopGet (AOP (left), offset, FALSE),
5149 else if (bytelit == 0)
5151 aopPut (AOP (result), "!zero", offset);
5155 // faster than result <- left, anl result,right
5156 // and better if result is SFR
5157 if (AOP_TYPE (left) == AOP_ACC)
5158 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5161 _moveA (aopGet (AOP (left), offset, FALSE));
5163 aopGet (AOP (right), offset, FALSE));
5165 aopPut (AOP (result), "a", offset);
5172 freeAsmop (left, NULL, ic);
5173 freeAsmop (right, NULL, ic);
5174 freeAsmop (result, NULL, ic);
5177 /*-----------------------------------------------------------------*/
5178 /* genOr - code for or */
5179 /*-----------------------------------------------------------------*/
5181 genOr (iCode * ic, iCode * ifx)
5183 operand *left, *right, *result;
5184 int size, offset = 0;
5185 unsigned long lit = 0L;
5188 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5189 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5190 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5192 /* if left is a literal & right is not then exchange them */
5193 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5194 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5196 operand *tmp = right;
5201 /* if result = right then exchange them */
5202 if (sameRegs (AOP (result), AOP (right)))
5204 operand *tmp = right;
5209 /* if right is bit then exchange them */
5210 if (AOP_TYPE (right) == AOP_CRY &&
5211 AOP_TYPE (left) != AOP_CRY)
5213 operand *tmp = right;
5217 if (AOP_TYPE (right) == AOP_LIT)
5218 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5220 size = AOP_SIZE (result);
5222 if (AOP_TYPE (left) == AOP_CRY)
5224 wassertl (0, "Tried to OR where left is a bit");
5228 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5229 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5230 if ((AOP_TYPE (right) == AOP_LIT) &&
5231 (AOP_TYPE (result) == AOP_CRY) &&
5232 (AOP_TYPE (left) != AOP_CRY))
5234 symbol *tlbl = newiTempLabel (NULL);
5235 int sizel = AOP_SIZE (left);
5239 wassertl (0, "Result is assigned to a bit");
5241 /* PENDING: Modeled after the AND code which is inefficent. */
5244 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5246 _moveA (aopGet (AOP (left), offset, FALSE));
5247 /* OR with any literal is the same as OR with itself. */
5249 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5255 jmpTrueOrFalse (ifx, tlbl);
5260 /* if left is same as result */
5261 if (sameRegs (AOP (result), AOP (left)))
5263 for (; size--; offset++)
5265 if (AOP_TYPE (right) == AOP_LIT)
5267 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5271 _moveA (aopGet (AOP (left), offset, FALSE));
5273 aopGet (AOP (right), offset, FALSE));
5274 aopPut (AOP (result), "a", offset);
5279 if (AOP_TYPE (left) == AOP_ACC)
5280 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5283 _moveA (aopGet (AOP (left), offset, FALSE));
5285 aopGet (AOP (right), offset, FALSE));
5286 aopPut (AOP (result), "a", offset);
5293 // left & result in different registers
5294 if (AOP_TYPE (result) == AOP_CRY)
5296 wassertl (0, "Result of OR is in a bit");
5299 for (; (size--); offset++)
5302 // result = left & right
5303 if (AOP_TYPE (right) == AOP_LIT)
5305 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5307 aopPut (AOP (result),
5308 aopGet (AOP (left), offset, FALSE),
5313 // faster than result <- left, anl result,right
5314 // and better if result is SFR
5315 if (AOP_TYPE (left) == AOP_ACC)
5316 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5319 _moveA (aopGet (AOP (left), offset, FALSE));
5321 aopGet (AOP (right), offset, FALSE));
5323 aopPut (AOP (result), "a", offset);
5324 /* PENDING: something weird is going on here. Add exception. */
5325 if (AOP_TYPE (result) == AOP_ACC)
5331 freeAsmop (left, NULL, ic);
5332 freeAsmop (right, NULL, ic);
5333 freeAsmop (result, NULL, ic);
5336 /*-----------------------------------------------------------------*/
5337 /* genXor - code for xclusive or */
5338 /*-----------------------------------------------------------------*/
5340 genXor (iCode * ic, iCode * ifx)
5342 operand *left, *right, *result;
5343 int size, offset = 0;
5344 unsigned long lit = 0L;
5346 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5347 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5348 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5350 /* if left is a literal & right is not then exchange them */
5351 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5352 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5354 operand *tmp = right;
5359 /* if result = right then exchange them */
5360 if (sameRegs (AOP (result), AOP (right)))
5362 operand *tmp = right;
5367 /* if right is bit then exchange them */
5368 if (AOP_TYPE (right) == AOP_CRY &&
5369 AOP_TYPE (left) != AOP_CRY)
5371 operand *tmp = right;
5375 if (AOP_TYPE (right) == AOP_LIT)
5376 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5378 size = AOP_SIZE (result);
5380 if (AOP_TYPE (left) == AOP_CRY)
5382 wassertl (0, "Tried to XOR a bit");
5386 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5387 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5388 if ((AOP_TYPE (right) == AOP_LIT) &&
5389 (AOP_TYPE (result) == AOP_CRY) &&
5390 (AOP_TYPE (left) != AOP_CRY))
5392 symbol *tlbl = newiTempLabel (NULL);
5393 int sizel = AOP_SIZE (left);
5397 /* PENDING: Test case for this. */
5398 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5402 _moveA (aopGet (AOP (left), offset, FALSE));
5403 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5404 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5409 jmpTrueOrFalse (ifx, tlbl);
5413 wassertl (0, "Result of XOR was destined for a bit");
5418 /* if left is same as result */
5419 if (sameRegs (AOP (result), AOP (left)))
5421 for (; size--; offset++)
5423 if (AOP_TYPE (right) == AOP_LIT)
5425 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5429 _moveA (aopGet (AOP (left), offset, FALSE));
5431 aopGet (AOP (right), offset, FALSE));
5432 aopPut (AOP (result), "a", offset);
5437 if (AOP_TYPE (left) == AOP_ACC)
5439 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5443 _moveA (aopGet (AOP (left), offset, FALSE));
5445 aopGet (AOP (right), offset, FALSE));
5446 aopPut (AOP (result), "a", offset);
5453 // left & result in different registers
5454 if (AOP_TYPE (result) == AOP_CRY)
5456 wassertl (0, "Result of XOR is in a bit");
5459 for (; (size--); offset++)
5462 // result = left & right
5463 if (AOP_TYPE (right) == AOP_LIT)
5465 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5467 aopPut (AOP (result),
5468 aopGet (AOP (left), offset, FALSE),
5473 // faster than result <- left, anl result,right
5474 // and better if result is SFR
5475 if (AOP_TYPE (left) == AOP_ACC)
5477 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5481 _moveA (aopGet (AOP (left), offset, FALSE));
5483 aopGet (AOP (right), offset, FALSE));
5485 aopPut (AOP (result), "a", offset);
5490 freeAsmop (left, NULL, ic);
5491 freeAsmop (right, NULL, ic);
5492 freeAsmop (result, NULL, ic);
5495 /*-----------------------------------------------------------------*/
5496 /* genInline - write the inline code out */
5497 /*-----------------------------------------------------------------*/
5499 genInline (iCode * ic)
5501 char *buffer, *bp, *bp1;
5503 _G.lines.isInline += (!options.asmpeep);
5505 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5506 strcpy (buffer, IC_INLINE (ic));
5508 /* emit each line as a code */
5533 _G.lines.isInline -= (!options.asmpeep);
5537 /*-----------------------------------------------------------------*/
5538 /* genRRC - rotate right with carry */
5539 /*-----------------------------------------------------------------*/
5546 /*-----------------------------------------------------------------*/
5547 /* genRLC - generate code for rotate left with carry */
5548 /*-----------------------------------------------------------------*/
5555 /*-----------------------------------------------------------------*/
5556 /* genGetHbit - generates code get highest order bit */
5557 /*-----------------------------------------------------------------*/
5559 genGetHbit (iCode * ic)
5561 operand *left, *result;
5562 left = IC_LEFT (ic);
5563 result = IC_RESULT (ic);
5565 aopOp (left, ic, FALSE, FALSE);
5566 aopOp (result, ic, FALSE, FALSE);
5568 /* get the highest order byte into a */
5569 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5571 if (AOP_TYPE (result) == AOP_CRY)
5579 emit2 ("and a,!one");
5584 freeAsmop (left, NULL, ic);
5585 freeAsmop (result, NULL, ic);
5589 emitRsh2 (asmop *aop, int size, int is_signed)
5595 const char *l = aopGet (aop, size, FALSE);
5598 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5608 /*-----------------------------------------------------------------*/
5609 /* shiftR2Left2Result - shift right two bytes from left to result */
5610 /*-----------------------------------------------------------------*/
5612 shiftR2Left2Result (operand * left, int offl,
5613 operand * result, int offr,
5614 int shCount, int is_signed)
5617 symbol *tlbl, *tlbl1;
5619 movLeft2Result (left, offl, result, offr, 0);
5620 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5622 /* if (AOP(result)->type == AOP_REG) { */
5624 tlbl = newiTempLabel (NULL);
5625 tlbl1 = newiTempLabel (NULL);
5627 /* Left is already in result - so now do the shift */
5632 emitRsh2 (AOP (result), size, is_signed);
5637 emit2 ("ld a,!immedbyte+1", shCount);
5638 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5639 emitLabel (tlbl->key + 100);
5641 emitRsh2 (AOP (result), size, is_signed);
5643 emitLabel (tlbl1->key + 100);
5645 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5649 /*-----------------------------------------------------------------*/
5650 /* shiftL2Left2Result - shift left two bytes from left to result */
5651 /*-----------------------------------------------------------------*/
5653 shiftL2Left2Result (operand * left, int offl,
5654 operand * result, int offr, int shCount)
5656 if (sameRegs (AOP (result), AOP (left)) &&
5657 ((offl + MSB16) == offr))
5663 /* Copy left into result */
5664 movLeft2Result (left, offl, result, offr, 0);
5665 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5668 if (getPairId (AOP (result)) == PAIR_HL)
5672 emit2 ("add hl,hl");
5679 symbol *tlbl, *tlbl1;
5682 tlbl = newiTempLabel (NULL);
5683 tlbl1 = newiTempLabel (NULL);
5685 if (AOP (result)->type == AOP_REG)
5689 for (offset = 0; offset < size; offset++)
5691 l = aopGet (AOP (result), offset, FALSE);
5695 emit2 ("sla %s", l);
5706 /* Left is already in result - so now do the shift */
5709 emit2 ("ld a,!immedbyte+1", shCount);
5710 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5711 emitLabel (tlbl->key + 100);
5716 l = aopGet (AOP (result), offset, FALSE);
5720 emit2 ("sla %s", l);
5731 emitLabel (tlbl1->key + 100);
5733 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5739 /*-----------------------------------------------------------------*/
5740 /* AccRol - rotate left accumulator by known count */
5741 /*-----------------------------------------------------------------*/
5743 AccRol (int shCount)
5745 shCount &= 0x0007; // shCount : 0..7
5822 /*-----------------------------------------------------------------*/
5823 /* AccLsh - left shift accumulator by known count */
5824 /*-----------------------------------------------------------------*/
5826 AccLsh (int shCount)
5828 static const unsigned char SLMask[] =
5830 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5839 else if (shCount == 2)
5846 /* rotate left accumulator */
5848 /* and kill the lower order bits */
5849 emit2 ("and a,!immedbyte", SLMask[shCount]);
5854 /*-----------------------------------------------------------------*/
5855 /* shiftL1Left2Result - shift left one byte from left to result */
5856 /*-----------------------------------------------------------------*/
5858 shiftL1Left2Result (operand * left, int offl,
5859 operand * result, int offr, int shCount)
5862 l = aopGet (AOP (left), offl, FALSE);
5864 /* shift left accumulator */
5866 aopPut (AOP (result), "a", offr);
5870 /*-----------------------------------------------------------------*/
5871 /* genlshTwo - left shift two bytes by known amount != 0 */
5872 /*-----------------------------------------------------------------*/
5874 genlshTwo (operand * result, operand * left, int shCount)
5876 int size = AOP_SIZE (result);
5878 wassert (size == 2);
5880 /* if shCount >= 8 */
5888 movLeft2Result (left, LSB, result, MSB16, 0);
5889 aopPut (AOP (result), "!zero", 0);
5890 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5894 movLeft2Result (left, LSB, result, MSB16, 0);
5895 aopPut (AOP (result), "!zero", 0);
5900 aopPut (AOP (result), "!zero", LSB);
5903 /* 1 <= shCount <= 7 */
5912 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5917 /*-----------------------------------------------------------------*/
5918 /* genlshOne - left shift a one byte quantity by known count */
5919 /*-----------------------------------------------------------------*/
5921 genlshOne (operand * result, operand * left, int shCount)
5923 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5926 /*-----------------------------------------------------------------*/
5927 /* genLeftShiftLiteral - left shifting by known count */
5928 /*-----------------------------------------------------------------*/
5930 genLeftShiftLiteral (operand * left,
5935 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5938 freeAsmop (right, NULL, ic);
5940 aopOp (left, ic, FALSE, FALSE);
5941 aopOp (result, ic, FALSE, FALSE);
5943 size = getSize (operandType (result));
5945 /* I suppose that the left size >= result size */
5951 else if (shCount >= (size * 8))
5955 aopPut (AOP (result), "!zero", size);
5963 genlshOne (result, left, shCount);
5966 genlshTwo (result, left, shCount);
5969 wassertl (0, "Shifting of longs is currently unsupported");
5975 freeAsmop (left, NULL, ic);
5976 freeAsmop (result, NULL, ic);
5979 /*-----------------------------------------------------------------*/
5980 /* genLeftShift - generates code for left shifting */
5981 /*-----------------------------------------------------------------*/
5983 genLeftShift (iCode * ic)
5987 symbol *tlbl, *tlbl1;
5988 operand *left, *right, *result;
5990 right = IC_RIGHT (ic);
5991 left = IC_LEFT (ic);
5992 result = IC_RESULT (ic);
5994 aopOp (right, ic, FALSE, FALSE);
5996 /* if the shift count is known then do it
5997 as efficiently as possible */
5998 if (AOP_TYPE (right) == AOP_LIT)
6000 genLeftShiftLiteral (left, right, result, ic);
6004 /* shift count is unknown then we have to form a loop get the loop
6005 count in B : Note: we take only the lower order byte since
6006 shifting more that 32 bits make no sense anyway, ( the largest
6007 size of an object can be only 32 bits ) */
6008 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6010 freeAsmop (right, NULL, ic);
6011 aopOp (left, ic, FALSE, FALSE);
6012 aopOp (result, ic, FALSE, FALSE);
6014 /* now move the left to the result if they are not the
6017 if (!sameRegs (AOP (left), AOP (result)))
6020 size = AOP_SIZE (result);
6024 l = aopGet (AOP (left), offset, FALSE);
6025 aopPut (AOP (result), l, offset);
6030 tlbl = newiTempLabel (NULL);
6031 size = AOP_SIZE (result);
6033 tlbl1 = newiTempLabel (NULL);
6035 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6036 emitLabel (tlbl->key + 100);
6037 l = aopGet (AOP (result), offset, FALSE);
6041 l = aopGet (AOP (result), offset, FALSE);
6045 emit2 ("sla %s", l);
6053 emitLabel (tlbl1->key + 100);
6055 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6057 freeAsmop (left, NULL, ic);
6058 freeAsmop (result, NULL, ic);
6061 /*-----------------------------------------------------------------*/
6062 /* genrshOne - left shift two bytes by known amount != 0 */
6063 /*-----------------------------------------------------------------*/
6065 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6068 int size = AOP_SIZE (result);
6071 wassert (size == 1);
6072 wassert (shCount < 8);
6074 l = aopGet (AOP (left), 0, FALSE);
6076 if (AOP (result)->type == AOP_REG)
6078 aopPut (AOP (result), l, 0);
6079 l = aopGet (AOP (result), 0, FALSE);
6082 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6090 emit2 ("%s a", is_signed ? "sra" : "srl");
6092 aopPut (AOP (result), "a", 0);
6096 /*-----------------------------------------------------------------*/
6097 /* AccRsh - right shift accumulator by known count */
6098 /*-----------------------------------------------------------------*/
6100 AccRsh (int shCount)
6102 static const unsigned char SRMask[] =
6104 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6109 /* rotate right accumulator */
6110 AccRol (8 - shCount);
6111 /* and kill the higher order bits */
6112 emit2 ("and a,!immedbyte", SRMask[shCount]);
6116 /*-----------------------------------------------------------------*/
6117 /* shiftR1Left2Result - shift right one byte from left to result */
6118 /*-----------------------------------------------------------------*/
6120 shiftR1Left2Result (operand * left, int offl,
6121 operand * result, int offr,
6122 int shCount, int sign)
6124 _moveA (aopGet (AOP (left), offl, FALSE));
6129 emit2 ("%s a", sign ? "sra" : "srl");
6136 aopPut (AOP (result), "a", offr);
6139 /*-----------------------------------------------------------------*/
6140 /* genrshTwo - right shift two bytes by known amount != 0 */
6141 /*-----------------------------------------------------------------*/
6143 genrshTwo (operand * result, operand * left,
6144 int shCount, int sign)
6146 /* if shCount >= 8 */
6152 shiftR1Left2Result (left, MSB16, result, LSB,
6157 movLeft2Result (left, MSB16, result, LSB, sign);
6161 /* Sign extend the result */
6162 _moveA(aopGet (AOP (result), 0, FALSE));
6166 aopPut (AOP (result), ACC_NAME, MSB16);
6170 aopPut (AOP (result), "!zero", 1);
6173 /* 1 <= shCount <= 7 */
6176 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6180 /*-----------------------------------------------------------------*/
6181 /* genRightShiftLiteral - left shifting by known count */
6182 /*-----------------------------------------------------------------*/
6184 genRightShiftLiteral (operand * left,
6190 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6193 freeAsmop (right, NULL, ic);
6195 aopOp (left, ic, FALSE, FALSE);
6196 aopOp (result, ic, FALSE, FALSE);
6198 size = getSize (operandType (result));
6200 /* I suppose that the left size >= result size */
6206 else if (shCount >= (size * 8)) {
6208 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6209 _moveA(aopGet (AOP (left), 0, FALSE));
6217 aopPut (AOP (result), s, size);
6224 genrshOne (result, left, shCount, sign);
6227 genrshTwo (result, left, shCount, sign);
6230 wassertl (0, "Asked to shift right a long which should be a function call");
6233 wassertl (0, "Entered default case in right shift delegate");
6236 freeAsmop (left, NULL, ic);
6237 freeAsmop (result, NULL, ic);
6240 /*-----------------------------------------------------------------*/
6241 /* genRightShift - generate code for right shifting */
6242 /*-----------------------------------------------------------------*/
6244 genRightShift (iCode * ic)
6246 operand *right, *left, *result;
6248 int size, offset, first = 1;
6252 symbol *tlbl, *tlbl1;
6254 /* if signed then we do it the hard way preserve the
6255 sign bit moving it inwards */
6256 retype = getSpec (operandType (IC_RESULT (ic)));
6258 is_signed = !SPEC_USIGN (retype);
6260 /* signed & unsigned types are treated the same : i.e. the
6261 signed is NOT propagated inwards : quoting from the
6262 ANSI - standard : "for E1 >> E2, is equivalent to division
6263 by 2**E2 if unsigned or if it has a non-negative value,
6264 otherwise the result is implementation defined ", MY definition
6265 is that the sign does not get propagated */
6267 right = IC_RIGHT (ic);
6268 left = IC_LEFT (ic);
6269 result = IC_RESULT (ic);
6271 aopOp (right, ic, FALSE, FALSE);
6273 /* if the shift count is known then do it
6274 as efficiently as possible */
6275 if (AOP_TYPE (right) == AOP_LIT)
6277 genRightShiftLiteral (left, right, result, ic, is_signed);
6281 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6283 freeAsmop (right, NULL, ic);
6285 aopOp (left, ic, FALSE, FALSE);
6286 aopOp (result, ic, FALSE, FALSE);
6288 /* now move the left to the result if they are not the
6290 if (!sameRegs (AOP (left), AOP (result)))
6293 size = AOP_SIZE (result);
6297 l = aopGet (AOP (left), offset, FALSE);
6298 aopPut (AOP (result), l, offset);
6303 tlbl = newiTempLabel (NULL);
6304 tlbl1 = newiTempLabel (NULL);
6305 size = AOP_SIZE (result);
6308 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6309 emitLabel (tlbl->key + 100);
6312 l = aopGet (AOP (result), offset--, FALSE);
6315 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6323 emitLabel (tlbl1->key + 100);
6325 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6327 freeAsmop (left, NULL, ic);
6328 freeAsmop (result, NULL, ic);
6332 /*-----------------------------------------------------------------*/
6333 /* genUnpackBits - generates code for unpacking bits */
6334 /*-----------------------------------------------------------------*/
6336 genUnpackBits (operand * result, int pair)
6338 int offset = 0; /* result byte offset */
6339 int rsize; /* result size */
6340 int rlen = 0; /* remaining bitfield length */
6341 sym_link *etype; /* bitfield type information */
6342 int blen; /* bitfield length */
6343 int bstr; /* bitfield starting bit within byte */
6345 emitDebug ("; genUnpackBits");
6347 etype = getSpec (operandType (result));
6348 rsize = getSize (operandType (result));
6349 blen = SPEC_BLEN (etype);
6350 bstr = SPEC_BSTR (etype);
6352 /* If the bitfield length is less than a byte */
6355 emit2 ("ld a,!*pair", _pairs[pair].name);
6357 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6358 aopPut (AOP (result), "a", offset++);
6362 /* TODO: what if pair == PAIR_DE ? */
6363 if (getPairId (AOP (result)) == PAIR_HL)
6365 wassertl (rsize == 2, "HL must be of size 2");
6366 emit2 ("ld a,!*hl");
6368 emit2 ("ld h,!*hl");
6371 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6373 spillPair (PAIR_HL);
6377 /* Bit field did not fit in a byte. Copy all
6378 but the partial byte at the end. */
6379 for (rlen=blen;rlen>=8;rlen-=8)
6381 emit2 ("ld a,!*pair", _pairs[pair].name);
6382 aopPut (AOP (result), "a", offset++);
6385 emit2 ("inc %s", _pairs[pair].name);
6386 _G.pairs[pair].offset++;
6390 /* Handle the partial byte at the end */
6393 emit2 ("ld a,!*pair", _pairs[pair].name);
6394 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6395 aopPut (AOP (result), "a", offset++);
6403 aopPut (AOP (result), "!zero", offset++);
6407 /*-----------------------------------------------------------------*/
6408 /* genGenPointerGet - get value from generic pointer space */
6409 /*-----------------------------------------------------------------*/
6411 genGenPointerGet (operand * left,
6412 operand * result, iCode * ic)
6415 sym_link *retype = getSpec (operandType (result));
6421 aopOp (left, ic, FALSE, FALSE);
6422 aopOp (result, ic, FALSE, FALSE);
6424 size = AOP_SIZE (result);
6426 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6429 if (isPtrPair (AOP (left)))
6431 tsprintf (buffer, sizeof(buffer),
6432 "!*pair", getPairName (AOP (left)));
6433 aopPut (AOP (result), buffer, 0);
6437 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6438 aopPut (AOP (result), "a", 0);
6440 freeAsmop (left, NULL, ic);
6444 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6451 tsprintf (at, sizeof(at), "!*iyx", offset);
6452 aopPut (AOP (result), at, offset);
6456 freeAsmop (left, NULL, ic);
6460 /* For now we always load into IY */
6461 /* if this is remateriazable */
6462 fetchPair (pair, AOP (left));
6464 /* if bit then unpack */
6465 if (IS_BITVAR (retype))
6467 genUnpackBits (result, pair);
6468 freeAsmop (left, NULL, ic);
6472 else if (getPairId (AOP (result)) == PAIR_HL)
6474 wassertl (size == 2, "HL must be of size 2");
6475 emit2 ("ld a,!*hl");
6477 emit2 ("ld h,!*hl");
6479 spillPair (PAIR_HL);
6481 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6483 size = AOP_SIZE (result);
6488 /* PENDING: make this better */
6489 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6491 aopPut (AOP (result), "!*hl", offset++);
6495 emit2 ("ld a,!*pair", _pairs[pair].name);
6496 aopPut (AOP (result), "a", offset++);
6500 emit2 ("inc %s", _pairs[pair].name);
6501 _G.pairs[pair].offset++;
6504 /* Fixup HL back down */
6505 for (size = AOP_SIZE (result)-1; size; size--)
6507 emit2 ("dec %s", _pairs[pair].name);
6512 size = AOP_SIZE (result);
6517 /* PENDING: make this better */
6519 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6521 aopPut (AOP (result), "!*hl", offset++);
6525 emit2 ("ld a,!*pair", _pairs[pair].name);
6526 aopPut (AOP (result), "a", offset++);
6530 emit2 ("inc %s", _pairs[pair].name);
6531 _G.pairs[pair].offset++;
6536 freeAsmop (left, NULL, ic);
6539 freeAsmop (result, NULL, ic);
6542 /*-----------------------------------------------------------------*/
6543 /* genPointerGet - generate code for pointer get */
6544 /*-----------------------------------------------------------------*/
6546 genPointerGet (iCode * ic)
6548 operand *left, *result;
6549 sym_link *type, *etype;
6551 left = IC_LEFT (ic);
6552 result = IC_RESULT (ic);
6554 /* depending on the type of pointer we need to
6555 move it to the correct pointer register */
6556 type = operandType (left);
6557 etype = getSpec (type);
6559 genGenPointerGet (left, result, ic);
6563 isRegOrLit (asmop * aop)
6565 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6571 /*-----------------------------------------------------------------*/
6572 /* genPackBits - generates code for packed bit storage */
6573 /*-----------------------------------------------------------------*/
6575 genPackBits (sym_link * etype,
6580 int offset = 0; /* source byte offset */
6581 int rlen = 0; /* remaining bitfield length */
6582 int blen; /* bitfield length */
6583 int bstr; /* bitfield starting bit within byte */
6584 int litval; /* source literal value (if AOP_LIT) */
6585 unsigned char mask; /* bitmask within current byte */
6586 int extraPair; /* a tempory register */
6587 bool needPopExtra=0; /* need to restore original value of temp reg */
6589 emitDebug ("; genPackBits","");
6591 blen = SPEC_BLEN (etype);
6592 bstr = SPEC_BSTR (etype);
6594 /* If the bitfield length is less than a byte */
6597 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6598 (unsigned char) (0xFF >> (8 - bstr)));
6600 if (AOP_TYPE (right) == AOP_LIT)
6602 /* Case with a bitfield length <8 and literal source
6604 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6606 litval &= (~mask) & 0xff;
6607 emit2 ("ld a,!*pair", _pairs[pair].name);
6608 if ((mask|litval)!=0xff)
6609 emit2 ("and a,!immedbyte", mask);
6611 emit2 ("or a,!immedbyte", litval);
6612 emit2 ("ld !*pair,a", _pairs[pair].name);
6617 /* Case with a bitfield length <8 and arbitrary source
6619 _moveA (aopGet (AOP (right), 0, FALSE));
6620 /* shift and mask source value */
6622 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6624 extraPair = getFreePairId(ic);
6625 if (extraPair == PAIR_INVALID)
6627 extraPair = PAIR_BC;
6628 if (getPairId (AOP (right)) != PAIR_BC
6629 || !isLastUse (ic, right))
6635 emit2 ("ld %s,a", _pairs[extraPair].l);
6636 emit2 ("ld a,!*pair", _pairs[pair].name);
6638 emit2 ("and a,!immedbyte", mask);
6639 emit2 ("or a,%s", _pairs[extraPair].l);
6640 emit2 ("ld !*pair,a", _pairs[pair].name);
6647 /* Bit length is greater than 7 bits. In this case, copy */
6648 /* all except the partial byte at the end */
6649 for (rlen=blen;rlen>=8;rlen-=8)
6651 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6652 emit2 ("ld !*pair,a", _pairs[pair].name);
6655 emit2 ("inc %s", _pairs[pair].name);
6656 _G.pairs[pair].offset++;
6660 /* If there was a partial byte at the end */
6663 mask = (((unsigned char) -1 << rlen) & 0xff);
6665 if (AOP_TYPE (right) == AOP_LIT)
6667 /* Case with partial byte and literal source
6669 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6670 litval >>= (blen-rlen);
6671 litval &= (~mask) & 0xff;
6672 emit2 ("ld a,!*pair", _pairs[pair].name);
6673 if ((mask|litval)!=0xff)
6674 emit2 ("and a,!immedbyte", mask);
6676 emit2 ("or a,!immedbyte", litval);
6680 /* Case with partial byte and arbitrary source
6682 _moveA (aopGet (AOP (right), offset++, FALSE));
6683 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6685 extraPair = getFreePairId(ic);
6686 if (extraPair == PAIR_INVALID)
6688 extraPair = getPairId (AOP (right));
6689 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6690 extraPair = PAIR_BC;
6692 if (getPairId (AOP (right)) != PAIR_BC
6693 || !isLastUse (ic, right))
6699 emit2 ("ld %s,a", _pairs[extraPair].l);
6700 emit2 ("ld a,!*pair", _pairs[pair].name);
6702 emit2 ("and a,!immedbyte", mask);
6703 emit2 ("or a,%s", _pairs[extraPair].l);
6708 emit2 ("ld !*pair,a", _pairs[pair].name);
6713 /*-----------------------------------------------------------------*/
6714 /* genGenPointerSet - stores the value into a pointer location */
6715 /*-----------------------------------------------------------------*/
6717 genGenPointerSet (operand * right,
6718 operand * result, iCode * ic)
6721 sym_link *retype = getSpec (operandType (right));
6722 sym_link *letype = getSpec (operandType (result));
6723 PAIR_ID pairId = PAIR_HL;
6726 aopOp (result, ic, FALSE, FALSE);
6727 aopOp (right, ic, FALSE, FALSE);
6732 size = AOP_SIZE (right);
6734 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6735 emitDebug("; isBitvar = %d", isBitvar);
6737 /* Handle the exceptions first */
6738 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6741 const char *l = aopGet (AOP (right), 0, FALSE);
6742 const char *pair = getPairName (AOP (result));
6743 if (canAssignToPtr (l) && isPtr (pair))
6745 emit2 ("ld !*pair,%s", pair, l);
6750 emit2 ("ld !*pair,a", pair);
6755 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6758 const char *l = aopGet (AOP (right), 0, FALSE);
6763 if (canAssignToPtr (l))
6765 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6769 _moveA (aopGet (AOP (right), offset, FALSE));
6770 emit2 ("ld !*iyx,a", offset);
6776 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6783 const char *l = aopGet (AOP (right), offset, FALSE);
6784 if (isRegOrLit (AOP (right)) && !IS_GB)
6786 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6791 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6795 emit2 ("inc %s", _pairs[PAIR_HL].name);
6796 _G.pairs[PAIR_HL].offset++;
6801 /* Fixup HL back down */
6802 for (size = AOP_SIZE (right)-1; size; size--)
6804 emit2 ("dec %s", _pairs[PAIR_HL].name);
6809 /* if the operand is already in dptr
6810 then we do nothing else we move the value to dptr */
6811 if (AOP_TYPE (result) != AOP_STR)
6813 fetchPair (pairId, AOP (result));
6815 /* so hl know contains the address */
6816 freeAsmop (result, NULL, ic);
6818 /* if bit then unpack */
6821 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6831 const char *l = aopGet (AOP (right), offset, FALSE);
6832 if (isRegOrLit (AOP (right)) && !IS_GB)
6834 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6839 emit2 ("ld !*pair,a", _pairs[pairId].name);
6843 emit2 ("inc %s", _pairs[pairId].name);
6844 _G.pairs[pairId].offset++;
6850 freeAsmop (right, NULL, ic);
6853 /*-----------------------------------------------------------------*/
6854 /* genPointerSet - stores the value into a pointer location */
6855 /*-----------------------------------------------------------------*/
6857 genPointerSet (iCode * ic)
6859 operand *right, *result;
6860 sym_link *type, *etype;
6862 right = IC_RIGHT (ic);
6863 result = IC_RESULT (ic);
6865 /* depending on the type of pointer we need to
6866 move it to the correct pointer register */
6867 type = operandType (result);
6868 etype = getSpec (type);
6870 genGenPointerSet (right, result, ic);
6873 /*-----------------------------------------------------------------*/
6874 /* genIfx - generate code for Ifx statement */
6875 /*-----------------------------------------------------------------*/
6877 genIfx (iCode * ic, iCode * popIc)
6879 operand *cond = IC_COND (ic);
6882 aopOp (cond, ic, FALSE, TRUE);
6884 /* get the value into acc */
6885 if (AOP_TYPE (cond) != AOP_CRY)
6889 /* the result is now in the accumulator */
6890 freeAsmop (cond, NULL, ic);
6892 /* if there was something to be popped then do it */
6896 /* if the condition is a bit variable */
6897 if (isbit && IS_ITEMP (cond) &&
6899 genIfxJump (ic, SPIL_LOC (cond)->rname);
6900 else if (isbit && !IS_ITEMP (cond))
6901 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6903 genIfxJump (ic, "a");
6908 /*-----------------------------------------------------------------*/
6909 /* genAddrOf - generates code for address of */
6910 /*-----------------------------------------------------------------*/
6912 genAddrOf (iCode * ic)
6914 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6916 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6918 /* if the operand is on the stack then we
6919 need to get the stack offset of this
6926 if (sym->stack <= 0)
6928 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6932 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6934 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6938 emit2 ("ld de,!hashedstr", sym->rname);
6939 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6947 /* if it has an offset then we need to compute it */
6949 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6951 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6952 emit2 ("add hl,sp");
6956 emit2 ("ld hl,!hashedstr", sym->rname);
6958 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6960 freeAsmop (IC_RESULT (ic), NULL, ic);
6963 /*-----------------------------------------------------------------*/
6964 /* genAssign - generate code for assignment */
6965 /*-----------------------------------------------------------------*/
6967 genAssign (iCode * ic)
6969 operand *result, *right;
6971 unsigned long lit = 0L;
6973 result = IC_RESULT (ic);
6974 right = IC_RIGHT (ic);
6976 /* Dont bother assigning if they are the same */
6977 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6979 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6983 aopOp (right, ic, FALSE, FALSE);
6984 aopOp (result, ic, TRUE, FALSE);
6986 /* if they are the same registers */
6987 if (sameRegs (AOP (right), AOP (result)))
6989 emitDebug ("; (registers are the same)");
6993 /* if the result is a bit */
6994 if (AOP_TYPE (result) == AOP_CRY)
6996 wassertl (0, "Tried to assign to a bit");
7000 size = AOP_SIZE (result);
7003 if (AOP_TYPE (right) == AOP_LIT)
7005 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7008 if (isPair (AOP (result)))
7010 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7012 else if ((size > 1) &&
7013 (AOP_TYPE (result) != AOP_REG) &&
7014 (AOP_TYPE (right) == AOP_LIT) &&
7015 !IS_FLOAT (operandType (right)) &&
7018 bool fXored = FALSE;
7020 /* Work from the top down.
7021 Done this way so that we can use the cached copy of 0
7022 in A for a fast clear */
7025 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7027 if (!fXored && size > 1)
7034 aopPut (AOP (result), "a", offset);
7038 aopPut (AOP (result), "!zero", offset);
7042 aopPut (AOP (result),
7043 aopGet (AOP (right), offset, FALSE),
7048 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7050 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7051 aopPut (AOP (result), "l", LSB);
7052 aopPut (AOP (result), "h", MSB16);
7054 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7056 /* Special case. Load into a and d, then load out. */
7057 _moveA (aopGet (AOP (right), 0, FALSE));
7058 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7059 aopPut (AOP (result), "a", 0);
7060 aopPut (AOP (result), "e", 1);
7062 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7064 /* Special case - simple memcpy */
7065 aopGet (AOP (right), LSB, FALSE);
7068 aopGet (AOP (result), LSB, FALSE);
7072 emit2 ("ld a,(de)");
7073 /* Peephole will optimise this. */
7074 emit2 ("ld (hl),a");
7082 spillPair (PAIR_HL);
7088 /* PENDING: do this check better */
7089 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7091 _moveA (aopGet (AOP (right), offset, FALSE));
7092 aopPut (AOP (result), "a", offset);
7095 aopPut (AOP (result),
7096 aopGet (AOP (right), offset, FALSE),
7103 freeAsmop (right, NULL, ic);
7104 freeAsmop (result, NULL, ic);
7107 /*-----------------------------------------------------------------*/
7108 /* genJumpTab - genrates code for jump table */
7109 /*-----------------------------------------------------------------*/
7111 genJumpTab (iCode * ic)
7116 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7117 /* get the condition into accumulator */
7118 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7121 emit2 ("ld e,%s", l);
7122 emit2 ("ld d,!zero");
7123 jtab = newiTempLabel (NULL);
7125 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7126 emit2 ("add hl,de");
7127 emit2 ("add hl,de");
7128 emit2 ("add hl,de");
7129 freeAsmop (IC_JTCOND (ic), NULL, ic);
7133 emitLabel (jtab->key + 100);
7134 /* now generate the jump labels */
7135 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7136 jtab = setNextItem (IC_JTLABELS (ic)))
7137 emit2 ("jp !tlabel", jtab->key + 100);
7140 /*-----------------------------------------------------------------*/
7141 /* genCast - gen code for casting */
7142 /*-----------------------------------------------------------------*/
7144 genCast (iCode * ic)
7146 operand *result = IC_RESULT (ic);
7147 sym_link *rtype = operandType (IC_RIGHT (ic));
7148 operand *right = IC_RIGHT (ic);
7151 /* if they are equivalent then do nothing */
7152 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7155 aopOp (right, ic, FALSE, FALSE);
7156 aopOp (result, ic, FALSE, FALSE);
7158 /* if the result is a bit */
7159 if (AOP_TYPE (result) == AOP_CRY)
7161 wassertl (0, "Tried to cast to a bit");
7164 /* if they are the same size : or less */
7165 if (AOP_SIZE (result) <= AOP_SIZE (right))
7168 /* if they are in the same place */
7169 if (sameRegs (AOP (right), AOP (result)))
7172 /* if they in different places then copy */
7173 size = AOP_SIZE (result);
7177 aopPut (AOP (result),
7178 aopGet (AOP (right), offset, FALSE),
7185 /* So we now know that the size of destination is greater
7186 than the size of the source */
7187 /* we move to result for the size of source */
7188 size = AOP_SIZE (right);
7192 aopPut (AOP (result),
7193 aopGet (AOP (right), offset, FALSE),
7198 /* now depending on the sign of the destination */
7199 size = AOP_SIZE (result) - AOP_SIZE (right);
7200 /* Unsigned or not an integral type - right fill with zeros */
7201 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7204 aopPut (AOP (result), "!zero", offset++);
7208 /* we need to extend the sign :{ */
7209 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7215 aopPut (AOP (result), "a", offset++);
7219 freeAsmop (right, NULL, ic);
7220 freeAsmop (result, NULL, ic);
7223 /*-----------------------------------------------------------------*/
7224 /* genReceive - generate code for a receive iCode */
7225 /*-----------------------------------------------------------------*/
7227 genReceive (iCode * ic)
7229 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7230 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7231 IS_TRUE_SYMOP (IC_RESULT (ic))))
7241 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7242 size = AOP_SIZE(IC_RESULT(ic));
7244 for (i = 0; i < size; i++) {
7245 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7249 freeAsmop (IC_RESULT (ic), NULL, ic);
7252 /*-----------------------------------------------------------------*/
7253 /* genDummyRead - generate code for dummy read of volatiles */
7254 /*-----------------------------------------------------------------*/
7256 genDummyRead (iCode * ic)
7262 if (op && IS_SYMOP (op))
7264 aopOp (op, ic, FALSE, FALSE);
7267 size = AOP_SIZE (op);
7272 _moveA (aopGet (AOP (op), offset, FALSE));
7276 freeAsmop (op, NULL, ic);
7280 if (op && IS_SYMOP (op))
7282 aopOp (op, ic, FALSE, FALSE);
7285 size = AOP_SIZE (op);
7290 _moveA (aopGet (AOP (op), offset, FALSE));
7294 freeAsmop (op, NULL, ic);
7300 /** Maximum number of bytes to emit per line. */
7304 /** Context for the byte output chunker. */
7307 unsigned char buffer[DBEMIT_MAX_RUN];
7312 /** Flushes a byte chunker by writing out all in the buffer and
7316 _dbFlush(DBEMITCTX *self)
7323 sprintf(line, ".db 0x%02X", self->buffer[0]);
7325 for (i = 1; i < self->pos; i++)
7327 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7334 /** Write out another byte, buffering until a decent line is
7338 _dbEmit(DBEMITCTX *self, int c)
7340 if (self->pos == DBEMIT_MAX_RUN)
7344 self->buffer[self->pos++] = c;
7347 /** Context for a simple run length encoder. */
7351 unsigned char buffer[128];
7353 /** runLen may be equivalent to pos. */
7359 RLE_CHANGE_COST = 4,
7363 /** Flush the buffer of a run length encoder by writing out the run or
7364 data that it currently contains.
7367 _rleCommit(RLECTX *self)
7373 memset(&db, 0, sizeof(db));
7375 emit2(".db %u", self->pos);
7377 for (i = 0; i < self->pos; i++)
7379 _dbEmit(&db, self->buffer[i]);
7388 Can get either a run or a block of random stuff.
7389 Only want to change state if a good run comes in or a run ends.
7390 Detecting run end is easy.
7393 Say initial state is in run, len zero, last zero. Then if you get a
7394 few zeros then something else then a short run will be output.
7395 Seems OK. While in run mode, keep counting. While in random mode,
7396 keep a count of the run. If run hits margin, output all up to run,
7397 restart, enter run mode.
7400 /** Add another byte into the run length encoder, flushing as
7401 required. The run length encoder uses the Amiga IFF style, where
7402 a block is prefixed by its run length. A positive length means
7403 the next n bytes pass straight through. A negative length means
7404 that the next byte is repeated -n times. A zero terminates the
7408 _rleAppend(RLECTX *self, int c)
7412 if (c != self->last)
7414 /* The run has stopped. See if it is worthwhile writing it out
7415 as a run. Note that the random data comes in as runs of
7418 if (self->runLen > RLE_CHANGE_COST)
7420 /* Yes, worthwhile. */
7421 /* Commit whatever was in the buffer. */
7423 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7427 /* Not worthwhile. Append to the end of the random list. */
7428 for (i = 0; i < self->runLen; i++)
7430 if (self->pos >= RLE_MAX_BLOCK)
7435 self->buffer[self->pos++] = self->last;
7443 if (self->runLen >= RLE_MAX_BLOCK)
7445 /* Commit whatever was in the buffer. */
7448 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7456 _rleFlush(RLECTX *self)
7458 _rleAppend(self, -1);
7465 /** genArrayInit - Special code for initialising an array with constant
7469 genArrayInit (iCode * ic)
7473 int elementSize = 0, eIndex, i;
7474 unsigned val, lastVal;
7478 memset(&rle, 0, sizeof(rle));
7480 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7482 _saveRegsForCall(ic, 0);
7484 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7485 emit2 ("call __initrleblock");
7487 type = operandType(IC_LEFT(ic));
7489 if (type && type->next)
7491 elementSize = getSize(type->next);
7495 wassertl (0, "Can't determine element size in genArrayInit.");
7498 iLoop = IC_ARRAYILIST(ic);
7499 lastVal = (unsigned)-1;
7501 /* Feed all the bytes into the run length encoder which will handle
7503 This works well for mixed char data, and for random int and long
7512 for (i = 0; i < ix; i++)
7514 for (eIndex = 0; eIndex < elementSize; eIndex++)
7516 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7517 _rleAppend(&rle, val);
7522 iLoop = iLoop->next;
7526 /* Mark the end of the run. */
7529 _restoreRegsAfterCall();
7533 freeAsmop (IC_LEFT(ic), NULL, ic);
7537 _swap (PAIR_ID one, PAIR_ID two)
7539 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7545 emit2 ("ld a,%s", _pairs[one].l);
7546 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7547 emit2 ("ld %s,a", _pairs[two].l);
7548 emit2 ("ld a,%s", _pairs[one].h);
7549 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7550 emit2 ("ld %s,a", _pairs[two].h);
7554 /* The problem is that we may have all three pairs used and they may
7555 be needed in a different order.
7560 hl = hl => unity, fine
7564 hl = hl hl = hl, swap de <=> bc
7572 hl = bc de = de, swap bc <=> hl
7580 hl = de bc = bc, swap hl <=> de
7585 * Any pair = pair are done last
7586 * Any pair = iTemp are done last
7587 * Any swaps can be done any time
7595 So how do we detect the cases?
7596 How about a 3x3 matrix?
7600 x x x x (Fourth for iTemp/other)
7602 First determin which mode to use by counting the number of unity and
7605 Two - Assign the pair first, then the rest
7606 One - Swap the two, then the rest
7610 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7612 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7614 PAIR_BC, PAIR_HL, PAIR_DE
7616 int i, j, nunity = 0;
7617 memset (ids, PAIR_INVALID, sizeof (ids));
7620 wassert (nparams == 3);
7622 /* First save everything that needs to be saved. */
7623 _saveRegsForCall (ic, 0);
7625 /* Loading HL first means that DE is always fine. */
7626 for (i = 0; i < nparams; i++)
7628 aopOp (pparams[i], ic, FALSE, FALSE);
7629 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7632 /* Count the number of unity or iTemp assigns. */
7633 for (i = 0; i < 3; i++)
7635 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7643 /* Any order, fall through. */
7645 else if (nunity == 2)
7647 /* One is assigned. Pull it out and assign. */
7648 for (i = 0; i < 3; i++)
7650 for (j = 0; j < NUM_PAIRS; j++)
7652 if (ids[dest[i]][j] == TRUE)
7654 /* Found it. See if it's the right one. */
7655 if (j == PAIR_INVALID || j == dest[i])
7661 fetchPair(dest[i], AOP (pparams[i]));
7668 else if (nunity == 1)
7670 /* Find the pairs to swap. */
7671 for (i = 0; i < 3; i++)
7673 for (j = 0; j < NUM_PAIRS; j++)
7675 if (ids[dest[i]][j] == TRUE)
7677 if (j == PAIR_INVALID || j == dest[i])
7692 int next = getPairId (AOP (pparams[0]));
7693 emit2 ("push %s", _pairs[next].name);
7695 if (next == dest[1])
7697 fetchPair (dest[1], AOP (pparams[1]));
7698 fetchPair (dest[2], AOP (pparams[2]));
7702 fetchPair (dest[2], AOP (pparams[2]));
7703 fetchPair (dest[1], AOP (pparams[1]));
7705 emit2 ("pop %s", _pairs[dest[0]].name);
7708 /* Finally pull out all of the iTemps */
7709 for (i = 0; i < 3; i++)
7711 if (ids[dest[i]][PAIR_INVALID] == 1)
7713 fetchPair (dest[i], AOP (pparams[i]));
7719 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7725 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7729 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7731 setupForBuiltin3 (ic, nParams, pparams);
7733 label = newiTempLabel(NULL);
7735 emitLabel (label->key);
7736 emit2 ("ld a,(hl)");
7739 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7741 freeAsmop (from, NULL, ic->next);
7742 freeAsmop (to, NULL, ic);
7746 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7748 operand *from, *to, *count;
7751 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7756 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7758 setupForBuiltin3 (ic, nParams, pparams);
7762 freeAsmop (count, NULL, ic->next->next);
7763 freeAsmop (from, NULL, ic);
7765 _restoreRegsAfterCall();
7767 /* if we need assign a result value */
7768 if ((IS_ITEMP (IC_RESULT (ic)) &&
7769 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7770 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7771 IS_TRUE_SYMOP (IC_RESULT (ic)))
7773 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7774 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7775 freeAsmop (IC_RESULT (ic), NULL, ic);
7778 freeAsmop (to, NULL, ic->next);
7781 /*-----------------------------------------------------------------*/
7782 /* genBuiltIn - calls the appropriate function to generating code */
7783 /* for a built in function */
7784 /*-----------------------------------------------------------------*/
7785 static void genBuiltIn (iCode *ic)
7787 operand *bi_parms[MAX_BUILTIN_ARGS];
7792 /* get all the arguments for a built in function */
7793 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7795 /* which function is it */
7796 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7798 if (strcmp(bif->name,"__builtin_strcpy")==0)
7800 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7802 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7804 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7808 wassertl (0, "Unknown builtin function encountered");
7812 /*-----------------------------------------------------------------*/
7813 /* genZ80Code - generate code for Z80 based controllers */
7814 /*-----------------------------------------------------------------*/
7816 genZ80Code (iCode * lic)
7824 _fReturn = _gbz80_return;
7825 _fTmp = _gbz80_return;
7829 _fReturn = _z80_return;
7830 _fTmp = _z80_return;
7833 _G.lines.head = _G.lines.current = NULL;
7835 /* if debug information required */
7836 if (options.debug && currFunc)
7838 debugFile->writeFunction(currFunc);
7839 _G.lines.isDebug = 1;
7840 if (IS_STATIC (currFunc->etype))
7841 sprintf (buffer, "F%s$%s$0$0", moduleName, currFunc->name);
7843 sprintf (buffer, "G$%s$0$0", currFunc->name);
7844 emit2 ("!labeldef", buffer);
7845 _G.lines.isDebug = 0;
7848 for (ic = lic; ic; ic = ic->next)
7850 _G.current_iCode = ic;
7852 if (ic->lineno && cln != ic->lineno)
7856 _G.lines.isDebug = 1;
7857 sprintf (buffer, "C$%s$%d$%d$%d",
7858 FileBaseName (ic->filename), ic->lineno,
7859 ic->level, ic->block);
7860 emit2 ("%s !equ .", buffer);
7861 emit2 ("!global", buffer);
7862 _G.lines.isDebug = 0;
7864 if (!options.noCcodeInAsm) {
7865 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7866 printCLine(ic->filename, ic->lineno));
7870 if (options.iCodeInAsm) {
7871 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7873 /* if the result is marked as
7874 spilt and rematerializable or code for
7875 this has already been generated then
7877 if (resultRemat (ic) || ic->generated)
7880 /* depending on the operation */
7884 emitDebug ("; genNot");
7889 emitDebug ("; genCpl");
7894 emitDebug ("; genUminus");
7899 emitDebug ("; genIpush");
7904 /* IPOP happens only when trying to restore a
7905 spilt live range, if there is an ifx statement
7906 following this pop then the if statement might
7907 be using some of the registers being popped which
7908 would destory the contents of the register so
7909 we need to check for this condition and handle it */
7911 ic->next->op == IFX &&
7912 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7914 emitDebug ("; genIfx");
7915 genIfx (ic->next, ic);
7919 emitDebug ("; genIpop");
7925 emitDebug ("; genCall");
7930 emitDebug ("; genPcall");
7935 emitDebug ("; genFunction");
7940 emitDebug ("; genEndFunction");
7941 genEndFunction (ic);
7945 emitDebug ("; genRet");
7950 emitDebug ("; genLabel");
7955 emitDebug ("; genGoto");
7960 emitDebug ("; genPlus");
7965 emitDebug ("; genMinus");
7970 emitDebug ("; genMult");
7975 emitDebug ("; genDiv");
7980 emitDebug ("; genMod");
7985 emitDebug ("; genCmpGt");
7986 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7990 emitDebug ("; genCmpLt");
7991 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7998 /* note these two are xlated by algebraic equivalence
7999 during parsing SDCC.y */
8000 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8001 "got '>=' or '<=' shouldn't have come here");
8005 emitDebug ("; genCmpEq");
8006 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8010 emitDebug ("; genAndOp");
8015 emitDebug ("; genOrOp");
8020 emitDebug ("; genXor");
8021 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8025 emitDebug ("; genOr");
8026 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8030 emitDebug ("; genAnd");
8031 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8035 emitDebug ("; genInline");
8040 emitDebug ("; genRRC");
8045 emitDebug ("; genRLC");
8050 emitDebug ("; genGetHBIT");
8055 emitDebug ("; genLeftShift");
8060 emitDebug ("; genRightShift");
8064 case GET_VALUE_AT_ADDRESS:
8065 emitDebug ("; genPointerGet");
8071 if (POINTER_SET (ic))
8073 emitDebug ("; genAssign (pointer)");
8078 emitDebug ("; genAssign");
8084 emitDebug ("; genIfx");
8089 emitDebug ("; genAddrOf");
8094 emitDebug ("; genJumpTab");
8099 emitDebug ("; genCast");
8104 emitDebug ("; genReceive");
8109 if (ic->builtinSEND)
8111 emitDebug ("; genBuiltIn");
8116 emitDebug ("; addSet");
8117 addSet (&_G.sendSet, ic);
8122 emitDebug ("; genArrayInit");
8126 case DUMMY_READ_VOLATILE:
8127 emitDebug ("; genDummyRead");
8137 /* now we are ready to call the
8138 peep hole optimizer */
8139 if (!options.nopeep)
8140 peepHole (&_G.lines.head);
8142 /* This is unfortunate */
8143 /* now do the actual printing */
8145 FILE *fp = codeOutFile;
8146 if (isInHome () && codeOutFile == code->oFile)
8147 codeOutFile = home->oFile;
8148 printLine (_G.lines.head, codeOutFile);
8149 if (_G.flushStatics)
8152 _G.flushStatics = 0;
8157 freeTrace(&_G.lines.trace);
8158 freeTrace(&_G.trace.aops);
8164 _isPairUsed (iCode * ic, PAIR_ID pairId)
8170 if (bitVectBitValue (ic->rMask, D_IDX))
8172 if (bitVectBitValue (ic->rMask, E_IDX))
8182 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8185 value *val = aop->aopu.aop_lit;
8187 wassert (aop->type == AOP_LIT);
8188 wassert (!IS_FLOAT (val->type));
8190 v = (unsigned long) floatFromVal (val);
8198 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8199 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));