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 struct dbuf_s *codeOutBuf;
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 (const 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)
407 dbuf_init(&dbuf, INITIAL_INLINEASM);
409 dbuf_tvprintf (&dbuf, szFormat, ap);
411 buffer = dbuf_c_str(&dbuf);
413 _tidyUp ((char *)buffer);
414 _G.lines.current = (_G.lines.current ?
415 connectLine (_G.lines.current, _newLineNode (buffer)) :
416 (_G.lines.head = _newLineNode (buffer)));
418 _G.lines.current->isInline = _G.lines.isInline;
419 _G.lines.current->isDebug = _G.lines.isDebug;
420 _G.lines.current->ic = _G.current_iCode;
421 _G.lines.current->isComment = (*buffer == ';');
427 emit2 (const char *szFormat,...)
431 va_start (ap, szFormat);
433 _vemit2 (szFormat, ap);
439 emitDebug (const char *szFormat,...)
445 va_start (ap, szFormat);
447 _vemit2 (szFormat, ap);
453 /*-----------------------------------------------------------------*/
454 /* z80_emitDebuggerSymbol - associate the current code location */
455 /* with a debugger symbol */
456 /*-----------------------------------------------------------------*/
458 z80_emitDebuggerSymbol (char * debugSym)
460 _G.lines.isDebug = 1;
461 emit2 ("%s !equ .", debugSym);
462 emit2 ("!global", debugSym);
463 _G.lines.isDebug = 0;
466 /*-----------------------------------------------------------------*/
467 /* emit2 - writes the code into a file : for now it is simple */
468 /*-----------------------------------------------------------------*/
470 _emit2 (const char *inst, const char *fmt,...)
473 char lb[INITIAL_INLINEASM];
480 sprintf (lb, "%s\t", inst);
481 vsprintf (lb + (strlen (lb)), fmt, ap);
484 vsprintf (lb, fmt, ap);
486 while (isspace (*lbp))
491 _G.lines.current = (_G.lines.current ?
492 connectLine (_G.lines.current, _newLineNode (lb)) :
493 (_G.lines.head = _newLineNode (lb)));
495 _G.lines.current->isInline = _G.lines.isInline;
496 _G.lines.current->ic = _G.current_iCode;
501 _emitMove(const char *to, const char *from)
503 if (STRCASECMP(to, from) != 0)
505 emit2("ld %s,%s", to, from);
510 // Could leave this to the peephole, but sometimes the peephole is inhibited.
515 aopDump(const char *plabel, asmop *aop)
521 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
526 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
529 for (i=aop->size-1;i>=0;i--)
530 *rbp++ = *(aop->aopu.aop_reg[i]->name);
532 emitDebug("; reg = %s", regbuf);
535 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
538 /* No information. */
544 _moveA(const char *moveFrom)
546 // Let the peephole optimiser take care of redundent loads
547 _emitMove(ACC_NAME, moveFrom);
557 getPairName (asmop * aop)
559 if (aop->type == AOP_REG)
561 switch (aop->aopu.aop_reg[0]->rIdx)
574 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
577 for (i = 0; i < NUM_PAIRS; i++)
579 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
581 return _pairs[i].name;
585 wassertl (0, "Tried to get the pair name of something that isn't a pair");
590 getPairId (asmop * aop)
594 if (aop->type == AOP_REG)
596 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
600 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
604 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
609 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
612 for (i = 0; i < NUM_PAIRS; i++)
614 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
624 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
628 return (getPairId (aop) != PAIR_INVALID);
631 /** Returns TRUE if the registers used in aop cannot be split into high
634 isUnsplitable (asmop * aop)
636 switch (getPairId (aop))
648 isPtrPair (asmop * aop)
650 PAIR_ID pairId = getPairId (aop);
663 spillPair (PAIR_ID pairId)
665 _G.pairs[pairId].last_type = AOP_INVALID;
666 _G.pairs[pairId].base = NULL;
669 /* Given a register name, spill the pair (if any) the register is part of */
671 spillPairReg (const char *regname)
673 if (strlen(regname)==1)
693 /** Push a register pair onto the stack */
695 genPairPush (asmop * aop)
697 emit2 ("push %s", getPairName (aop));
701 _push (PAIR_ID pairId)
703 emit2 ("push %s", _pairs[pairId].name);
704 _G.stack.pushed += 2;
708 _pop (PAIR_ID pairId)
710 emit2 ("pop %s", _pairs[pairId].name);
711 _G.stack.pushed -= 2;
716 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
729 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
736 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
737 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
740 wassertl (0, "Tried to move a nonphysical pair");
742 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
743 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
744 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
748 /*-----------------------------------------------------------------*/
749 /* newAsmop - creates a new asmOp */
750 /*-----------------------------------------------------------------*/
752 newAsmop (short type)
756 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
761 /*-----------------------------------------------------------------*/
762 /* aopForSym - for a true symbol */
763 /*-----------------------------------------------------------------*/
765 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
772 wassert (sym->etype);
774 space = SPEC_OCLS (sym->etype);
776 /* if already has one */
782 /* Assign depending on the storage class */
783 if (sym->onStack || sym->iaccess)
785 /* The pointer that is used depends on how big the offset is.
786 Normally everything is AOP_STK, but for offsets of < -128 or
787 > 127 on the Z80 an extended stack pointer is used.
789 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
791 emitDebug ("; AOP_EXSTK for %s", sym->rname);
792 sym->aop = aop = newAsmop (AOP_EXSTK);
796 emitDebug ("; AOP_STK for %s", sym->rname);
797 sym->aop = aop = newAsmop (AOP_STK);
800 aop->size = getSize (sym->type);
801 aop->aopu.aop_stk = sym->stack;
805 /* special case for a function */
806 if (IS_FUNC (sym->type))
808 sym->aop = aop = newAsmop (AOP_IMMD);
809 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
814 if( IN_REGSP( space ))
815 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
818 /* if it is in direct space */
821 sym->aop = aop = newAsmop (AOP_SFR);
822 aop->aopu.aop_dir = sym->rname;
823 aop->size = getSize (sym->type);
824 emitDebug ("; AOP_SFR for %s", sym->rname);
829 { /*.p.t.20030716 adding SFR support to the Z80 port */
830 aop = newAsmop (AOP_SFR);
832 aop->aopu.aop_dir = sym->rname;
833 aop->size = getSize( sym->type );
834 aop->paged = FUNC_REGBANK(sym->type);
835 aop->bcInUse = isPairInUse( PAIR_BC, ic );
836 aop->deInUse = isPairInUse( PAIR_DE, ic );
837 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
843 /* only remaining is far space */
844 /* in which case DPTR gets the address */
847 emitDebug ("; AOP_HL for %s", sym->rname);
848 sym->aop = aop = newAsmop (AOP_HL);
852 sym->aop = aop = newAsmop (AOP_IY);
854 aop->size = getSize (sym->type);
855 aop->aopu.aop_dir = sym->rname;
857 /* if it is in code space */
858 if (IN_CODESPACE (space))
864 /*-----------------------------------------------------------------*/
865 /* aopForRemat - rematerialzes an object */
866 /*-----------------------------------------------------------------*/
868 aopForRemat (symbol * sym)
871 iCode *ic = sym->rematiCode;
872 asmop *aop = newAsmop (AOP_IMMD);
876 /* if plus or minus print the right hand side */
877 if (ic->op == '+' || ic->op == '-')
879 /* PENDING: for re-target */
880 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
883 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
886 /* we reached the end */
887 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
891 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
895 /*-----------------------------------------------------------------*/
896 /* regsInCommon - two operands have some registers in common */
897 /*-----------------------------------------------------------------*/
899 regsInCommon (operand * op1, operand * op2)
904 /* if they have registers in common */
905 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
908 sym1 = OP_SYMBOL (op1);
909 sym2 = OP_SYMBOL (op2);
911 if (sym1->nRegs == 0 || sym2->nRegs == 0)
914 for (i = 0; i < sym1->nRegs; i++)
920 for (j = 0; j < sym2->nRegs; j++)
925 if (sym2->regs[j] == sym1->regs[i])
933 /*-----------------------------------------------------------------*/
934 /* operandsEqu - equivalent */
935 /*-----------------------------------------------------------------*/
937 operandsEqu (operand * op1, operand * op2)
941 /* if they not symbols */
942 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
945 sym1 = OP_SYMBOL (op1);
946 sym2 = OP_SYMBOL (op2);
948 /* if both are itemps & one is spilt
949 and the other is not then false */
950 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
951 sym1->isspilt != sym2->isspilt)
954 /* if they are the same */
958 if (sym1->rname[0] && sym2->rname[0]
959 && strcmp (sym1->rname, sym2->rname) == 0)
962 /* if left is a tmp & right is not */
963 if (IS_ITEMP (op1) &&
966 (sym1->usl.spillLoc == sym2))
969 if (IS_ITEMP (op2) &&
973 (sym2->usl.spillLoc == sym1))
979 /*-----------------------------------------------------------------*/
980 /* sameRegs - two asmops have the same registers */
981 /*-----------------------------------------------------------------*/
983 sameRegs (asmop * aop1, asmop * aop2)
987 if (aop1->type == AOP_SFR ||
988 aop2->type == AOP_SFR)
994 if (aop1->type != AOP_REG ||
995 aop2->type != AOP_REG)
998 if (aop1->size != aop2->size)
1001 for (i = 0; i < aop1->size; i++)
1002 if (aop1->aopu.aop_reg[i] !=
1003 aop2->aopu.aop_reg[i])
1009 /*-----------------------------------------------------------------*/
1010 /* aopOp - allocates an asmop for an operand : */
1011 /*-----------------------------------------------------------------*/
1013 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1022 /* if this a literal */
1023 if (IS_OP_LITERAL (op))
1025 op->aop = aop = newAsmop (AOP_LIT);
1026 aop->aopu.aop_lit = op->operand.valOperand;
1027 aop->size = getSize (operandType (op));
1031 /* if already has a asmop then continue */
1034 if (op->aop->type == AOP_SFR)
1036 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1037 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1042 /* if the underlying symbol has a aop */
1043 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1045 op->aop = OP_SYMBOL (op)->aop;
1046 if (op->aop->type == AOP_SFR)
1048 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1049 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1054 /* if this is a true symbol */
1055 if (IS_TRUE_SYMOP (op))
1057 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1061 /* this is a temporary : this has
1067 e) can be a return use only */
1069 sym = OP_SYMBOL (op);
1071 /* if the type is a conditional */
1072 if (sym->regType == REG_CND)
1074 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1079 /* if it is spilt then two situations
1081 b) has a spill location */
1082 if (sym->isspilt || sym->nRegs == 0)
1084 /* rematerialize it NOW */
1087 sym->aop = op->aop = aop =
1089 aop->size = getSize (sym->type);
1096 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1097 aop->size = getSize (sym->type);
1098 for (i = 0; i < 4; i++)
1099 aop->aopu.aop_str[i] = _fReturn[i];
1105 if (sym->accuse == ACCUSE_A)
1107 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1108 aop->size = getSize (sym->type);
1109 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1111 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1113 else if (sym->accuse == ACCUSE_SCRATCH)
1115 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1116 aop->size = getSize (sym->type);
1117 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1118 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1119 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1121 else if (sym->accuse == ACCUSE_IY)
1123 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1124 aop->size = getSize (sym->type);
1125 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1126 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1127 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1131 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1136 if (sym->usl.spillLoc)
1138 asmop *oldAsmOp = NULL;
1140 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1142 /* force a new aop if sizes differ */
1143 oldAsmOp = sym->usl.spillLoc->aop;
1144 sym->usl.spillLoc->aop = NULL;
1146 sym->aop = op->aop = aop =
1147 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1148 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1150 /* Don't reuse the new aop, go with the last one */
1151 sym->usl.spillLoc->aop = oldAsmOp;
1153 aop->size = getSize (sym->type);
1157 /* else must be a dummy iTemp */
1158 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1159 aop->size = getSize (sym->type);
1163 /* must be in a register */
1164 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1165 aop->size = sym->nRegs;
1166 for (i = 0; i < sym->nRegs; i++)
1167 aop->aopu.aop_reg[i] = sym->regs[i];
1170 /*-----------------------------------------------------------------*/
1171 /* freeAsmop - free up the asmop given to an operand */
1172 /*----------------------------------------------------------------*/
1174 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1191 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1193 _pop (aop->aopu.aop_pairId);
1196 if (getPairId (aop) == PAIR_HL)
1198 spillPair (PAIR_HL);
1202 /* all other cases just dealloc */
1208 OP_SYMBOL (op)->aop = NULL;
1209 /* if the symbol has a spill */
1211 SPIL_LOC (op)->aop = NULL;
1218 isLitWord (asmop * aop)
1220 /* if (aop->size != 2)
1233 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1235 /* depending on type */
1241 /* PENDING: for re-target */
1244 tsprintf (buffer, sizeof(buffer),
1245 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1247 else if (offset == 0)
1249 tsprintf (buffer, sizeof(buffer),
1250 "%s", aop->aopu.aop_immd);
1254 tsprintf (buffer, sizeof(buffer),
1255 "%s + %d", aop->aopu.aop_immd, offset);
1257 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1261 value *val = aop->aopu.aop_lit;
1262 /* if it is a float then it gets tricky */
1263 /* otherwise it is fairly simple */
1264 if (!IS_FLOAT (val->type))
1266 unsigned long v = (unsigned long) floatFromVal (val);
1272 else if (offset == 0)
1278 wassertl(0, "Encountered an invalid offset while fetching a literal");
1282 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1284 tsprintf (buffer, sizeof(buffer), "!constword", v);
1286 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1297 /* it is type float */
1298 fl.f = (float) floatFromVal (val);
1300 #ifdef WORDS_BIGENDIAN
1301 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1303 i = fl.c[offset] | (fl.c[offset+1]<<8);
1306 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1308 tsprintf (buffer, sizeof(buffer), "!constword", i);
1310 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1319 aopGetWord (asmop * aop, int offset)
1321 return aopGetLitWordLong (aop, offset, TRUE);
1325 isPtr (const char *s)
1327 if (!strcmp (s, "hl"))
1329 if (!strcmp (s, "ix"))
1331 if (!strcmp (s, "iy"))
1337 adjustPair (const char *pair, int *pold, int new)
1343 emit2 ("inc %s", pair);
1348 emit2 ("dec %s", pair);
1356 spillPair (PAIR_HL);
1357 spillPair (PAIR_IY);
1361 requiresHL (asmop * aop)
1377 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1379 const char *l, *base;
1380 const char *pair = _pairs[pairId].name;
1381 l = aopGetLitWordLong (left, offset, FALSE);
1382 base = aopGetLitWordLong (left, 0, FALSE);
1383 wassert (l && pair && base);
1387 if (pairId == PAIR_HL || pairId == PAIR_IY)
1389 if (_G.pairs[pairId].last_type == left->type)
1391 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1393 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1395 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1398 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1405 _G.pairs[pairId].last_type = left->type;
1406 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1407 _G.pairs[pairId].offset = offset;
1409 /* Both a lit on the right and a true symbol on the left */
1410 emit2 ("ld %s,!hashedstr", pair, l);
1414 makeFreePairId (iCode *ic, bool *pisUsed)
1420 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1424 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1442 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1444 /* if this is remateriazable */
1445 if (isLitWord (aop)) {
1446 fetchLitPair (pairId, aop, offset);
1450 if (getPairId (aop) == pairId)
1454 /* we need to get it byte by byte */
1455 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1456 aopGet (aop, offset, FALSE);
1457 switch (aop->size - offset) {
1459 emit2 ("ld l,!*hl");
1460 emit2 ("ld h,!immedbyte", 0);
1463 // PENDING: Requires that you are only fetching two bytes.
1466 emit2 ("ld h,!*hl");
1470 wassertl (0, "Attempted to fetch too much data into HL");
1474 else if (IS_Z80 && aop->type == AOP_IY) {
1475 /* Instead of fetching relative to IY, just grab directly
1476 from the address IY refers to */
1477 char *l = aopGetLitWordLong (aop, offset, FALSE);
1479 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1481 if (aop->size < 2) {
1482 emit2("ld %s,!zero", _pairs[pairId].h);
1485 else if (pairId == PAIR_IY)
1489 emit2 ("push %s", _pairs[getPairId(aop)].name);
1495 PAIR_ID id = makeFreePairId (ic, &isUsed);
1498 /* Can't load into parts, so load into HL then exchange. */
1499 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1500 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1501 emit2 ("push %s", _pairs[id].name);
1507 else if (isUnsplitable(aop))
1509 emit2("push %s", _pairs[getPairId(aop)].name);
1510 emit2("pop %s", _pairs[pairId].name);
1514 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1515 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1517 /* PENDING: check? */
1518 if (pairId == PAIR_HL)
1519 spillPair (PAIR_HL);
1524 fetchPair (PAIR_ID pairId, asmop * aop)
1526 fetchPairLong (pairId, aop, NULL, 0);
1530 fetchHL (asmop * aop)
1532 fetchPair (PAIR_HL, aop);
1536 setupPairFromSP (PAIR_ID id, int offset)
1538 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1540 if (_G.preserveCarry)
1546 if (offset < INT8MIN || offset > INT8MAX)
1548 emit2 ("ld hl,!immedword", offset);
1549 emit2 ("add hl,sp");
1553 emit2 ("!ldahlsp", offset);
1556 if (_G.preserveCarry)
1564 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1569 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1570 fetchLitPair (pairId, aop, 0);
1574 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1576 fetchLitPair (pairId, aop, offset);
1577 _G.pairs[pairId].offset = offset;
1581 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1582 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1585 int offset = aop->aopu.aop_stk + _G.stack.offset;
1587 if (_G.pairs[pairId].last_type == aop->type &&
1588 _G.pairs[pairId].offset == offset)
1594 /* PENDING: Do this better. */
1595 if (_G.preserveCarry)
1597 sprintf (buffer, "%d", offset + _G.stack.pushed);
1598 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1599 emit2 ("add %s,sp", _pairs[pairId].name);
1600 _G.pairs[pairId].last_type = aop->type;
1601 _G.pairs[pairId].offset = offset;
1602 if (_G.preserveCarry)
1610 /* Doesnt include _G.stack.pushed */
1611 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1613 if (aop->aopu.aop_stk > 0)
1615 abso += _G.stack.param_offset;
1617 assert (pairId == PAIR_HL);
1618 /* In some cases we can still inc or dec hl */
1619 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1621 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1625 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1627 _G.pairs[pairId].offset = abso;
1632 if (pairId != aop->aopu.aop_pairId)
1633 genMovePairPair(aop->aopu.aop_pairId, pairId);
1634 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1640 _G.pairs[pairId].last_type = aop->type;
1646 emit2 ("!tlabeldef", key);
1647 _G.lines.current->isLabel = 1;
1651 /*-----------------------------------------------------------------*/
1652 /* aopGet - for fetching value of the aop */
1653 /*-----------------------------------------------------------------*/
1655 aopGet (asmop * aop, int offset, bool bit16)
1657 // char *s = buffer;
1659 /* offset is greater than size then zero */
1660 /* PENDING: this seems a bit screwed in some pointer cases. */
1661 if (offset > (aop->size - 1) &&
1662 aop->type != AOP_LIT)
1664 tsprintf (buffer, sizeof(buffer), "!zero");
1665 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1668 /* depending on type */
1672 tsprintf (buffer, sizeof(buffer), "!zero");
1673 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1676 /* PENDING: re-target */
1678 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1683 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1686 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1689 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1692 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1695 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1699 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1700 SNPRINTF (buffer, sizeof(buffer), "a");
1702 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1708 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1709 SNPRINTF (buffer, sizeof(buffer), "a");
1711 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1714 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1717 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1718 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1719 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1721 else if( z80_opts.port_mode == 180 )
1722 { /* z180 in0/out0 mode */
1723 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1727 emit2( "in a,(%s)", aop->aopu.aop_dir );
1730 SNPRINTF (buffer, sizeof(buffer), "a");
1732 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1736 return aop->aopu.aop_reg[offset]->name;
1740 setupPair (PAIR_HL, aop, offset);
1741 tsprintf (buffer, sizeof(buffer), "!*hl");
1743 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1747 setupPair (PAIR_IY, aop, offset);
1748 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1750 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1754 setupPair (PAIR_IY, aop, offset);
1755 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1757 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1762 setupPair (PAIR_HL, aop, offset);
1763 tsprintf (buffer, sizeof(buffer), "!*hl");
1767 if (aop->aopu.aop_stk >= 0)
1768 offset += _G.stack.param_offset;
1769 tsprintf (buffer, sizeof(buffer),
1770 "!*ixx", aop->aopu.aop_stk + offset);
1773 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1776 wassertl (0, "Tried to fetch from a bit variable");
1785 tsprintf(buffer, sizeof(buffer), "!zero");
1786 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1790 wassert (offset < 2);
1791 return aop->aopu.aop_str[offset];
1794 return aopLiteral (aop->aopu.aop_lit, offset);
1798 unsigned long v = aop->aopu.aop_simplelit;
1801 tsprintf (buffer, sizeof(buffer),
1802 "!immedbyte", (unsigned int) v & 0xff);
1804 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1808 return aop->aopu.aop_str[offset];
1811 setupPair (aop->aopu.aop_pairId, aop, offset);
1812 if (aop->aopu.aop_pairId==PAIR_IX)
1813 SNPRINTF (buffer, sizeof(buffer),
1815 else if (aop->aopu.aop_pairId==PAIR_IY)
1816 SNPRINTF (buffer, sizeof(buffer),
1819 SNPRINTF (buffer, sizeof(buffer),
1820 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1822 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1827 wassertl (0, "aopget got unsupported aop->type");
1832 isRegString (const char *s)
1834 if (!strcmp (s, "b") ||
1846 isConstant (const char *s)
1848 /* This is a bit of a hack... */
1849 return (*s == '#' || *s == '$');
1853 canAssignToPtr (const char *s)
1855 if (isRegString (s))
1862 /*-----------------------------------------------------------------*/
1863 /* aopPut - puts a string for a aop */
1864 /*-----------------------------------------------------------------*/
1866 aopPut (asmop * aop, const char *s, int offset)
1870 if (aop->size && offset > (aop->size - 1))
1872 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1873 "aopPut got offset > aop->size");
1878 tsprintf(buffer2, sizeof(buffer2), s);
1881 /* will assign value to value */
1882 /* depending on where it is ofcourse */
1886 _moveA (s); /* in case s is volatile */
1892 if (strcmp (s, "a"))
1893 emit2 ("ld a,%s", s);
1894 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1901 if (strcmp (s, "a"))
1902 emit2 ("ld a,%s", s);
1903 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1906 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1913 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1914 && s[0] != 'h' && s[0] != 'l'))
1916 emit2( "ld a,%s", s );
1920 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1921 emit2( "out (c),%s", s );
1926 spillPair (PAIR_BC);
1928 else if( z80_opts.port_mode == 180 )
1929 { /* z180 in0/out0 mode */
1930 emit2( "ld a,%s", s );
1931 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1935 emit2( "ld a,%s", s );
1936 emit2( "out (%s),a", aop->aopu.aop_dir );
1942 if (!strcmp (s, "!*hl"))
1943 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1946 aop->aopu.aop_reg[offset]->name, s);
1947 spillPairReg(aop->aopu.aop_reg[offset]->name);
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);
1967 /* PENDING: for re-target */
1968 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1970 emit2 ("ld a,!*hl");
1973 setupPair (PAIR_HL, aop, offset);
1975 emit2 ("ld !*hl,%s", s);
1980 if (!canAssignToPtr (s))
1982 emit2 ("ld a,%s", s);
1983 setupPair (PAIR_IY, aop, offset);
1984 emit2 ("ld !*iyx,a", offset);
1988 setupPair (PAIR_IY, aop, offset);
1989 emit2 ("ld !*iyx,%s", offset, s);
1996 /* PENDING: re-target */
1997 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1999 emit2 ("ld a,!*hl");
2002 setupPair (PAIR_HL, aop, offset);
2003 if (!canAssignToPtr (s))
2005 emit2 ("ld a,%s", s);
2006 emit2 ("ld !*hl,a");
2009 emit2 ("ld !*hl,%s", s);
2013 if (aop->aopu.aop_stk >= 0)
2014 offset += _G.stack.param_offset;
2015 if (!canAssignToPtr (s))
2017 emit2 ("ld a,%s", s);
2018 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2022 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2028 /* if bit variable */
2029 if (!aop->aopu.aop_dir)
2031 emit2 ("ld a,!zero");
2036 /* In bit space but not in C - cant happen */
2037 wassertl (0, "Tried to write into a bit variable");
2043 if (strcmp (aop->aopu.aop_str[offset], s))
2045 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2047 spillPairReg(aop->aopu.aop_str[offset]);
2052 if (!offset && (strcmp (s, "acc") == 0))
2056 wassertl (0, "Tried to access past the end of A");
2060 if (strcmp (aop->aopu.aop_str[offset], s))
2062 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2063 spillPairReg(aop->aopu.aop_str[offset]);
2069 wassert (offset < 2);
2070 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2071 spillPairReg(aop->aopu.aop_str[offset]);
2075 setupPair (aop->aopu.aop_pairId, aop, offset);
2076 if (aop->aopu.aop_pairId==PAIR_IX)
2077 emit2 ("ld !*ixx,%s", 0, s);
2078 else if (aop->aopu.aop_pairId==PAIR_IY)
2079 emit2 ("ld !*iyx,%s", 0, s);
2081 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2085 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2086 "aopPut got unsupported aop->type");
2091 #define AOP(op) op->aop
2092 #define AOP_TYPE(op) AOP(op)->type
2093 #define AOP_SIZE(op) AOP(op)->size
2094 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2097 commitPair (asmop * aop, PAIR_ID id)
2099 /* PENDING: Verify this. */
2100 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2104 aopPut (aop, "a", 0);
2105 aopPut (aop, "d", 1);
2110 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2112 char *l = aopGetLitWordLong (aop, 0, FALSE);
2115 emit2 ("ld (%s),%s", l, _pairs[id].name);
2119 aopPut (aop, _pairs[id].l, 0);
2120 aopPut (aop, _pairs[id].h, 1);
2125 /*-----------------------------------------------------------------*/
2126 /* getDataSize - get the operand data size */
2127 /*-----------------------------------------------------------------*/
2129 getDataSize (operand * op)
2132 size = AOP_SIZE (op);
2136 wassertl (0, "Somehow got a three byte data pointer");
2141 /*-----------------------------------------------------------------*/
2142 /* movLeft2Result - move byte from left to result */
2143 /*-----------------------------------------------------------------*/
2145 movLeft2Result (operand * left, int offl,
2146 operand * result, int offr, int sign)
2150 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2152 l = aopGet (AOP (left), offl, FALSE);
2156 aopPut (AOP (result), l, offr);
2160 if (getDataSize (left) == offl + 1)
2162 emit2 ("ld a,%s", l);
2163 aopPut (AOP (result), "a", offr);
2170 movLeft2ResultLong (operand * left, int offl,
2171 operand * result, int offr, int sign,
2176 movLeft2Result (left, offl, result, offr, sign);
2180 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2181 wassertl (size == 2, "Only implemented for two bytes or one");
2183 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2185 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2186 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2188 spillPair (PAIR_HL);
2190 else if ( getPairId ( AOP (result)) == PAIR_IY)
2192 PAIR_ID id = getPairId (AOP (left));
2193 if (id != PAIR_INVALID)
2195 emit2("push %s", _pairs[id].name);
2206 movLeft2Result (left, offl, result, offr, sign);
2207 movLeft2Result (left, offl+1, result, offr+1, sign);
2212 /** Put Acc into a register set
2215 outAcc (operand * result)
2218 size = getDataSize (result);
2221 aopPut (AOP (result), "a", 0);
2224 /* unsigned or positive */
2227 aopPut (AOP (result), "!zero", offset++);
2232 /** Take the value in carry and put it into a register
2235 outBitCLong (operand * result, bool swap_sense)
2237 /* if the result is bit */
2238 if (AOP_TYPE (result) == AOP_CRY)
2240 wassertl (0, "Tried to write carry to a bit");
2244 emit2 ("ld a,!zero");
2247 emit2 ("xor a,!immedbyte", 1);
2253 outBitC (operand * result)
2255 outBitCLong (result, FALSE);
2258 /*-----------------------------------------------------------------*/
2259 /* toBoolean - emit code for orl a,operator(sizeop) */
2260 /*-----------------------------------------------------------------*/
2262 _toBoolean (operand * oper)
2264 int size = AOP_SIZE (oper);
2268 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2271 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2275 if (AOP (oper)->type != AOP_ACC)
2278 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2284 /*-----------------------------------------------------------------*/
2285 /* genNot - generate code for ! operation */
2286 /*-----------------------------------------------------------------*/
2291 /* assign asmOps to operand & result */
2292 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2293 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2295 /* if in bit space then a special case */
2296 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2298 wassertl (0, "Tried to negate a bit");
2301 _toBoolean (IC_LEFT (ic));
2306 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2307 emit2 ("sub a,!one");
2308 outBitC (IC_RESULT (ic));
2310 /* release the aops */
2311 freeAsmop (IC_LEFT (ic), NULL, ic);
2312 freeAsmop (IC_RESULT (ic), NULL, ic);
2315 /*-----------------------------------------------------------------*/
2316 /* genCpl - generate code for complement */
2317 /*-----------------------------------------------------------------*/
2325 /* assign asmOps to operand & result */
2326 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2327 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2329 /* if both are in bit space then
2331 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2332 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2334 wassertl (0, "Left and the result are in bit space");
2337 size = AOP_SIZE (IC_RESULT (ic));
2340 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2343 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2346 /* release the aops */
2347 freeAsmop (IC_LEFT (ic), NULL, ic);
2348 freeAsmop (IC_RESULT (ic), NULL, ic);
2352 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2359 store de into result
2364 store de into result
2366 const char *first = isAdd ? "add" : "sub";
2367 const char *later = isAdd ? "adc" : "sbc";
2369 wassertl (IS_GB, "Code is only relevent to the gbz80");
2370 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2372 fetchPair (PAIR_DE, left);
2375 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2378 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2381 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2382 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2384 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2385 aopGet (right, MSB24, FALSE);
2389 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2392 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2394 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2395 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2399 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2401 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2404 /*-----------------------------------------------------------------*/
2405 /* genUminusFloat - unary minus for floating points */
2406 /*-----------------------------------------------------------------*/
2408 genUminusFloat (operand * op, operand * result)
2410 int size, offset = 0;
2412 emitDebug("; genUminusFloat");
2414 /* for this we just need to flip the
2415 first bit then copy the rest in place */
2416 size = AOP_SIZE (op) - 1;
2418 _moveA(aopGet (AOP (op), MSB32, FALSE));
2420 emit2("xor a,!immedbyte", 0x80);
2421 aopPut (AOP (result), "a", MSB32);
2425 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2430 /*-----------------------------------------------------------------*/
2431 /* genUminus - unary minus code generation */
2432 /*-----------------------------------------------------------------*/
2434 genUminus (iCode * ic)
2437 sym_link *optype, *rtype;
2440 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2441 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2443 /* if both in bit space then special
2445 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2446 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2448 wassertl (0, "Left and right are in bit space");
2452 optype = operandType (IC_LEFT (ic));
2453 rtype = operandType (IC_RESULT (ic));
2455 /* if float then do float stuff */
2456 if (IS_FLOAT (optype))
2458 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2462 /* otherwise subtract from zero */
2463 size = AOP_SIZE (IC_LEFT (ic));
2465 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2467 /* Create a new asmop with value zero */
2468 asmop *azero = newAsmop (AOP_SIMPLELIT);
2469 azero->aopu.aop_simplelit = 0;
2471 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2479 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2480 emit2 ("ld a,!zero");
2481 emit2 ("sbc a,%s", l);
2482 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2485 /* if any remaining bytes in the result */
2486 /* we just need to propagate the sign */
2487 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2492 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2496 /* release the aops */
2497 freeAsmop (IC_LEFT (ic), NULL, ic);
2498 freeAsmop (IC_RESULT (ic), NULL, ic);
2501 /*-----------------------------------------------------------------*/
2502 /* assignResultValue - */
2503 /*-----------------------------------------------------------------*/
2505 assignResultValue (operand * oper)
2507 int size = AOP_SIZE (oper);
2510 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2511 topInA = requiresHL (AOP (oper));
2513 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2515 /* We do it the hard way here. */
2517 aopPut (AOP (oper), _fReturn[0], 0);
2518 aopPut (AOP (oper), _fReturn[1], 1);
2520 aopPut (AOP (oper), _fReturn[0], 2);
2521 aopPut (AOP (oper), _fReturn[1], 3);
2525 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2526 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2529 _emitMove ("a", _fReturn[size-1]);
2530 _emitMove (_fReturn[size-1], _fReturn[size]);
2531 _emitMove (_fReturn[size], "a");
2532 aopPut (AOP (oper), _fReturn[size], size-1);
2537 aopPut (AOP (oper), _fReturn[size], size);
2542 /** Simple restore that doesn't take into account what is used in the
2546 _restoreRegsAfterCall(void)
2548 if (_G.stack.pushedDE)
2551 _G.stack.pushedDE = FALSE;
2553 if (_G.stack.pushedBC)
2556 _G.stack.pushedBC = FALSE;
2558 _G.saves.saved = FALSE;
2562 _saveRegsForCall(iCode *ic, int sendSetSize)
2565 o Stack parameters are pushed before this function enters
2566 o DE and BC may be used in this function.
2567 o HL and DE may be used to return the result.
2568 o HL and DE may be used to send variables.
2569 o DE and BC may be used to store the result value.
2570 o HL may be used in computing the sent value of DE
2571 o The iPushes for other parameters occur before any addSets
2573 Logic: (to be run inside the first iPush or if none, before sending)
2574 o Compute if DE and/or BC are in use over the call
2575 o Compute if DE is used in the send set
2576 o Compute if DE and/or BC are used to hold the result value
2577 o If (DE is used, or in the send set) and is not used in the result, push.
2578 o If BC is used and is not in the result, push
2580 o If DE is used in the send set, fetch
2581 o If HL is used in the send set, fetch
2585 if (_G.saves.saved == FALSE) {
2586 bool deInUse, bcInUse;
2588 bool bcInRet = FALSE, deInRet = FALSE;
2591 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2592 z80_rUmaskForOp (IC_RESULT(ic)));
2594 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2595 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2597 deSending = (sendSetSize > 1);
2599 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2601 if (bcInUse && bcInRet == FALSE) {
2603 _G.stack.pushedBC = TRUE;
2605 if (deInUse && deInRet == FALSE) {
2607 _G.stack.pushedDE = TRUE;
2610 _G.saves.saved = TRUE;
2613 /* Already saved. */
2617 /*-----------------------------------------------------------------*/
2618 /* genIpush - genrate code for pushing this gets a little complex */
2619 /*-----------------------------------------------------------------*/
2621 genIpush (iCode * ic)
2623 int size, offset = 0;
2626 /* if this is not a parm push : ie. it is spill push
2627 and spill push is always done on the local stack */
2630 wassertl(0, "Encountered an unsupported spill push.");
2634 if (_G.saves.saved == FALSE) {
2635 /* Caller saves, and this is the first iPush. */
2636 /* Scan ahead until we find the function that we are pushing parameters to.
2637 Count the number of addSets on the way to figure out what registers
2638 are used in the send set.
2641 iCode *walk = ic->next;
2644 if (walk->op == SEND) {
2647 else if (walk->op == CALL || walk->op == PCALL) {
2656 _saveRegsForCall(walk, nAddSets);
2659 /* Already saved by another iPush. */
2662 /* then do the push */
2663 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2665 size = AOP_SIZE (IC_LEFT (ic));
2667 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2669 _G.stack.pushed += 2;
2670 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2676 fetchHL (AOP (IC_LEFT (ic)));
2678 spillPair (PAIR_HL);
2679 _G.stack.pushed += 2;
2684 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2686 spillPair (PAIR_HL);
2687 _G.stack.pushed += 2;
2688 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2690 spillPair (PAIR_HL);
2691 _G.stack.pushed += 2;
2697 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2699 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2701 emit2 ("ld a,(%s)", l);
2705 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2706 emit2 ("ld a,%s", l);
2714 freeAsmop (IC_LEFT (ic), NULL, ic);
2717 /*-----------------------------------------------------------------*/
2718 /* genIpop - recover the registers: can happen only for spilling */
2719 /*-----------------------------------------------------------------*/
2721 genIpop (iCode * ic)
2726 /* if the temp was not pushed then */
2727 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2730 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2731 size = AOP_SIZE (IC_LEFT (ic));
2732 offset = (size - 1);
2733 if (isPair (AOP (IC_LEFT (ic))))
2735 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2743 spillPair (PAIR_HL);
2744 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2748 freeAsmop (IC_LEFT (ic), NULL, ic);
2751 /* This is quite unfortunate */
2753 setArea (int inHome)
2756 static int lastArea = 0;
2758 if (_G.in_home != inHome) {
2760 const char *sz = port->mem.code_name;
2761 port->mem.code_name = "HOME";
2762 emit2("!area", CODE_NAME);
2763 port->mem.code_name = sz;
2766 emit2("!area", CODE_NAME); */
2767 _G.in_home = inHome;
2778 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2782 symbol *sym = OP_SYMBOL (op);
2784 if (sym->isspilt || sym->nRegs == 0)
2787 aopOp (op, ic, FALSE, FALSE);
2790 if (aop->type == AOP_REG)
2793 for (i = 0; i < aop->size; i++)
2795 if (pairId == PAIR_DE)
2797 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2798 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2800 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2803 else if (pairId == PAIR_BC)
2805 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2806 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2808 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2818 freeAsmop (IC_LEFT (ic), NULL, ic);
2822 /** Emit the code for a call statement
2825 emitCall (iCode * ic, bool ispcall)
2827 bool bInRet, cInRet, dInRet, eInRet;
2828 sym_link *dtype = operandType (IC_LEFT (ic));
2830 /* if caller saves & we have not saved then */
2836 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2838 /* if send set is not empty then assign */
2843 int nSend = elementsInSet(_G.sendSet);
2844 bool swapped = FALSE;
2846 int _z80_sendOrder[] = {
2851 /* Check if the parameters are swapped. If so route through hl instead. */
2852 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2854 sic = setFirstItem(_G.sendSet);
2855 sic = setNextItem(_G.sendSet);
2857 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2858 /* The second send value is loaded from one the one that holds the first
2859 send, i.e. it is overwritten. */
2860 /* Cache the first in HL, and load the second from HL instead. */
2861 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2862 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2868 for (sic = setFirstItem (_G.sendSet); sic;
2869 sic = setNextItem (_G.sendSet))
2872 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2874 size = AOP_SIZE (IC_LEFT (sic));
2875 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2876 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2878 // PENDING: Mild hack
2879 if (swapped == TRUE && send == 1) {
2881 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2884 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2886 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2889 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2893 freeAsmop (IC_LEFT (sic), NULL, sic);
2900 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2902 werror (W_INDIR_BANKED);
2904 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2906 if (isLitWord (AOP (IC_LEFT (ic))))
2908 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2912 symbol *rlbl = newiTempLabel (NULL);
2913 spillPair (PAIR_HL);
2914 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2916 _G.stack.pushed += 2;
2918 fetchHL (AOP (IC_LEFT (ic)));
2920 emit2 ("!tlabeldef", (rlbl->key + 100));
2921 _G.lines.current->isLabel = 1;
2922 _G.stack.pushed -= 2;
2924 freeAsmop (IC_LEFT (ic), NULL, ic);
2928 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2929 OP_SYMBOL (IC_LEFT (ic))->rname :
2930 OP_SYMBOL (IC_LEFT (ic))->name;
2931 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2933 emit2 ("call banked_call");
2934 emit2 ("!dws", name);
2935 emit2 ("!dw !bankimmeds", name);
2940 emit2 ("call %s", name);
2945 /* Mark the registers as restored. */
2946 _G.saves.saved = FALSE;
2948 /* if we need assign a result value */
2949 if ((IS_ITEMP (IC_RESULT (ic)) &&
2950 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2951 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2952 IS_TRUE_SYMOP (IC_RESULT (ic)))
2955 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2957 assignResultValue (IC_RESULT (ic));
2959 freeAsmop (IC_RESULT (ic), NULL, ic);
2962 /* adjust the stack for parameters if required */
2965 int i = ic->parmBytes;
2967 _G.stack.pushed -= i;
2970 emit2 ("!ldaspsp", i);
2977 emit2 ("ld iy,!immedword", i);
2978 emit2 ("add iy,sp");
2999 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3000 bInRet = bitVectBitValue(result, B_IDX);
3001 cInRet = bitVectBitValue(result, C_IDX);
3002 dInRet = bitVectBitValue(result, D_IDX);
3003 eInRet = bitVectBitValue(result, E_IDX);
3013 if (_G.stack.pushedDE)
3015 if (dInRet && eInRet)
3017 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3021 /* Only restore E */
3028 /* Only restore D */
3036 _G.stack.pushedDE = FALSE;
3039 if (_G.stack.pushedBC)
3041 if (bInRet && cInRet)
3043 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3047 /* Only restore C */
3054 /* Only restore B */
3062 _G.stack.pushedBC = FALSE;
3066 /*-----------------------------------------------------------------*/
3067 /* genCall - generates a call statement */
3068 /*-----------------------------------------------------------------*/
3070 genCall (iCode * ic)
3072 emitCall (ic, FALSE);
3075 /*-----------------------------------------------------------------*/
3076 /* genPcall - generates a call by pointer statement */
3077 /*-----------------------------------------------------------------*/
3079 genPcall (iCode * ic)
3081 emitCall (ic, TRUE);
3084 /*-----------------------------------------------------------------*/
3085 /* resultRemat - result is rematerializable */
3086 /*-----------------------------------------------------------------*/
3088 resultRemat (iCode * ic)
3090 if (SKIP_IC (ic) || ic->op == IFX)
3093 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3095 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3096 if (sym->remat && !POINTER_SET (ic))
3103 extern set *publics;
3105 /*-----------------------------------------------------------------*/
3106 /* genFunction - generated code for function entry */
3107 /*-----------------------------------------------------------------*/
3109 genFunction (iCode * ic)
3113 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3116 bool bcInUse = FALSE;
3117 bool deInUse = FALSE;
3119 setArea (IFFUNC_NONBANKED (sym->type));
3121 /* PENDING: Reset the receive offset as it
3122 doesn't seem to get reset anywhere else.
3124 _G.receiveOffset = 0;
3126 /* Record the last function name for debugging. */
3127 _G.lastFunctionName = sym->rname;
3129 /* Create the function header */
3130 emit2 ("!functionheader", sym->name);
3131 if (!IS_STATIC(sym->etype))
3133 sprintf (buffer, "%s_start", sym->rname);
3134 emit2 ("!labeldef", buffer);
3135 _G.lines.current->isLabel = 1;
3137 emit2 ("!functionlabeldef", sym->rname);
3138 _G.lines.current->isLabel = 1;
3140 ftype = operandType (IC_LEFT (ic));
3142 if (IFFUNC_ISNAKED(ftype))
3144 emitDebug("; naked function: no prologue.");
3148 /* if this is an interrupt service routine
3149 then save all potentially used registers. */
3150 if (IFFUNC_ISISR (sym->type))
3152 /* If critical function then turn interrupts off */
3153 /* except when no interrupt number is given then it implies the NMI handler */
3154 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3163 /* This is a non-ISR function.
3164 If critical function then turn interrupts off */
3165 if (IFFUNC_ISCRITICAL (sym->type))
3173 //get interrupt enable flag IFF2 into P/O
3182 if (options.profile)
3184 emit2 ("!profileenter");
3187 /* PENDING: callee-save etc */
3189 _G.stack.param_offset = 0;
3191 if (z80_opts.calleeSavesBC)
3196 /* Detect which registers are used. */
3197 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3200 for (i = 0; i < sym->regsUsed->size; i++)
3202 if (bitVectBitValue (sym->regsUsed, i))
3216 /* Other systems use DE as a temporary. */
3227 _G.stack.param_offset += 2;
3230 _G.calleeSaves.pushedBC = bcInUse;
3235 _G.stack.param_offset += 2;
3238 _G.calleeSaves.pushedDE = deInUse;
3240 /* adjust the stack for the function */
3241 _G.stack.last = sym->stack;
3244 for (sym = setFirstItem (istack->syms); sym;
3245 sym = setNextItem (istack->syms))
3247 if (sym->_isparm && !IS_REGPARM (sym->etype))
3253 sym = OP_SYMBOL (IC_LEFT (ic));
3255 _G.omitFramePtr = options.ommitFramePtr;
3256 if (IS_Z80 && !stackParm && !sym->stack)
3258 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3259 /* the above !sym->stack condition can be removed. -- EEP */
3261 emit2 ("!ldaspsp", -sym->stack);
3262 _G.omitFramePtr = TRUE;
3264 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3265 emit2 ("!enterxl", sym->stack);
3266 else if (sym->stack)
3267 emit2 ("!enterx", sym->stack);
3271 _G.stack.offset = sym->stack;
3274 /*-----------------------------------------------------------------*/
3275 /* genEndFunction - generates epilogue for functions */
3276 /*-----------------------------------------------------------------*/
3278 genEndFunction (iCode * ic)
3280 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3282 if (IFFUNC_ISNAKED(sym->type))
3284 emitDebug("; naked function: no epilogue.");
3288 /* PENDING: calleeSave */
3289 if (IS_Z80 && _G.omitFramePtr)
3291 if (_G.stack.offset)
3292 emit2 ("!ldaspsp", _G.stack.offset);
3294 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3296 emit2 ("!leavexl", _G.stack.offset);
3298 else if (_G.stack.offset)
3300 emit2 ("!leavex", _G.stack.offset);
3307 if (_G.calleeSaves.pushedDE)
3310 _G.calleeSaves.pushedDE = FALSE;
3313 if (_G.calleeSaves.pushedBC)
3316 _G.calleeSaves.pushedBC = FALSE;
3319 if (options.profile)
3321 emit2 ("!profileexit");
3324 /* if this is an interrupt service routine
3325 then save all potentially used registers. */
3326 if (IFFUNC_ISISR (sym->type))
3330 /* If critical function then turn interrupts back on */
3331 /* except when no interrupt number is given then it implies the NMI handler */
3332 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3339 /* This is a non-ISR function.
3340 If critical function then turn interrupts back on */
3341 if (IFFUNC_ISCRITICAL (sym->type))
3349 symbol *tlbl = newiTempLabel (NULL);
3352 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3353 //don't enable interrupts as they were off before
3354 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3356 emit2 ("!tlabeldef", (tlbl->key + 100));
3357 _G.lines.current->isLabel = 1;
3362 if (options.debug && currFunc)
3364 debugFile->writeEndFunction (currFunc, ic, 1);
3367 if (IFFUNC_ISISR (sym->type))
3369 /* "critical interrupt" is used to imply NMI handler */
3370 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3377 /* Both banked and non-banked just ret */
3381 if (!IS_STATIC(sym->etype))
3383 sprintf (buffer, "%s_end", sym->rname);
3384 emit2 ("!labeldef", buffer);
3385 _G.lines.current->isLabel = 1;
3388 _G.flushStatics = 1;
3389 _G.stack.pushed = 0;
3390 _G.stack.offset = 0;
3393 /*-----------------------------------------------------------------*/
3394 /* genRet - generate code for return statement */
3395 /*-----------------------------------------------------------------*/
3400 /* Errk. This is a hack until I can figure out how
3401 to cause dehl to spill on a call */
3402 int size, offset = 0;
3404 /* if we have no return value then
3405 just generate the "ret" */
3409 /* we have something to return then
3410 move the return value into place */
3411 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3412 size = AOP_SIZE (IC_LEFT (ic));
3414 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3417 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3421 emit2 ("ld de,%s", l);
3425 emit2 ("ld hl,%s", l);
3431 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3435 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3437 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3438 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3444 l = aopGet (AOP (IC_LEFT (ic)), offset,
3446 if (strcmp (_fReturn[offset], l))
3447 emit2 ("ld %s,%s", _fReturn[offset], l);
3452 freeAsmop (IC_LEFT (ic), NULL, ic);
3455 /* generate a jump to the return label
3456 if the next is not the return statement */
3457 if (!(ic->next && ic->next->op == LABEL &&
3458 IC_LABEL (ic->next) == returnLabel))
3460 emit2 ("jp !tlabel", returnLabel->key + 100);
3463 /*-----------------------------------------------------------------*/
3464 /* genLabel - generates a label */
3465 /*-----------------------------------------------------------------*/
3467 genLabel (iCode * ic)
3469 /* special case never generate */
3470 if (IC_LABEL (ic) == entryLabel)
3473 emitLabel (IC_LABEL (ic)->key + 100);
3476 /*-----------------------------------------------------------------*/
3477 /* genGoto - generates a ljmp */
3478 /*-----------------------------------------------------------------*/
3480 genGoto (iCode * ic)
3482 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3485 /*-----------------------------------------------------------------*/
3486 /* genPlusIncr :- does addition with increment if possible */
3487 /*-----------------------------------------------------------------*/
3489 genPlusIncr (iCode * ic)
3491 unsigned int icount;
3492 unsigned int size = getDataSize (IC_RESULT (ic));
3493 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3495 /* will try to generate an increment */
3496 /* if the right side is not a literal
3498 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3501 emitDebug ("; genPlusIncr");
3503 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3505 /* If result is a pair */
3506 if (resultId != PAIR_INVALID)
3508 if (isLitWord (AOP (IC_LEFT (ic))))
3510 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3513 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3515 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3517 PAIR_ID freep = getFreePairId (ic);
3518 if (freep != PAIR_INVALID)
3520 fetchPair (freep, AOP (IC_RIGHT (ic)));
3521 emit2 ("add hl,%s", _pairs[freep].name);
3527 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3528 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3535 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3539 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3543 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3548 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3550 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3551 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3555 /* if the literal value of the right hand side
3556 is greater than 4 then it is not worth it */
3560 /* if increment 16 bits in register */
3561 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3567 symbol *tlbl = NULL;
3568 tlbl = newiTempLabel (NULL);
3571 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3574 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3577 emitLabel (tlbl->key + 100);
3581 /* if the sizes are greater than 1 then we cannot */
3582 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3583 AOP_SIZE (IC_LEFT (ic)) > 1)
3586 /* If the result is in a register then we can load then increment.
3588 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3590 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3593 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3598 /* we can if the aops of the left & result match or
3599 if they are in registers and the registers are the
3601 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3605 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3613 /*-----------------------------------------------------------------*/
3614 /* outBitAcc - output a bit in acc */
3615 /*-----------------------------------------------------------------*/
3617 outBitAcc (operand * result)
3619 symbol *tlbl = newiTempLabel (NULL);
3620 /* if the result is a bit */
3621 if (AOP_TYPE (result) == AOP_CRY)
3623 wassertl (0, "Tried to write A into a bit");
3627 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3628 emit2 ("ld a,!one");
3629 emitLabel (tlbl->key + 100);
3635 couldDestroyCarry (asmop *aop)
3639 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3648 shiftIntoPair (int idx, asmop *aop)
3650 PAIR_ID id = PAIR_INVALID;
3652 wassertl (IS_Z80, "Only implemented for the Z80");
3653 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3655 emitDebug ("; Shift into pair idx %u", idx);
3661 setupPair (PAIR_HL, aop, 0);
3666 setupPair (PAIR_IY, aop, 0);
3668 emit2 ("pop %s", _pairs[id].name);
3672 setupPair (PAIR_IY, aop, 0);
3675 wassertl (0, "Internal error - hit default case");
3678 aop->type = AOP_PAIRPTR;
3679 aop->aopu.aop_pairId = id;
3680 _G.pairs[id].offset = 0;
3681 _G.pairs[id].last_type = aop->type;
3685 setupToPreserveCarry (iCode * ic)
3687 asmop *left = AOP (IC_LEFT (ic));
3688 asmop *right = AOP (IC_RIGHT (ic));
3689 asmop *result = AOP (IC_RESULT (ic));
3691 wassert (left && right);
3695 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3697 shiftIntoPair (0, right);
3698 /* check result again, in case right == result */
3699 if (couldDestroyCarry (result))
3701 if (!isPairInUse (PAIR_DE, ic))
3702 shiftIntoPair (1, result);
3704 shiftIntoPair (2, result);
3707 else if (couldDestroyCarry (right))
3709 if (getPairId (result) == PAIR_HL)
3710 _G.preserveCarry = TRUE;
3712 shiftIntoPair (0, right);
3714 else if (couldDestroyCarry (result))
3716 shiftIntoPair (0, result);
3725 /*-----------------------------------------------------------------*/
3726 /* genPlus - generates code for addition */
3727 /*-----------------------------------------------------------------*/
3729 genPlus (iCode * ic)
3731 int size, offset = 0;
3733 /* special cases :- */
3735 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3736 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3737 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3739 /* Swap the left and right operands if:
3741 if literal, literal on the right or
3742 if left requires ACC or right is already
3745 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3746 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3747 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3749 operand *t = IC_RIGHT (ic);
3750 IC_RIGHT (ic) = IC_LEFT (ic);
3754 /* if both left & right are in bit
3756 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3757 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3760 wassertl (0, "Tried to add two bits");
3763 /* if left in bit space & right literal */
3764 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3765 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3767 /* Can happen I guess */
3768 wassertl (0, "Tried to add a bit to a literal");
3771 /* if I can do an increment instead
3772 of add then GOOD for ME */
3773 if (genPlusIncr (ic) == TRUE)
3776 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3778 size = getDataSize (IC_RESULT (ic));
3780 /* Special case when left and right are constant */
3781 if (isPair (AOP (IC_RESULT (ic))))
3784 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3785 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3787 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3793 sprintf (buffer, "#(%s + %s)", left, right);
3794 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3799 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3801 /* Fetch into HL then do the add */
3802 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3803 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3805 spillPair (PAIR_HL);
3807 if (left == PAIR_HL && right != PAIR_INVALID)
3809 emit2 ("add hl,%s", _pairs[right].name);
3812 else if (right == PAIR_HL && left != PAIR_INVALID)
3814 emit2 ("add hl,%s", _pairs[left].name);
3817 else if (right != PAIR_INVALID && right != PAIR_HL)
3819 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3820 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3823 else if (left != PAIR_INVALID && left != PAIR_HL)
3825 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3826 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3835 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3837 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3838 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3840 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3845 ld hl,sp+n trashes C so we can't afford to do it during an
3846 add with stack based variables. Worst case is:
3859 So you can't afford to load up hl if either left, right, or result
3860 is on the stack (*sigh*) The alt is:
3868 Combinations in here are:
3869 * If left or right are in bc then the loss is small - trap later
3870 * If the result is in bc then the loss is also small
3874 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3875 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3876 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3878 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3879 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3880 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3881 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3883 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3885 /* Swap left and right */
3886 operand *t = IC_RIGHT (ic);
3887 IC_RIGHT (ic) = IC_LEFT (ic);
3890 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3892 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3893 emit2 ("add hl,bc");
3897 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3898 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3899 emit2 ("add hl,de");
3901 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3907 /* Be paranoid on the GB with 4 byte variables due to how C
3908 can be trashed by lda hl,n(sp).
3910 _gbz80_emitAddSubLong (ic, TRUE);
3915 setupToPreserveCarry (ic);
3919 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3921 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3924 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3927 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3931 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3934 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3937 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3939 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3943 _G.preserveCarry = FALSE;
3944 freeAsmop (IC_LEFT (ic), NULL, ic);
3945 freeAsmop (IC_RIGHT (ic), NULL, ic);
3946 freeAsmop (IC_RESULT (ic), NULL, ic);
3949 /*-----------------------------------------------------------------*/
3950 /* genMinusDec :- does subtraction with deccrement if possible */
3951 /*-----------------------------------------------------------------*/
3953 genMinusDec (iCode * ic)
3955 unsigned int icount;
3956 unsigned int size = getDataSize (IC_RESULT (ic));
3958 /* will try to generate an increment */
3959 /* if the right side is not a literal we cannot */
3960 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3963 /* if the literal value of the right hand side
3964 is greater than 4 then it is not worth it */
3965 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3968 size = getDataSize (IC_RESULT (ic));
3970 /* if decrement 16 bits in register */
3971 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3972 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3975 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3979 /* If result is a pair */
3980 if (isPair (AOP (IC_RESULT (ic))))
3982 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3984 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3988 /* if increment 16 bits in register */
3989 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3993 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3996 emit2 ("dec %s", _getTempPairName());
3999 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4005 /* if the sizes are greater than 1 then we cannot */
4006 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4007 AOP_SIZE (IC_LEFT (ic)) > 1)
4010 /* we can if the aops of the left & result match or if they are in
4011 registers and the registers are the same */
4012 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4015 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4022 /*-----------------------------------------------------------------*/
4023 /* genMinus - generates code for subtraction */
4024 /*-----------------------------------------------------------------*/
4026 genMinus (iCode * ic)
4028 int size, offset = 0;
4029 unsigned long lit = 0L;
4031 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4032 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4033 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4035 /* special cases :- */
4036 /* if both left & right are in bit space */
4037 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4038 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4040 wassertl (0, "Tried to subtract two bits");
4044 /* if I can do an decrement instead of subtract then GOOD for ME */
4045 if (genMinusDec (ic) == TRUE)
4048 size = getDataSize (IC_RESULT (ic));
4050 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4055 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4059 /* Same logic as genPlus */
4062 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4063 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4064 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4066 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4067 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4068 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4069 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4071 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4072 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4074 if (left == PAIR_INVALID && right == PAIR_INVALID)
4079 else if (right == PAIR_INVALID)
4081 else if (left == PAIR_INVALID)
4084 fetchPair (left, AOP (IC_LEFT (ic)));
4085 /* Order is important. Right may be HL */
4086 fetchPair (right, AOP (IC_RIGHT (ic)));
4088 emit2 ("ld a,%s", _pairs[left].l);
4089 emit2 ("sub a,%s", _pairs[right].l);
4091 emit2 ("ld a,%s", _pairs[left].h);
4092 emit2 ("sbc a,%s", _pairs[right].h);
4094 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4096 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4098 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4104 /* Be paranoid on the GB with 4 byte variables due to how C
4105 can be trashed by lda hl,n(sp).
4107 _gbz80_emitAddSubLong (ic, FALSE);
4112 setupToPreserveCarry (ic);
4114 /* if literal, add a,#-lit, else normal subb */
4117 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4118 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4122 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4125 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4129 /* first add without previous c */
4131 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4133 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4135 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4138 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4139 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4140 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4142 wassertl (0, "Tried to subtract on a long pointer");
4146 _G.preserveCarry = FALSE;
4147 freeAsmop (IC_LEFT (ic), NULL, ic);
4148 freeAsmop (IC_RIGHT (ic), NULL, ic);
4149 freeAsmop (IC_RESULT (ic), NULL, ic);
4152 /*-----------------------------------------------------------------*/
4153 /* genMult - generates code for multiplication */
4154 /*-----------------------------------------------------------------*/
4156 genMult (iCode * ic)
4160 /* If true then the final operation should be a subtract */
4161 bool active = FALSE;
4164 /* Shouldn't occur - all done through function calls */
4165 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4166 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4167 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4169 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4171 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4172 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4173 AOP_SIZE (IC_RESULT (ic)) > 2)
4175 wassertl (0, "Multiplication is handled through support function calls");
4178 /* Swap left and right such that right is a literal */
4179 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4181 operand *t = IC_RIGHT (ic);
4182 IC_RIGHT (ic) = IC_LEFT (ic);
4186 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4188 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4189 // wassertl (val > 0, "Multiply must be positive");
4190 wassertl (val != 1, "Can't multiply by 1");
4192 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4194 _G.stack.pushedDE = TRUE;
4197 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4199 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4210 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4215 /* Fully unroled version of mul.s. Not the most efficient.
4217 for (count = 0; count < 16; count++)
4219 if (count != 0 && active)
4221 emit2 ("add hl,hl");
4225 if (active == FALSE)
4233 emit2 ("add hl,de");
4242 if (IS_Z80 && _G.stack.pushedDE)
4245 _G.stack.pushedDE = FALSE;
4249 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4251 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4253 freeAsmop (IC_LEFT (ic), NULL, ic);
4254 freeAsmop (IC_RIGHT (ic), NULL, ic);
4255 freeAsmop (IC_RESULT (ic), NULL, ic);
4258 /*-----------------------------------------------------------------*/
4259 /* genDiv - generates code for division */
4260 /*-----------------------------------------------------------------*/
4264 /* Shouldn't occur - all done through function calls */
4265 wassertl (0, "Division is handled through support function calls");
4268 /*-----------------------------------------------------------------*/
4269 /* genMod - generates code for division */
4270 /*-----------------------------------------------------------------*/
4274 /* Shouldn't occur - all done through function calls */
4278 /*-----------------------------------------------------------------*/
4279 /* genIfxJump :- will create a jump depending on the ifx */
4280 /*-----------------------------------------------------------------*/
4282 genIfxJump (iCode * ic, char *jval)
4287 /* if true label then we jump if condition
4291 jlbl = IC_TRUE (ic);
4292 if (!strcmp (jval, "a"))
4296 else if (!strcmp (jval, "c"))
4300 else if (!strcmp (jval, "nc"))
4304 else if (!strcmp (jval, "m"))
4308 else if (!strcmp (jval, "p"))
4314 /* The buffer contains the bit on A that we should test */
4320 /* false label is present */
4321 jlbl = IC_FALSE (ic);
4322 if (!strcmp (jval, "a"))
4326 else if (!strcmp (jval, "c"))
4330 else if (!strcmp (jval, "nc"))
4334 else if (!strcmp (jval, "m"))
4338 else if (!strcmp (jval, "p"))
4344 /* The buffer contains the bit on A that we should test */
4348 /* Z80 can do a conditional long jump */
4349 if (!strcmp (jval, "a"))
4353 else if (!strcmp (jval, "c"))
4356 else if (!strcmp (jval, "nc"))
4359 else if (!strcmp (jval, "m"))
4362 else if (!strcmp (jval, "p"))
4367 emit2 ("bit %s,a", jval);
4369 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4371 /* mark the icode as generated */
4377 _getPairIdName (PAIR_ID id)
4379 return _pairs[id].name;
4384 /* if unsigned char cmp with lit, just compare */
4386 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4388 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4391 emit2 ("xor a,!immedbyte", 0x80);
4392 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4395 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4397 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4399 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4400 // Pull left into DE and right into HL
4401 aopGet (AOP(left), LSB, FALSE);
4404 aopGet (AOP(right), LSB, FALSE);
4408 if (size == 0 && sign)
4410 // Highest byte when signed needs the bits flipped
4413 emit2 ("ld a,(de)");
4414 emit2 ("xor !immedbyte", 0x80);
4416 emit2 ("ld a,(hl)");
4417 emit2 ("xor !immedbyte", 0x80);
4421 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4425 emit2 ("ld a,(de)");
4426 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4436 spillPair (PAIR_HL);
4438 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4440 setupPair (PAIR_HL, AOP (left), 0);
4441 aopGet (AOP(right), LSB, FALSE);
4445 if (size == 0 && sign)
4447 // Highest byte when signed needs the bits flipped
4450 emit2 ("ld a,(hl)");
4451 emit2 ("xor !immedbyte", 0x80);
4453 emit2 ("ld a,%d(iy)", offset);
4454 emit2 ("xor !immedbyte", 0x80);
4458 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4462 emit2 ("ld a,(hl)");
4463 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4472 spillPair (PAIR_HL);
4473 spillPair (PAIR_IY);
4477 if (AOP_TYPE (right) == AOP_LIT)
4479 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4480 /* optimize if(x < 0) or if(x >= 0) */
4485 /* No sign so it's always false */
4490 /* Just load in the top most bit */
4491 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4492 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4494 genIfxJump (ifx, "7");
4506 /* First setup h and l contaning the top most bytes XORed */
4507 bool fDidXor = FALSE;
4508 if (AOP_TYPE (left) == AOP_LIT)
4510 unsigned long lit = (unsigned long)
4511 floatFromVal (AOP (left)->aopu.aop_lit);
4512 emit2 ("ld %s,!immedbyte", _fTmp[0],
4513 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4517 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4518 emit2 ("xor a,!immedbyte", 0x80);
4519 emit2 ("ld %s,a", _fTmp[0]);
4522 if (AOP_TYPE (right) == AOP_LIT)
4524 unsigned long lit = (unsigned long)
4525 floatFromVal (AOP (right)->aopu.aop_lit);
4526 emit2 ("ld %s,!immedbyte", _fTmp[1],
4527 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4531 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4532 emit2 ("xor a,!immedbyte", 0x80);
4533 emit2 ("ld %s,a", _fTmp[1]);
4539 /* Do a long subtract */
4542 _moveA (aopGet (AOP (left), offset, FALSE));
4544 if (sign && size == 0)
4546 emit2 ("ld a,%s", _fTmp[0]);
4547 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4551 /* Subtract through, propagating the carry */
4552 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4560 /** Generic compare for > or <
4563 genCmp (operand * left, operand * right,
4564 operand * result, iCode * ifx, int sign)
4566 int size, offset = 0;
4567 unsigned long lit = 0L;
4568 bool swap_sense = FALSE;
4570 /* if left & right are bit variables */
4571 if (AOP_TYPE (left) == AOP_CRY &&
4572 AOP_TYPE (right) == AOP_CRY)
4574 /* Cant happen on the Z80 */
4575 wassertl (0, "Tried to compare two bits");
4579 /* Do a long subtract of right from left. */
4580 size = max (AOP_SIZE (left), AOP_SIZE (right));
4582 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4584 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4585 // Pull left into DE and right into HL
4586 aopGet (AOP(left), LSB, FALSE);
4589 aopGet (AOP(right), LSB, FALSE);
4593 emit2 ("ld a,(de)");
4594 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4603 spillPair (PAIR_HL);
4607 if (AOP_TYPE (right) == AOP_LIT)
4609 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4610 /* optimize if(x < 0) or if(x >= 0) */
4615 /* No sign so it's always false */
4620 /* Just load in the top most bit */
4621 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4622 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4624 genIfxJump (ifx, "7");
4635 genIfxJump (ifx, swap_sense ? "c" : "nc");
4646 _moveA (aopGet (AOP (left), offset, FALSE));
4647 /* Subtract through, propagating the carry */
4648 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4654 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4658 /* Shift the sign bit up into carry */
4661 outBitCLong (result, swap_sense);
4665 /* if the result is used in the next
4666 ifx conditional branch then generate
4667 code a little differently */
4675 genIfxJump (ifx, swap_sense ? "nc" : "c");
4679 genIfxJump (ifx, swap_sense ? "p" : "m");
4684 genIfxJump (ifx, swap_sense ? "nc" : "c");
4691 /* Shift the sign bit up into carry */
4694 outBitCLong (result, swap_sense);
4696 /* leave the result in acc */
4700 /*-----------------------------------------------------------------*/
4701 /* genCmpGt :- greater than comparison */
4702 /*-----------------------------------------------------------------*/
4704 genCmpGt (iCode * ic, iCode * ifx)
4706 operand *left, *right, *result;
4707 sym_link *letype, *retype;
4710 left = IC_LEFT (ic);
4711 right = IC_RIGHT (ic);
4712 result = IC_RESULT (ic);
4714 letype = getSpec (operandType (left));
4715 retype = getSpec (operandType (right));
4716 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4717 /* assign the amsops */
4718 aopOp (left, ic, FALSE, FALSE);
4719 aopOp (right, ic, FALSE, FALSE);
4720 aopOp (result, ic, TRUE, FALSE);
4722 genCmp (right, left, result, ifx, sign);
4724 freeAsmop (left, NULL, ic);
4725 freeAsmop (right, NULL, ic);
4726 freeAsmop (result, NULL, ic);
4729 /*-----------------------------------------------------------------*/
4730 /* genCmpLt - less than comparisons */
4731 /*-----------------------------------------------------------------*/
4733 genCmpLt (iCode * ic, iCode * ifx)
4735 operand *left, *right, *result;
4736 sym_link *letype, *retype;
4739 left = IC_LEFT (ic);
4740 right = IC_RIGHT (ic);
4741 result = IC_RESULT (ic);
4743 letype = getSpec (operandType (left));
4744 retype = getSpec (operandType (right));
4745 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4747 /* assign the amsops */
4748 aopOp (left, ic, FALSE, FALSE);
4749 aopOp (right, ic, FALSE, FALSE);
4750 aopOp (result, ic, TRUE, FALSE);
4752 genCmp (left, right, result, ifx, sign);
4754 freeAsmop (left, NULL, ic);
4755 freeAsmop (right, NULL, ic);
4756 freeAsmop (result, NULL, ic);
4759 /*-----------------------------------------------------------------*/
4760 /* gencjneshort - compare and jump if not equal */
4761 /*-----------------------------------------------------------------*/
4763 gencjneshort (operand * left, operand * right, symbol * lbl)
4765 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4767 unsigned long lit = 0L;
4769 /* Swap the left and right if it makes the computation easier */
4770 if (AOP_TYPE (left) == AOP_LIT)
4777 if (AOP_TYPE (right) == AOP_LIT)
4779 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4782 /* if the right side is a literal then anything goes */
4783 if (AOP_TYPE (right) == AOP_LIT &&
4784 AOP_TYPE (left) != AOP_DIR)
4788 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4793 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4800 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4806 _moveA (aopGet (AOP (left), offset, FALSE));
4807 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4810 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4811 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4816 /* if the right side is in a register or in direct space or
4817 if the left is a pointer register & right is not */
4818 else if (AOP_TYPE (right) == AOP_REG ||
4819 AOP_TYPE (right) == AOP_DIR ||
4820 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4824 _moveA (aopGet (AOP (left), offset, FALSE));
4825 if (/*AOP_TYPE (left) == AOP_DIR &&*/ AOP_TYPE (right) == AOP_LIT &&
4826 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4829 /* MB: pending what? doesn't this need "or a,a"? */
4830 /* and I don't think AOP_TYPE(left) has anything to do with this */
4832 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4836 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4837 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4844 /* right is a pointer reg need both a & b */
4845 /* PENDING: is this required? */
4848 _moveA (aopGet (AOP (right), offset, FALSE));
4849 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4850 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4856 /*-----------------------------------------------------------------*/
4857 /* gencjne - compare and jump if not equal */
4858 /*-----------------------------------------------------------------*/
4860 gencjne (operand * left, operand * right, symbol * lbl)
4862 symbol *tlbl = newiTempLabel (NULL);
4864 gencjneshort (left, right, lbl);
4867 emit2 ("ld a,!one");
4868 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4869 emitLabel (lbl->key + 100);
4871 emitLabel (tlbl->key + 100);
4874 /*-----------------------------------------------------------------*/
4875 /* genCmpEq - generates code for equal to */
4876 /*-----------------------------------------------------------------*/
4878 genCmpEq (iCode * ic, iCode * ifx)
4880 operand *left, *right, *result;
4882 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4883 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4884 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4886 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4888 /* Swap operands if it makes the operation easier. ie if:
4889 1. Left is a literal.
4891 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4893 operand *t = IC_RIGHT (ic);
4894 IC_RIGHT (ic) = IC_LEFT (ic);
4898 if (ifx && !AOP_SIZE (result))
4901 /* if they are both bit variables */
4902 if (AOP_TYPE (left) == AOP_CRY &&
4903 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4905 wassertl (0, "Tried to compare two bits");
4909 tlbl = newiTempLabel (NULL);
4910 gencjneshort (left, right, tlbl);
4913 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4914 emitLabel (tlbl->key + 100);
4918 /* PENDING: do this better */
4919 symbol *lbl = newiTempLabel (NULL);
4920 emit2 ("!shortjp !tlabel", lbl->key + 100);
4921 emitLabel (tlbl->key + 100);
4922 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4923 emitLabel (lbl->key + 100);
4926 /* mark the icode as generated */
4931 /* if they are both bit variables */
4932 if (AOP_TYPE (left) == AOP_CRY &&
4933 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4935 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4941 gencjne (left, right, newiTempLabel (NULL));
4942 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4949 genIfxJump (ifx, "a");
4952 /* if the result is used in an arithmetic operation
4953 then put the result in place */
4954 if (AOP_TYPE (result) != AOP_CRY)
4959 /* leave the result in acc */
4963 freeAsmop (left, NULL, ic);
4964 freeAsmop (right, NULL, ic);
4965 freeAsmop (result, NULL, ic);
4968 /*-----------------------------------------------------------------*/
4969 /* ifxForOp - returns the icode containing the ifx for operand */
4970 /*-----------------------------------------------------------------*/
4972 ifxForOp (operand * op, iCode * ic)
4974 /* if true symbol then needs to be assigned */
4975 if (IS_TRUE_SYMOP (op))
4978 /* if this has register type condition and
4979 the next instruction is ifx with the same operand
4980 and live to of the operand is upto the ifx only then */
4982 ic->next->op == IFX &&
4983 IC_COND (ic->next)->key == op->key &&
4984 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4990 /*-----------------------------------------------------------------*/
4991 /* genAndOp - for && operation */
4992 /*-----------------------------------------------------------------*/
4994 genAndOp (iCode * ic)
4996 operand *left, *right, *result;
4999 /* note here that && operations that are in an if statement are
5000 taken away by backPatchLabels only those used in arthmetic
5001 operations remain */
5002 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5003 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5004 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5006 /* if both are bit variables */
5007 if (AOP_TYPE (left) == AOP_CRY &&
5008 AOP_TYPE (right) == AOP_CRY)
5010 wassertl (0, "Tried to and two bits");
5014 tlbl = newiTempLabel (NULL);
5016 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5018 emitLabel (tlbl->key + 100);
5022 freeAsmop (left, NULL, ic);
5023 freeAsmop (right, NULL, ic);
5024 freeAsmop (result, NULL, ic);
5027 /*-----------------------------------------------------------------*/
5028 /* genOrOp - for || operation */
5029 /*-----------------------------------------------------------------*/
5031 genOrOp (iCode * ic)
5033 operand *left, *right, *result;
5036 /* note here that || operations that are in an
5037 if statement are taken away by backPatchLabels
5038 only those used in arthmetic operations remain */
5039 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5040 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5041 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5043 /* if both are bit variables */
5044 if (AOP_TYPE (left) == AOP_CRY &&
5045 AOP_TYPE (right) == AOP_CRY)
5047 wassertl (0, "Tried to OR two bits");
5051 tlbl = newiTempLabel (NULL);
5053 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5055 emitLabel (tlbl->key + 100);
5059 freeAsmop (left, NULL, ic);
5060 freeAsmop (right, NULL, ic);
5061 freeAsmop (result, NULL, ic);
5064 /*-----------------------------------------------------------------*/
5065 /* isLiteralBit - test if lit == 2^n */
5066 /*-----------------------------------------------------------------*/
5068 isLiteralBit (unsigned long lit)
5070 unsigned long pw[32] =
5071 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5072 0x100L, 0x200L, 0x400L, 0x800L,
5073 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5074 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5075 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5076 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5077 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5080 for (idx = 0; idx < 32; idx++)
5086 /*-----------------------------------------------------------------*/
5087 /* jmpTrueOrFalse - */
5088 /*-----------------------------------------------------------------*/
5090 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5092 // ugly but optimized by peephole
5095 symbol *nlbl = newiTempLabel (NULL);
5096 emit2 ("jp !tlabel", nlbl->key + 100);
5097 emitLabel (tlbl->key + 100);
5098 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5099 emitLabel (nlbl->key + 100);
5103 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5104 emitLabel (tlbl->key + 100);
5109 /*-----------------------------------------------------------------*/
5110 /* genAnd - code for and */
5111 /*-----------------------------------------------------------------*/
5113 genAnd (iCode * ic, iCode * ifx)
5115 operand *left, *right, *result;
5116 int size, offset = 0;
5117 unsigned long lit = 0L;
5120 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5121 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5122 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5124 /* if left is a literal & right is not then exchange them */
5125 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5126 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5128 operand *tmp = right;
5133 /* if result = right then exchange them */
5134 if (sameRegs (AOP (result), AOP (right)))
5136 operand *tmp = right;
5141 /* if right is bit then exchange them */
5142 if (AOP_TYPE (right) == AOP_CRY &&
5143 AOP_TYPE (left) != AOP_CRY)
5145 operand *tmp = right;
5149 if (AOP_TYPE (right) == AOP_LIT)
5150 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5152 size = AOP_SIZE (result);
5154 if (AOP_TYPE (left) == AOP_CRY)
5156 wassertl (0, "Tried to perform an AND with a bit as an operand");
5160 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5161 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5162 if ((AOP_TYPE (right) == AOP_LIT) &&
5163 (AOP_TYPE (result) == AOP_CRY) &&
5164 (AOP_TYPE (left) != AOP_CRY))
5166 symbol *tlbl = newiTempLabel (NULL);
5167 int sizel = AOP_SIZE (left);
5170 /* PENDING: Test case for this. */
5175 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5177 _moveA (aopGet (AOP (left), offset, FALSE));
5178 if (bytelit != 0x0FFL)
5180 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5187 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5191 // bit = left & literal
5195 emit2 ("!tlabeldef", tlbl->key + 100);
5196 _G.lines.current->isLabel = 1;
5198 // if(left & literal)
5203 jmpTrueOrFalse (ifx, tlbl);
5211 /* if left is same as result */
5212 if (sameRegs (AOP (result), AOP (left)))
5214 for (; size--; offset++)
5216 if (AOP_TYPE (right) == AOP_LIT)
5218 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5223 aopPut (AOP (result), "!zero", offset);
5226 _moveA (aopGet (AOP (left), offset, FALSE));
5228 aopGet (AOP (right), offset, FALSE));
5229 aopPut (AOP (left), "a", offset);
5236 if (AOP_TYPE (left) == AOP_ACC)
5238 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5242 _moveA (aopGet (AOP (left), offset, FALSE));
5244 aopGet (AOP (right), offset, FALSE));
5245 aopPut (AOP (left), "a", offset);
5252 // left & result in different registers
5253 if (AOP_TYPE (result) == AOP_CRY)
5255 wassertl (0, "Tried to AND where the result is in carry");
5259 for (; (size--); offset++)
5262 // result = left & right
5263 if (AOP_TYPE (right) == AOP_LIT)
5265 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5267 aopPut (AOP (result),
5268 aopGet (AOP (left), offset, FALSE),
5272 else if (bytelit == 0)
5274 aopPut (AOP (result), "!zero", offset);
5278 // faster than result <- left, anl result,right
5279 // and better if result is SFR
5280 if (AOP_TYPE (left) == AOP_ACC)
5281 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5284 _moveA (aopGet (AOP (left), offset, FALSE));
5286 aopGet (AOP (right), offset, FALSE));
5288 aopPut (AOP (result), "a", offset);
5295 freeAsmop (left, NULL, ic);
5296 freeAsmop (right, NULL, ic);
5297 freeAsmop (result, NULL, ic);
5300 /*-----------------------------------------------------------------*/
5301 /* genOr - code for or */
5302 /*-----------------------------------------------------------------*/
5304 genOr (iCode * ic, iCode * ifx)
5306 operand *left, *right, *result;
5307 int size, offset = 0;
5308 unsigned long lit = 0L;
5311 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5312 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5313 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5315 /* if left is a literal & right is not then exchange them */
5316 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5317 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5319 operand *tmp = right;
5324 /* if result = right then exchange them */
5325 if (sameRegs (AOP (result), AOP (right)))
5327 operand *tmp = right;
5332 /* if right is bit then exchange them */
5333 if (AOP_TYPE (right) == AOP_CRY &&
5334 AOP_TYPE (left) != AOP_CRY)
5336 operand *tmp = right;
5340 if (AOP_TYPE (right) == AOP_LIT)
5341 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5343 size = AOP_SIZE (result);
5345 if (AOP_TYPE (left) == AOP_CRY)
5347 wassertl (0, "Tried to OR where left is a bit");
5351 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5352 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5353 if ((AOP_TYPE (right) == AOP_LIT) &&
5354 (AOP_TYPE (result) == AOP_CRY) &&
5355 (AOP_TYPE (left) != AOP_CRY))
5357 symbol *tlbl = newiTempLabel (NULL);
5358 int sizel = AOP_SIZE (left);
5362 wassertl (0, "Result is assigned to a bit");
5364 /* PENDING: Modeled after the AND code which is inefficient. */
5367 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5369 _moveA (aopGet (AOP (left), offset, FALSE));
5370 /* OR with any literal is the same as OR with itself. */
5372 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5378 jmpTrueOrFalse (ifx, tlbl);
5383 /* if left is same as result */
5384 if (sameRegs (AOP (result), AOP (left)))
5386 for (; size--; offset++)
5388 if (AOP_TYPE (right) == AOP_LIT)
5390 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5394 _moveA (aopGet (AOP (left), offset, FALSE));
5396 aopGet (AOP (right), offset, FALSE));
5397 aopPut (AOP (result), "a", offset);
5402 if (AOP_TYPE (left) == AOP_ACC)
5403 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5406 _moveA (aopGet (AOP (left), offset, FALSE));
5408 aopGet (AOP (right), offset, FALSE));
5409 aopPut (AOP (result), "a", offset);
5416 // left & result in different registers
5417 if (AOP_TYPE (result) == AOP_CRY)
5419 wassertl (0, "Result of OR is in a bit");
5422 for (; (size--); offset++)
5425 // result = left & right
5426 if (AOP_TYPE (right) == AOP_LIT)
5428 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5430 aopPut (AOP (result),
5431 aopGet (AOP (left), offset, FALSE),
5436 // faster than result <- left, anl result,right
5437 // and better if result is SFR
5438 if (AOP_TYPE (left) == AOP_ACC)
5439 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5442 _moveA (aopGet (AOP (left), offset, FALSE));
5444 aopGet (AOP (right), offset, FALSE));
5446 aopPut (AOP (result), "a", offset);
5447 /* PENDING: something weird is going on here. Add exception. */
5448 if (AOP_TYPE (result) == AOP_ACC)
5454 freeAsmop (left, NULL, ic);
5455 freeAsmop (right, NULL, ic);
5456 freeAsmop (result, NULL, ic);
5459 /*-----------------------------------------------------------------*/
5460 /* genXor - code for xclusive or */
5461 /*-----------------------------------------------------------------*/
5463 genXor (iCode * ic, iCode * ifx)
5465 operand *left, *right, *result;
5466 int size, offset = 0;
5467 unsigned long lit = 0L;
5469 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5470 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5471 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5473 /* if left is a literal & right is not then exchange them */
5474 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5475 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5477 operand *tmp = right;
5482 /* if result = right then exchange them */
5483 if (sameRegs (AOP (result), AOP (right)))
5485 operand *tmp = right;
5490 /* if right is bit then exchange them */
5491 if (AOP_TYPE (right) == AOP_CRY &&
5492 AOP_TYPE (left) != AOP_CRY)
5494 operand *tmp = right;
5498 if (AOP_TYPE (right) == AOP_LIT)
5499 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5501 size = AOP_SIZE (result);
5503 if (AOP_TYPE (left) == AOP_CRY)
5505 wassertl (0, "Tried to XOR a bit");
5509 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5510 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5511 if ((AOP_TYPE (right) == AOP_LIT) &&
5512 (AOP_TYPE (result) == AOP_CRY) &&
5513 (AOP_TYPE (left) != AOP_CRY))
5515 symbol *tlbl = newiTempLabel (NULL);
5516 int sizel = AOP_SIZE (left);
5520 /* PENDING: Test case for this. */
5521 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5525 _moveA (aopGet (AOP (left), offset, FALSE));
5526 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5527 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5532 jmpTrueOrFalse (ifx, tlbl);
5536 wassertl (0, "Result of XOR was destined for a bit");
5541 /* if left is same as result */
5542 if (sameRegs (AOP (result), AOP (left)))
5544 for (; size--; offset++)
5546 if (AOP_TYPE (right) == AOP_LIT)
5548 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5552 _moveA (aopGet (AOP (left), offset, FALSE));
5554 aopGet (AOP (right), offset, FALSE));
5555 aopPut (AOP (result), "a", offset);
5560 if (AOP_TYPE (left) == AOP_ACC)
5562 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5566 _moveA (aopGet (AOP (left), offset, FALSE));
5568 aopGet (AOP (right), offset, FALSE));
5569 aopPut (AOP (result), "a", offset);
5576 // left & result in different registers
5577 if (AOP_TYPE (result) == AOP_CRY)
5579 wassertl (0, "Result of XOR is in a bit");
5582 for (; (size--); offset++)
5585 // result = left & right
5586 if (AOP_TYPE (right) == AOP_LIT)
5588 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5590 aopPut (AOP (result),
5591 aopGet (AOP (left), offset, FALSE),
5596 // faster than result <- left, anl result,right
5597 // and better if result is SFR
5598 if (AOP_TYPE (left) == AOP_ACC)
5600 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5604 _moveA (aopGet (AOP (left), offset, FALSE));
5606 aopGet (AOP (right), offset, FALSE));
5608 aopPut (AOP (result), "a", offset);
5613 freeAsmop (left, NULL, ic);
5614 freeAsmop (right, NULL, ic);
5615 freeAsmop (result, NULL, ic);
5618 /*-----------------------------------------------------------------*/
5619 /* genInline - write the inline code out */
5620 /*-----------------------------------------------------------------*/
5622 genInline (iCode * ic)
5624 char *buffer, *bp, *bp1;
5626 _G.lines.isInline += (!options.asmpeep);
5628 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5629 strcpy (buffer, IC_INLINE (ic));
5631 /* emit each line as a code */
5656 _G.lines.isInline -= (!options.asmpeep);
5660 /*-----------------------------------------------------------------*/
5661 /* genRRC - rotate right with carry */
5662 /*-----------------------------------------------------------------*/
5669 /*-----------------------------------------------------------------*/
5670 /* genRLC - generate code for rotate left with carry */
5671 /*-----------------------------------------------------------------*/
5678 /*-----------------------------------------------------------------*/
5679 /* genGetHbit - generates code get highest order bit */
5680 /*-----------------------------------------------------------------*/
5682 genGetHbit (iCode * ic)
5684 operand *left, *result;
5685 left = IC_LEFT (ic);
5686 result = IC_RESULT (ic);
5688 aopOp (left, ic, FALSE, FALSE);
5689 aopOp (result, ic, FALSE, FALSE);
5691 /* get the highest order byte into a */
5692 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5694 if (AOP_TYPE (result) == AOP_CRY)
5702 emit2 ("and a,!one");
5707 freeAsmop (left, NULL, ic);
5708 freeAsmop (result, NULL, ic);
5712 emitRsh2 (asmop *aop, int size, int is_signed)
5718 const char *l = aopGet (aop, size, FALSE);
5721 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5731 /*-----------------------------------------------------------------*/
5732 /* shiftR2Left2Result - shift right two bytes from left to result */
5733 /*-----------------------------------------------------------------*/
5735 shiftR2Left2Result (operand * left, int offl,
5736 operand * result, int offr,
5737 int shCount, int is_signed)
5740 symbol *tlbl, *tlbl1;
5742 movLeft2Result (left, offl, result, offr, 0);
5743 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5748 /* if (AOP(result)->type == AOP_REG) { */
5750 tlbl = newiTempLabel (NULL);
5751 tlbl1 = newiTempLabel (NULL);
5753 /* Left is already in result - so now do the shift */
5758 emitRsh2 (AOP (result), size, is_signed);
5763 emit2 ("ld a,!immedbyte+1", shCount);
5764 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5765 emitLabel (tlbl->key + 100);
5767 emitRsh2 (AOP (result), size, is_signed);
5769 emitLabel (tlbl1->key + 100);
5771 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5775 /*-----------------------------------------------------------------*/
5776 /* shiftL2Left2Result - shift left two bytes from left to result */
5777 /*-----------------------------------------------------------------*/
5779 shiftL2Left2Result (operand * left, int offl,
5780 operand * result, int offr, int shCount)
5782 if (sameRegs (AOP (result), AOP (left)) &&
5783 ((offl + MSB16) == offr))
5789 /* Copy left into result */
5790 movLeft2Result (left, offl, result, offr, 0);
5791 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5797 if (getPairId (AOP (result)) == PAIR_HL)
5801 emit2 ("add hl,hl");
5808 symbol *tlbl, *tlbl1;
5811 tlbl = newiTempLabel (NULL);
5812 tlbl1 = newiTempLabel (NULL);
5814 if (AOP (result)->type == AOP_REG)
5818 for (offset = 0; offset < size; offset++)
5820 l = aopGet (AOP (result), offset, FALSE);
5824 emit2 ("sla %s", l);
5835 /* Left is already in result - so now do the shift */
5838 emit2 ("ld a,!immedbyte+1", shCount);
5839 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5840 emitLabel (tlbl->key + 100);
5845 l = aopGet (AOP (result), offset, FALSE);
5849 emit2 ("sla %s", l);
5860 emitLabel (tlbl1->key + 100);
5862 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5868 /*-----------------------------------------------------------------*/
5869 /* AccRol - rotate left accumulator by known count */
5870 /*-----------------------------------------------------------------*/
5872 AccRol (int shCount)
5874 shCount &= 0x0007; // shCount : 0..7
5951 /*-----------------------------------------------------------------*/
5952 /* AccLsh - left shift accumulator by known count */
5953 /*-----------------------------------------------------------------*/
5955 AccLsh (int shCount)
5957 static const unsigned char SLMask[] =
5959 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5968 else if (shCount == 2)
5975 /* rotate left accumulator */
5977 /* and kill the lower order bits */
5978 emit2 ("and a,!immedbyte", SLMask[shCount]);
5983 /*-----------------------------------------------------------------*/
5984 /* shiftL1Left2Result - shift left one byte from left to result */
5985 /*-----------------------------------------------------------------*/
5987 shiftL1Left2Result (operand * left, int offl,
5988 operand * result, int offr, int shCount)
5991 l = aopGet (AOP (left), offl, FALSE);
5993 /* shift left accumulator */
5995 aopPut (AOP (result), "a", offr);
5999 /*-----------------------------------------------------------------*/
6000 /* genlshTwo - left shift two bytes by known amount */
6001 /*-----------------------------------------------------------------*/
6003 genlshTwo (operand * result, operand * left, int shCount)
6005 int size = AOP_SIZE (result);
6007 wassert (size == 2);
6009 /* if shCount >= 8 */
6017 movLeft2Result (left, LSB, result, MSB16, 0);
6018 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6019 aopPut (AOP (result), "!zero", LSB);
6023 movLeft2Result (left, LSB, result, MSB16, 0);
6024 aopPut (AOP (result), "!zero", 0);
6029 aopPut (AOP (result), "!zero", LSB);
6032 /* 0 <= shCount <= 7 */
6041 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6046 /*-----------------------------------------------------------------*/
6047 /* genlshOne - left shift a one byte quantity by known count */
6048 /*-----------------------------------------------------------------*/
6050 genlshOne (operand * result, operand * left, int shCount)
6052 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6055 /*-----------------------------------------------------------------*/
6056 /* genLeftShiftLiteral - left shifting by known count */
6057 /*-----------------------------------------------------------------*/
6059 genLeftShiftLiteral (operand * left,
6064 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6067 freeAsmop (right, NULL, ic);
6069 aopOp (left, ic, FALSE, FALSE);
6070 aopOp (result, ic, FALSE, FALSE);
6072 size = getSize (operandType (result));
6074 /* I suppose that the left size >= result size */
6076 if (shCount >= (size * 8))
6080 aopPut (AOP (result), "!zero", size);
6088 genlshOne (result, left, shCount);
6091 genlshTwo (result, left, shCount);
6094 wassertl (0, "Shifting of longs is currently unsupported");
6100 freeAsmop (left, NULL, ic);
6101 freeAsmop (result, NULL, ic);
6104 /*-----------------------------------------------------------------*/
6105 /* genLeftShift - generates code for left shifting */
6106 /*-----------------------------------------------------------------*/
6108 genLeftShift (iCode * ic)
6112 symbol *tlbl, *tlbl1;
6113 operand *left, *right, *result;
6115 right = IC_RIGHT (ic);
6116 left = IC_LEFT (ic);
6117 result = IC_RESULT (ic);
6119 aopOp (right, ic, FALSE, FALSE);
6121 /* if the shift count is known then do it
6122 as efficiently as possible */
6123 if (AOP_TYPE (right) == AOP_LIT)
6125 genLeftShiftLiteral (left, right, result, ic);
6129 /* shift count is unknown then we have to form a loop get the loop
6130 count in B : Note: we take only the lower order byte since
6131 shifting more that 32 bits make no sense anyway, ( the largest
6132 size of an object can be only 32 bits ) */
6133 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6135 freeAsmop (right, NULL, ic);
6136 aopOp (left, ic, FALSE, FALSE);
6137 aopOp (result, ic, FALSE, FALSE);
6139 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6142 /* now move the left to the result if they are not the
6145 if (!sameRegs (AOP (left), AOP (result)))
6148 size = AOP_SIZE (result);
6152 l = aopGet (AOP (left), offset, FALSE);
6153 aopPut (AOP (result), l, offset);
6158 tlbl = newiTempLabel (NULL);
6159 size = AOP_SIZE (result);
6161 tlbl1 = newiTempLabel (NULL);
6163 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6166 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6167 emitLabel (tlbl->key + 100);
6168 l = aopGet (AOP (result), offset, FALSE);
6172 l = aopGet (AOP (result), offset, FALSE);
6176 emit2 ("sla %s", l);
6184 emitLabel (tlbl1->key + 100);
6186 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6188 freeAsmop (left, NULL, ic);
6189 freeAsmop (result, NULL, ic);
6192 /*-----------------------------------------------------------------*/
6193 /* genrshOne - left shift two bytes by known amount != 0 */
6194 /*-----------------------------------------------------------------*/
6196 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6199 int size = AOP_SIZE (result);
6202 wassert (size == 1);
6203 wassert (shCount < 8);
6205 l = aopGet (AOP (left), 0, FALSE);
6207 if (AOP (result)->type == AOP_REG)
6209 aopPut (AOP (result), l, 0);
6210 l = aopGet (AOP (result), 0, FALSE);
6213 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6221 emit2 ("%s a", is_signed ? "sra" : "srl");
6223 aopPut (AOP (result), "a", 0);
6227 /*-----------------------------------------------------------------*/
6228 /* AccRsh - right shift accumulator by known count */
6229 /*-----------------------------------------------------------------*/
6231 AccRsh (int shCount)
6233 static const unsigned char SRMask[] =
6235 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6240 /* rotate right accumulator */
6241 AccRol (8 - shCount);
6242 /* and kill the higher order bits */
6243 emit2 ("and a,!immedbyte", SRMask[shCount]);
6247 /*-----------------------------------------------------------------*/
6248 /* shiftR1Left2Result - shift right one byte from left to result */
6249 /*-----------------------------------------------------------------*/
6251 shiftR1Left2Result (operand * left, int offl,
6252 operand * result, int offr,
6253 int shCount, int sign)
6255 _moveA (aopGet (AOP (left), offl, FALSE));
6260 emit2 ("%s a", sign ? "sra" : "srl");
6267 aopPut (AOP (result), "a", offr);
6270 /*-----------------------------------------------------------------*/
6271 /* genrshTwo - right shift two bytes by known amount */
6272 /*-----------------------------------------------------------------*/
6274 genrshTwo (operand * result, operand * left,
6275 int shCount, int sign)
6277 /* if shCount >= 8 */
6283 shiftR1Left2Result (left, MSB16, result, LSB,
6288 movLeft2Result (left, MSB16, result, LSB, sign);
6292 /* Sign extend the result */
6293 _moveA(aopGet (AOP (result), 0, FALSE));
6297 aopPut (AOP (result), ACC_NAME, MSB16);
6301 aopPut (AOP (result), "!zero", 1);
6304 /* 0 <= shCount <= 7 */
6307 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6311 /*-----------------------------------------------------------------*/
6312 /* genRightShiftLiteral - left shifting by known count */
6313 /*-----------------------------------------------------------------*/
6315 genRightShiftLiteral (operand * left,
6321 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6324 freeAsmop (right, NULL, ic);
6326 aopOp (left, ic, FALSE, FALSE);
6327 aopOp (result, ic, FALSE, FALSE);
6329 size = getSize (operandType (result));
6331 /* I suppose that the left size >= result size */
6333 if (shCount >= (size * 8)) {
6335 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6336 _moveA(aopGet (AOP (left), 0, FALSE));
6344 aopPut (AOP (result), s, size);
6351 genrshOne (result, left, shCount, sign);
6354 genrshTwo (result, left, shCount, sign);
6357 wassertl (0, "Asked to shift right a long which should be a function call");
6360 wassertl (0, "Entered default case in right shift delegate");
6363 freeAsmop (left, NULL, ic);
6364 freeAsmop (result, NULL, ic);
6367 /*-----------------------------------------------------------------*/
6368 /* genRightShift - generate code for right shifting */
6369 /*-----------------------------------------------------------------*/
6371 genRightShift (iCode * ic)
6373 operand *right, *left, *result;
6375 int size, offset, first = 1;
6379 symbol *tlbl, *tlbl1;
6381 /* if signed then we do it the hard way preserve the
6382 sign bit moving it inwards */
6383 retype = getSpec (operandType (IC_RESULT (ic)));
6385 is_signed = !SPEC_USIGN (retype);
6387 /* signed & unsigned types are treated the same : i.e. the
6388 signed is NOT propagated inwards : quoting from the
6389 ANSI - standard : "for E1 >> E2, is equivalent to division
6390 by 2**E2 if unsigned or if it has a non-negative value,
6391 otherwise the result is implementation defined ", MY definition
6392 is that the sign does not get propagated */
6394 right = IC_RIGHT (ic);
6395 left = IC_LEFT (ic);
6396 result = IC_RESULT (ic);
6398 aopOp (right, ic, FALSE, FALSE);
6400 /* if the shift count is known then do it
6401 as efficiently as possible */
6402 if (AOP_TYPE (right) == AOP_LIT)
6404 genRightShiftLiteral (left, right, result, ic, is_signed);
6408 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6410 freeAsmop (right, NULL, ic);
6412 aopOp (left, ic, FALSE, FALSE);
6413 aopOp (result, ic, FALSE, FALSE);
6415 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6418 /* now move the left to the result if they are not the
6420 if (!sameRegs (AOP (left), AOP (result)))
6423 size = AOP_SIZE (result);
6427 l = aopGet (AOP (left), offset, FALSE);
6428 aopPut (AOP (result), l, offset);
6433 tlbl = newiTempLabel (NULL);
6434 tlbl1 = newiTempLabel (NULL);
6435 size = AOP_SIZE (result);
6438 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6441 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6442 emitLabel (tlbl->key + 100);
6445 l = aopGet (AOP (result), offset--, FALSE);
6448 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6456 emitLabel (tlbl1->key + 100);
6458 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6460 freeAsmop (left, NULL, ic);
6461 freeAsmop (result, NULL, ic);
6465 /*-----------------------------------------------------------------*/
6466 /* genUnpackBits - generates code for unpacking bits */
6467 /*-----------------------------------------------------------------*/
6469 genUnpackBits (operand * result, int pair)
6471 int offset = 0; /* result byte offset */
6472 int rsize; /* result size */
6473 int rlen = 0; /* remaining bitfield length */
6474 sym_link *etype; /* bitfield type information */
6475 int blen; /* bitfield length */
6476 int bstr; /* bitfield starting bit within byte */
6478 emitDebug ("; genUnpackBits");
6480 etype = getSpec (operandType (result));
6481 rsize = getSize (operandType (result));
6482 blen = SPEC_BLEN (etype);
6483 bstr = SPEC_BSTR (etype);
6485 /* If the bitfield length is less than a byte */
6488 emit2 ("ld a,!*pair", _pairs[pair].name);
6490 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6491 if (!SPEC_USIGN (etype))
6493 /* signed bitfield */
6494 symbol *tlbl = newiTempLabel (NULL);
6496 emit2 ("bit %d,a", blen - 1);
6497 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6498 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6499 emitLabel (tlbl->key + 100);
6501 aopPut (AOP (result), "a", offset++);
6505 /* TODO: what if pair == PAIR_DE ? */
6506 if (getPairId (AOP (result)) == PAIR_HL)
6508 wassertl (rsize == 2, "HL must be of size 2");
6509 emit2 ("ld a,!*hl");
6511 emit2 ("ld h,!*hl");
6514 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6515 if (!SPEC_USIGN (etype))
6517 /* signed bitfield */
6518 symbol *tlbl = newiTempLabel (NULL);
6520 emit2 ("bit %d,a", blen - 1);
6521 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6522 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6523 emitLabel (tlbl->key + 100);
6526 spillPair (PAIR_HL);
6530 /* Bit field did not fit in a byte. Copy all
6531 but the partial byte at the end. */
6532 for (rlen=blen;rlen>=8;rlen-=8)
6534 emit2 ("ld a,!*pair", _pairs[pair].name);
6535 aopPut (AOP (result), "a", offset++);
6538 emit2 ("inc %s", _pairs[pair].name);
6539 _G.pairs[pair].offset++;
6543 /* Handle the partial byte at the end */
6546 emit2 ("ld a,!*pair", _pairs[pair].name);
6547 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6548 if (!SPEC_USIGN (etype))
6550 /* signed bitfield */
6551 symbol *tlbl = newiTempLabel (NULL);
6553 emit2 ("bit %d,a", rlen - 1);
6554 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6555 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6556 emitLabel (tlbl->key + 100);
6558 aopPut (AOP (result), "a", offset++);
6566 if (SPEC_USIGN (etype))
6570 /* signed bitfield: sign extension with 0x00 or 0xff */
6578 aopPut (AOP (result), source, offset++);
6582 /*-----------------------------------------------------------------*/
6583 /* genGenPointerGet - get value from generic pointer space */
6584 /*-----------------------------------------------------------------*/
6586 genGenPointerGet (operand * left,
6587 operand * result, iCode * ic)
6590 sym_link *retype = getSpec (operandType (result));
6596 aopOp (left, ic, FALSE, FALSE);
6597 aopOp (result, ic, FALSE, FALSE);
6599 size = AOP_SIZE (result);
6601 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6604 if (isPtrPair (AOP (left)))
6606 tsprintf (buffer, sizeof(buffer),
6607 "!*pair", getPairName (AOP (left)));
6608 aopPut (AOP (result), buffer, 0);
6612 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6613 aopPut (AOP (result), "a", 0);
6615 freeAsmop (left, NULL, ic);
6619 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6626 tsprintf (at, sizeof(at), "!*iyx", offset);
6627 aopPut (AOP (result), at, offset);
6631 freeAsmop (left, NULL, ic);
6635 /* For now we always load into IY */
6636 /* if this is remateriazable */
6637 fetchPair (pair, AOP (left));
6639 /* if bit then unpack */
6640 if (IS_BITVAR (retype))
6642 genUnpackBits (result, pair);
6643 freeAsmop (left, NULL, ic);
6647 else if (getPairId (AOP (result)) == PAIR_HL)
6649 wassertl (size == 2, "HL must be of size 2");
6650 emit2 ("ld a,!*hl");
6652 emit2 ("ld h,!*hl");
6654 spillPair (PAIR_HL);
6656 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6658 size = AOP_SIZE (result);
6663 /* PENDING: make this better */
6664 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6666 aopPut (AOP (result), "!*hl", offset++);
6670 emit2 ("ld a,!*pair", _pairs[pair].name);
6671 aopPut (AOP (result), "a", offset++);
6675 emit2 ("inc %s", _pairs[pair].name);
6676 _G.pairs[pair].offset++;
6679 /* Fixup HL back down */
6680 for (size = AOP_SIZE (result)-1; size; size--)
6682 emit2 ("dec %s", _pairs[pair].name);
6687 size = AOP_SIZE (result);
6692 /* PENDING: make this better */
6694 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6696 aopPut (AOP (result), "!*hl", offset++);
6700 emit2 ("ld a,!*pair", _pairs[pair].name);
6701 aopPut (AOP (result), "a", offset++);
6705 emit2 ("inc %s", _pairs[pair].name);
6706 _G.pairs[pair].offset++;
6711 freeAsmop (left, NULL, ic);
6714 freeAsmop (result, NULL, ic);
6717 /*-----------------------------------------------------------------*/
6718 /* genPointerGet - generate code for pointer get */
6719 /*-----------------------------------------------------------------*/
6721 genPointerGet (iCode * ic)
6723 operand *left, *result;
6724 sym_link *type, *etype;
6726 left = IC_LEFT (ic);
6727 result = IC_RESULT (ic);
6729 /* depending on the type of pointer we need to
6730 move it to the correct pointer register */
6731 type = operandType (left);
6732 etype = getSpec (type);
6734 genGenPointerGet (left, result, ic);
6738 isRegOrLit (asmop * aop)
6740 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6746 /*-----------------------------------------------------------------*/
6747 /* genPackBits - generates code for packed bit storage */
6748 /*-----------------------------------------------------------------*/
6750 genPackBits (sym_link * etype,
6755 int offset = 0; /* source byte offset */
6756 int rlen = 0; /* remaining bitfield length */
6757 int blen; /* bitfield length */
6758 int bstr; /* bitfield starting bit within byte */
6759 int litval; /* source literal value (if AOP_LIT) */
6760 unsigned char mask; /* bitmask within current byte */
6761 int extraPair; /* a tempory register */
6762 bool needPopExtra=0; /* need to restore original value of temp reg */
6764 emitDebug ("; genPackBits","");
6766 blen = SPEC_BLEN (etype);
6767 bstr = SPEC_BSTR (etype);
6769 /* If the bitfield length is less than a byte */
6772 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6773 (unsigned char) (0xFF >> (8 - bstr)));
6775 if (AOP_TYPE (right) == AOP_LIT)
6777 /* Case with a bitfield length <8 and literal source
6779 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6781 litval &= (~mask) & 0xff;
6782 emit2 ("ld a,!*pair", _pairs[pair].name);
6783 if ((mask|litval)!=0xff)
6784 emit2 ("and a,!immedbyte", mask);
6786 emit2 ("or a,!immedbyte", litval);
6787 emit2 ("ld !*pair,a", _pairs[pair].name);
6792 /* Case with a bitfield length <8 and arbitrary source
6794 _moveA (aopGet (AOP (right), 0, FALSE));
6795 /* shift and mask source value */
6797 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6799 extraPair = getFreePairId(ic);
6800 if (extraPair == PAIR_INVALID)
6802 extraPair = PAIR_BC;
6803 if (getPairId (AOP (right)) != PAIR_BC
6804 || !isLastUse (ic, right))
6810 emit2 ("ld %s,a", _pairs[extraPair].l);
6811 emit2 ("ld a,!*pair", _pairs[pair].name);
6813 emit2 ("and a,!immedbyte", mask);
6814 emit2 ("or a,%s", _pairs[extraPair].l);
6815 emit2 ("ld !*pair,a", _pairs[pair].name);
6822 /* Bit length is greater than 7 bits. In this case, copy */
6823 /* all except the partial byte at the end */
6824 for (rlen=blen;rlen>=8;rlen-=8)
6826 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6827 emit2 ("ld !*pair,a", _pairs[pair].name);
6830 emit2 ("inc %s", _pairs[pair].name);
6831 _G.pairs[pair].offset++;
6835 /* If there was a partial byte at the end */
6838 mask = (((unsigned char) -1 << rlen) & 0xff);
6840 if (AOP_TYPE (right) == AOP_LIT)
6842 /* Case with partial byte and literal source
6844 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6845 litval >>= (blen-rlen);
6846 litval &= (~mask) & 0xff;
6847 emit2 ("ld a,!*pair", _pairs[pair].name);
6848 if ((mask|litval)!=0xff)
6849 emit2 ("and a,!immedbyte", mask);
6851 emit2 ("or a,!immedbyte", litval);
6855 /* Case with partial byte and arbitrary source
6857 _moveA (aopGet (AOP (right), offset++, FALSE));
6858 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6860 extraPair = getFreePairId(ic);
6861 if (extraPair == PAIR_INVALID)
6863 extraPair = getPairId (AOP (right));
6864 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6865 extraPair = PAIR_BC;
6867 if (getPairId (AOP (right)) != PAIR_BC
6868 || !isLastUse (ic, right))
6874 emit2 ("ld %s,a", _pairs[extraPair].l);
6875 emit2 ("ld a,!*pair", _pairs[pair].name);
6877 emit2 ("and a,!immedbyte", mask);
6878 emit2 ("or a,%s", _pairs[extraPair].l);
6883 emit2 ("ld !*pair,a", _pairs[pair].name);
6888 /*-----------------------------------------------------------------*/
6889 /* genGenPointerSet - stores the value into a pointer location */
6890 /*-----------------------------------------------------------------*/
6892 genGenPointerSet (operand * right,
6893 operand * result, iCode * ic)
6896 sym_link *retype = getSpec (operandType (right));
6897 sym_link *letype = getSpec (operandType (result));
6898 PAIR_ID pairId = PAIR_HL;
6901 aopOp (result, ic, FALSE, FALSE);
6902 aopOp (right, ic, FALSE, FALSE);
6907 size = AOP_SIZE (right);
6909 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6910 emitDebug("; isBitvar = %d", isBitvar);
6912 /* Handle the exceptions first */
6913 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6916 const char *l = aopGet (AOP (right), 0, FALSE);
6917 const char *pair = getPairName (AOP (result));
6918 if (canAssignToPtr (l) && isPtr (pair))
6920 emit2 ("ld !*pair,%s", pair, l);
6925 emit2 ("ld !*pair,a", pair);
6930 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6933 const char *l = aopGet (AOP (right), 0, FALSE);
6938 if (canAssignToPtr (l))
6940 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6944 _moveA (aopGet (AOP (right), offset, FALSE));
6945 emit2 ("ld !*iyx,a", offset);
6951 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6958 const char *l = aopGet (AOP (right), offset, FALSE);
6959 if (isRegOrLit (AOP (right)) && !IS_GB)
6961 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6966 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6970 emit2 ("inc %s", _pairs[PAIR_HL].name);
6971 _G.pairs[PAIR_HL].offset++;
6976 /* Fixup HL back down */
6977 for (size = AOP_SIZE (right)-1; size; size--)
6979 emit2 ("dec %s", _pairs[PAIR_HL].name);
6984 /* if the operand is already in dptr
6985 then we do nothing else we move the value to dptr */
6986 if (AOP_TYPE (result) != AOP_STR)
6988 fetchPair (pairId, AOP (result));
6990 /* so hl now contains the address */
6991 freeAsmop (result, NULL, ic);
6993 /* if bit then unpack */
6996 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7006 const char *l = aopGet (AOP (right), offset, FALSE);
7007 if (isRegOrLit (AOP (right)) && !IS_GB)
7009 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7014 emit2 ("ld !*pair,a", _pairs[pairId].name);
7018 emit2 ("inc %s", _pairs[pairId].name);
7019 _G.pairs[pairId].offset++;
7025 freeAsmop (right, NULL, ic);
7028 /*-----------------------------------------------------------------*/
7029 /* genPointerSet - stores the value into a pointer location */
7030 /*-----------------------------------------------------------------*/
7032 genPointerSet (iCode * ic)
7034 operand *right, *result;
7035 sym_link *type, *etype;
7037 right = IC_RIGHT (ic);
7038 result = IC_RESULT (ic);
7040 /* depending on the type of pointer we need to
7041 move it to the correct pointer register */
7042 type = operandType (result);
7043 etype = getSpec (type);
7045 genGenPointerSet (right, result, ic);
7048 /*-----------------------------------------------------------------*/
7049 /* genIfx - generate code for Ifx statement */
7050 /*-----------------------------------------------------------------*/
7052 genIfx (iCode * ic, iCode * popIc)
7054 operand *cond = IC_COND (ic);
7057 aopOp (cond, ic, FALSE, TRUE);
7059 /* get the value into acc */
7060 if (AOP_TYPE (cond) != AOP_CRY)
7064 /* the result is now in the accumulator */
7065 freeAsmop (cond, NULL, ic);
7067 /* if there was something to be popped then do it */
7071 /* if the condition is a bit variable */
7072 if (isbit && IS_ITEMP (cond) &&
7074 genIfxJump (ic, SPIL_LOC (cond)->rname);
7075 else if (isbit && !IS_ITEMP (cond))
7076 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7078 genIfxJump (ic, "a");
7083 /*-----------------------------------------------------------------*/
7084 /* genAddrOf - generates code for address of */
7085 /*-----------------------------------------------------------------*/
7087 genAddrOf (iCode * ic)
7089 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7091 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7093 /* if the operand is on the stack then we
7094 need to get the stack offset of this
7101 if (sym->stack <= 0)
7103 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7107 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7109 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7113 emit2 ("ld de,!hashedstr", sym->rname);
7114 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7122 /* if it has an offset then we need to compute it */
7124 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7126 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7127 emit2 ("add hl,sp");
7131 emit2 ("ld hl,!hashedstr", sym->rname);
7133 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7135 freeAsmop (IC_RESULT (ic), NULL, ic);
7138 /*-----------------------------------------------------------------*/
7139 /* genAssign - generate code for assignment */
7140 /*-----------------------------------------------------------------*/
7142 genAssign (iCode * ic)
7144 operand *result, *right;
7146 unsigned long lit = 0L;
7148 result = IC_RESULT (ic);
7149 right = IC_RIGHT (ic);
7151 /* Dont bother assigning if they are the same */
7152 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7154 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7158 aopOp (right, ic, FALSE, FALSE);
7159 aopOp (result, ic, TRUE, FALSE);
7161 /* if they are the same registers */
7162 if (sameRegs (AOP (right), AOP (result)))
7164 emitDebug ("; (registers are the same)");
7168 /* if the result is a bit */
7169 if (AOP_TYPE (result) == AOP_CRY)
7171 wassertl (0, "Tried to assign to a bit");
7175 size = AOP_SIZE (result);
7178 if (AOP_TYPE (right) == AOP_LIT)
7180 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7183 if (isPair (AOP (result)))
7185 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7187 else if ((size > 1) &&
7188 (AOP_TYPE (result) != AOP_REG) &&
7189 (AOP_TYPE (right) == AOP_LIT) &&
7190 !IS_FLOAT (operandType (right)) &&
7193 bool fXored = FALSE;
7195 /* Work from the top down.
7196 Done this way so that we can use the cached copy of 0
7197 in A for a fast clear */
7200 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7202 if (!fXored && size > 1)
7209 aopPut (AOP (result), "a", offset);
7213 aopPut (AOP (result), "!zero", offset);
7217 aopPut (AOP (result),
7218 aopGet (AOP (right), offset, FALSE),
7223 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7225 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7226 aopPut (AOP (result), "l", LSB);
7227 aopPut (AOP (result), "h", MSB16);
7229 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7231 /* Special case. Load into a and d, then load out. */
7232 _moveA (aopGet (AOP (right), 0, FALSE));
7233 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7234 aopPut (AOP (result), "a", 0);
7235 aopPut (AOP (result), "e", 1);
7237 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7239 /* Special case - simple memcpy */
7240 aopGet (AOP (right), LSB, FALSE);
7243 aopGet (AOP (result), LSB, FALSE);
7247 emit2 ("ld a,(de)");
7248 /* Peephole will optimise this. */
7249 emit2 ("ld (hl),a");
7257 spillPair (PAIR_HL);
7263 /* PENDING: do this check better */
7264 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7266 _moveA (aopGet (AOP (right), offset, FALSE));
7267 aopPut (AOP (result), "a", offset);
7270 aopPut (AOP (result),
7271 aopGet (AOP (right), offset, FALSE),
7278 freeAsmop (right, NULL, ic);
7279 freeAsmop (result, NULL, ic);
7282 /*-----------------------------------------------------------------*/
7283 /* genJumpTab - genrates code for jump table */
7284 /*-----------------------------------------------------------------*/
7286 genJumpTab (iCode * ic)
7291 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7292 /* get the condition into accumulator */
7293 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7296 emit2 ("ld e,%s", l);
7297 emit2 ("ld d,!zero");
7298 jtab = newiTempLabel (NULL);
7300 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7301 emit2 ("add hl,de");
7302 emit2 ("add hl,de");
7303 emit2 ("add hl,de");
7304 freeAsmop (IC_JTCOND (ic), NULL, ic);
7308 emitLabel (jtab->key + 100);
7309 /* now generate the jump labels */
7310 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7311 jtab = setNextItem (IC_JTLABELS (ic)))
7312 emit2 ("jp !tlabel", jtab->key + 100);
7315 /*-----------------------------------------------------------------*/
7316 /* genCast - gen code for casting */
7317 /*-----------------------------------------------------------------*/
7319 genCast (iCode * ic)
7321 operand *result = IC_RESULT (ic);
7322 sym_link *rtype = operandType (IC_RIGHT (ic));
7323 operand *right = IC_RIGHT (ic);
7326 /* if they are equivalent then do nothing */
7327 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7330 aopOp (right, ic, FALSE, FALSE);
7331 aopOp (result, ic, FALSE, FALSE);
7333 /* if the result is a bit */
7334 if (AOP_TYPE (result) == AOP_CRY)
7336 wassertl (0, "Tried to cast to a bit");
7339 /* if they are the same size : or less */
7340 if (AOP_SIZE (result) <= AOP_SIZE (right))
7343 /* if they are in the same place */
7344 if (sameRegs (AOP (right), AOP (result)))
7347 /* if they in different places then copy */
7348 size = AOP_SIZE (result);
7352 aopPut (AOP (result),
7353 aopGet (AOP (right), offset, FALSE),
7360 /* So we now know that the size of destination is greater
7361 than the size of the source */
7362 /* we move to result for the size of source */
7363 size = AOP_SIZE (right);
7367 aopPut (AOP (result),
7368 aopGet (AOP (right), offset, FALSE),
7373 /* now depending on the sign of the destination */
7374 size = AOP_SIZE (result) - AOP_SIZE (right);
7375 /* Unsigned or not an integral type - right fill with zeros */
7376 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7379 aopPut (AOP (result), "!zero", offset++);
7383 /* we need to extend the sign :{ */
7384 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7390 aopPut (AOP (result), "a", offset++);
7394 freeAsmop (right, NULL, ic);
7395 freeAsmop (result, NULL, ic);
7398 /*-----------------------------------------------------------------*/
7399 /* genReceive - generate code for a receive iCode */
7400 /*-----------------------------------------------------------------*/
7402 genReceive (iCode * ic)
7404 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7405 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7406 IS_TRUE_SYMOP (IC_RESULT (ic))))
7416 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7417 size = AOP_SIZE(IC_RESULT(ic));
7419 for (i = 0; i < size; i++) {
7420 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7424 freeAsmop (IC_RESULT (ic), NULL, ic);
7427 /*-----------------------------------------------------------------*/
7428 /* genDummyRead - generate code for dummy read of volatiles */
7429 /*-----------------------------------------------------------------*/
7431 genDummyRead (iCode * ic)
7437 if (op && IS_SYMOP (op))
7439 aopOp (op, ic, FALSE, FALSE);
7442 size = AOP_SIZE (op);
7447 _moveA (aopGet (AOP (op), offset, FALSE));
7451 freeAsmop (op, NULL, ic);
7455 if (op && IS_SYMOP (op))
7457 aopOp (op, ic, FALSE, FALSE);
7460 size = AOP_SIZE (op);
7465 _moveA (aopGet (AOP (op), offset, FALSE));
7469 freeAsmop (op, NULL, ic);
7473 /*-----------------------------------------------------------------*/
7474 /* genCritical - generate code for start of a critical sequence */
7475 /*-----------------------------------------------------------------*/
7477 genCritical (iCode *ic)
7479 symbol *tlbl = newiTempLabel (NULL);
7485 else if (IC_RESULT (ic))
7487 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7488 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7489 //get interrupt enable flag IFF2 into P/O
7493 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7494 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7495 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7496 emit2 ("!tlabeldef", (tlbl->key + 100));
7497 _G.lines.current->isLabel = 1;
7498 freeAsmop (IC_RESULT (ic), NULL, ic);
7502 //get interrupt enable flag IFF2 into P/O
7511 /*-----------------------------------------------------------------*/
7512 /* genEndCritical - generate code for end of a critical sequence */
7513 /*-----------------------------------------------------------------*/
7515 genEndCritical (iCode *ic)
7517 symbol *tlbl = newiTempLabel (NULL);
7523 else if (IC_RIGHT (ic))
7525 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7526 _toBoolean (IC_RIGHT (ic));
7527 //don't enable interrupts if they were off before
7528 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7530 emitLabel (tlbl->key + 100);
7531 freeAsmop (IC_RIGHT (ic), NULL, ic);
7537 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7538 //don't enable interrupts as they were off before
7539 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7541 emit2 ("!tlabeldef", (tlbl->key + 100));
7542 _G.lines.current->isLabel = 1;
7548 /** Maximum number of bytes to emit per line. */
7552 /** Context for the byte output chunker. */
7555 unsigned char buffer[DBEMIT_MAX_RUN];
7560 /** Flushes a byte chunker by writing out all in the buffer and
7564 _dbFlush(DBEMITCTX *self)
7571 sprintf(line, ".db 0x%02X", self->buffer[0]);
7573 for (i = 1; i < self->pos; i++)
7575 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7582 /** Write out another byte, buffering until a decent line is
7586 _dbEmit(DBEMITCTX *self, int c)
7588 if (self->pos == DBEMIT_MAX_RUN)
7592 self->buffer[self->pos++] = c;
7595 /** Context for a simple run length encoder. */
7599 unsigned char buffer[128];
7601 /** runLen may be equivalent to pos. */
7607 RLE_CHANGE_COST = 4,
7611 /** Flush the buffer of a run length encoder by writing out the run or
7612 data that it currently contains.
7615 _rleCommit(RLECTX *self)
7621 memset(&db, 0, sizeof(db));
7623 emit2(".db %u", self->pos);
7625 for (i = 0; i < self->pos; i++)
7627 _dbEmit(&db, self->buffer[i]);
7636 Can get either a run or a block of random stuff.
7637 Only want to change state if a good run comes in or a run ends.
7638 Detecting run end is easy.
7641 Say initial state is in run, len zero, last zero. Then if you get a
7642 few zeros then something else then a short run will be output.
7643 Seems OK. While in run mode, keep counting. While in random mode,
7644 keep a count of the run. If run hits margin, output all up to run,
7645 restart, enter run mode.
7648 /** Add another byte into the run length encoder, flushing as
7649 required. The run length encoder uses the Amiga IFF style, where
7650 a block is prefixed by its run length. A positive length means
7651 the next n bytes pass straight through. A negative length means
7652 that the next byte is repeated -n times. A zero terminates the
7656 _rleAppend(RLECTX *self, unsigned c)
7660 if (c != self->last)
7662 /* The run has stopped. See if it is worthwhile writing it out
7663 as a run. Note that the random data comes in as runs of
7666 if (self->runLen > RLE_CHANGE_COST)
7668 /* Yes, worthwhile. */
7669 /* Commit whatever was in the buffer. */
7671 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7675 /* Not worthwhile. Append to the end of the random list. */
7676 for (i = 0; i < self->runLen; i++)
7678 if (self->pos >= RLE_MAX_BLOCK)
7683 self->buffer[self->pos++] = self->last;
7691 if (self->runLen >= RLE_MAX_BLOCK)
7693 /* Commit whatever was in the buffer. */
7696 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7704 _rleFlush(RLECTX *self)
7706 _rleAppend(self, -1);
7713 /** genArrayInit - Special code for initialising an array with constant
7717 genArrayInit (iCode * ic)
7721 int elementSize = 0, eIndex, i;
7722 unsigned val, lastVal;
7726 memset(&rle, 0, sizeof(rle));
7728 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7730 _saveRegsForCall(ic, 0);
7732 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7733 emit2 ("call __initrleblock");
7735 type = operandType(IC_LEFT(ic));
7737 if (type && type->next)
7739 if (IS_SPEC(type->next) || IS_PTR(type->next))
7741 elementSize = getSize(type->next);
7743 else if (IS_ARRAY(type->next) && type->next->next)
7745 elementSize = getSize(type->next->next);
7749 printTypeChainRaw (type, NULL);
7750 wassertl (0, "Can't determine element size in genArrayInit.");
7755 wassertl (0, "Can't determine element size in genArrayInit.");
7758 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7760 iLoop = IC_ARRAYILIST(ic);
7761 lastVal = (unsigned)-1;
7763 /* Feed all the bytes into the run length encoder which will handle
7765 This works well for mixed char data, and for random int and long
7772 for (i = 0; i < ix; i++)
7774 for (eIndex = 0; eIndex < elementSize; eIndex++)
7776 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7777 _rleAppend(&rle, val);
7781 iLoop = iLoop->next;
7785 /* Mark the end of the run. */
7788 _restoreRegsAfterCall();
7792 freeAsmop (IC_LEFT(ic), NULL, ic);
7796 _swap (PAIR_ID one, PAIR_ID two)
7798 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7804 emit2 ("ld a,%s", _pairs[one].l);
7805 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7806 emit2 ("ld %s,a", _pairs[two].l);
7807 emit2 ("ld a,%s", _pairs[one].h);
7808 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7809 emit2 ("ld %s,a", _pairs[two].h);
7813 /* The problem is that we may have all three pairs used and they may
7814 be needed in a different order.
7819 hl = hl => unity, fine
7823 hl = hl hl = hl, swap de <=> bc
7831 hl = bc de = de, swap bc <=> hl
7839 hl = de bc = bc, swap hl <=> de
7844 * Any pair = pair are done last
7845 * Any pair = iTemp are done last
7846 * Any swaps can be done any time
7854 So how do we detect the cases?
7855 How about a 3x3 matrix?
7859 x x x x (Fourth for iTemp/other)
7861 First determin which mode to use by counting the number of unity and
7864 Two - Assign the pair first, then the rest
7865 One - Swap the two, then the rest
7869 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7871 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7873 PAIR_BC, PAIR_HL, PAIR_DE
7875 int i, j, nunity = 0;
7876 memset (ids, PAIR_INVALID, sizeof (ids));
7879 wassert (nparams == 3);
7881 /* First save everything that needs to be saved. */
7882 _saveRegsForCall (ic, 0);
7884 /* Loading HL first means that DE is always fine. */
7885 for (i = 0; i < nparams; i++)
7887 aopOp (pparams[i], ic, FALSE, FALSE);
7888 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7891 /* Count the number of unity or iTemp assigns. */
7892 for (i = 0; i < 3; i++)
7894 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7902 /* Any order, fall through. */
7904 else if (nunity == 2)
7906 /* One is assigned. Pull it out and assign. */
7907 for (i = 0; i < 3; i++)
7909 for (j = 0; j < NUM_PAIRS; j++)
7911 if (ids[dest[i]][j] == TRUE)
7913 /* Found it. See if it's the right one. */
7914 if (j == PAIR_INVALID || j == dest[i])
7920 fetchPair(dest[i], AOP (pparams[i]));
7927 else if (nunity == 1)
7929 /* Find the pairs to swap. */
7930 for (i = 0; i < 3; i++)
7932 for (j = 0; j < NUM_PAIRS; j++)
7934 if (ids[dest[i]][j] == TRUE)
7936 if (j == PAIR_INVALID || j == dest[i])
7951 int next = getPairId (AOP (pparams[0]));
7952 emit2 ("push %s", _pairs[next].name);
7954 if (next == dest[1])
7956 fetchPair (dest[1], AOP (pparams[1]));
7957 fetchPair (dest[2], AOP (pparams[2]));
7961 fetchPair (dest[2], AOP (pparams[2]));
7962 fetchPair (dest[1], AOP (pparams[1]));
7964 emit2 ("pop %s", _pairs[dest[0]].name);
7967 /* Finally pull out all of the iTemps */
7968 for (i = 0; i < 3; i++)
7970 if (ids[dest[i]][PAIR_INVALID] == 1)
7972 fetchPair (dest[i], AOP (pparams[i]));
7978 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7984 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7988 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7990 setupForBuiltin3 (ic, nParams, pparams);
7992 label = newiTempLabel(NULL);
7994 emitLabel (label->key);
7995 emit2 ("ld a,(hl)");
7998 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8000 freeAsmop (from, NULL, ic->next);
8001 freeAsmop (to, NULL, ic);
8005 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8007 operand *from, *to, *count;
8010 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8015 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8017 setupForBuiltin3 (ic, nParams, pparams);
8021 freeAsmop (count, NULL, ic->next->next);
8022 freeAsmop (from, NULL, ic);
8024 _restoreRegsAfterCall();
8026 /* if we need assign a result value */
8027 if ((IS_ITEMP (IC_RESULT (ic)) &&
8028 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8029 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8030 IS_TRUE_SYMOP (IC_RESULT (ic)))
8032 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8033 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8034 freeAsmop (IC_RESULT (ic), NULL, ic);
8037 freeAsmop (to, NULL, ic->next);
8040 /*-----------------------------------------------------------------*/
8041 /* genBuiltIn - calls the appropriate function to generating code */
8042 /* for a built in function */
8043 /*-----------------------------------------------------------------*/
8044 static void genBuiltIn (iCode *ic)
8046 operand *bi_parms[MAX_BUILTIN_ARGS];
8051 /* get all the arguments for a built in function */
8052 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8054 /* which function is it */
8055 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8057 if (strcmp(bif->name,"__builtin_strcpy")==0)
8059 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8061 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8063 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8067 wassertl (0, "Unknown builtin function encountered");
8071 /*-----------------------------------------------------------------*/
8072 /* genZ80Code - generate code for Z80 based controllers */
8073 /*-----------------------------------------------------------------*/
8075 genZ80Code (iCode * lic)
8083 _fReturn = _gbz80_return;
8084 _fTmp = _gbz80_return;
8088 _fReturn = _z80_return;
8089 _fTmp = _z80_return;
8092 _G.lines.head = _G.lines.current = NULL;
8094 /* if debug information required */
8095 if (options.debug && currFunc)
8097 debugFile->writeFunction (currFunc, lic);
8100 for (ic = lic; ic; ic = ic->next)
8102 _G.current_iCode = ic;
8104 if (ic->lineno && cln != ic->lineno)
8108 debugFile->writeCLine (ic);
8110 if (!options.noCcodeInAsm)
8112 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8113 printCLine(ic->filename, ic->lineno));
8117 if (options.iCodeInAsm)
8119 char *iLine = printILine(ic);
8120 emit2 (";ic:%d: %s", ic->key, iLine);
8123 /* if the result is marked as
8124 spilt and rematerializable or code for
8125 this has already been generated then
8127 if (resultRemat (ic) || ic->generated)
8130 /* depending on the operation */
8134 emitDebug ("; genNot");
8139 emitDebug ("; genCpl");
8144 emitDebug ("; genUminus");
8149 emitDebug ("; genIpush");
8154 /* IPOP happens only when trying to restore a
8155 spilt live range, if there is an ifx statement
8156 following this pop then the if statement might
8157 be using some of the registers being popped which
8158 would destroy the contents of the register so
8159 we need to check for this condition and handle it */
8161 ic->next->op == IFX &&
8162 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8164 emitDebug ("; genIfx");
8165 genIfx (ic->next, ic);
8169 emitDebug ("; genIpop");
8175 emitDebug ("; genCall");
8180 emitDebug ("; genPcall");
8185 emitDebug ("; genFunction");
8190 emitDebug ("; genEndFunction");
8191 genEndFunction (ic);
8195 emitDebug ("; genRet");
8200 emitDebug ("; genLabel");
8205 emitDebug ("; genGoto");
8210 emitDebug ("; genPlus");
8215 emitDebug ("; genMinus");
8220 emitDebug ("; genMult");
8225 emitDebug ("; genDiv");
8230 emitDebug ("; genMod");
8235 emitDebug ("; genCmpGt");
8236 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8240 emitDebug ("; genCmpLt");
8241 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8248 /* note these two are xlated by algebraic equivalence
8249 during parsing SDCC.y */
8250 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8251 "got '>=' or '<=' shouldn't have come here");
8255 emitDebug ("; genCmpEq");
8256 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8260 emitDebug ("; genAndOp");
8265 emitDebug ("; genOrOp");
8270 emitDebug ("; genXor");
8271 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8275 emitDebug ("; genOr");
8276 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8280 emitDebug ("; genAnd");
8281 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8285 emitDebug ("; genInline");
8290 emitDebug ("; genRRC");
8295 emitDebug ("; genRLC");
8300 emitDebug ("; genGetHBIT");
8305 emitDebug ("; genLeftShift");
8310 emitDebug ("; genRightShift");
8314 case GET_VALUE_AT_ADDRESS:
8315 emitDebug ("; genPointerGet");
8321 if (POINTER_SET (ic))
8323 emitDebug ("; genAssign (pointer)");
8328 emitDebug ("; genAssign");
8334 emitDebug ("; genIfx");
8339 emitDebug ("; genAddrOf");
8344 emitDebug ("; genJumpTab");
8349 emitDebug ("; genCast");
8354 emitDebug ("; genReceive");
8359 if (ic->builtinSEND)
8361 emitDebug ("; genBuiltIn");
8366 emitDebug ("; addSet");
8367 addSet (&_G.sendSet, ic);
8372 emitDebug ("; genArrayInit");
8376 case DUMMY_READ_VOLATILE:
8377 emitDebug ("; genDummyRead");
8382 emitDebug ("; genCritical");
8387 emitDebug ("; genEndCritical");
8388 genEndCritical (ic);
8397 /* now we are ready to call the
8398 peep hole optimizer */
8399 if (!options.nopeep)
8400 peepHole (&_G.lines.head);
8402 /* This is unfortunate */
8403 /* now do the actual printing */
8405 struct dbuf_s *buf = codeOutBuf;
8406 if (isInHome () && codeOutBuf == &code->oBuf)
8407 codeOutBuf = &home->oBuf;
8408 printLine (_G.lines.head, codeOutBuf);
8409 if (_G.flushStatics)
8412 _G.flushStatics = 0;
8417 freeTrace(&_G.lines.trace);
8418 freeTrace(&_G.trace.aops);
8424 _isPairUsed (iCode * ic, PAIR_ID pairId)
8430 if (bitVectBitValue (ic->rMask, D_IDX))
8432 if (bitVectBitValue (ic->rMask, E_IDX))
8442 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8445 value *val = aop->aopu.aop_lit;
8447 wassert (aop->type == AOP_LIT);
8448 wassert (!IS_FLOAT (val->type));
8450 v = (unsigned long) floatFromVal (val);
8458 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8459 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));