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;
4046 /* Shouldn't occur - all done through function calls */
4047 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4048 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4049 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4051 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4052 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4053 AOP_SIZE (IC_RESULT (ic)) > 2)
4055 wassertl (0, "Multiplication is handled through support function calls");
4058 /* Swap left and right such that right is a literal */
4059 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4061 operand *t = IC_RIGHT (ic);
4062 IC_RIGHT (ic) = IC_LEFT (ic);
4066 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4068 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4069 // wassertl (val > 0, "Multiply must be positive");
4070 wassertl (val != 1, "Can't multiply by 1");
4072 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4074 _G.stack.pushedDE = TRUE;
4077 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4079 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4087 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4092 /* Fully unroled version of mul.s. Not the most efficient.
4094 for (count = 0; count < 16; count++)
4096 if (count != 0 && active)
4098 emit2 ("add hl,hl");
4102 if (active == FALSE)
4109 emit2 ("add hl,de");
4118 if (IS_Z80 && _G.stack.pushedDE)
4121 _G.stack.pushedDE = FALSE;
4124 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4126 freeAsmop (IC_LEFT (ic), NULL, ic);
4127 freeAsmop (IC_RIGHT (ic), NULL, ic);
4128 freeAsmop (IC_RESULT (ic), NULL, ic);
4131 /*-----------------------------------------------------------------*/
4132 /* genDiv - generates code for division */
4133 /*-----------------------------------------------------------------*/
4137 /* Shouldn't occur - all done through function calls */
4138 wassertl (0, "Division is handled through support function calls");
4141 /*-----------------------------------------------------------------*/
4142 /* genMod - generates code for division */
4143 /*-----------------------------------------------------------------*/
4147 /* Shouldn't occur - all done through function calls */
4151 /*-----------------------------------------------------------------*/
4152 /* genIfxJump :- will create a jump depending on the ifx */
4153 /*-----------------------------------------------------------------*/
4155 genIfxJump (iCode * ic, char *jval)
4160 /* if true label then we jump if condition
4164 jlbl = IC_TRUE (ic);
4165 if (!strcmp (jval, "a"))
4169 else if (!strcmp (jval, "c"))
4173 else if (!strcmp (jval, "nc"))
4177 else if (!strcmp (jval, "m"))
4181 else if (!strcmp (jval, "p"))
4187 /* The buffer contains the bit on A that we should test */
4193 /* false label is present */
4194 jlbl = IC_FALSE (ic);
4195 if (!strcmp (jval, "a"))
4199 else if (!strcmp (jval, "c"))
4203 else if (!strcmp (jval, "nc"))
4207 else if (!strcmp (jval, "m"))
4211 else if (!strcmp (jval, "p"))
4217 /* The buffer contains the bit on A that we should test */
4221 /* Z80 can do a conditional long jump */
4222 if (!strcmp (jval, "a"))
4226 else if (!strcmp (jval, "c"))
4229 else if (!strcmp (jval, "nc"))
4232 else if (!strcmp (jval, "m"))
4235 else if (!strcmp (jval, "p"))
4240 emit2 ("bit %s,a", jval);
4242 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4244 /* mark the icode as generated */
4250 _getPairIdName (PAIR_ID id)
4252 return _pairs[id].name;
4257 /* if unsigned char cmp with lit, just compare */
4259 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4261 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4264 emit2 ("xor a,!immedbyte", 0x80);
4265 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4268 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4270 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4272 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4273 // Pull left into DE and right into HL
4274 aopGet (AOP(left), LSB, FALSE);
4277 aopGet (AOP(right), LSB, FALSE);
4281 if (size == 0 && sign)
4283 // Highest byte when signed needs the bits flipped
4286 emit2 ("ld a,(de)");
4287 emit2 ("xor !immedbyte", 0x80);
4289 emit2 ("ld a,(hl)");
4290 emit2 ("xor !immedbyte", 0x80);
4294 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4298 emit2 ("ld a,(de)");
4299 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4309 spillPair (PAIR_HL);
4311 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4313 setupPair (PAIR_HL, AOP (left), 0);
4314 aopGet (AOP(right), LSB, FALSE);
4318 if (size == 0 && sign)
4320 // Highest byte when signed needs the bits flipped
4323 emit2 ("ld a,(hl)");
4324 emit2 ("xor !immedbyte", 0x80);
4326 emit2 ("ld a,%d(iy)", offset);
4327 emit2 ("xor !immedbyte", 0x80);
4331 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4335 emit2 ("ld a,(hl)");
4336 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4345 spillPair (PAIR_HL);
4346 spillPair (PAIR_IY);
4350 if (AOP_TYPE (right) == AOP_LIT)
4352 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4353 /* optimize if(x < 0) or if(x >= 0) */
4358 /* No sign so it's always false */
4363 /* Just load in the top most bit */
4364 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4365 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4367 genIfxJump (ifx, "7");
4379 /* First setup h and l contaning the top most bytes XORed */
4380 bool fDidXor = FALSE;
4381 if (AOP_TYPE (left) == AOP_LIT)
4383 unsigned long lit = (unsigned long)
4384 floatFromVal (AOP (left)->aopu.aop_lit);
4385 emit2 ("ld %s,!immedbyte", _fTmp[0],
4386 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4390 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4391 emit2 ("xor a,!immedbyte", 0x80);
4392 emit2 ("ld %s,a", _fTmp[0]);
4395 if (AOP_TYPE (right) == AOP_LIT)
4397 unsigned long lit = (unsigned long)
4398 floatFromVal (AOP (right)->aopu.aop_lit);
4399 emit2 ("ld %s,!immedbyte", _fTmp[1],
4400 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4404 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4405 emit2 ("xor a,!immedbyte", 0x80);
4406 emit2 ("ld %s,a", _fTmp[1]);
4412 /* Do a long subtract */
4415 _moveA (aopGet (AOP (left), offset, FALSE));
4417 if (sign && size == 0)
4419 emit2 ("ld a,%s", _fTmp[0]);
4420 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4424 /* Subtract through, propagating the carry */
4425 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4433 /** Generic compare for > or <
4436 genCmp (operand * left, operand * right,
4437 operand * result, iCode * ifx, int sign)
4439 int size, offset = 0;
4440 unsigned long lit = 0L;
4441 bool swap_sense = FALSE;
4443 /* if left & right are bit variables */
4444 if (AOP_TYPE (left) == AOP_CRY &&
4445 AOP_TYPE (right) == AOP_CRY)
4447 /* Cant happen on the Z80 */
4448 wassertl (0, "Tried to compare two bits");
4452 /* Do a long subtract of right from left. */
4453 size = max (AOP_SIZE (left), AOP_SIZE (right));
4455 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4457 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4458 // Pull left into DE and right into HL
4459 aopGet (AOP(left), LSB, FALSE);
4462 aopGet (AOP(right), LSB, FALSE);
4466 emit2 ("ld a,(de)");
4467 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4476 spillPair (PAIR_HL);
4480 if (AOP_TYPE (right) == AOP_LIT)
4482 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4483 /* optimize if(x < 0) or if(x >= 0) */
4488 /* No sign so it's always false */
4493 /* Just load in the top most bit */
4494 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4495 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4497 genIfxJump (ifx, "7");
4508 genIfxJump (ifx, swap_sense ? "c" : "nc");
4519 _moveA (aopGet (AOP (left), offset, FALSE));
4520 /* Subtract through, propagating the carry */
4521 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4527 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4531 /* Shift the sign bit up into carry */
4534 outBitCLong (result, swap_sense);
4538 /* if the result is used in the next
4539 ifx conditional branch then generate
4540 code a little differently */
4548 genIfxJump (ifx, swap_sense ? "nc" : "c");
4552 genIfxJump (ifx, swap_sense ? "p" : "m");
4557 genIfxJump (ifx, swap_sense ? "nc" : "c");
4564 /* Shift the sign bit up into carry */
4567 outBitCLong (result, swap_sense);
4569 /* leave the result in acc */
4573 /*-----------------------------------------------------------------*/
4574 /* genCmpGt :- greater than comparison */
4575 /*-----------------------------------------------------------------*/
4577 genCmpGt (iCode * ic, iCode * ifx)
4579 operand *left, *right, *result;
4580 sym_link *letype, *retype;
4583 left = IC_LEFT (ic);
4584 right = IC_RIGHT (ic);
4585 result = IC_RESULT (ic);
4587 letype = getSpec (operandType (left));
4588 retype = getSpec (operandType (right));
4589 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4590 /* assign the amsops */
4591 aopOp (left, ic, FALSE, FALSE);
4592 aopOp (right, ic, FALSE, FALSE);
4593 aopOp (result, ic, TRUE, FALSE);
4595 genCmp (right, left, result, ifx, sign);
4597 freeAsmop (left, NULL, ic);
4598 freeAsmop (right, NULL, ic);
4599 freeAsmop (result, NULL, ic);
4602 /*-----------------------------------------------------------------*/
4603 /* genCmpLt - less than comparisons */
4604 /*-----------------------------------------------------------------*/
4606 genCmpLt (iCode * ic, iCode * ifx)
4608 operand *left, *right, *result;
4609 sym_link *letype, *retype;
4612 left = IC_LEFT (ic);
4613 right = IC_RIGHT (ic);
4614 result = IC_RESULT (ic);
4616 letype = getSpec (operandType (left));
4617 retype = getSpec (operandType (right));
4618 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4620 /* assign the amsops */
4621 aopOp (left, ic, FALSE, FALSE);
4622 aopOp (right, ic, FALSE, FALSE);
4623 aopOp (result, ic, TRUE, FALSE);
4625 genCmp (left, right, result, ifx, sign);
4627 freeAsmop (left, NULL, ic);
4628 freeAsmop (right, NULL, ic);
4629 freeAsmop (result, NULL, ic);
4632 /*-----------------------------------------------------------------*/
4633 /* gencjneshort - compare and jump if not equal */
4634 /*-----------------------------------------------------------------*/
4636 gencjneshort (operand * left, operand * right, symbol * lbl)
4638 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4640 unsigned long lit = 0L;
4642 /* Swap the left and right if it makes the computation easier */
4643 if (AOP_TYPE (left) == AOP_LIT)
4650 if (AOP_TYPE (right) == AOP_LIT)
4652 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4655 /* if the right side is a literal then anything goes */
4656 if (AOP_TYPE (right) == AOP_LIT &&
4657 AOP_TYPE (left) != AOP_DIR)
4661 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4666 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4673 emit2 ("jp nz,!tlabel", lbl->key + 100);
4679 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4680 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4683 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4684 emit2 ("jp nz,!tlabel", lbl->key + 100);
4689 /* if the right side is in a register or in direct space or
4690 if the left is a pointer register & right is not */
4691 else if (AOP_TYPE (right) == AOP_REG ||
4692 AOP_TYPE (right) == AOP_DIR ||
4693 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4697 _moveA (aopGet (AOP (left), offset, FALSE));
4698 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4699 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4701 emit2 ("jp nz,!tlabel", lbl->key + 100);
4704 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4705 emit2 ("jp nz,!tlabel", lbl->key + 100);
4712 /* right is a pointer reg need both a & b */
4713 /* PENDING: is this required? */
4716 _moveA (aopGet (AOP (right), offset, FALSE));
4717 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4718 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4724 /*-----------------------------------------------------------------*/
4725 /* gencjne - compare and jump if not equal */
4726 /*-----------------------------------------------------------------*/
4728 gencjne (operand * left, operand * right, symbol * lbl)
4730 symbol *tlbl = newiTempLabel (NULL);
4732 gencjneshort (left, right, lbl);
4735 emit2 ("ld a,!one");
4736 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4737 emitLabel (lbl->key + 100);
4739 emitLabel (tlbl->key + 100);
4742 /*-----------------------------------------------------------------*/
4743 /* genCmpEq - generates code for equal to */
4744 /*-----------------------------------------------------------------*/
4746 genCmpEq (iCode * ic, iCode * ifx)
4748 operand *left, *right, *result;
4750 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4751 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4752 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4754 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4756 /* Swap operands if it makes the operation easier. ie if:
4757 1. Left is a literal.
4759 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4761 operand *t = IC_RIGHT (ic);
4762 IC_RIGHT (ic) = IC_LEFT (ic);
4766 if (ifx && !AOP_SIZE (result))
4769 /* if they are both bit variables */
4770 if (AOP_TYPE (left) == AOP_CRY &&
4771 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4773 wassertl (0, "Tried to compare two bits");
4777 tlbl = newiTempLabel (NULL);
4778 gencjneshort (left, right, tlbl);
4781 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4782 emitLabel (tlbl->key + 100);
4786 /* PENDING: do this better */
4787 symbol *lbl = newiTempLabel (NULL);
4788 emit2 ("!shortjp !tlabel", lbl->key + 100);
4789 emitLabel (tlbl->key + 100);
4790 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4791 emitLabel (lbl->key + 100);
4794 /* mark the icode as generated */
4799 /* if they are both bit variables */
4800 if (AOP_TYPE (left) == AOP_CRY &&
4801 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4803 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4809 gencjne (left, right, newiTempLabel (NULL));
4810 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4817 genIfxJump (ifx, "a");
4820 /* if the result is used in an arithmetic operation
4821 then put the result in place */
4822 if (AOP_TYPE (result) != AOP_CRY)
4827 /* leave the result in acc */
4831 freeAsmop (left, NULL, ic);
4832 freeAsmop (right, NULL, ic);
4833 freeAsmop (result, NULL, ic);
4836 /*-----------------------------------------------------------------*/
4837 /* ifxForOp - returns the icode containing the ifx for operand */
4838 /*-----------------------------------------------------------------*/
4840 ifxForOp (operand * op, iCode * ic)
4842 /* if true symbol then needs to be assigned */
4843 if (IS_TRUE_SYMOP (op))
4846 /* if this has register type condition and
4847 the next instruction is ifx with the same operand
4848 and live to of the operand is upto the ifx only then */
4850 ic->next->op == IFX &&
4851 IC_COND (ic->next)->key == op->key &&
4852 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4858 /*-----------------------------------------------------------------*/
4859 /* genAndOp - for && operation */
4860 /*-----------------------------------------------------------------*/
4862 genAndOp (iCode * ic)
4864 operand *left, *right, *result;
4867 /* note here that && operations that are in an if statement are
4868 taken away by backPatchLabels only those used in arthmetic
4869 operations remain */
4870 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4871 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4872 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4874 /* if both are bit variables */
4875 if (AOP_TYPE (left) == AOP_CRY &&
4876 AOP_TYPE (right) == AOP_CRY)
4878 wassertl (0, "Tried to and two bits");
4882 tlbl = newiTempLabel (NULL);
4884 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4886 emitLabel (tlbl->key + 100);
4890 freeAsmop (left, NULL, ic);
4891 freeAsmop (right, NULL, ic);
4892 freeAsmop (result, NULL, ic);
4895 /*-----------------------------------------------------------------*/
4896 /* genOrOp - for || operation */
4897 /*-----------------------------------------------------------------*/
4899 genOrOp (iCode * ic)
4901 operand *left, *right, *result;
4904 /* note here that || operations that are in an
4905 if statement are taken away by backPatchLabels
4906 only those used in arthmetic operations remain */
4907 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4908 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4909 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4911 /* if both are bit variables */
4912 if (AOP_TYPE (left) == AOP_CRY &&
4913 AOP_TYPE (right) == AOP_CRY)
4915 wassertl (0, "Tried to OR two bits");
4919 tlbl = newiTempLabel (NULL);
4921 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4923 emitLabel (tlbl->key + 100);
4927 freeAsmop (left, NULL, ic);
4928 freeAsmop (right, NULL, ic);
4929 freeAsmop (result, NULL, ic);
4932 /*-----------------------------------------------------------------*/
4933 /* isLiteralBit - test if lit == 2^n */
4934 /*-----------------------------------------------------------------*/
4936 isLiteralBit (unsigned long lit)
4938 unsigned long pw[32] =
4939 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4940 0x100L, 0x200L, 0x400L, 0x800L,
4941 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4942 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4943 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4944 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4945 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4948 for (idx = 0; idx < 32; idx++)
4954 /*-----------------------------------------------------------------*/
4955 /* jmpTrueOrFalse - */
4956 /*-----------------------------------------------------------------*/
4958 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4960 // ugly but optimized by peephole
4963 symbol *nlbl = newiTempLabel (NULL);
4964 emit2 ("jp !tlabel", nlbl->key + 100);
4965 emitLabel (tlbl->key + 100);
4966 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4967 emitLabel (nlbl->key + 100);
4971 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4972 emitLabel (tlbl->key + 100);
4977 /*-----------------------------------------------------------------*/
4978 /* genAnd - code for and */
4979 /*-----------------------------------------------------------------*/
4981 genAnd (iCode * ic, iCode * ifx)
4983 operand *left, *right, *result;
4984 int size, offset = 0;
4985 unsigned long lit = 0L;
4988 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4989 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4990 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4992 /* if left is a literal & right is not then exchange them */
4993 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4994 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
4996 operand *tmp = right;
5001 /* if result = right then exchange them */
5002 if (sameRegs (AOP (result), AOP (right)))
5004 operand *tmp = right;
5009 /* if right is bit then exchange them */
5010 if (AOP_TYPE (right) == AOP_CRY &&
5011 AOP_TYPE (left) != AOP_CRY)
5013 operand *tmp = right;
5017 if (AOP_TYPE (right) == AOP_LIT)
5018 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5020 size = AOP_SIZE (result);
5022 if (AOP_TYPE (left) == AOP_CRY)
5024 wassertl (0, "Tried to perform an AND with a bit as an operand");
5028 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5029 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5030 if ((AOP_TYPE (right) == AOP_LIT) &&
5031 (AOP_TYPE (result) == AOP_CRY) &&
5032 (AOP_TYPE (left) != AOP_CRY))
5034 symbol *tlbl = newiTempLabel (NULL);
5035 int sizel = AOP_SIZE (left);
5038 /* PENDING: Test case for this. */
5043 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5045 _moveA (aopGet (AOP (left), offset, FALSE));
5046 if (bytelit != 0x0FFL)
5048 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5055 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5059 // bit = left & literal
5063 emit2 ("!tlabeldef", tlbl->key + 100);
5065 // if(left & literal)
5070 jmpTrueOrFalse (ifx, tlbl);
5078 /* if left is same as result */
5079 if (sameRegs (AOP (result), AOP (left)))
5081 for (; size--; offset++)
5083 if (AOP_TYPE (right) == AOP_LIT)
5085 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5090 aopPut (AOP (result), "!zero", offset);
5093 _moveA (aopGet (AOP (left), offset, FALSE));
5095 aopGet (AOP (right), offset, FALSE));
5096 aopPut (AOP (left), "a", offset);
5103 if (AOP_TYPE (left) == AOP_ACC)
5105 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5109 _moveA (aopGet (AOP (left), offset, FALSE));
5111 aopGet (AOP (right), offset, FALSE));
5112 aopPut (AOP (left), "a", offset);
5119 // left & result in different registers
5120 if (AOP_TYPE (result) == AOP_CRY)
5122 wassertl (0, "Tried to AND where the result is in carry");
5126 for (; (size--); offset++)
5129 // result = left & right
5130 if (AOP_TYPE (right) == AOP_LIT)
5132 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5134 aopPut (AOP (result),
5135 aopGet (AOP (left), offset, FALSE),
5139 else if (bytelit == 0)
5141 aopPut (AOP (result), "!zero", offset);
5145 // faster than result <- left, anl result,right
5146 // and better if result is SFR
5147 if (AOP_TYPE (left) == AOP_ACC)
5148 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5151 _moveA (aopGet (AOP (left), offset, FALSE));
5153 aopGet (AOP (right), offset, FALSE));
5155 aopPut (AOP (result), "a", offset);
5162 freeAsmop (left, NULL, ic);
5163 freeAsmop (right, NULL, ic);
5164 freeAsmop (result, NULL, ic);
5167 /*-----------------------------------------------------------------*/
5168 /* genOr - code for or */
5169 /*-----------------------------------------------------------------*/
5171 genOr (iCode * ic, iCode * ifx)
5173 operand *left, *right, *result;
5174 int size, offset = 0;
5175 unsigned long lit = 0L;
5178 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5179 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5180 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5182 /* if left is a literal & right is not then exchange them */
5183 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5184 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5186 operand *tmp = right;
5191 /* if result = right then exchange them */
5192 if (sameRegs (AOP (result), AOP (right)))
5194 operand *tmp = right;
5199 /* if right is bit then exchange them */
5200 if (AOP_TYPE (right) == AOP_CRY &&
5201 AOP_TYPE (left) != AOP_CRY)
5203 operand *tmp = right;
5207 if (AOP_TYPE (right) == AOP_LIT)
5208 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5210 size = AOP_SIZE (result);
5212 if (AOP_TYPE (left) == AOP_CRY)
5214 wassertl (0, "Tried to OR where left is a bit");
5218 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5219 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5220 if ((AOP_TYPE (right) == AOP_LIT) &&
5221 (AOP_TYPE (result) == AOP_CRY) &&
5222 (AOP_TYPE (left) != AOP_CRY))
5224 symbol *tlbl = newiTempLabel (NULL);
5225 int sizel = AOP_SIZE (left);
5229 wassertl (0, "Result is assigned to a bit");
5231 /* PENDING: Modeled after the AND code which is inefficent. */
5234 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5236 _moveA (aopGet (AOP (left), offset, FALSE));
5237 /* OR with any literal is the same as OR with itself. */
5239 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5245 jmpTrueOrFalse (ifx, tlbl);
5250 /* if left is same as result */
5251 if (sameRegs (AOP (result), AOP (left)))
5253 for (; size--; offset++)
5255 if (AOP_TYPE (right) == AOP_LIT)
5257 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5261 _moveA (aopGet (AOP (left), offset, FALSE));
5263 aopGet (AOP (right), offset, FALSE));
5264 aopPut (AOP (result), "a", offset);
5269 if (AOP_TYPE (left) == AOP_ACC)
5270 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5273 _moveA (aopGet (AOP (left), offset, FALSE));
5275 aopGet (AOP (right), offset, FALSE));
5276 aopPut (AOP (result), "a", offset);
5283 // left & result in different registers
5284 if (AOP_TYPE (result) == AOP_CRY)
5286 wassertl (0, "Result of OR is in a bit");
5289 for (; (size--); offset++)
5292 // result = left & right
5293 if (AOP_TYPE (right) == AOP_LIT)
5295 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5297 aopPut (AOP (result),
5298 aopGet (AOP (left), offset, FALSE),
5303 // faster than result <- left, anl result,right
5304 // and better if result is SFR
5305 if (AOP_TYPE (left) == AOP_ACC)
5306 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5309 _moveA (aopGet (AOP (left), offset, FALSE));
5311 aopGet (AOP (right), offset, FALSE));
5313 aopPut (AOP (result), "a", offset);
5314 /* PENDING: something weird is going on here. Add exception. */
5315 if (AOP_TYPE (result) == AOP_ACC)
5321 freeAsmop (left, NULL, ic);
5322 freeAsmop (right, NULL, ic);
5323 freeAsmop (result, NULL, ic);
5326 /*-----------------------------------------------------------------*/
5327 /* genXor - code for xclusive or */
5328 /*-----------------------------------------------------------------*/
5330 genXor (iCode * ic, iCode * ifx)
5332 operand *left, *right, *result;
5333 int size, offset = 0;
5334 unsigned long lit = 0L;
5336 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5337 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5338 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5340 /* if left is a literal & right is not then exchange them */
5341 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5342 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5344 operand *tmp = right;
5349 /* if result = right then exchange them */
5350 if (sameRegs (AOP (result), AOP (right)))
5352 operand *tmp = right;
5357 /* if right is bit then exchange them */
5358 if (AOP_TYPE (right) == AOP_CRY &&
5359 AOP_TYPE (left) != AOP_CRY)
5361 operand *tmp = right;
5365 if (AOP_TYPE (right) == AOP_LIT)
5366 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5368 size = AOP_SIZE (result);
5370 if (AOP_TYPE (left) == AOP_CRY)
5372 wassertl (0, "Tried to XOR a bit");
5376 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5377 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5378 if ((AOP_TYPE (right) == AOP_LIT) &&
5379 (AOP_TYPE (result) == AOP_CRY) &&
5380 (AOP_TYPE (left) != AOP_CRY))
5382 symbol *tlbl = newiTempLabel (NULL);
5383 int sizel = AOP_SIZE (left);
5387 /* PENDING: Test case for this. */
5388 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5392 _moveA (aopGet (AOP (left), offset, FALSE));
5393 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5394 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5399 jmpTrueOrFalse (ifx, tlbl);
5403 wassertl (0, "Result of XOR was destined for a bit");
5408 /* if left is same as result */
5409 if (sameRegs (AOP (result), AOP (left)))
5411 for (; size--; offset++)
5413 if (AOP_TYPE (right) == AOP_LIT)
5415 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5419 _moveA (aopGet (AOP (left), offset, FALSE));
5421 aopGet (AOP (right), offset, FALSE));
5422 aopPut (AOP (result), "a", offset);
5427 if (AOP_TYPE (left) == AOP_ACC)
5429 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5433 _moveA (aopGet (AOP (left), offset, FALSE));
5435 aopGet (AOP (right), offset, FALSE));
5436 aopPut (AOP (result), "a", offset);
5443 // left & result in different registers
5444 if (AOP_TYPE (result) == AOP_CRY)
5446 wassertl (0, "Result of XOR is in a bit");
5449 for (; (size--); offset++)
5452 // result = left & right
5453 if (AOP_TYPE (right) == AOP_LIT)
5455 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5457 aopPut (AOP (result),
5458 aopGet (AOP (left), offset, FALSE),
5463 // faster than result <- left, anl result,right
5464 // and better if result is SFR
5465 if (AOP_TYPE (left) == AOP_ACC)
5467 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5471 _moveA (aopGet (AOP (left), offset, FALSE));
5473 aopGet (AOP (right), offset, FALSE));
5475 aopPut (AOP (result), "a", offset);
5480 freeAsmop (left, NULL, ic);
5481 freeAsmop (right, NULL, ic);
5482 freeAsmop (result, NULL, ic);
5485 /*-----------------------------------------------------------------*/
5486 /* genInline - write the inline code out */
5487 /*-----------------------------------------------------------------*/
5489 genInline (iCode * ic)
5491 char *buffer, *bp, *bp1;
5493 _G.lines.isInline += (!options.asmpeep);
5495 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5496 strcpy (buffer, IC_INLINE (ic));
5498 /* emit each line as a code */
5523 _G.lines.isInline -= (!options.asmpeep);
5527 /*-----------------------------------------------------------------*/
5528 /* genRRC - rotate right with carry */
5529 /*-----------------------------------------------------------------*/
5536 /*-----------------------------------------------------------------*/
5537 /* genRLC - generate code for rotate left with carry */
5538 /*-----------------------------------------------------------------*/
5545 /*-----------------------------------------------------------------*/
5546 /* genGetHbit - generates code get highest order bit */
5547 /*-----------------------------------------------------------------*/
5549 genGetHbit (iCode * ic)
5551 operand *left, *result;
5552 left = IC_LEFT (ic);
5553 result = IC_RESULT (ic);
5555 aopOp (left, ic, FALSE, FALSE);
5556 aopOp (result, ic, FALSE, FALSE);
5558 /* get the highest order byte into a */
5559 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5561 if (AOP_TYPE (result) == AOP_CRY)
5569 emit2 ("and a,!one");
5574 freeAsmop (left, NULL, ic);
5575 freeAsmop (result, NULL, ic);
5579 emitRsh2 (asmop *aop, int size, int is_signed)
5585 const char *l = aopGet (aop, size, FALSE);
5588 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5598 /*-----------------------------------------------------------------*/
5599 /* shiftR2Left2Result - shift right two bytes from left to result */
5600 /*-----------------------------------------------------------------*/
5602 shiftR2Left2Result (operand * left, int offl,
5603 operand * result, int offr,
5604 int shCount, int is_signed)
5607 symbol *tlbl, *tlbl1;
5609 movLeft2Result (left, offl, result, offr, 0);
5610 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5612 /* if (AOP(result)->type == AOP_REG) { */
5614 tlbl = newiTempLabel (NULL);
5615 tlbl1 = newiTempLabel (NULL);
5617 /* Left is already in result - so now do the shift */
5622 emitRsh2 (AOP (result), size, is_signed);
5627 emit2 ("ld a,!immedbyte+1", shCount);
5628 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5629 emitLabel (tlbl->key + 100);
5631 emitRsh2 (AOP (result), size, is_signed);
5633 emitLabel (tlbl1->key + 100);
5635 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5639 /*-----------------------------------------------------------------*/
5640 /* shiftL2Left2Result - shift left two bytes from left to result */
5641 /*-----------------------------------------------------------------*/
5643 shiftL2Left2Result (operand * left, int offl,
5644 operand * result, int offr, int shCount)
5646 if (sameRegs (AOP (result), AOP (left)) &&
5647 ((offl + MSB16) == offr))
5653 /* Copy left into result */
5654 movLeft2Result (left, offl, result, offr, 0);
5655 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5658 if (getPairId (AOP (result)) == PAIR_HL)
5662 emit2 ("add hl,hl");
5669 symbol *tlbl, *tlbl1;
5672 tlbl = newiTempLabel (NULL);
5673 tlbl1 = newiTempLabel (NULL);
5675 if (AOP (result)->type == AOP_REG)
5679 for (offset = 0; offset < size; offset++)
5681 l = aopGet (AOP (result), offset, FALSE);
5685 emit2 ("sla %s", l);
5696 /* Left is already in result - so now do the shift */
5699 emit2 ("ld a,!immedbyte+1", shCount);
5700 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5701 emitLabel (tlbl->key + 100);
5706 l = aopGet (AOP (result), offset, FALSE);
5710 emit2 ("sla %s", l);
5721 emitLabel (tlbl1->key + 100);
5723 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5729 /*-----------------------------------------------------------------*/
5730 /* AccRol - rotate left accumulator by known count */
5731 /*-----------------------------------------------------------------*/
5733 AccRol (int shCount)
5735 shCount &= 0x0007; // shCount : 0..7
5812 /*-----------------------------------------------------------------*/
5813 /* AccLsh - left shift accumulator by known count */
5814 /*-----------------------------------------------------------------*/
5816 AccLsh (int shCount)
5818 static const unsigned char SLMask[] =
5820 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5829 else if (shCount == 2)
5836 /* rotate left accumulator */
5838 /* and kill the lower order bits */
5839 emit2 ("and a,!immedbyte", SLMask[shCount]);
5844 /*-----------------------------------------------------------------*/
5845 /* shiftL1Left2Result - shift left one byte from left to result */
5846 /*-----------------------------------------------------------------*/
5848 shiftL1Left2Result (operand * left, int offl,
5849 operand * result, int offr, int shCount)
5852 l = aopGet (AOP (left), offl, FALSE);
5854 /* shift left accumulator */
5856 aopPut (AOP (result), "a", offr);
5860 /*-----------------------------------------------------------------*/
5861 /* genlshTwo - left shift two bytes by known amount != 0 */
5862 /*-----------------------------------------------------------------*/
5864 genlshTwo (operand * result, operand * left, int shCount)
5866 int size = AOP_SIZE (result);
5868 wassert (size == 2);
5870 /* if shCount >= 8 */
5878 movLeft2Result (left, LSB, result, MSB16, 0);
5879 aopPut (AOP (result), "!zero", 0);
5880 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5884 movLeft2Result (left, LSB, result, MSB16, 0);
5885 aopPut (AOP (result), "!zero", 0);
5890 aopPut (AOP (result), "!zero", LSB);
5893 /* 1 <= shCount <= 7 */
5902 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5907 /*-----------------------------------------------------------------*/
5908 /* genlshOne - left shift a one byte quantity by known count */
5909 /*-----------------------------------------------------------------*/
5911 genlshOne (operand * result, operand * left, int shCount)
5913 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5916 /*-----------------------------------------------------------------*/
5917 /* genLeftShiftLiteral - left shifting by known count */
5918 /*-----------------------------------------------------------------*/
5920 genLeftShiftLiteral (operand * left,
5925 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5928 freeAsmop (right, NULL, ic);
5930 aopOp (left, ic, FALSE, FALSE);
5931 aopOp (result, ic, FALSE, FALSE);
5933 size = getSize (operandType (result));
5935 /* I suppose that the left size >= result size */
5941 else if (shCount >= (size * 8))
5945 aopPut (AOP (result), "!zero", size);
5953 genlshOne (result, left, shCount);
5956 genlshTwo (result, left, shCount);
5959 wassertl (0, "Shifting of longs is currently unsupported");
5965 freeAsmop (left, NULL, ic);
5966 freeAsmop (result, NULL, ic);
5969 /*-----------------------------------------------------------------*/
5970 /* genLeftShift - generates code for left shifting */
5971 /*-----------------------------------------------------------------*/
5973 genLeftShift (iCode * ic)
5977 symbol *tlbl, *tlbl1;
5978 operand *left, *right, *result;
5980 right = IC_RIGHT (ic);
5981 left = IC_LEFT (ic);
5982 result = IC_RESULT (ic);
5984 aopOp (right, ic, FALSE, FALSE);
5986 /* if the shift count is known then do it
5987 as efficiently as possible */
5988 if (AOP_TYPE (right) == AOP_LIT)
5990 genLeftShiftLiteral (left, right, result, ic);
5994 /* shift count is unknown then we have to form a loop get the loop
5995 count in B : Note: we take only the lower order byte since
5996 shifting more that 32 bits make no sense anyway, ( the largest
5997 size of an object can be only 32 bits ) */
5998 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6000 freeAsmop (right, NULL, ic);
6001 aopOp (left, ic, FALSE, FALSE);
6002 aopOp (result, ic, FALSE, FALSE);
6004 /* now move the left to the result if they are not the
6007 if (!sameRegs (AOP (left), AOP (result)))
6010 size = AOP_SIZE (result);
6014 l = aopGet (AOP (left), offset, FALSE);
6015 aopPut (AOP (result), l, offset);
6020 tlbl = newiTempLabel (NULL);
6021 size = AOP_SIZE (result);
6023 tlbl1 = newiTempLabel (NULL);
6025 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6026 emitLabel (tlbl->key + 100);
6027 l = aopGet (AOP (result), offset, FALSE);
6031 l = aopGet (AOP (result), offset, FALSE);
6035 emit2 ("sla %s", l);
6043 emitLabel (tlbl1->key + 100);
6045 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6047 freeAsmop (left, NULL, ic);
6048 freeAsmop (result, NULL, ic);
6051 /*-----------------------------------------------------------------*/
6052 /* genrshOne - left shift two bytes by known amount != 0 */
6053 /*-----------------------------------------------------------------*/
6055 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6058 int size = AOP_SIZE (result);
6061 wassert (size == 1);
6062 wassert (shCount < 8);
6064 l = aopGet (AOP (left), 0, FALSE);
6066 if (AOP (result)->type == AOP_REG)
6068 aopPut (AOP (result), l, 0);
6069 l = aopGet (AOP (result), 0, FALSE);
6072 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6080 emit2 ("%s a", is_signed ? "sra" : "srl");
6082 aopPut (AOP (result), "a", 0);
6086 /*-----------------------------------------------------------------*/
6087 /* AccRsh - right shift accumulator by known count */
6088 /*-----------------------------------------------------------------*/
6090 AccRsh (int shCount)
6092 static const unsigned char SRMask[] =
6094 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6099 /* rotate right accumulator */
6100 AccRol (8 - shCount);
6101 /* and kill the higher order bits */
6102 emit2 ("and a,!immedbyte", SRMask[shCount]);
6106 /*-----------------------------------------------------------------*/
6107 /* shiftR1Left2Result - shift right one byte from left to result */
6108 /*-----------------------------------------------------------------*/
6110 shiftR1Left2Result (operand * left, int offl,
6111 operand * result, int offr,
6112 int shCount, int sign)
6114 _moveA (aopGet (AOP (left), offl, FALSE));
6119 emit2 ("%s a", sign ? "sra" : "srl");
6126 aopPut (AOP (result), "a", offr);
6129 /*-----------------------------------------------------------------*/
6130 /* genrshTwo - right shift two bytes by known amount != 0 */
6131 /*-----------------------------------------------------------------*/
6133 genrshTwo (operand * result, operand * left,
6134 int shCount, int sign)
6136 /* if shCount >= 8 */
6142 shiftR1Left2Result (left, MSB16, result, LSB,
6147 movLeft2Result (left, MSB16, result, LSB, sign);
6151 /* Sign extend the result */
6152 _moveA(aopGet (AOP (result), 0, FALSE));
6156 aopPut (AOP (result), ACC_NAME, MSB16);
6160 aopPut (AOP (result), "!zero", 1);
6163 /* 1 <= shCount <= 7 */
6166 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6170 /*-----------------------------------------------------------------*/
6171 /* genRightShiftLiteral - left shifting by known count */
6172 /*-----------------------------------------------------------------*/
6174 genRightShiftLiteral (operand * left,
6180 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6183 freeAsmop (right, NULL, ic);
6185 aopOp (left, ic, FALSE, FALSE);
6186 aopOp (result, ic, FALSE, FALSE);
6188 size = getSize (operandType (result));
6190 /* I suppose that the left size >= result size */
6196 else if (shCount >= (size * 8)) {
6198 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6199 _moveA(aopGet (AOP (left), 0, FALSE));
6207 aopPut (AOP (result), s, size);
6214 genrshOne (result, left, shCount, sign);
6217 genrshTwo (result, left, shCount, sign);
6220 wassertl (0, "Asked to shift right a long which should be a function call");
6223 wassertl (0, "Entered default case in right shift delegate");
6226 freeAsmop (left, NULL, ic);
6227 freeAsmop (result, NULL, ic);
6230 /*-----------------------------------------------------------------*/
6231 /* genRightShift - generate code for right shifting */
6232 /*-----------------------------------------------------------------*/
6234 genRightShift (iCode * ic)
6236 operand *right, *left, *result;
6238 int size, offset, first = 1;
6242 symbol *tlbl, *tlbl1;
6244 /* if signed then we do it the hard way preserve the
6245 sign bit moving it inwards */
6246 retype = getSpec (operandType (IC_RESULT (ic)));
6248 is_signed = !SPEC_USIGN (retype);
6250 /* signed & unsigned types are treated the same : i.e. the
6251 signed is NOT propagated inwards : quoting from the
6252 ANSI - standard : "for E1 >> E2, is equivalent to division
6253 by 2**E2 if unsigned or if it has a non-negative value,
6254 otherwise the result is implementation defined ", MY definition
6255 is that the sign does not get propagated */
6257 right = IC_RIGHT (ic);
6258 left = IC_LEFT (ic);
6259 result = IC_RESULT (ic);
6261 aopOp (right, ic, FALSE, FALSE);
6263 /* if the shift count is known then do it
6264 as efficiently as possible */
6265 if (AOP_TYPE (right) == AOP_LIT)
6267 genRightShiftLiteral (left, right, result, ic, is_signed);
6271 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6273 freeAsmop (right, NULL, ic);
6275 aopOp (left, ic, FALSE, FALSE);
6276 aopOp (result, ic, FALSE, FALSE);
6278 /* now move the left to the result if they are not the
6280 if (!sameRegs (AOP (left), AOP (result)))
6283 size = AOP_SIZE (result);
6287 l = aopGet (AOP (left), offset, FALSE);
6288 aopPut (AOP (result), l, offset);
6293 tlbl = newiTempLabel (NULL);
6294 tlbl1 = newiTempLabel (NULL);
6295 size = AOP_SIZE (result);
6298 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6299 emitLabel (tlbl->key + 100);
6302 l = aopGet (AOP (result), offset--, FALSE);
6305 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6313 emitLabel (tlbl1->key + 100);
6315 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6317 freeAsmop (left, NULL, ic);
6318 freeAsmop (result, NULL, ic);
6322 /*-----------------------------------------------------------------*/
6323 /* genUnpackBits - generates code for unpacking bits */
6324 /*-----------------------------------------------------------------*/
6326 genUnpackBits (operand * result, int pair)
6328 int offset = 0; /* result byte offset */
6329 int rsize; /* result size */
6330 int rlen = 0; /* remaining bitfield length */
6331 sym_link *etype; /* bitfield type information */
6332 int blen; /* bitfield length */
6333 int bstr; /* bitfield starting bit within byte */
6335 emitDebug ("; genUnpackBits");
6337 etype = getSpec (operandType (result));
6338 rsize = getSize (operandType (result));
6339 blen = SPEC_BLEN (etype);
6340 bstr = SPEC_BSTR (etype);
6342 /* If the bitfield length is less than a byte */
6345 emit2 ("ld a,!*pair", _pairs[pair].name);
6347 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6348 aopPut (AOP (result), "a", offset++);
6352 /* TODO: what if pair == PAIR_DE ? */
6353 if (getPairId (AOP (result)) == PAIR_HL)
6355 wassertl (rsize == 2, "HL must be of size 2");
6356 emit2 ("ld a,!*hl");
6358 emit2 ("ld h,!*hl");
6361 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6363 spillPair (PAIR_HL);
6367 /* Bit field did not fit in a byte. Copy all
6368 but the partial byte at the end. */
6369 for (rlen=blen;rlen>=8;rlen-=8)
6371 emit2 ("ld a,!*pair", _pairs[pair].name);
6372 aopPut (AOP (result), "a", offset++);
6375 emit2 ("inc %s", _pairs[pair].name);
6376 _G.pairs[pair].offset++;
6380 /* Handle the partial byte at the end */
6383 emit2 ("ld a,!*pair", _pairs[pair].name);
6384 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6385 aopPut (AOP (result), "a", offset++);
6393 aopPut (AOP (result), "!zero", offset++);
6397 /*-----------------------------------------------------------------*/
6398 /* genGenPointerGet - get value from generic pointer space */
6399 /*-----------------------------------------------------------------*/
6401 genGenPointerGet (operand * left,
6402 operand * result, iCode * ic)
6405 sym_link *retype = getSpec (operandType (result));
6411 aopOp (left, ic, FALSE, FALSE);
6412 aopOp (result, ic, FALSE, FALSE);
6414 size = AOP_SIZE (result);
6416 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6419 if (isPtrPair (AOP (left)))
6421 tsprintf (buffer, sizeof(buffer),
6422 "!*pair", getPairName (AOP (left)));
6423 aopPut (AOP (result), buffer, 0);
6427 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6428 aopPut (AOP (result), "a", 0);
6430 freeAsmop (left, NULL, ic);
6434 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6441 tsprintf (at, sizeof(at), "!*iyx", offset);
6442 aopPut (AOP (result), at, offset);
6446 freeAsmop (left, NULL, ic);
6450 /* For now we always load into IY */
6451 /* if this is remateriazable */
6452 fetchPair (pair, AOP (left));
6454 /* if bit then unpack */
6455 if (IS_BITVAR (retype))
6457 genUnpackBits (result, pair);
6458 freeAsmop (left, NULL, ic);
6462 else if (getPairId (AOP (result)) == PAIR_HL)
6464 wassertl (size == 2, "HL must be of size 2");
6465 emit2 ("ld a,!*hl");
6467 emit2 ("ld h,!*hl");
6469 spillPair (PAIR_HL);
6471 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6473 size = AOP_SIZE (result);
6478 /* PENDING: make this better */
6479 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6481 aopPut (AOP (result), "!*hl", offset++);
6485 emit2 ("ld a,!*pair", _pairs[pair].name);
6486 aopPut (AOP (result), "a", offset++);
6490 emit2 ("inc %s", _pairs[pair].name);
6491 _G.pairs[pair].offset++;
6494 /* Fixup HL back down */
6495 for (size = AOP_SIZE (result)-1; size; size--)
6497 emit2 ("dec %s", _pairs[pair].name);
6502 size = AOP_SIZE (result);
6507 /* PENDING: make this better */
6509 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6511 aopPut (AOP (result), "!*hl", offset++);
6515 emit2 ("ld a,!*pair", _pairs[pair].name);
6516 aopPut (AOP (result), "a", offset++);
6520 emit2 ("inc %s", _pairs[pair].name);
6521 _G.pairs[pair].offset++;
6526 freeAsmop (left, NULL, ic);
6529 freeAsmop (result, NULL, ic);
6532 /*-----------------------------------------------------------------*/
6533 /* genPointerGet - generate code for pointer get */
6534 /*-----------------------------------------------------------------*/
6536 genPointerGet (iCode * ic)
6538 operand *left, *result;
6539 sym_link *type, *etype;
6541 left = IC_LEFT (ic);
6542 result = IC_RESULT (ic);
6544 /* depending on the type of pointer we need to
6545 move it to the correct pointer register */
6546 type = operandType (left);
6547 etype = getSpec (type);
6549 genGenPointerGet (left, result, ic);
6553 isRegOrLit (asmop * aop)
6555 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6561 /*-----------------------------------------------------------------*/
6562 /* genPackBits - generates code for packed bit storage */
6563 /*-----------------------------------------------------------------*/
6565 genPackBits (sym_link * etype,
6570 int offset = 0; /* source byte offset */
6571 int rlen = 0; /* remaining bitfield length */
6572 int blen; /* bitfield length */
6573 int bstr; /* bitfield starting bit within byte */
6574 int litval; /* source literal value (if AOP_LIT) */
6575 unsigned char mask; /* bitmask within current byte */
6576 int extraPair; /* a tempory register */
6577 bool needPopExtra=0; /* need to restore original value of temp reg */
6579 emitDebug ("; genPackBits","");
6581 blen = SPEC_BLEN (etype);
6582 bstr = SPEC_BSTR (etype);
6584 /* If the bitfield length is less than a byte */
6587 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6588 (unsigned char) (0xFF >> (8 - bstr)));
6590 if (AOP_TYPE (right) == AOP_LIT)
6592 /* Case with a bitfield length <8 and literal source
6594 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6596 litval &= (~mask) & 0xff;
6597 emit2 ("ld a,!*pair", _pairs[pair].name);
6598 if ((mask|litval)!=0xff)
6599 emit2 ("and a,!immedbyte", mask);
6601 emit2 ("or a,!immedbyte", litval);
6602 emit2 ("ld !*pair,a", _pairs[pair].name);
6607 /* Case with a bitfield length <8 and arbitrary source
6609 _moveA (aopGet (AOP (right), 0, FALSE));
6610 /* shift and mask source value */
6612 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6614 extraPair = getFreePairId(ic);
6615 if (extraPair == PAIR_INVALID)
6617 extraPair = PAIR_BC;
6618 if (getPairId (AOP (right)) != PAIR_BC
6619 || !isLastUse (ic, right))
6625 emit2 ("ld %s,a", _pairs[extraPair].l);
6626 emit2 ("ld a,!*pair", _pairs[pair].name);
6628 emit2 ("and a,!immedbyte", mask);
6629 emit2 ("or a,%s", _pairs[extraPair].l);
6630 emit2 ("ld !*pair,a", _pairs[pair].name);
6637 /* Bit length is greater than 7 bits. In this case, copy */
6638 /* all except the partial byte at the end */
6639 for (rlen=blen;rlen>=8;rlen-=8)
6641 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6642 emit2 ("ld !*pair,a", _pairs[pair].name);
6645 emit2 ("inc %s", _pairs[pair].name);
6646 _G.pairs[pair].offset++;
6650 /* If there was a partial byte at the end */
6653 mask = (((unsigned char) -1 << rlen) & 0xff);
6655 if (AOP_TYPE (right) == AOP_LIT)
6657 /* Case with partial byte and literal source
6659 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6660 litval >>= (blen-rlen);
6661 litval &= (~mask) & 0xff;
6662 emit2 ("ld a,!*pair", _pairs[pair].name);
6663 if ((mask|litval)!=0xff)
6664 emit2 ("and a,!immedbyte", mask);
6666 emit2 ("or a,!immedbyte", litval);
6670 /* Case with partial byte and arbitrary source
6672 _moveA (aopGet (AOP (right), offset++, FALSE));
6673 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6675 extraPair = getFreePairId(ic);
6676 if (extraPair == PAIR_INVALID)
6678 extraPair = getPairId (AOP (right));
6679 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6680 extraPair = PAIR_BC;
6682 if (getPairId (AOP (right)) != PAIR_BC
6683 || !isLastUse (ic, right))
6689 emit2 ("ld %s,a", _pairs[extraPair].l);
6690 emit2 ("ld a,!*pair", _pairs[pair].name);
6692 emit2 ("and a,!immedbyte", mask);
6693 emit2 ("or a,%s", _pairs[extraPair].l);
6698 emit2 ("ld !*pair,a", _pairs[pair].name);
6703 /*-----------------------------------------------------------------*/
6704 /* genGenPointerSet - stores the value into a pointer location */
6705 /*-----------------------------------------------------------------*/
6707 genGenPointerSet (operand * right,
6708 operand * result, iCode * ic)
6711 sym_link *retype = getSpec (operandType (right));
6712 sym_link *letype = getSpec (operandType (result));
6713 PAIR_ID pairId = PAIR_HL;
6716 aopOp (result, ic, FALSE, FALSE);
6717 aopOp (right, ic, FALSE, FALSE);
6722 size = AOP_SIZE (right);
6724 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6725 emitDebug("; isBitvar = %d", isBitvar);
6727 /* Handle the exceptions first */
6728 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6731 const char *l = aopGet (AOP (right), 0, FALSE);
6732 const char *pair = getPairName (AOP (result));
6733 if (canAssignToPtr (l) && isPtr (pair))
6735 emit2 ("ld !*pair,%s", pair, l);
6740 emit2 ("ld !*pair,a", pair);
6745 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6748 const char *l = aopGet (AOP (right), 0, FALSE);
6753 if (canAssignToPtr (l))
6755 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6759 _moveA (aopGet (AOP (right), offset, FALSE));
6760 emit2 ("ld !*iyx,a", offset);
6766 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6773 const char *l = aopGet (AOP (right), offset, FALSE);
6774 if (isRegOrLit (AOP (right)) && !IS_GB)
6776 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6781 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6785 emit2 ("inc %s", _pairs[PAIR_HL].name);
6786 _G.pairs[PAIR_HL].offset++;
6791 /* Fixup HL back down */
6792 for (size = AOP_SIZE (right)-1; size; size--)
6794 emit2 ("dec %s", _pairs[PAIR_HL].name);
6799 /* if the operand is already in dptr
6800 then we do nothing else we move the value to dptr */
6801 if (AOP_TYPE (result) != AOP_STR)
6803 fetchPair (pairId, AOP (result));
6805 /* so hl know contains the address */
6806 freeAsmop (result, NULL, ic);
6808 /* if bit then unpack */
6811 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6821 const char *l = aopGet (AOP (right), offset, FALSE);
6822 if (isRegOrLit (AOP (right)) && !IS_GB)
6824 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6829 emit2 ("ld !*pair,a", _pairs[pairId].name);
6833 emit2 ("inc %s", _pairs[pairId].name);
6834 _G.pairs[pairId].offset++;
6840 freeAsmop (right, NULL, ic);
6843 /*-----------------------------------------------------------------*/
6844 /* genPointerSet - stores the value into a pointer location */
6845 /*-----------------------------------------------------------------*/
6847 genPointerSet (iCode * ic)
6849 operand *right, *result;
6850 sym_link *type, *etype;
6852 right = IC_RIGHT (ic);
6853 result = IC_RESULT (ic);
6855 /* depending on the type of pointer we need to
6856 move it to the correct pointer register */
6857 type = operandType (result);
6858 etype = getSpec (type);
6860 genGenPointerSet (right, result, ic);
6863 /*-----------------------------------------------------------------*/
6864 /* genIfx - generate code for Ifx statement */
6865 /*-----------------------------------------------------------------*/
6867 genIfx (iCode * ic, iCode * popIc)
6869 operand *cond = IC_COND (ic);
6872 aopOp (cond, ic, FALSE, TRUE);
6874 /* get the value into acc */
6875 if (AOP_TYPE (cond) != AOP_CRY)
6879 /* the result is now in the accumulator */
6880 freeAsmop (cond, NULL, ic);
6882 /* if there was something to be popped then do it */
6886 /* if the condition is a bit variable */
6887 if (isbit && IS_ITEMP (cond) &&
6889 genIfxJump (ic, SPIL_LOC (cond)->rname);
6890 else if (isbit && !IS_ITEMP (cond))
6891 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6893 genIfxJump (ic, "a");
6898 /*-----------------------------------------------------------------*/
6899 /* genAddrOf - generates code for address of */
6900 /*-----------------------------------------------------------------*/
6902 genAddrOf (iCode * ic)
6904 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6906 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6908 /* if the operand is on the stack then we
6909 need to get the stack offset of this
6916 if (sym->stack <= 0)
6918 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6922 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6924 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6928 emit2 ("ld de,!hashedstr", sym->rname);
6929 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6937 /* if it has an offset then we need to compute it */
6939 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6941 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6942 emit2 ("add hl,sp");
6946 emit2 ("ld hl,!hashedstr", sym->rname);
6948 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6950 freeAsmop (IC_RESULT (ic), NULL, ic);
6953 /*-----------------------------------------------------------------*/
6954 /* genAssign - generate code for assignment */
6955 /*-----------------------------------------------------------------*/
6957 genAssign (iCode * ic)
6959 operand *result, *right;
6961 unsigned long lit = 0L;
6963 result = IC_RESULT (ic);
6964 right = IC_RIGHT (ic);
6966 /* Dont bother assigning if they are the same */
6967 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6969 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6973 aopOp (right, ic, FALSE, FALSE);
6974 aopOp (result, ic, TRUE, FALSE);
6976 /* if they are the same registers */
6977 if (sameRegs (AOP (right), AOP (result)))
6979 emitDebug ("; (registers are the same)");
6983 /* if the result is a bit */
6984 if (AOP_TYPE (result) == AOP_CRY)
6986 wassertl (0, "Tried to assign to a bit");
6990 size = AOP_SIZE (result);
6993 if (AOP_TYPE (right) == AOP_LIT)
6995 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6998 if (isPair (AOP (result)))
7000 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7002 else if ((size > 1) &&
7003 (AOP_TYPE (result) != AOP_REG) &&
7004 (AOP_TYPE (right) == AOP_LIT) &&
7005 !IS_FLOAT (operandType (right)) &&
7008 bool fXored = FALSE;
7010 /* Work from the top down.
7011 Done this way so that we can use the cached copy of 0
7012 in A for a fast clear */
7015 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7017 if (!fXored && size > 1)
7024 aopPut (AOP (result), "a", offset);
7028 aopPut (AOP (result), "!zero", offset);
7032 aopPut (AOP (result),
7033 aopGet (AOP (right), offset, FALSE),
7038 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7040 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7041 aopPut (AOP (result), "l", LSB);
7042 aopPut (AOP (result), "h", MSB16);
7044 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7046 /* Special case. Load into a and d, then load out. */
7047 _moveA (aopGet (AOP (right), 0, FALSE));
7048 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7049 aopPut (AOP (result), "a", 0);
7050 aopPut (AOP (result), "e", 1);
7052 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7054 /* Special case - simple memcpy */
7055 aopGet (AOP (right), LSB, FALSE);
7058 aopGet (AOP (result), LSB, FALSE);
7062 emit2 ("ld a,(de)");
7063 /* Peephole will optimise this. */
7064 emit2 ("ld (hl),a");
7072 spillPair (PAIR_HL);
7078 /* PENDING: do this check better */
7079 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7081 _moveA (aopGet (AOP (right), offset, FALSE));
7082 aopPut (AOP (result), "a", offset);
7085 aopPut (AOP (result),
7086 aopGet (AOP (right), offset, FALSE),
7093 freeAsmop (right, NULL, ic);
7094 freeAsmop (result, NULL, ic);
7097 /*-----------------------------------------------------------------*/
7098 /* genJumpTab - genrates code for jump table */
7099 /*-----------------------------------------------------------------*/
7101 genJumpTab (iCode * ic)
7106 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7107 /* get the condition into accumulator */
7108 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7111 emit2 ("ld e,%s", l);
7112 emit2 ("ld d,!zero");
7113 jtab = newiTempLabel (NULL);
7115 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7116 emit2 ("add hl,de");
7117 emit2 ("add hl,de");
7118 emit2 ("add hl,de");
7119 freeAsmop (IC_JTCOND (ic), NULL, ic);
7123 emitLabel (jtab->key + 100);
7124 /* now generate the jump labels */
7125 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7126 jtab = setNextItem (IC_JTLABELS (ic)))
7127 emit2 ("jp !tlabel", jtab->key + 100);
7130 /*-----------------------------------------------------------------*/
7131 /* genCast - gen code for casting */
7132 /*-----------------------------------------------------------------*/
7134 genCast (iCode * ic)
7136 operand *result = IC_RESULT (ic);
7137 sym_link *rtype = operandType (IC_RIGHT (ic));
7138 operand *right = IC_RIGHT (ic);
7141 /* if they are equivalent then do nothing */
7142 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7145 aopOp (right, ic, FALSE, FALSE);
7146 aopOp (result, ic, FALSE, FALSE);
7148 /* if the result is a bit */
7149 if (AOP_TYPE (result) == AOP_CRY)
7151 wassertl (0, "Tried to cast to a bit");
7154 /* if they are the same size : or less */
7155 if (AOP_SIZE (result) <= AOP_SIZE (right))
7158 /* if they are in the same place */
7159 if (sameRegs (AOP (right), AOP (result)))
7162 /* if they in different places then copy */
7163 size = AOP_SIZE (result);
7167 aopPut (AOP (result),
7168 aopGet (AOP (right), offset, FALSE),
7175 /* So we now know that the size of destination is greater
7176 than the size of the source */
7177 /* we move to result for the size of source */
7178 size = AOP_SIZE (right);
7182 aopPut (AOP (result),
7183 aopGet (AOP (right), offset, FALSE),
7188 /* now depending on the sign of the destination */
7189 size = AOP_SIZE (result) - AOP_SIZE (right);
7190 /* Unsigned or not an integral type - right fill with zeros */
7191 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7194 aopPut (AOP (result), "!zero", offset++);
7198 /* we need to extend the sign :{ */
7199 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7205 aopPut (AOP (result), "a", offset++);
7209 freeAsmop (right, NULL, ic);
7210 freeAsmop (result, NULL, ic);
7213 /*-----------------------------------------------------------------*/
7214 /* genReceive - generate code for a receive iCode */
7215 /*-----------------------------------------------------------------*/
7217 genReceive (iCode * ic)
7219 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7220 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7221 IS_TRUE_SYMOP (IC_RESULT (ic))))
7231 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7232 size = AOP_SIZE(IC_RESULT(ic));
7234 for (i = 0; i < size; i++) {
7235 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7239 freeAsmop (IC_RESULT (ic), NULL, ic);
7242 /*-----------------------------------------------------------------*/
7243 /* genDummyRead - generate code for dummy read of volatiles */
7244 /*-----------------------------------------------------------------*/
7246 genDummyRead (iCode * ic)
7252 if (op && IS_SYMOP (op))
7254 aopOp (op, ic, FALSE, FALSE);
7257 size = AOP_SIZE (op);
7262 _moveA (aopGet (AOP (op), offset, FALSE));
7266 freeAsmop (op, NULL, ic);
7270 if (op && IS_SYMOP (op))
7272 aopOp (op, ic, FALSE, FALSE);
7275 size = AOP_SIZE (op);
7280 _moveA (aopGet (AOP (op), offset, FALSE));
7284 freeAsmop (op, NULL, ic);
7290 /** Maximum number of bytes to emit per line. */
7294 /** Context for the byte output chunker. */
7297 unsigned char buffer[DBEMIT_MAX_RUN];
7302 /** Flushes a byte chunker by writing out all in the buffer and
7306 _dbFlush(DBEMITCTX *self)
7313 sprintf(line, ".db 0x%02X", self->buffer[0]);
7315 for (i = 1; i < self->pos; i++)
7317 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7324 /** Write out another byte, buffering until a decent line is
7328 _dbEmit(DBEMITCTX *self, int c)
7330 if (self->pos == DBEMIT_MAX_RUN)
7334 self->buffer[self->pos++] = c;
7337 /** Context for a simple run length encoder. */
7341 unsigned char buffer[128];
7343 /** runLen may be equivalent to pos. */
7349 RLE_CHANGE_COST = 4,
7353 /** Flush the buffer of a run length encoder by writing out the run or
7354 data that it currently contains.
7357 _rleCommit(RLECTX *self)
7363 memset(&db, 0, sizeof(db));
7365 emit2(".db %u", self->pos);
7367 for (i = 0; i < self->pos; i++)
7369 _dbEmit(&db, self->buffer[i]);
7378 Can get either a run or a block of random stuff.
7379 Only want to change state if a good run comes in or a run ends.
7380 Detecting run end is easy.
7383 Say initial state is in run, len zero, last zero. Then if you get a
7384 few zeros then something else then a short run will be output.
7385 Seems OK. While in run mode, keep counting. While in random mode,
7386 keep a count of the run. If run hits margin, output all up to run,
7387 restart, enter run mode.
7390 /** Add another byte into the run length encoder, flushing as
7391 required. The run length encoder uses the Amiga IFF style, where
7392 a block is prefixed by its run length. A positive length means
7393 the next n bytes pass straight through. A negative length means
7394 that the next byte is repeated -n times. A zero terminates the
7398 _rleAppend(RLECTX *self, int c)
7402 if (c != self->last)
7404 /* The run has stopped. See if it is worthwhile writing it out
7405 as a run. Note that the random data comes in as runs of
7408 if (self->runLen > RLE_CHANGE_COST)
7410 /* Yes, worthwhile. */
7411 /* Commit whatever was in the buffer. */
7413 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7417 /* Not worthwhile. Append to the end of the random list. */
7418 for (i = 0; i < self->runLen; i++)
7420 if (self->pos >= RLE_MAX_BLOCK)
7425 self->buffer[self->pos++] = self->last;
7433 if (self->runLen >= RLE_MAX_BLOCK)
7435 /* Commit whatever was in the buffer. */
7438 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7446 _rleFlush(RLECTX *self)
7448 _rleAppend(self, -1);
7455 /** genArrayInit - Special code for initialising an array with constant
7459 genArrayInit (iCode * ic)
7463 int elementSize = 0, eIndex, i;
7464 unsigned val, lastVal;
7468 memset(&rle, 0, sizeof(rle));
7470 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7472 _saveRegsForCall(ic, 0);
7474 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7475 emit2 ("call __initrleblock");
7477 type = operandType(IC_LEFT(ic));
7479 if (type && type->next)
7481 elementSize = getSize(type->next);
7485 wassertl (0, "Can't determine element size in genArrayInit.");
7488 iLoop = IC_ARRAYILIST(ic);
7489 lastVal = (unsigned)-1;
7491 /* Feed all the bytes into the run length encoder which will handle
7493 This works well for mixed char data, and for random int and long
7502 for (i = 0; i < ix; i++)
7504 for (eIndex = 0; eIndex < elementSize; eIndex++)
7506 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7507 _rleAppend(&rle, val);
7512 iLoop = iLoop->next;
7516 /* Mark the end of the run. */
7519 _restoreRegsAfterCall();
7523 freeAsmop (IC_LEFT(ic), NULL, ic);
7527 _swap (PAIR_ID one, PAIR_ID two)
7529 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7535 emit2 ("ld a,%s", _pairs[one].l);
7536 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7537 emit2 ("ld %s,a", _pairs[two].l);
7538 emit2 ("ld a,%s", _pairs[one].h);
7539 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7540 emit2 ("ld %s,a", _pairs[two].h);
7544 /* The problem is that we may have all three pairs used and they may
7545 be needed in a different order.
7550 hl = hl => unity, fine
7554 hl = hl hl = hl, swap de <=> bc
7562 hl = bc de = de, swap bc <=> hl
7570 hl = de bc = bc, swap hl <=> de
7575 * Any pair = pair are done last
7576 * Any pair = iTemp are done last
7577 * Any swaps can be done any time
7585 So how do we detect the cases?
7586 How about a 3x3 matrix?
7590 x x x x (Fourth for iTemp/other)
7592 First determin which mode to use by counting the number of unity and
7595 Two - Assign the pair first, then the rest
7596 One - Swap the two, then the rest
7600 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7602 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7604 PAIR_BC, PAIR_HL, PAIR_DE
7606 int i, j, nunity = 0;
7607 memset (ids, PAIR_INVALID, sizeof (ids));
7610 wassert (nparams == 3);
7612 /* First save everything that needs to be saved. */
7613 _saveRegsForCall (ic, 0);
7615 /* Loading HL first means that DE is always fine. */
7616 for (i = 0; i < nparams; i++)
7618 aopOp (pparams[i], ic, FALSE, FALSE);
7619 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7622 /* Count the number of unity or iTemp assigns. */
7623 for (i = 0; i < 3; i++)
7625 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7633 /* Any order, fall through. */
7635 else if (nunity == 2)
7637 /* One is assigned. Pull it out and assign. */
7638 for (i = 0; i < 3; i++)
7640 for (j = 0; j < NUM_PAIRS; j++)
7642 if (ids[dest[i]][j] == TRUE)
7644 /* Found it. See if it's the right one. */
7645 if (j == PAIR_INVALID || j == dest[i])
7651 fetchPair(dest[i], AOP (pparams[i]));
7658 else if (nunity == 1)
7660 /* Find the pairs to swap. */
7661 for (i = 0; i < 3; i++)
7663 for (j = 0; j < NUM_PAIRS; j++)
7665 if (ids[dest[i]][j] == TRUE)
7667 if (j == PAIR_INVALID || j == dest[i])
7682 int next = getPairId (AOP (pparams[0]));
7683 emit2 ("push %s", _pairs[next].name);
7685 if (next == dest[1])
7687 fetchPair (dest[1], AOP (pparams[1]));
7688 fetchPair (dest[2], AOP (pparams[2]));
7692 fetchPair (dest[2], AOP (pparams[2]));
7693 fetchPair (dest[1], AOP (pparams[1]));
7695 emit2 ("pop %s", _pairs[dest[0]].name);
7698 /* Finally pull out all of the iTemps */
7699 for (i = 0; i < 3; i++)
7701 if (ids[dest[i]][PAIR_INVALID] == 1)
7703 fetchPair (dest[i], AOP (pparams[i]));
7709 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7715 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7719 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7721 setupForBuiltin3 (ic, nParams, pparams);
7723 label = newiTempLabel(NULL);
7725 emitLabel (label->key);
7726 emit2 ("ld a,(hl)");
7729 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7731 freeAsmop (from, NULL, ic->next);
7732 freeAsmop (to, NULL, ic);
7736 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7738 operand *from, *to, *count;
7741 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7746 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7748 setupForBuiltin3 (ic, nParams, pparams);
7752 freeAsmop (count, NULL, ic->next->next);
7753 freeAsmop (from, NULL, ic);
7755 _restoreRegsAfterCall();
7757 /* if we need assign a result value */
7758 if ((IS_ITEMP (IC_RESULT (ic)) &&
7759 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7760 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7761 IS_TRUE_SYMOP (IC_RESULT (ic)))
7763 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7764 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7765 freeAsmop (IC_RESULT (ic), NULL, ic);
7768 freeAsmop (to, NULL, ic->next);
7771 /*-----------------------------------------------------------------*/
7772 /* genBuiltIn - calls the appropriate function to generating code */
7773 /* for a built in function */
7774 /*-----------------------------------------------------------------*/
7775 static void genBuiltIn (iCode *ic)
7777 operand *bi_parms[MAX_BUILTIN_ARGS];
7782 /* get all the arguments for a built in function */
7783 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7785 /* which function is it */
7786 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7788 if (strcmp(bif->name,"__builtin_strcpy")==0)
7790 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7792 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7794 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7798 wassertl (0, "Unknown builtin function encountered");
7802 /*-----------------------------------------------------------------*/
7803 /* genZ80Code - generate code for Z80 based controllers */
7804 /*-----------------------------------------------------------------*/
7806 genZ80Code (iCode * lic)
7814 _fReturn = _gbz80_return;
7815 _fTmp = _gbz80_return;
7819 _fReturn = _z80_return;
7820 _fTmp = _z80_return;
7823 _G.lines.head = _G.lines.current = NULL;
7825 /* if debug information required */
7826 if (options.debug && currFunc)
7828 debugFile->writeFunction(currFunc);
7829 _G.lines.isDebug = 1;
7830 if (IS_STATIC (currFunc->etype))
7831 sprintf (buffer, "F%s$%s$0$0", moduleName, currFunc->name);
7833 sprintf (buffer, "G$%s$0$0", currFunc->name);
7834 emit2 ("!labeldef", buffer);
7835 _G.lines.isDebug = 0;
7838 for (ic = lic; ic; ic = ic->next)
7840 _G.current_iCode = ic;
7842 if (ic->lineno && cln != ic->lineno)
7846 _G.lines.isDebug = 1;
7847 sprintf (buffer, "C$%s$%d$%d$%d",
7848 FileBaseName (ic->filename), ic->lineno,
7849 ic->level, ic->block);
7850 emit2 ("%s !equ .", buffer);
7851 emit2 ("!global", buffer);
7852 _G.lines.isDebug = 0;
7854 if (!options.noCcodeInAsm) {
7855 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7856 printCLine(ic->filename, ic->lineno));
7860 if (options.iCodeInAsm) {
7861 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7863 /* if the result is marked as
7864 spilt and rematerializable or code for
7865 this has already been generated then
7867 if (resultRemat (ic) || ic->generated)
7870 /* depending on the operation */
7874 emitDebug ("; genNot");
7879 emitDebug ("; genCpl");
7884 emitDebug ("; genUminus");
7889 emitDebug ("; genIpush");
7894 /* IPOP happens only when trying to restore a
7895 spilt live range, if there is an ifx statement
7896 following this pop then the if statement might
7897 be using some of the registers being popped which
7898 would destory the contents of the register so
7899 we need to check for this condition and handle it */
7901 ic->next->op == IFX &&
7902 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7904 emitDebug ("; genIfx");
7905 genIfx (ic->next, ic);
7909 emitDebug ("; genIpop");
7915 emitDebug ("; genCall");
7920 emitDebug ("; genPcall");
7925 emitDebug ("; genFunction");
7930 emitDebug ("; genEndFunction");
7931 genEndFunction (ic);
7935 emitDebug ("; genRet");
7940 emitDebug ("; genLabel");
7945 emitDebug ("; genGoto");
7950 emitDebug ("; genPlus");
7955 emitDebug ("; genMinus");
7960 emitDebug ("; genMult");
7965 emitDebug ("; genDiv");
7970 emitDebug ("; genMod");
7975 emitDebug ("; genCmpGt");
7976 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7980 emitDebug ("; genCmpLt");
7981 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7988 /* note these two are xlated by algebraic equivalence
7989 during parsing SDCC.y */
7990 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7991 "got '>=' or '<=' shouldn't have come here");
7995 emitDebug ("; genCmpEq");
7996 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8000 emitDebug ("; genAndOp");
8005 emitDebug ("; genOrOp");
8010 emitDebug ("; genXor");
8011 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8015 emitDebug ("; genOr");
8016 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8020 emitDebug ("; genAnd");
8021 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8025 emitDebug ("; genInline");
8030 emitDebug ("; genRRC");
8035 emitDebug ("; genRLC");
8040 emitDebug ("; genGetHBIT");
8045 emitDebug ("; genLeftShift");
8050 emitDebug ("; genRightShift");
8054 case GET_VALUE_AT_ADDRESS:
8055 emitDebug ("; genPointerGet");
8061 if (POINTER_SET (ic))
8063 emitDebug ("; genAssign (pointer)");
8068 emitDebug ("; genAssign");
8074 emitDebug ("; genIfx");
8079 emitDebug ("; genAddrOf");
8084 emitDebug ("; genJumpTab");
8089 emitDebug ("; genCast");
8094 emitDebug ("; genReceive");
8099 if (ic->builtinSEND)
8101 emitDebug ("; genBuiltIn");
8106 emitDebug ("; addSet");
8107 addSet (&_G.sendSet, ic);
8112 emitDebug ("; genArrayInit");
8116 case DUMMY_READ_VOLATILE:
8117 emitDebug ("; genDummyRead");
8127 /* now we are ready to call the
8128 peep hole optimizer */
8129 if (!options.nopeep)
8130 peepHole (&_G.lines.head);
8132 /* This is unfortunate */
8133 /* now do the actual printing */
8135 FILE *fp = codeOutFile;
8136 if (isInHome () && codeOutFile == code->oFile)
8137 codeOutFile = home->oFile;
8138 printLine (_G.lines.head, codeOutFile);
8139 if (_G.flushStatics)
8142 _G.flushStatics = 0;
8147 freeTrace(&_G.lines.trace);
8148 freeTrace(&_G.trace.aops);
8154 _isPairUsed (iCode * ic, PAIR_ID pairId)
8160 if (bitVectBitValue (ic->rMask, D_IDX))
8162 if (bitVectBitValue (ic->rMask, E_IDX))
8172 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8175 value *val = aop->aopu.aop_lit;
8177 wassert (aop->type == AOP_LIT);
8178 wassert (!IS_FLOAT (val->type));
8180 v = (unsigned long) floatFromVal (val);
8188 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8189 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));