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.
91 #include "SDCCglobl.h"
92 #include "SDCCpeeph.h"
97 /* This is the down and dirty file with all kinds of kludgy & hacky
98 stuff. This is what it is all about CODE GENERATION for a specific MCU.
99 Some of the routines may be reusable, will have to see */
101 /* Z80 calling convention description.
102 Parameters are passed right to left. As the stack grows downwards,
103 the parameters are arranged in left to right in memory.
104 Parameters may be passed in the HL and DE registers with one
106 PENDING: What if the parameter is a long?
107 Everything is caller saves. i.e. the caller must save any registers
108 that it wants to preserve over the call.
109 GB: The return value is returned in DEHL. DE is normally used as a
110 working register pair. Caller saves allows it to be used for a
112 va args functions do not use register parameters. All arguments
113 are passed on the stack.
114 IX is used as an index register to the top of the local variable
115 area. ix-0 is the top most local variable.
120 /* Set to enable debugging trace statements in the output assembly code. */
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129 { "c", "b", "e", "d" };
131 static char **_fReturn;
134 extern struct dbuf_s *codeOutBuf;
142 /** Enum covering all the possible register pairs.
161 } _pairs[NUM_PAIRS] = {
162 { "??1", "?2", "?3" },
167 { "iy", "iyl", "iyh" },
168 { "ix", "ixl", "ixh" }
172 #define ACC_NAME _pairs[PAIR_AF].h
182 /** Code generator persistent data.
186 /** Used to optimised setting up of a pair by remebering what it
187 contains and adjusting instead of reloading where possible.
216 const char *lastFunctionName;
217 iCode *current_iCode;
224 /** TRUE if the registers have already been saved. */
243 static const char *aopGet (asmop * aop, int offset, bool bit16);
245 static const char *aopNames[] = {
266 isLastUse (iCode *ic, operand *op)
268 bitVect *uses = bitVectCopy (OP_USES (op));
270 while (!bitVectIsZero (uses))
272 if (bitVectFirstBit (uses) == ic->key)
274 if (bitVectnBitsOn (uses) == 1)
283 bitVectUnSetBit (uses, bitVectFirstBit (uses));
303 _getTempPairName(void)
305 return _pairs[_getTempPairId()].name;
309 isPairInUse (PAIR_ID id, iCode *ic)
313 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
315 else if (id == PAIR_BC)
317 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
321 wassertl (0, "Only implemented for DE and BC");
327 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
331 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
335 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
339 wassertl (0, "Only implemented for DE");
345 getFreePairId (iCode *ic)
347 if (!isPairInUse (PAIR_BC, ic))
351 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
364 /* Clean up the line so that it is 'prettier' */
365 if (strchr (buf, ':'))
367 /* Is a label - cant do anything */
370 /* Change the first (and probably only) ' ' to a tab so
385 _newLineNode (const char *line)
389 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
390 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
396 _vemit2 (const char *szFormat, va_list ap)
401 dbuf_init(&dbuf, INITIAL_INLINEASM);
403 dbuf_tvprintf (&dbuf, szFormat, ap);
405 buffer = dbuf_c_str(&dbuf);
407 _tidyUp ((char *)buffer);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
413 _G.lines.current->isDebug = _G.lines.isDebug;
414 _G.lines.current->ic = _G.current_iCode;
415 _G.lines.current->isComment = (*buffer == ';');
421 emit2 (const char *szFormat,...)
425 va_start (ap, szFormat);
427 _vemit2 (szFormat, ap);
433 emitDebug (const char *szFormat,...)
435 if (!options.verboseAsm)
441 va_start (ap, szFormat);
443 _vemit2 (szFormat, ap);
449 /*-----------------------------------------------------------------*/
450 /* z80_emitDebuggerSymbol - associate the current code location */
451 /* with a debugger symbol */
452 /*-----------------------------------------------------------------*/
454 z80_emitDebuggerSymbol (char * debugSym)
456 _G.lines.isDebug = 1;
457 emit2 ("%s !equ .", debugSym);
458 emit2 ("!global", debugSym);
459 _G.lines.isDebug = 0;
462 /*-----------------------------------------------------------------*/
463 /* emit2 - writes the code into a file : for now it is simple */
464 /*-----------------------------------------------------------------*/
466 _emit2 (const char *inst, const char *fmt,...)
469 char lb[INITIAL_INLINEASM];
476 sprintf (lb, "%s\t", inst);
477 vsprintf (lb + (strlen (lb)), fmt, ap);
480 vsprintf (lb, fmt, ap);
482 while (isspace (*lbp))
487 _G.lines.current = (_G.lines.current ?
488 connectLine (_G.lines.current, _newLineNode (lb)) :
489 (_G.lines.head = _newLineNode (lb)));
491 _G.lines.current->isInline = _G.lines.isInline;
492 _G.lines.current->ic = _G.current_iCode;
497 _emitMove(const char *to, const char *from)
499 if (STRCASECMP(to, from) != 0)
501 emit2("ld %s,%s", to, from);
506 // Could leave this to the peephole, but sometimes the peephole is inhibited.
511 aopDump(const char *plabel, asmop *aop)
517 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
522 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
525 for (i=aop->size-1;i>=0;i--)
526 *rbp++ = *(aop->aopu.aop_reg[i]->name);
528 emitDebug("; reg = %s", regbuf);
531 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
534 /* No information. */
540 _moveA(const char *moveFrom)
542 // Let the peephole optimiser take care of redundent loads
543 _emitMove(ACC_NAME, moveFrom);
553 getPairName (asmop * aop)
555 if (aop->type == AOP_REG)
557 switch (aop->aopu.aop_reg[0]->rIdx)
570 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
573 for (i = 0; i < NUM_PAIRS; i++)
575 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
577 return _pairs[i].name;
581 wassertl (0, "Tried to get the pair name of something that isn't a pair");
586 getPairId (asmop * aop)
590 if (aop->type == AOP_REG)
592 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
596 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
600 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
605 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
608 for (i = 0; i < NUM_PAIRS; i++)
610 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
620 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
624 return (getPairId (aop) != PAIR_INVALID);
627 /** Returns TRUE if the registers used in aop cannot be split into high
630 isUnsplitable (asmop * aop)
632 switch (getPairId (aop))
644 isPtrPair (asmop * aop)
646 PAIR_ID pairId = getPairId (aop);
659 spillPair (PAIR_ID pairId)
661 _G.pairs[pairId].last_type = AOP_INVALID;
662 _G.pairs[pairId].base = NULL;
665 /* Given a register name, spill the pair (if any) the register is part of */
667 spillPairReg (const char *regname)
669 if (strlen(regname)==1)
689 /** Push a register pair onto the stack */
691 genPairPush (asmop * aop)
693 emit2 ("push %s", getPairName (aop));
697 _push (PAIR_ID pairId)
699 emit2 ("push %s", _pairs[pairId].name);
700 _G.stack.pushed += 2;
704 _pop (PAIR_ID pairId)
706 if (pairId != PAIR_INVALID)
708 emit2 ("pop %s", _pairs[pairId].name);
709 _G.stack.pushed -= 2;
715 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
728 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
735 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
736 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
739 wassertl (0, "Tried to move a nonphysical pair");
741 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
742 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
743 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
747 /*-----------------------------------------------------------------*/
748 /* newAsmop - creates a new asmOp */
749 /*-----------------------------------------------------------------*/
751 newAsmop (short type)
755 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
760 /*-----------------------------------------------------------------*/
761 /* aopForSym - for a true symbol */
762 /*-----------------------------------------------------------------*/
764 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
771 wassert (sym->etype);
773 space = SPEC_OCLS (sym->etype);
775 /* if already has one */
781 /* Assign depending on the storage class */
782 if (sym->onStack || sym->iaccess)
784 /* The pointer that is used depends on how big the offset is.
785 Normally everything is AOP_STK, but for offsets of < -128 or
786 > 127 on the Z80 an extended stack pointer is used.
788 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
790 emitDebug ("; AOP_EXSTK for %s", sym->rname);
791 sym->aop = aop = newAsmop (AOP_EXSTK);
795 emitDebug ("; AOP_STK for %s", sym->rname);
796 sym->aop = aop = newAsmop (AOP_STK);
799 aop->size = getSize (sym->type);
800 aop->aopu.aop_stk = sym->stack;
804 /* special case for a function */
805 if (IS_FUNC (sym->type))
807 sym->aop = aop = newAsmop (AOP_IMMD);
808 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
813 if( IN_REGSP( space ))
814 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
817 /* if it is in direct space */
820 sym->aop = aop = newAsmop (AOP_SFR);
821 aop->aopu.aop_dir = sym->rname;
822 aop->size = getSize (sym->type);
823 emitDebug ("; AOP_SFR for %s", sym->rname);
828 { /*.p.t.20030716 adding SFR support to the Z80 port */
829 aop = newAsmop (AOP_SFR);
831 aop->aopu.aop_dir = sym->rname;
832 aop->size = getSize( sym->type );
833 aop->paged = FUNC_REGBANK(sym->type);
834 aop->bcInUse = isPairInUse( PAIR_BC, ic );
835 aop->deInUse = isPairInUse( PAIR_DE, ic );
836 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
842 /* only remaining is far space */
843 /* in which case DPTR gets the address */
846 emitDebug ("; AOP_HL for %s", sym->rname);
847 sym->aop = aop = newAsmop (AOP_HL);
851 sym->aop = aop = newAsmop (AOP_IY);
853 aop->size = getSize (sym->type);
854 aop->aopu.aop_dir = sym->rname;
856 /* if it is in code space */
857 if (IN_CODESPACE (space))
863 /*-----------------------------------------------------------------*/
864 /* aopForRemat - rematerialzes an object */
865 /*-----------------------------------------------------------------*/
867 aopForRemat (symbol * sym)
870 iCode *ic = sym->rematiCode;
871 asmop *aop = newAsmop (AOP_IMMD);
875 /* if plus or minus print the right hand side */
876 if (ic->op == '+' || ic->op == '-')
878 /* PENDING: for re-target */
879 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
882 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
885 /* we reached the end */
886 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
890 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
894 /*-----------------------------------------------------------------*/
895 /* regsInCommon - two operands have some registers in common */
896 /*-----------------------------------------------------------------*/
898 regsInCommon (operand * op1, operand * op2)
903 /* if they have registers in common */
904 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
907 sym1 = OP_SYMBOL (op1);
908 sym2 = OP_SYMBOL (op2);
910 if (sym1->nRegs == 0 || sym2->nRegs == 0)
913 for (i = 0; i < sym1->nRegs; i++)
919 for (j = 0; j < sym2->nRegs; j++)
924 if (sym2->regs[j] == sym1->regs[i])
932 /*-----------------------------------------------------------------*/
933 /* operandsEqu - equivalent */
934 /*-----------------------------------------------------------------*/
936 operandsEqu (operand * op1, operand * op2)
940 /* if they not symbols */
941 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
944 sym1 = OP_SYMBOL (op1);
945 sym2 = OP_SYMBOL (op2);
947 /* if both are itemps & one is spilt
948 and the other is not then false */
949 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
950 sym1->isspilt != sym2->isspilt)
953 /* if they are the same */
957 if (sym1->rname[0] && sym2->rname[0]
958 && strcmp (sym1->rname, sym2->rname) == 0)
961 /* if left is a tmp & right is not */
962 if (IS_ITEMP (op1) &&
965 (sym1->usl.spillLoc == sym2))
968 if (IS_ITEMP (op2) &&
972 (sym2->usl.spillLoc == sym1))
978 /*-----------------------------------------------------------------*/
979 /* sameRegs - two asmops have the same registers */
980 /*-----------------------------------------------------------------*/
982 sameRegs (asmop * aop1, asmop * aop2)
986 if (aop1->type == AOP_SFR ||
987 aop2->type == AOP_SFR)
993 if (aop1->type != AOP_REG ||
994 aop2->type != AOP_REG)
997 if (aop1->size != aop2->size)
1000 for (i = 0; i < aop1->size; i++)
1001 if (aop1->aopu.aop_reg[i] !=
1002 aop2->aopu.aop_reg[i])
1008 /*-----------------------------------------------------------------*/
1009 /* aopOp - allocates an asmop for an operand : */
1010 /*-----------------------------------------------------------------*/
1012 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1021 /* if this a literal */
1022 if (IS_OP_LITERAL (op))
1024 op->aop = aop = newAsmop (AOP_LIT);
1025 aop->aopu.aop_lit = op->operand.valOperand;
1026 aop->size = getSize (operandType (op));
1030 /* if already has a asmop then continue */
1033 if (op->aop->type == AOP_SFR)
1035 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1036 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1041 /* if the underlying symbol has a aop */
1042 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1044 op->aop = OP_SYMBOL (op)->aop;
1045 if (op->aop->type == AOP_SFR)
1047 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1048 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1053 /* if this is a true symbol */
1054 if (IS_TRUE_SYMOP (op))
1056 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1060 /* this is a temporary : this has
1066 e) can be a return use only */
1068 sym = OP_SYMBOL (op);
1070 /* if the type is a conditional */
1071 if (sym->regType == REG_CND)
1073 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1078 /* if it is spilt then two situations
1080 b) has a spill location */
1081 if (sym->isspilt || sym->nRegs == 0)
1083 /* rematerialize it NOW */
1086 sym->aop = op->aop = aop =
1088 aop->size = getSize (sym->type);
1095 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1096 aop->size = getSize (sym->type);
1097 for (i = 0; i < 4; i++)
1098 aop->aopu.aop_str[i] = _fReturn[i];
1104 if (sym->accuse == ACCUSE_A)
1106 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1107 aop->size = getSize (sym->type);
1108 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1110 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1112 else if (sym->accuse == ACCUSE_SCRATCH)
1114 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1115 aop->size = getSize (sym->type);
1116 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1117 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1118 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1120 else if (sym->accuse == ACCUSE_IY)
1122 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1123 aop->size = getSize (sym->type);
1124 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1125 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1126 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1130 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1135 if (sym->usl.spillLoc)
1137 asmop *oldAsmOp = NULL;
1139 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1141 /* force a new aop if sizes differ */
1142 oldAsmOp = sym->usl.spillLoc->aop;
1143 sym->usl.spillLoc->aop = NULL;
1145 sym->aop = op->aop = aop =
1146 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1147 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1149 /* Don't reuse the new aop, go with the last one */
1150 sym->usl.spillLoc->aop = oldAsmOp;
1152 aop->size = getSize (sym->type);
1156 /* else must be a dummy iTemp */
1157 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1158 aop->size = getSize (sym->type);
1162 /* must be in a register */
1163 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1164 aop->size = sym->nRegs;
1165 for (i = 0; i < sym->nRegs; i++)
1166 aop->aopu.aop_reg[i] = sym->regs[i];
1169 /*-----------------------------------------------------------------*/
1170 /* freeAsmop - free up the asmop given to an operand */
1171 /*----------------------------------------------------------------*/
1173 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1190 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1192 _pop (aop->aopu.aop_pairId);
1195 if (getPairId (aop) == PAIR_HL)
1197 spillPair (PAIR_HL);
1201 /* all other cases just dealloc */
1207 OP_SYMBOL (op)->aop = NULL;
1208 /* if the symbol has a spill */
1210 SPIL_LOC (op)->aop = NULL;
1217 isLitWord (asmop * aop)
1219 /* if (aop->size != 2)
1232 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1234 /* depending on type */
1240 /* PENDING: for re-target */
1243 tsprintf (buffer, sizeof(buffer),
1244 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1246 else if (offset == 0)
1248 tsprintf (buffer, sizeof(buffer),
1249 "%s", aop->aopu.aop_immd);
1253 tsprintf (buffer, sizeof(buffer),
1254 "%s + %d", aop->aopu.aop_immd, offset);
1256 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1260 value *val = aop->aopu.aop_lit;
1261 /* if it is a float then it gets tricky */
1262 /* otherwise it is fairly simple */
1263 if (!IS_FLOAT (val->type))
1265 unsigned long v = ulFromVal (val);
1271 else if (offset == 0)
1277 wassertl(0, "Encountered an invalid offset while fetching a literal");
1281 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1283 tsprintf (buffer, sizeof(buffer), "!constword", v);
1285 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1296 /* it is type float */
1297 fl.f = (float) floatFromVal (val);
1299 #ifdef WORDS_BIGENDIAN
1300 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1302 i = fl.c[offset] | (fl.c[offset+1]<<8);
1305 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1307 tsprintf (buffer, sizeof(buffer), "!constword", i);
1309 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1318 aopGetWord (asmop * aop, int offset)
1320 return aopGetLitWordLong (aop, offset, TRUE);
1324 isPtr (const char *s)
1326 if (!strcmp (s, "hl"))
1328 if (!strcmp (s, "ix"))
1330 if (!strcmp (s, "iy"))
1336 adjustPair (const char *pair, int *pold, int new)
1342 emit2 ("inc %s", pair);
1347 emit2 ("dec %s", pair);
1355 spillPair (PAIR_HL);
1356 spillPair (PAIR_IY);
1360 requiresHL (asmop * aop)
1376 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1378 const char *l, *base;
1379 const char *pair = _pairs[pairId].name;
1380 l = aopGetLitWordLong (left, offset, FALSE);
1381 base = aopGetLitWordLong (left, 0, FALSE);
1382 wassert (l && pair && base);
1386 if (pairId == PAIR_HL || pairId == PAIR_IY)
1388 if (_G.pairs[pairId].last_type == left->type)
1390 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1392 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1394 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1397 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1404 _G.pairs[pairId].last_type = left->type;
1405 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1406 _G.pairs[pairId].offset = offset;
1408 /* Both a lit on the right and a true symbol on the left */
1409 emit2 ("ld %s,!hashedstr", pair, l);
1413 makeFreePairId (iCode *ic, bool *pisUsed)
1419 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1423 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1441 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1443 /* if this is remateriazable */
1444 if (isLitWord (aop)) {
1445 fetchLitPair (pairId, aop, offset);
1449 if (getPairId (aop) == pairId)
1453 /* we need to get it byte by byte */
1454 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1455 aopGet (aop, offset, FALSE);
1456 switch (aop->size - offset) {
1458 emit2 ("ld l,!*hl");
1459 emit2 ("ld h,!immedbyte", 0);
1462 // PENDING: Requires that you are only fetching two bytes.
1465 emit2 ("ld h,!*hl");
1469 wassertl (0, "Attempted to fetch too much data into HL");
1473 else if (IS_Z80 && aop->type == AOP_IY) {
1474 /* Instead of fetching relative to IY, just grab directly
1475 from the address IY refers to */
1476 char *l = aopGetLitWordLong (aop, offset, FALSE);
1478 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1480 if (aop->size < 2) {
1481 emit2("ld %s,!zero", _pairs[pairId].h);
1484 else if (pairId == PAIR_IY)
1488 emit2 ("push %s", _pairs[getPairId(aop)].name);
1494 PAIR_ID id = makeFreePairId (ic, &isUsed);
1497 /* Can't load into parts, so load into HL then exchange. */
1498 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1499 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1500 emit2 ("push %s", _pairs[id].name);
1506 else if (isUnsplitable(aop))
1508 emit2("push %s", _pairs[getPairId(aop)].name);
1509 emit2("pop %s", _pairs[pairId].name);
1513 /* Swapping register contents within register pair */
1514 if(!strcmp(aopGet (aop, offset, FALSE), _pairs[pairId].h))
1516 emit2 ("ld a,%s",aopGet (aop, offset + 1, FALSE));
1517 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1518 emit2 ("ld %s,a", _pairs[pairId].h);
1522 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1523 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1526 /* PENDING: check? */
1527 if (pairId == PAIR_HL)
1528 spillPair (PAIR_HL);
1533 fetchPair (PAIR_ID pairId, asmop * aop)
1535 fetchPairLong (pairId, aop, NULL, 0);
1539 fetchHL (asmop * aop)
1541 fetchPair (PAIR_HL, aop);
1545 setupPairFromSP (PAIR_ID id, int offset)
1547 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1549 if (_G.preserveCarry)
1555 if (offset < INT8MIN || offset > INT8MAX)
1557 emit2 ("ld hl,!immedword", offset);
1558 emit2 ("add hl,sp");
1562 emit2 ("!ldahlsp", offset);
1565 if (_G.preserveCarry)
1573 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1578 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1579 fetchLitPair (pairId, aop, 0);
1583 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1585 fetchLitPair (pairId, aop, offset);
1586 _G.pairs[pairId].offset = offset;
1590 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1591 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1594 int offset = aop->aopu.aop_stk + _G.stack.offset;
1596 if (_G.pairs[pairId].last_type == aop->type &&
1597 _G.pairs[pairId].offset == offset)
1603 /* PENDING: Do this better. */
1604 if (_G.preserveCarry)
1606 sprintf (buffer, "%d", offset + _G.stack.pushed);
1607 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1608 emit2 ("add %s,sp", _pairs[pairId].name);
1609 _G.pairs[pairId].last_type = aop->type;
1610 _G.pairs[pairId].offset = offset;
1611 if (_G.preserveCarry)
1619 /* Doesnt include _G.stack.pushed */
1620 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1622 if (aop->aopu.aop_stk > 0)
1624 abso += _G.stack.param_offset;
1626 assert (pairId == PAIR_HL);
1627 /* In some cases we can still inc or dec hl */
1628 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1630 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1634 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1636 _G.pairs[pairId].offset = abso;
1641 if (pairId != aop->aopu.aop_pairId)
1642 genMovePairPair(aop->aopu.aop_pairId, pairId);
1643 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1649 _G.pairs[pairId].last_type = aop->type;
1655 emit2 ("!tlabeldef", key);
1656 _G.lines.current->isLabel = 1;
1660 /*-----------------------------------------------------------------*/
1661 /* aopGet - for fetching value of the aop */
1662 /*-----------------------------------------------------------------*/
1664 aopGet (asmop * aop, int offset, bool bit16)
1666 // char *s = buffer;
1668 /* offset is greater than size then zero */
1669 /* PENDING: this seems a bit screwed in some pointer cases. */
1670 if (offset > (aop->size - 1) &&
1671 aop->type != AOP_LIT)
1673 tsprintf (buffer, sizeof(buffer), "!zero");
1674 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1677 /* depending on type */
1681 tsprintf (buffer, sizeof(buffer), "!zero");
1682 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1685 /* PENDING: re-target */
1687 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1692 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1695 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1698 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1701 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1704 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1708 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1709 SNPRINTF (buffer, sizeof(buffer), "a");
1711 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1717 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1718 SNPRINTF (buffer, sizeof(buffer), "a");
1720 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1723 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1726 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1727 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1728 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1730 else if( z80_opts.port_mode == 180 )
1731 { /* z180 in0/out0 mode */
1732 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1736 emit2( "in a,(%s)", aop->aopu.aop_dir );
1739 SNPRINTF (buffer, sizeof(buffer), "a");
1741 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1745 return aop->aopu.aop_reg[offset]->name;
1749 setupPair (PAIR_HL, aop, offset);
1750 tsprintf (buffer, sizeof(buffer), "!*hl");
1752 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1756 setupPair (PAIR_IY, aop, offset);
1757 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1759 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1763 setupPair (PAIR_IY, aop, offset);
1764 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1766 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1771 setupPair (PAIR_HL, aop, offset);
1772 tsprintf (buffer, sizeof(buffer), "!*hl");
1776 if (aop->aopu.aop_stk >= 0)
1777 offset += _G.stack.param_offset;
1778 tsprintf (buffer, sizeof(buffer),
1779 "!*ixx", aop->aopu.aop_stk + offset);
1782 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1785 wassertl (0, "Tried to fetch from a bit variable");
1794 tsprintf(buffer, sizeof(buffer), "!zero");
1795 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1799 wassert (offset < 2);
1800 return aop->aopu.aop_str[offset];
1803 return aopLiteral (aop->aopu.aop_lit, offset);
1807 unsigned long v = aop->aopu.aop_simplelit;
1810 tsprintf (buffer, sizeof(buffer),
1811 "!immedbyte", (unsigned int) v & 0xff);
1813 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1817 return aop->aopu.aop_str[offset];
1820 setupPair (aop->aopu.aop_pairId, aop, offset);
1821 if (aop->aopu.aop_pairId==PAIR_IX)
1822 SNPRINTF (buffer, sizeof(buffer),
1824 else if (aop->aopu.aop_pairId==PAIR_IY)
1825 SNPRINTF (buffer, sizeof(buffer),
1828 SNPRINTF (buffer, sizeof(buffer),
1829 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1831 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1836 wassertl (0, "aopget got unsupported aop->type");
1841 isRegString (const char *s)
1843 if (!strcmp (s, "b") ||
1855 isConstant (const char *s)
1857 /* This is a bit of a hack... */
1858 return (*s == '#' || *s == '$');
1862 canAssignToPtr (const char *s)
1864 if (isRegString (s))
1871 /*-----------------------------------------------------------------*/
1872 /* aopPut - puts a string for a aop */
1873 /*-----------------------------------------------------------------*/
1875 aopPut (asmop * aop, const char *s, int offset)
1879 if (aop->size && offset > (aop->size - 1))
1881 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1882 "aopPut got offset > aop->size");
1887 tsprintf(buffer2, sizeof(buffer2), s);
1890 /* will assign value to value */
1891 /* depending on where it is ofcourse */
1895 _moveA (s); /* in case s is volatile */
1901 if (strcmp (s, "a"))
1902 emit2 ("ld a,%s", s);
1903 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1910 if (strcmp (s, "a"))
1911 emit2 ("ld a,%s", s);
1912 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1915 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1922 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1923 && s[0] != 'h' && s[0] != 'l'))
1925 emit2( "ld a,%s", s );
1929 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1930 emit2( "out (c),%s", s );
1935 spillPair (PAIR_BC);
1937 else if( z80_opts.port_mode == 180 )
1938 { /* z180 in0/out0 mode */
1939 emit2( "ld a,%s", s );
1940 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1944 emit2( "ld a,%s", s );
1945 emit2( "out (%s),a", aop->aopu.aop_dir );
1951 if (!strcmp (s, "!*hl"))
1952 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1955 aop->aopu.aop_reg[offset]->name, s);
1956 spillPairReg(aop->aopu.aop_reg[offset]->name);
1961 if (!canAssignToPtr (s))
1963 emit2 ("ld a,%s", s);
1964 setupPair (PAIR_IY, aop, offset);
1965 emit2 ("ld !*iyx,a", offset);
1969 setupPair (PAIR_IY, aop, offset);
1970 emit2 ("ld !*iyx,%s", offset, s);
1976 /* PENDING: for re-target */
1977 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1979 emit2 ("ld a,!*hl");
1982 setupPair (PAIR_HL, aop, offset);
1984 emit2 ("ld !*hl,%s", s);
1989 if (!canAssignToPtr (s))
1991 emit2 ("ld a,%s", s);
1992 setupPair (PAIR_IY, aop, offset);
1993 emit2 ("ld !*iyx,a", offset);
1997 setupPair (PAIR_IY, aop, offset);
1998 emit2 ("ld !*iyx,%s", offset, s);
2005 /* PENDING: re-target */
2006 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2008 emit2 ("ld a,!*hl");
2011 setupPair (PAIR_HL, aop, offset);
2012 if (!canAssignToPtr (s))
2014 emit2 ("ld a,%s", s);
2015 emit2 ("ld !*hl,a");
2018 emit2 ("ld !*hl,%s", s);
2022 if (aop->aopu.aop_stk >= 0)
2023 offset += _G.stack.param_offset;
2024 if (!canAssignToPtr (s))
2026 emit2 ("ld a,%s", s);
2027 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2031 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2037 /* if bit variable */
2038 if (!aop->aopu.aop_dir)
2040 emit2 ("ld a,!zero");
2045 /* In bit space but not in C - cant happen */
2046 wassertl (0, "Tried to write into a bit variable");
2052 if (strcmp (aop->aopu.aop_str[offset], s))
2054 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2056 spillPairReg(aop->aopu.aop_str[offset]);
2061 if (!offset && (strcmp (s, "acc") == 0))
2065 wassertl (0, "Tried to access past the end of A");
2069 if (strcmp (aop->aopu.aop_str[offset], s))
2071 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2072 spillPairReg(aop->aopu.aop_str[offset]);
2078 wassert (offset < 2);
2079 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2080 spillPairReg(aop->aopu.aop_str[offset]);
2084 setupPair (aop->aopu.aop_pairId, aop, offset);
2085 if (aop->aopu.aop_pairId==PAIR_IX)
2086 emit2 ("ld !*ixx,%s", 0, s);
2087 else if (aop->aopu.aop_pairId==PAIR_IY)
2088 emit2 ("ld !*iyx,%s", 0, s);
2090 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2094 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2095 "aopPut got unsupported aop->type");
2100 #define AOP(op) op->aop
2101 #define AOP_TYPE(op) AOP(op)->type
2102 #define AOP_SIZE(op) AOP(op)->size
2103 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2104 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2107 commitPair (asmop * aop, PAIR_ID id)
2109 /* PENDING: Verify this. */
2110 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2114 aopPut (aop, "a", 0);
2115 aopPut (aop, "d", 1);
2120 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2122 char *l = aopGetLitWordLong (aop, 0, FALSE);
2125 emit2 ("ld (%s),%s", l, _pairs[id].name);
2129 aopPut (aop, _pairs[id].l, 0);
2130 aopPut (aop, _pairs[id].h, 1);
2135 /*-----------------------------------------------------------------*/
2136 /* getDataSize - get the operand data size */
2137 /*-----------------------------------------------------------------*/
2139 getDataSize (operand * op)
2142 size = AOP_SIZE (op);
2146 wassertl (0, "Somehow got a three byte data pointer");
2151 /*-----------------------------------------------------------------*/
2152 /* movLeft2Result - move byte from left to result */
2153 /*-----------------------------------------------------------------*/
2155 movLeft2Result (operand * left, int offl,
2156 operand * result, int offr, int sign)
2160 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2162 l = aopGet (AOP (left), offl, FALSE);
2166 aopPut (AOP (result), l, offr);
2170 if (getDataSize (left) == offl + 1)
2172 emit2 ("ld a,%s", l);
2173 aopPut (AOP (result), "a", offr);
2180 movLeft2ResultLong (operand * left, int offl,
2181 operand * result, int offr, int sign,
2186 movLeft2Result (left, offl, result, offr, sign);
2190 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2191 wassertl (size == 2, "Only implemented for two bytes or one");
2193 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2195 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2196 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2198 spillPair (PAIR_HL);
2200 else if ( getPairId ( AOP (result)) == PAIR_IY)
2202 PAIR_ID id = getPairId (AOP (left));
2203 if (id != PAIR_INVALID)
2205 emit2("push %s", _pairs[id].name);
2216 movLeft2Result (left, offl, result, offr, sign);
2217 movLeft2Result (left, offl+1, result, offr+1, sign);
2222 /** Put Acc into a register set
2225 outAcc (operand * result)
2228 size = getDataSize (result);
2231 aopPut (AOP (result), "a", 0);
2234 /* unsigned or positive */
2237 aopPut (AOP (result), "!zero", offset++);
2242 /** Take the value in carry and put it into a register
2245 outBitC (operand * result)
2247 /* if the result is bit */
2248 if (AOP_TYPE (result) == AOP_CRY)
2250 if (!IS_OP_RUONLY (result))
2251 aopPut (AOP (result), "c", 0);
2255 emit2 ("ld a,!zero");
2261 /*-----------------------------------------------------------------*/
2262 /* toBoolean - emit code for orl a,operator(sizeop) */
2263 /*-----------------------------------------------------------------*/
2265 _toBoolean (operand * oper)
2267 int size = AOP_SIZE (oper);
2271 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2274 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2278 if (AOP (oper)->type != AOP_ACC)
2281 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2287 /*-----------------------------------------------------------------*/
2288 /* genNot - generate code for ! operation */
2289 /*-----------------------------------------------------------------*/
2294 /* assign asmOps to operand & result */
2295 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2296 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2298 /* if in bit space then a special case */
2299 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2301 wassertl (0, "Tried to negate a bit");
2304 _toBoolean (IC_LEFT (ic));
2309 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2310 emit2 ("sub a,!one");
2311 outBitC (IC_RESULT (ic));
2313 /* release the aops */
2314 freeAsmop (IC_LEFT (ic), NULL, ic);
2315 freeAsmop (IC_RESULT (ic), NULL, ic);
2318 /*-----------------------------------------------------------------*/
2319 /* genCpl - generate code for complement */
2320 /*-----------------------------------------------------------------*/
2328 /* assign asmOps to operand & result */
2329 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2330 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2332 /* if both are in bit space then
2334 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2335 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2337 wassertl (0, "Left and the result are in bit space");
2340 size = AOP_SIZE (IC_RESULT (ic));
2343 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2346 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2349 /* release the aops */
2350 freeAsmop (IC_LEFT (ic), NULL, ic);
2351 freeAsmop (IC_RESULT (ic), NULL, ic);
2355 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2362 store de into result
2367 store de into result
2369 const char *first = isAdd ? "add" : "sub";
2370 const char *later = isAdd ? "adc" : "sbc";
2372 wassertl (IS_GB, "Code is only relevent to the gbz80");
2373 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2375 fetchPair (PAIR_DE, left);
2378 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2381 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2384 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2385 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2387 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2388 aopGet (right, MSB24, FALSE);
2392 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2395 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2397 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2398 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2402 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2404 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2407 /*-----------------------------------------------------------------*/
2408 /* genUminusFloat - unary minus for floating points */
2409 /*-----------------------------------------------------------------*/
2411 genUminusFloat (operand * op, operand * result)
2413 int size, offset = 0;
2415 emitDebug("; genUminusFloat");
2417 /* for this we just need to flip the
2418 first bit then copy the rest in place */
2419 size = AOP_SIZE (op) - 1;
2421 _moveA(aopGet (AOP (op), MSB32, FALSE));
2423 emit2("xor a,!immedbyte", 0x80);
2424 aopPut (AOP (result), "a", MSB32);
2428 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2433 /*-----------------------------------------------------------------*/
2434 /* genUminus - unary minus code generation */
2435 /*-----------------------------------------------------------------*/
2437 genUminus (iCode * ic)
2440 sym_link *optype, *rtype;
2443 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2444 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2446 /* if both in bit space then special
2448 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2449 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2451 wassertl (0, "Left and right are in bit space");
2455 optype = operandType (IC_LEFT (ic));
2456 rtype = operandType (IC_RESULT (ic));
2458 /* if float then do float stuff */
2459 if (IS_FLOAT (optype))
2461 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2465 /* otherwise subtract from zero */
2466 size = AOP_SIZE (IC_LEFT (ic));
2468 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2470 /* Create a new asmop with value zero */
2471 asmop *azero = newAsmop (AOP_SIMPLELIT);
2472 azero->aopu.aop_simplelit = 0;
2474 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2482 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2483 emit2 ("ld a,!zero");
2484 emit2 ("sbc a,%s", l);
2485 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2488 /* if any remaining bytes in the result */
2489 /* we just need to propagate the sign */
2490 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2495 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2499 /* release the aops */
2500 freeAsmop (IC_LEFT (ic), NULL, ic);
2501 freeAsmop (IC_RESULT (ic), NULL, ic);
2504 /*-----------------------------------------------------------------*/
2505 /* assignResultValue - */
2506 /*-----------------------------------------------------------------*/
2508 assignResultValue (operand * oper)
2510 int size = AOP_SIZE (oper);
2514 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2515 topInA = requiresHL (AOP (oper));
2517 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2519 /* We do it the hard way here. */
2521 aopPut (AOP (oper), _fReturn[0], 0);
2522 aopPut (AOP (oper), _fReturn[1], 1);
2524 aopPut (AOP (oper), _fReturn[0], 2);
2525 aopPut (AOP (oper), _fReturn[1], 3);
2529 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2530 !strcmp (AOP (oper)->aopu.aop_reg[size-2]->name, _fReturn[size-1]))
2533 _emitMove ("a", _fReturn[size-1]);
2534 _emitMove (_fReturn[size-1], _fReturn[size]);
2535 _emitMove (_fReturn[size], "a");
2536 aopPut (AOP (oper), _fReturn[size], size-1);
2539 for (i = 0; i < size; i++)
2541 aopPut (AOP (oper), _fReturn[i], i);
2546 /** Simple restore that doesn't take into account what is used in the
2550 _restoreRegsAfterCall(void)
2552 if (_G.stack.pushedDE)
2555 _G.stack.pushedDE = FALSE;
2557 if (_G.stack.pushedBC)
2560 _G.stack.pushedBC = FALSE;
2562 _G.saves.saved = FALSE;
2566 _saveRegsForCall(iCode *ic, int sendSetSize)
2569 o Stack parameters are pushed before this function enters
2570 o DE and BC may be used in this function.
2571 o HL and DE may be used to return the result.
2572 o HL and DE may be used to send variables.
2573 o DE and BC may be used to store the result value.
2574 o HL may be used in computing the sent value of DE
2575 o The iPushes for other parameters occur before any addSets
2577 Logic: (to be run inside the first iPush or if none, before sending)
2578 o Compute if DE and/or BC are in use over the call
2579 o Compute if DE is used in the send set
2580 o Compute if DE and/or BC are used to hold the result value
2581 o If (DE is used, or in the send set) and is not used in the result, push.
2582 o If BC is used and is not in the result, push
2584 o If DE is used in the send set, fetch
2585 o If HL is used in the send set, fetch
2589 if (_G.saves.saved == FALSE) {
2590 bool deInUse, bcInUse;
2592 bool bcInRet = FALSE, deInRet = FALSE;
2595 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2596 z80_rUmaskForOp (IC_RESULT(ic)));
2598 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2599 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2601 deSending = (sendSetSize > 1);
2603 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2605 if (bcInUse && bcInRet == FALSE) {
2607 _G.stack.pushedBC = TRUE;
2609 if (deInUse && deInRet == FALSE) {
2611 _G.stack.pushedDE = TRUE;
2614 _G.saves.saved = TRUE;
2617 /* Already saved. */
2621 /*-----------------------------------------------------------------*/
2622 /* genIpush - genrate code for pushing this gets a little complex */
2623 /*-----------------------------------------------------------------*/
2625 genIpush (iCode * ic)
2627 int size, offset = 0;
2630 /* if this is not a parm push : ie. it is spill push
2631 and spill push is always done on the local stack */
2634 wassertl(0, "Encountered an unsupported spill push.");
2638 if (_G.saves.saved == FALSE) {
2639 /* Caller saves, and this is the first iPush. */
2640 /* Scan ahead until we find the function that we are pushing parameters to.
2641 Count the number of addSets on the way to figure out what registers
2642 are used in the send set.
2645 iCode *walk = ic->next;
2648 if (walk->op == SEND) {
2651 else if (walk->op == CALL || walk->op == PCALL) {
2660 _saveRegsForCall(walk, nAddSets);
2663 /* Already saved by another iPush. */
2666 /* then do the push */
2667 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2669 size = AOP_SIZE (IC_LEFT (ic));
2671 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2673 _G.stack.pushed += 2;
2674 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2680 fetchHL (AOP (IC_LEFT (ic)));
2682 spillPair (PAIR_HL);
2683 _G.stack.pushed += 2;
2688 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2690 spillPair (PAIR_HL);
2691 _G.stack.pushed += 2;
2692 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2694 spillPair (PAIR_HL);
2695 _G.stack.pushed += 2;
2701 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2703 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2705 emit2 ("ld a,(%s)", l);
2710 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2711 if (!strcmp(l, "b"))
2713 else if (!strcmp(l, "d"))
2715 else if (!strcmp(l, "h"))
2719 emit2 ("ld a,%s", l);
2728 freeAsmop (IC_LEFT (ic), NULL, ic);
2731 /*-----------------------------------------------------------------*/
2732 /* genIpop - recover the registers: can happen only for spilling */
2733 /*-----------------------------------------------------------------*/
2735 genIpop (iCode * ic)
2740 /* if the temp was not pushed then */
2741 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2744 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2745 size = AOP_SIZE (IC_LEFT (ic));
2746 offset = (size - 1);
2747 if (isPair (AOP (IC_LEFT (ic))))
2749 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2757 spillPair (PAIR_HL);
2758 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2762 freeAsmop (IC_LEFT (ic), NULL, ic);
2765 /* This is quite unfortunate */
2767 setArea (int inHome)
2770 static int lastArea = 0;
2772 if (_G.in_home != inHome) {
2774 const char *sz = port->mem.code_name;
2775 port->mem.code_name = "HOME";
2776 emit2("!area", CODE_NAME);
2777 port->mem.code_name = sz;
2780 emit2("!area", CODE_NAME); */
2781 _G.in_home = inHome;
2792 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2796 symbol *sym = OP_SYMBOL (op);
2798 if (sym->isspilt || sym->nRegs == 0)
2801 aopOp (op, ic, FALSE, FALSE);
2804 if (aop->type == AOP_REG)
2807 for (i = 0; i < aop->size; i++)
2809 if (pairId == PAIR_DE)
2811 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2812 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2814 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2817 else if (pairId == PAIR_BC)
2819 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2820 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2822 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2832 freeAsmop (IC_LEFT (ic), NULL, ic);
2836 /** Emit the code for a call statement
2839 emitCall (iCode * ic, bool ispcall)
2841 bool bInRet, cInRet, dInRet, eInRet;
2842 sym_link *dtype = operandType (IC_LEFT (ic));
2844 /* if caller saves & we have not saved then */
2850 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2852 /* if send set is not empty then assign */
2857 int nSend = elementsInSet(_G.sendSet);
2858 bool swapped = FALSE;
2860 int _z80_sendOrder[] = {
2865 /* Check if the parameters are swapped. If so route through hl instead. */
2866 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2868 sic = setFirstItem(_G.sendSet);
2869 sic = setNextItem(_G.sendSet);
2871 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2872 /* The second send value is loaded from one the one that holds the first
2873 send, i.e. it is overwritten. */
2874 /* Cache the first in HL, and load the second from HL instead. */
2875 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2876 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2882 for (sic = setFirstItem (_G.sendSet); sic;
2883 sic = setNextItem (_G.sendSet))
2886 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2888 size = AOP_SIZE (IC_LEFT (sic));
2889 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2890 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2892 // PENDING: Mild hack
2893 if (swapped == TRUE && send == 1) {
2895 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2898 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2900 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2903 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2907 freeAsmop (IC_LEFT (sic), NULL, sic);
2914 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2916 werror (W_INDIR_BANKED);
2918 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2920 if (isLitWord (AOP (IC_LEFT (ic))))
2922 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2926 symbol *rlbl = newiTempLabel (NULL);
2927 spillPair (PAIR_HL);
2928 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2930 _G.stack.pushed += 2;
2932 fetchHL (AOP (IC_LEFT (ic)));
2934 emit2 ("!tlabeldef", (rlbl->key + 100));
2935 _G.lines.current->isLabel = 1;
2936 _G.stack.pushed -= 2;
2938 freeAsmop (IC_LEFT (ic), NULL, ic);
2942 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2943 OP_SYMBOL (IC_LEFT (ic))->rname :
2944 OP_SYMBOL (IC_LEFT (ic))->name;
2945 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2947 emit2 ("call banked_call");
2948 emit2 ("!dws", name);
2949 emit2 ("!dw !bankimmeds", name);
2954 emit2 ("call %s", name);
2959 /* Mark the registers as restored. */
2960 _G.saves.saved = FALSE;
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");
2996 /* if we need assign a result value */
2997 if ((IS_ITEMP (IC_RESULT (ic)) &&
2998 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2999 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3000 IS_TRUE_SYMOP (IC_RESULT (ic)))
3002 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3004 assignResultValue (IC_RESULT (ic));
3006 freeAsmop (IC_RESULT (ic), NULL, ic);
3012 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3013 bInRet = bitVectBitValue(result, B_IDX);
3014 cInRet = bitVectBitValue(result, C_IDX);
3015 dInRet = bitVectBitValue(result, D_IDX);
3016 eInRet = bitVectBitValue(result, E_IDX);
3026 if (_G.stack.pushedDE)
3028 if (dInRet && eInRet)
3030 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3034 /* Only restore E */
3041 /* Only restore D */
3049 _G.stack.pushedDE = FALSE;
3052 if (_G.stack.pushedBC)
3054 if (bInRet && cInRet)
3056 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3060 /* Only restore C */
3067 /* Only restore B */
3075 _G.stack.pushedBC = FALSE;
3079 /*-----------------------------------------------------------------*/
3080 /* genCall - generates a call statement */
3081 /*-----------------------------------------------------------------*/
3083 genCall (iCode * ic)
3085 emitCall (ic, FALSE);
3088 /*-----------------------------------------------------------------*/
3089 /* genPcall - generates a call by pointer statement */
3090 /*-----------------------------------------------------------------*/
3092 genPcall (iCode * ic)
3094 emitCall (ic, TRUE);
3097 /*-----------------------------------------------------------------*/
3098 /* resultRemat - result is rematerializable */
3099 /*-----------------------------------------------------------------*/
3101 resultRemat (iCode * ic)
3103 if (SKIP_IC (ic) || ic->op == IFX)
3106 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3108 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3109 if (sym->remat && !POINTER_SET (ic))
3116 extern set *publics;
3118 /*-----------------------------------------------------------------*/
3119 /* genFunction - generated code for function entry */
3120 /*-----------------------------------------------------------------*/
3122 genFunction (iCode * ic)
3126 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3129 bool bcInUse = FALSE;
3130 bool deInUse = FALSE;
3132 setArea (IFFUNC_NONBANKED (sym->type));
3134 /* PENDING: Reset the receive offset as it
3135 doesn't seem to get reset anywhere else.
3137 _G.receiveOffset = 0;
3139 /* Record the last function name for debugging. */
3140 _G.lastFunctionName = sym->rname;
3142 /* Create the function header */
3143 emit2 ("!functionheader", sym->name);
3144 if (!IS_STATIC(sym->etype))
3146 sprintf (buffer, "%s_start", sym->rname);
3147 emit2 ("!labeldef", buffer);
3148 _G.lines.current->isLabel = 1;
3150 emit2 ("!functionlabeldef", sym->rname);
3151 _G.lines.current->isLabel = 1;
3153 ftype = operandType (IC_LEFT (ic));
3155 if (IFFUNC_ISNAKED(ftype))
3157 emitDebug("; naked function: no prologue.");
3161 /* if this is an interrupt service routine
3162 then save all potentially used registers. */
3163 if (IFFUNC_ISISR (sym->type))
3165 /* If critical function then turn interrupts off */
3166 /* except when no interrupt number is given then it implies the NMI handler */
3167 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3176 /* This is a non-ISR function.
3177 If critical function then turn interrupts off */
3178 if (IFFUNC_ISCRITICAL (sym->type))
3186 //get interrupt enable flag IFF2 into P/O
3195 if (options.profile)
3197 emit2 ("!profileenter");
3200 /* PENDING: callee-save etc */
3202 _G.stack.param_offset = 0;
3204 if (z80_opts.calleeSavesBC)
3209 /* Detect which registers are used. */
3210 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3213 for (i = 0; i < sym->regsUsed->size; i++)
3215 if (bitVectBitValue (sym->regsUsed, i))
3229 /* Other systems use DE as a temporary. */
3240 _G.stack.param_offset += 2;
3243 _G.calleeSaves.pushedBC = bcInUse;
3248 _G.stack.param_offset += 2;
3251 _G.calleeSaves.pushedDE = deInUse;
3253 /* adjust the stack for the function */
3254 _G.stack.last = sym->stack;
3257 for (sym = setFirstItem (istack->syms); sym;
3258 sym = setNextItem (istack->syms))
3260 if (sym->_isparm && !IS_REGPARM (sym->etype))
3266 sym = OP_SYMBOL (IC_LEFT (ic));
3268 _G.omitFramePtr = options.ommitFramePtr;
3269 if (IS_Z80 && !stackParm && !sym->stack)
3271 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3272 /* the above !sym->stack condition can be removed. -- EEP */
3274 emit2 ("!ldaspsp", -sym->stack);
3275 _G.omitFramePtr = TRUE;
3277 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3278 emit2 ("!enterxl", sym->stack);
3279 else if (sym->stack)
3281 if (optimize.codeSize && sym->stack <= 8 || sym->stack <= 4)
3283 int stack = sym->stack;
3294 emit2 ("!enterx", sym->stack);
3299 _G.stack.offset = sym->stack;
3302 /*-----------------------------------------------------------------*/
3303 /* genEndFunction - generates epilogue for functions */
3304 /*-----------------------------------------------------------------*/
3306 genEndFunction (iCode * ic)
3308 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3310 if (IFFUNC_ISNAKED(sym->type))
3312 emitDebug("; naked function: no epilogue.");
3316 /* PENDING: calleeSave */
3317 if (IS_Z80 && _G.omitFramePtr)
3319 if (_G.stack.offset)
3320 emit2 ("!ldaspsp", _G.stack.offset);
3322 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3324 emit2 ("!leavexl", _G.stack.offset);
3326 else if (_G.stack.offset)
3328 emit2 ("!leavex", _G.stack.offset);
3335 if (_G.calleeSaves.pushedDE)
3338 _G.calleeSaves.pushedDE = FALSE;
3341 if (_G.calleeSaves.pushedBC)
3344 _G.calleeSaves.pushedBC = FALSE;
3347 if (options.profile)
3349 emit2 ("!profileexit");
3352 /* if this is an interrupt service routine
3353 then save all potentially used registers. */
3354 if (IFFUNC_ISISR (sym->type))
3358 /* If critical function then turn interrupts back on */
3359 /* except when no interrupt number is given then it implies the NMI handler */
3360 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3367 /* This is a non-ISR function.
3368 If critical function then turn interrupts back on */
3369 if (IFFUNC_ISCRITICAL (sym->type))
3377 symbol *tlbl = newiTempLabel (NULL);
3380 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3381 //don't enable interrupts as they were off before
3382 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3384 emit2 ("!tlabeldef", (tlbl->key + 100));
3385 _G.lines.current->isLabel = 1;
3390 if (options.debug && currFunc)
3392 debugFile->writeEndFunction (currFunc, ic, 1);
3395 if (IFFUNC_ISISR (sym->type))
3397 /* "critical interrupt" is used to imply NMI handler */
3398 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3405 /* Both banked and non-banked just ret */
3409 if (!IS_STATIC(sym->etype))
3411 sprintf (buffer, "%s_end", sym->rname);
3412 emit2 ("!labeldef", buffer);
3413 _G.lines.current->isLabel = 1;
3416 _G.flushStatics = 1;
3417 _G.stack.pushed = 0;
3418 _G.stack.offset = 0;
3421 /*-----------------------------------------------------------------*/
3422 /* genRet - generate code for return statement */
3423 /*-----------------------------------------------------------------*/
3428 /* Errk. This is a hack until I can figure out how
3429 to cause dehl to spill on a call */
3430 int size, offset = 0;
3432 /* if we have no return value then
3433 just generate the "ret" */
3437 /* we have something to return then
3438 move the return value into place */
3439 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3440 size = AOP_SIZE (IC_LEFT (ic));
3442 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3445 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3449 emit2 ("ld de,%s", l);
3453 emit2 ("ld hl,%s", l);
3459 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3463 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3465 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3466 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3472 l = aopGet (AOP (IC_LEFT (ic)), offset,
3474 if (strcmp (_fReturn[offset], l))
3475 emit2 ("ld %s,%s", _fReturn[offset], l);
3480 freeAsmop (IC_LEFT (ic), NULL, ic);
3483 /* generate a jump to the return label
3484 if the next is not the return statement */
3485 if (!(ic->next && ic->next->op == LABEL &&
3486 IC_LABEL (ic->next) == returnLabel))
3488 emit2 ("jp !tlabel", returnLabel->key + 100);
3491 /*-----------------------------------------------------------------*/
3492 /* genLabel - generates a label */
3493 /*-----------------------------------------------------------------*/
3495 genLabel (iCode * ic)
3497 /* special case never generate */
3498 if (IC_LABEL (ic) == entryLabel)
3501 emitLabel (IC_LABEL (ic)->key + 100);
3504 /*-----------------------------------------------------------------*/
3505 /* genGoto - generates a ljmp */
3506 /*-----------------------------------------------------------------*/
3508 genGoto (iCode * ic)
3510 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3513 /*-----------------------------------------------------------------*/
3514 /* genPlusIncr :- does addition with increment if possible */
3515 /*-----------------------------------------------------------------*/
3517 genPlusIncr (iCode * ic)
3519 unsigned int icount;
3520 unsigned int size = getDataSize (IC_RESULT (ic));
3521 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3523 /* will try to generate an increment */
3524 /* if the right side is not a literal
3526 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3529 emitDebug ("; genPlusIncr");
3531 icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3533 /* If result is a pair */
3534 if (resultId != PAIR_INVALID)
3536 if (isLitWord (AOP (IC_LEFT (ic))))
3538 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3541 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3543 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3545 PAIR_ID freep = getFreePairId (ic);
3546 if (freep != PAIR_INVALID)
3548 fetchPair (freep, AOP (IC_RIGHT (ic)));
3549 emit2 ("add hl,%s", _pairs[freep].name);
3555 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3556 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3563 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3567 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3571 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3576 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3578 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3579 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3583 /* if the literal value of the right hand side
3584 is greater than 4 then it is not worth it */
3588 /* if increment 16 bits in register */
3589 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3595 symbol *tlbl = NULL;
3596 tlbl = newiTempLabel (NULL);
3599 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3602 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3605 emitLabel (tlbl->key + 100);
3609 /* if the sizes are greater than 1 then we cannot */
3610 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3611 AOP_SIZE (IC_LEFT (ic)) > 1)
3614 /* If the result is in a register then we can load then increment.
3616 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3618 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3621 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3626 /* we can if the aops of the left & result match or
3627 if they are in registers and the registers are the
3629 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3633 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3641 /*-----------------------------------------------------------------*/
3642 /* outBitAcc - output a bit in acc */
3643 /*-----------------------------------------------------------------*/
3645 outBitAcc (operand * result)
3647 symbol *tlbl = newiTempLabel (NULL);
3648 /* if the result is a bit */
3649 if (AOP_TYPE (result) == AOP_CRY)
3651 wassertl (0, "Tried to write A into a bit");
3655 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3656 emit2 ("ld a,!one");
3657 emitLabel (tlbl->key + 100);
3663 couldDestroyCarry (asmop *aop)
3667 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3676 shiftIntoPair (int idx, asmop *aop)
3678 PAIR_ID id = PAIR_INVALID;
3680 wassertl (IS_Z80, "Only implemented for the Z80");
3681 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3683 emitDebug ("; Shift into pair idx %u", idx);
3689 setupPair (PAIR_HL, aop, 0);
3694 setupPair (PAIR_IY, aop, 0);
3696 emit2 ("pop %s", _pairs[id].name);
3700 setupPair (PAIR_IY, aop, 0);
3703 wassertl (0, "Internal error - hit default case");
3706 aop->type = AOP_PAIRPTR;
3707 aop->aopu.aop_pairId = id;
3708 _G.pairs[id].offset = 0;
3709 _G.pairs[id].last_type = aop->type;
3713 setupToPreserveCarry (iCode * ic)
3715 asmop *left = AOP (IC_LEFT (ic));
3716 asmop *right = AOP (IC_RIGHT (ic));
3717 asmop *result = AOP (IC_RESULT (ic));
3719 wassert (left && right);
3723 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3725 shiftIntoPair (0, right);
3726 /* check result again, in case right == result */
3727 if (couldDestroyCarry (result))
3729 if (!isPairInUse (PAIR_DE, ic))
3730 shiftIntoPair (1, result);
3732 shiftIntoPair (2, result);
3735 else if (couldDestroyCarry (right))
3737 if (getPairId (result) == PAIR_HL)
3738 _G.preserveCarry = TRUE;
3740 shiftIntoPair (0, right);
3742 else if (couldDestroyCarry (result))
3744 shiftIntoPair (0, result);
3753 /*-----------------------------------------------------------------*/
3754 /* genPlus - generates code for addition */
3755 /*-----------------------------------------------------------------*/
3757 genPlus (iCode * ic)
3759 int size, offset = 0;
3761 /* special cases :- */
3763 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3764 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3765 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3767 /* Swap the left and right operands if:
3769 if literal, literal on the right or
3770 if left requires ACC or right is already
3773 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3774 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3775 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3777 operand *t = IC_RIGHT (ic);
3778 IC_RIGHT (ic) = IC_LEFT (ic);
3782 /* if both left & right are in bit
3784 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3785 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3788 wassertl (0, "Tried to add two bits");
3791 /* if left in bit space & right literal */
3792 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3793 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3795 /* Can happen I guess */
3796 wassertl (0, "Tried to add a bit to a literal");
3799 /* if I can do an increment instead
3800 of add then GOOD for ME */
3801 if (genPlusIncr (ic) == TRUE)
3804 size = getDataSize (IC_RESULT (ic));
3806 /* Special case when left and right are constant */
3807 if (isPair (AOP (IC_RESULT (ic))))
3810 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3811 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3813 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3819 sprintf (buffer, "#(%s + %s)", left, right);
3820 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3825 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3827 /* Fetch into HL then do the add */
3828 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3829 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3831 spillPair (PAIR_HL);
3833 if (left == PAIR_HL && right != PAIR_INVALID)
3835 emit2 ("add hl,%s", _pairs[right].name);
3838 else if (right == PAIR_HL && left != PAIR_INVALID)
3840 emit2 ("add hl,%s", _pairs[left].name);
3843 else if (right != PAIR_INVALID && right != PAIR_HL)
3845 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3846 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3849 else if (left != PAIR_INVALID && left != PAIR_HL)
3851 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3852 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3861 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3863 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3864 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3865 spillPair (PAIR_HL);
3866 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3870 if (isPair (AOP (IC_LEFT (ic))) && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && getPairId (AOP (IC_LEFT (ic))) != PAIR_HL)
3872 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3873 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3874 spillPair (PAIR_HL);
3875 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3880 ld hl,sp+n trashes C so we can't afford to do it during an
3881 add with stack based variables. Worst case is:
3894 So you can't afford to load up hl if either left, right, or result
3895 is on the stack (*sigh*) The alt is:
3903 Combinations in here are:
3904 * If left or right are in bc then the loss is small - trap later
3905 * If the result is in bc then the loss is also small
3909 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3910 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3911 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3913 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3914 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3915 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3916 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3918 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3920 /* Swap left and right */
3921 operand *t = IC_RIGHT (ic);
3922 IC_RIGHT (ic) = IC_LEFT (ic);
3925 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3927 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3928 emit2 ("add hl,bc");
3932 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3933 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3934 emit2 ("add hl,de");
3936 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3942 /* Be paranoid on the GB with 4 byte variables due to how C
3943 can be trashed by lda hl,n(sp).
3945 _gbz80_emitAddSubLong (ic, TRUE);
3950 setupToPreserveCarry (ic);
3952 /* This is ugly, but it fixes the worst code generation bug on Z80. */
3953 /* Probably something similar has to be done for addition of larger numbers, too. */
3956 _moveA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3957 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), 0, FALSE));
3958 if(strcmp (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), aopGet (AOP (IC_LEFT (ic)), 1, FALSE)))
3960 aopPut (AOP (IC_RESULT (ic)), "a", 0);
3961 _moveA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3965 emitDebug ("; Addition result is in same register as operand of next addition.");
3966 if(strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'c') ||
3967 strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'b') )
3971 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3974 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3982 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3985 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3991 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), 1, FALSE));
3992 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3998 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4000 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4002 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4003 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4007 _G.preserveCarry = FALSE;
4008 freeAsmop (IC_LEFT (ic), NULL, ic);
4009 freeAsmop (IC_RIGHT (ic), NULL, ic);
4010 freeAsmop (IC_RESULT (ic), NULL, ic);
4013 /*-----------------------------------------------------------------*/
4014 /* genMinusDec :- does subtraction with deccrement if possible */
4015 /*-----------------------------------------------------------------*/
4017 genMinusDec (iCode * ic)
4019 unsigned int icount;
4020 unsigned int size = getDataSize (IC_RESULT (ic));
4022 /* will try to generate an increment */
4023 /* if the right side is not a literal we cannot */
4024 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4027 /* if the literal value of the right hand side
4028 is greater than 4 then it is not worth it */
4029 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
4032 size = getDataSize (IC_RESULT (ic));
4034 /* if decrement 16 bits in register */
4035 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4036 (size > 1) && isPair (AOP (IC_RESULT (ic))))
4039 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4043 /* If result is a pair */
4044 if (isPair (AOP (IC_RESULT (ic))))
4046 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
4048 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4052 /* if increment 16 bits in register */
4053 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4057 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4060 emit2 ("dec %s", _getTempPairName());
4063 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4069 /* if the sizes are greater than 1 then we cannot */
4070 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4071 AOP_SIZE (IC_LEFT (ic)) > 1)
4074 /* we can if the aops of the left & result match or if they are in
4075 registers and the registers are the same */
4076 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4079 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4086 /*-----------------------------------------------------------------*/
4087 /* genMinus - generates code for subtraction */
4088 /*-----------------------------------------------------------------*/
4090 genMinus (iCode * ic)
4092 int size, offset = 0;
4093 unsigned long lit = 0L;
4095 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4096 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4097 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4099 /* special cases :- */
4100 /* if both left & right are in bit space */
4101 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4102 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4104 wassertl (0, "Tried to subtract two bits");
4108 /* if I can do an decrement instead of subtract then GOOD for ME */
4109 if (genMinusDec (ic) == TRUE)
4112 size = getDataSize (IC_RESULT (ic));
4114 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4119 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4123 /* Same logic as genPlus */
4126 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4127 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4128 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4130 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4131 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4132 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4133 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4135 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4136 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4138 if (left == PAIR_INVALID && right == PAIR_INVALID)
4143 else if (right == PAIR_INVALID)
4145 else if (left == PAIR_INVALID)
4148 fetchPair (left, AOP (IC_LEFT (ic)));
4149 /* Order is important. Right may be HL */
4150 fetchPair (right, AOP (IC_RIGHT (ic)));
4152 emit2 ("ld a,%s", _pairs[left].l);
4153 emit2 ("sub a,%s", _pairs[right].l);
4155 emit2 ("ld a,%s", _pairs[left].h);
4156 emit2 ("sbc a,%s", _pairs[right].h);
4158 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4160 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4162 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4168 /* Be paranoid on the GB with 4 byte variables due to how C
4169 can be trashed by lda hl,n(sp).
4171 _gbz80_emitAddSubLong (ic, FALSE);
4176 setupToPreserveCarry (ic);
4178 /* if literal, add a,#-lit, else normal subb */
4181 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4182 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4186 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4189 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4193 /* first add without previous c */
4196 if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
4199 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4202 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4204 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4207 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4208 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4209 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4211 wassertl (0, "Tried to subtract on a long pointer");
4215 _G.preserveCarry = FALSE;
4216 freeAsmop (IC_LEFT (ic), NULL, ic);
4217 freeAsmop (IC_RIGHT (ic), NULL, ic);
4218 freeAsmop (IC_RESULT (ic), NULL, ic);
4221 /*-----------------------------------------------------------------*/
4222 /* genMult - generates code for multiplication */
4223 /*-----------------------------------------------------------------*/
4225 genMult (iCode * ic)
4229 /* If true then the final operation should be a subtract */
4230 bool active = FALSE;
4233 /* Shouldn't occur - all done through function calls */
4234 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4235 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4236 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4238 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4240 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4241 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4242 AOP_SIZE (IC_RESULT (ic)) > 2)
4244 wassertl (0, "Multiplication is handled through support function calls");
4247 /* Swap left and right such that right is a literal */
4248 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4250 operand *t = IC_RIGHT (ic);
4251 IC_RIGHT (ic) = IC_LEFT (ic);
4255 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4257 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4258 // wassertl (val > 0, "Multiply must be positive");
4259 wassertl (val != 1, "Can't multiply by 1");
4261 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4263 _G.stack.pushedDE = TRUE;
4267 emit2 ("ld a,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4268 else if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4270 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4281 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4286 for (count = 0; count < 16; count++)
4288 if (count != 0 && active)
4293 emit2 ("add hl,hl");
4297 if (active == FALSE)
4312 emit2 ("add hl,de");
4321 if (IS_Z80 && _G.stack.pushedDE)
4324 _G.stack.pushedDE = FALSE;
4328 aopPut (AOP (IC_RESULT (ic)), "a", 0);
4330 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4332 freeAsmop (IC_LEFT (ic), NULL, ic);
4333 freeAsmop (IC_RIGHT (ic), NULL, ic);
4334 freeAsmop (IC_RESULT (ic), NULL, ic);
4337 /*-----------------------------------------------------------------*/
4338 /* genDiv - generates code for division */
4339 /*-----------------------------------------------------------------*/
4343 /* Shouldn't occur - all done through function calls */
4344 wassertl (0, "Division is handled through support function calls");
4347 /*-----------------------------------------------------------------*/
4348 /* genMod - generates code for division */
4349 /*-----------------------------------------------------------------*/
4353 /* Shouldn't occur - all done through function calls */
4357 /*-----------------------------------------------------------------*/
4358 /* genIfxJump :- will create a jump depending on the ifx */
4359 /*-----------------------------------------------------------------*/
4361 genIfxJump (iCode * ic, char *jval)
4366 /* if true label then we jump if condition
4370 jlbl = IC_TRUE (ic);
4371 if (!strcmp (jval, "a"))
4375 else if (!strcmp (jval, "c"))
4379 else if (!strcmp (jval, "nc"))
4383 else if (!strcmp (jval, "m"))
4387 else if (!strcmp (jval, "p"))
4393 /* The buffer contains the bit on A that we should test */
4399 /* false label is present */
4400 jlbl = IC_FALSE (ic);
4401 if (!strcmp (jval, "a"))
4405 else if (!strcmp (jval, "c"))
4409 else if (!strcmp (jval, "nc"))
4413 else if (!strcmp (jval, "m"))
4417 else if (!strcmp (jval, "p"))
4423 /* The buffer contains the bit on A that we should test */
4427 /* Z80 can do a conditional long jump */
4428 if (!strcmp (jval, "a"))
4432 else if (!strcmp (jval, "c"))
4435 else if (!strcmp (jval, "nc"))
4438 else if (!strcmp (jval, "m"))
4441 else if (!strcmp (jval, "p"))
4446 emit2 ("bit %s,a", jval);
4448 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4450 /* mark the icode as generated */
4456 _getPairIdName (PAIR_ID id)
4458 return _pairs[id].name;
4463 /* if unsigned char cmp with lit, just compare */
4465 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4467 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4470 emit2 ("xor a,!immedbyte", 0x80);
4471 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4474 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4476 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4478 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4479 // Pull left into DE and right into HL
4480 aopGet (AOP(left), LSB, FALSE);
4483 aopGet (AOP(right), LSB, FALSE);
4487 if (size == 0 && sign)
4489 // Highest byte when signed needs the bits flipped
4492 emit2 ("ld a,(de)");
4493 emit2 ("xor !immedbyte", 0x80);
4495 emit2 ("ld a,(hl)");
4496 emit2 ("xor !immedbyte", 0x80);
4500 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4504 emit2 ("ld a,(de)");
4505 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4515 spillPair (PAIR_HL);
4517 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4519 setupPair (PAIR_HL, AOP (left), 0);
4520 aopGet (AOP(right), LSB, FALSE);
4524 if (size == 0 && sign)
4526 // Highest byte when signed needs the bits flipped
4529 emit2 ("ld a,(hl)");
4530 emit2 ("xor !immedbyte", 0x80);
4532 emit2 ("ld a,%d(iy)", offset);
4533 emit2 ("xor !immedbyte", 0x80);
4537 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4541 emit2 ("ld a,(hl)");
4542 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4551 spillPair (PAIR_HL);
4552 spillPair (PAIR_IY);
4556 if (AOP_TYPE (right) == AOP_LIT)
4558 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4559 /* optimize if(x < 0) or if(x >= 0) */
4564 /* No sign so it's always false */
4569 /* Just load in the top most bit */
4570 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4571 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4573 genIfxJump (ifx, "7");
4585 /* First setup h and l contaning the top most bytes XORed */
4586 bool fDidXor = FALSE;
4587 if (AOP_TYPE (left) == AOP_LIT)
4589 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4590 emit2 ("ld %s,!immedbyte", _fTmp[0],
4591 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4595 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4596 emit2 ("xor a,!immedbyte", 0x80);
4597 emit2 ("ld %s,a", _fTmp[0]);
4600 if (AOP_TYPE (right) == AOP_LIT)
4602 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4603 emit2 ("ld %s,!immedbyte", _fTmp[1],
4604 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4608 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4609 emit2 ("xor a,!immedbyte", 0x80);
4610 emit2 ("ld %s,a", _fTmp[1]);
4616 /* Do a long subtract */
4619 _moveA (aopGet (AOP (left), offset, FALSE));
4621 if (sign && size == 0)
4623 emit2 ("ld a,%s", _fTmp[0]);
4624 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4628 /* Subtract through, propagating the carry */
4629 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4637 /** Generic compare for > or <
4640 genCmp (operand * left, operand * right,
4641 operand * result, iCode * ifx, int sign)
4643 int size, offset = 0;
4644 unsigned long lit = 0L;
4646 /* if left & right are bit variables */
4647 if (AOP_TYPE (left) == AOP_CRY &&
4648 AOP_TYPE (right) == AOP_CRY)
4650 /* Cant happen on the Z80 */
4651 wassertl (0, "Tried to compare two bits");
4655 /* Do a long subtract of right from left. */
4656 size = max (AOP_SIZE (left), AOP_SIZE (right));
4658 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4660 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4661 // Pull left into DE and right into HL
4662 aopGet (AOP(left), LSB, FALSE);
4665 aopGet (AOP(right), LSB, FALSE);
4669 emit2 ("ld a,(de)");
4670 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4679 spillPair (PAIR_HL);
4683 if (AOP_TYPE (right) == AOP_LIT)
4685 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4686 /* optimize if(x < 0) or if(x >= 0) */
4691 /* No sign so it's always false */
4696 /* Just load in the top most bit */
4697 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4698 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4700 genIfxJump (ifx, "7");
4711 genIfxJump (ifx, "nc");
4722 _moveA (aopGet (AOP (left), offset, FALSE));
4723 /* Subtract through, propagating the carry */
4724 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4730 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4734 /* Shift the sign bit up into carry */
4741 /* if the result is used in the next
4742 ifx conditional branch then generate
4743 code a little differently */
4751 genIfxJump (ifx, "c");
4755 genIfxJump (ifx, "m");
4760 genIfxJump (ifx, "c");
4767 /* Shift the sign bit up into carry */
4772 /* leave the result in acc */
4776 /*-----------------------------------------------------------------*/
4777 /* genCmpGt :- greater than comparison */
4778 /*-----------------------------------------------------------------*/
4780 genCmpGt (iCode * ic, iCode * ifx)
4782 operand *left, *right, *result;
4783 sym_link *letype, *retype;
4786 left = IC_LEFT (ic);
4787 right = IC_RIGHT (ic);
4788 result = IC_RESULT (ic);
4790 letype = getSpec (operandType (left));
4791 retype = getSpec (operandType (right));
4792 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4793 /* assign the amsops */
4794 aopOp (left, ic, FALSE, FALSE);
4795 aopOp (right, ic, FALSE, FALSE);
4796 aopOp (result, ic, TRUE, FALSE);
4798 genCmp (right, left, result, ifx, sign);
4800 freeAsmop (left, NULL, ic);
4801 freeAsmop (right, NULL, ic);
4802 freeAsmop (result, NULL, ic);
4805 /*-----------------------------------------------------------------*/
4806 /* genCmpLt - less than comparisons */
4807 /*-----------------------------------------------------------------*/
4809 genCmpLt (iCode * ic, iCode * ifx)
4811 operand *left, *right, *result;
4812 sym_link *letype, *retype;
4815 left = IC_LEFT (ic);
4816 right = IC_RIGHT (ic);
4817 result = IC_RESULT (ic);
4819 letype = getSpec (operandType (left));
4820 retype = getSpec (operandType (right));
4821 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4823 /* assign the amsops */
4824 aopOp (left, ic, FALSE, FALSE);
4825 aopOp (right, ic, FALSE, FALSE);
4826 aopOp (result, ic, TRUE, FALSE);
4828 genCmp (left, right, result, ifx, sign);
4830 freeAsmop (left, NULL, ic);
4831 freeAsmop (right, NULL, ic);
4832 freeAsmop (result, NULL, ic);
4835 /*-----------------------------------------------------------------*/
4836 /* gencjneshort - compare and jump if not equal */
4837 /* returns pair that still needs to be popped */
4838 /*-----------------------------------------------------------------*/
4840 gencjneshort (operand * left, operand * right, symbol * lbl)
4842 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4844 unsigned long lit = 0L;
4846 /* Swap the left and right if it makes the computation easier */
4847 if (AOP_TYPE (left) == AOP_LIT)
4854 /* if the right side is a literal then anything goes */
4855 if (AOP_TYPE (right) == AOP_LIT)
4857 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4860 _moveA (aopGet (AOP (left), offset, FALSE));
4865 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4872 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4878 _moveA (aopGet (AOP (left), offset, FALSE));
4879 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4882 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4883 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4888 /* if the right side is in a register or
4889 pointed to by HL, IX or IY */
4890 else if (AOP_TYPE (right) == AOP_REG ||
4891 AOP_TYPE (right) == AOP_HL ||
4892 AOP_TYPE (right) == AOP_IY ||
4893 AOP_TYPE (right) == AOP_STK ||
4894 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4895 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4896 AOP_IS_PAIRPTR (right, PAIR_IY))
4900 _moveA (aopGet (AOP (left), offset, FALSE));
4901 if (AOP_TYPE (right) == AOP_LIT &&
4902 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4905 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4909 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4910 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4915 /* right is in direct space or a pointer reg, need both a & b */
4919 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4921 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4922 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4930 emit2 ("; direct compare");
4931 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4932 _moveA (aopGet (AOP (right), offset, FALSE));
4933 emit2 ("sub %s", _pairs[pair].l);
4934 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4939 return PAIR_INVALID;
4942 /*-----------------------------------------------------------------*/
4943 /* gencjne - compare and jump if not equal */
4944 /*-----------------------------------------------------------------*/
4946 gencjne (operand * left, operand * right, symbol * lbl)
4948 symbol *tlbl = newiTempLabel (NULL);
4950 PAIR_ID pop = gencjneshort (left, right, lbl);
4953 emit2 ("ld a,!one");
4954 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4955 emitLabel (lbl->key + 100);
4957 emitLabel (tlbl->key + 100);
4961 /*-----------------------------------------------------------------*/
4962 /* genCmpEq - generates code for equal to */
4963 /*-----------------------------------------------------------------*/
4965 genCmpEq (iCode * ic, iCode * ifx)
4967 operand *left, *right, *result;
4969 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4970 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4971 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4973 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4975 /* Swap operands if it makes the operation easier. ie if:
4976 1. Left is a literal.
4978 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4980 operand *t = IC_RIGHT (ic);
4981 IC_RIGHT (ic) = IC_LEFT (ic);
4985 if (ifx && !AOP_SIZE (result))
4988 /* if they are both bit variables */
4989 if (AOP_TYPE (left) == AOP_CRY &&
4990 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4992 wassertl (0, "Tried to compare two bits");
4997 tlbl = newiTempLabel (NULL);
4998 pop = gencjneshort (left, right, tlbl);
5002 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
5003 emitLabel (tlbl->key + 100);
5008 /* PENDING: do this better */
5009 symbol *lbl = newiTempLabel (NULL);
5011 emit2 ("!shortjp !tlabel", lbl->key + 100);
5012 emitLabel (tlbl->key + 100);
5014 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
5015 emitLabel (lbl->key + 100);
5018 /* mark the icode as generated */
5023 /* if they are both bit variables */
5024 if (AOP_TYPE (left) == AOP_CRY &&
5025 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5027 wassertl (0, "Tried to compare a bit to either a literal or another bit");
5033 gencjne (left, right, newiTempLabel (NULL));
5034 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5041 genIfxJump (ifx, "a");
5044 /* if the result is used in an arithmetic operation
5045 then put the result in place */
5046 if (AOP_TYPE (result) != AOP_CRY)
5051 /* leave the result in acc */
5055 freeAsmop (left, NULL, ic);
5056 freeAsmop (right, NULL, ic);
5057 freeAsmop (result, NULL, ic);
5060 /*-----------------------------------------------------------------*/
5061 /* ifxForOp - returns the icode containing the ifx for operand */
5062 /*-----------------------------------------------------------------*/
5064 ifxForOp (operand * op, iCode * ic)
5066 /* if true symbol then needs to be assigned */
5067 if (IS_TRUE_SYMOP (op))
5070 /* if this has register type condition and
5071 the next instruction is ifx with the same operand
5072 and live to of the operand is upto the ifx only then */
5074 ic->next->op == IFX &&
5075 IC_COND (ic->next)->key == op->key &&
5076 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5082 /*-----------------------------------------------------------------*/
5083 /* genAndOp - for && operation */
5084 /*-----------------------------------------------------------------*/
5086 genAndOp (iCode * ic)
5088 operand *left, *right, *result;
5091 /* note here that && operations that are in an if statement are
5092 taken away by backPatchLabels only those used in arthmetic
5093 operations remain */
5094 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5095 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5096 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5098 /* if both are bit variables */
5099 if (AOP_TYPE (left) == AOP_CRY &&
5100 AOP_TYPE (right) == AOP_CRY)
5102 wassertl (0, "Tried to and two bits");
5106 tlbl = newiTempLabel (NULL);
5108 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5110 emitLabel (tlbl->key + 100);
5114 freeAsmop (left, NULL, ic);
5115 freeAsmop (right, NULL, ic);
5116 freeAsmop (result, NULL, ic);
5119 /*-----------------------------------------------------------------*/
5120 /* genOrOp - for || operation */
5121 /*-----------------------------------------------------------------*/
5123 genOrOp (iCode * ic)
5125 operand *left, *right, *result;
5128 /* note here that || operations that are in an
5129 if statement are taken away by backPatchLabels
5130 only those used in arthmetic operations remain */
5131 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5132 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5133 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5135 /* if both are bit variables */
5136 if (AOP_TYPE (left) == AOP_CRY &&
5137 AOP_TYPE (right) == AOP_CRY)
5139 wassertl (0, "Tried to OR two bits");
5143 tlbl = newiTempLabel (NULL);
5145 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5147 emitLabel (tlbl->key + 100);
5151 freeAsmop (left, NULL, ic);
5152 freeAsmop (right, NULL, ic);
5153 freeAsmop (result, NULL, ic);
5156 /*-----------------------------------------------------------------*/
5157 /* isLiteralBit - test if lit == 2^n */
5158 /*-----------------------------------------------------------------*/
5160 isLiteralBit (unsigned long lit)
5162 unsigned long pw[32] =
5163 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5164 0x100L, 0x200L, 0x400L, 0x800L,
5165 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5166 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5167 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5168 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5169 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5172 for (idx = 0; idx < 32; idx++)
5178 /*-----------------------------------------------------------------*/
5179 /* jmpTrueOrFalse - */
5180 /*-----------------------------------------------------------------*/
5182 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5184 // ugly but optimized by peephole
5187 symbol *nlbl = newiTempLabel (NULL);
5188 emit2 ("jp !tlabel", nlbl->key + 100);
5189 emitLabel (tlbl->key + 100);
5190 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5191 emitLabel (nlbl->key + 100);
5195 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5196 emitLabel (tlbl->key + 100);
5201 /*-----------------------------------------------------------------*/
5202 /* genAnd - code for and */
5203 /*-----------------------------------------------------------------*/
5205 genAnd (iCode * ic, iCode * ifx)
5207 operand *left, *right, *result;
5208 int size, offset = 0;
5209 unsigned long lit = 0L;
5212 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5213 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5214 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5216 /* if left is a literal & right is not then exchange them */
5217 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5218 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5220 operand *tmp = right;
5225 /* if result = right then exchange them */
5226 if (sameRegs (AOP (result), AOP (right)))
5228 operand *tmp = right;
5233 /* if right is bit then exchange them */
5234 if (AOP_TYPE (right) == AOP_CRY &&
5235 AOP_TYPE (left) != AOP_CRY)
5237 operand *tmp = right;
5241 if (AOP_TYPE (right) == AOP_LIT)
5242 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5244 size = AOP_SIZE (result);
5246 if (AOP_TYPE (left) == AOP_CRY)
5248 wassertl (0, "Tried to perform an AND with a bit as an operand");
5252 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5253 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5254 if ((AOP_TYPE (right) == AOP_LIT) &&
5255 (AOP_TYPE (result) == AOP_CRY) &&
5256 (AOP_TYPE (left) != AOP_CRY))
5258 symbol *tlbl = newiTempLabel (NULL);
5259 int sizel = AOP_SIZE (left);
5262 /* PENDING: Test case for this. */
5267 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5269 _moveA (aopGet (AOP (left), offset, FALSE));
5270 if (bytelit != 0x0FFL)
5272 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5279 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5283 // bit = left & literal
5287 emit2 ("!tlabeldef", tlbl->key + 100);
5288 _G.lines.current->isLabel = 1;
5290 // if(left & literal)
5295 jmpTrueOrFalse (ifx, tlbl);
5303 /* if left is same as result */
5304 if (sameRegs (AOP (result), AOP (left)))
5306 for (; size--; offset++)
5308 if (AOP_TYPE (right) == AOP_LIT)
5310 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5315 aopPut (AOP (result), "!zero", offset);
5318 _moveA (aopGet (AOP (left), offset, FALSE));
5320 aopGet (AOP (right), offset, FALSE));
5321 aopPut (AOP (left), "a", offset);
5328 if (AOP_TYPE (left) == AOP_ACC)
5330 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5334 _moveA (aopGet (AOP (left), offset, FALSE));
5336 aopGet (AOP (right), offset, FALSE));
5337 aopPut (AOP (left), "a", offset);
5344 // left & result in different registers
5345 if (AOP_TYPE (result) == AOP_CRY)
5347 wassertl (0, "Tried to AND where the result is in carry");
5351 for (; (size--); offset++)
5354 // result = left & right
5355 if (AOP_TYPE (right) == AOP_LIT)
5357 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5359 aopPut (AOP (result),
5360 aopGet (AOP (left), offset, FALSE),
5364 else if (bytelit == 0)
5366 aopPut (AOP (result), "!zero", offset);
5370 // faster than result <- left, anl result,right
5371 // and better if result is SFR
5372 if (AOP_TYPE (left) == AOP_ACC)
5373 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5376 _moveA (aopGet (AOP (left), offset, FALSE));
5378 aopGet (AOP (right), offset, FALSE));
5380 aopPut (AOP (result), "a", offset);
5387 freeAsmop (left, NULL, ic);
5388 freeAsmop (right, NULL, ic);
5389 freeAsmop (result, NULL, ic);
5392 /*-----------------------------------------------------------------*/
5393 /* genOr - code for or */
5394 /*-----------------------------------------------------------------*/
5396 genOr (iCode * ic, iCode * ifx)
5398 operand *left, *right, *result;
5399 int size, offset = 0;
5400 unsigned long lit = 0L;
5403 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5404 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5405 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5407 /* if left is a literal & right is not then exchange them */
5408 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5409 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5411 operand *tmp = right;
5416 /* if result = right then exchange them */
5417 if (sameRegs (AOP (result), AOP (right)))
5419 operand *tmp = right;
5424 /* if right is bit then exchange them */
5425 if (AOP_TYPE (right) == AOP_CRY &&
5426 AOP_TYPE (left) != AOP_CRY)
5428 operand *tmp = right;
5432 if (AOP_TYPE (right) == AOP_LIT)
5433 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5435 size = AOP_SIZE (result);
5437 if (AOP_TYPE (left) == AOP_CRY)
5439 wassertl (0, "Tried to OR where left is a bit");
5443 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5444 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5445 if ((AOP_TYPE (right) == AOP_LIT) &&
5446 (AOP_TYPE (result) == AOP_CRY) &&
5447 (AOP_TYPE (left) != AOP_CRY))
5449 symbol *tlbl = newiTempLabel (NULL);
5450 int sizel = AOP_SIZE (left);
5454 wassertl (0, "Result is assigned to a bit");
5456 /* PENDING: Modeled after the AND code which is inefficient. */
5459 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5461 _moveA (aopGet (AOP (left), offset, FALSE));
5462 /* OR with any literal is the same as OR with itself. */
5464 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5470 jmpTrueOrFalse (ifx, tlbl);
5475 /* if left is same as result */
5476 if (sameRegs (AOP (result), AOP (left)))
5478 for (; size--; offset++)
5480 if (AOP_TYPE (right) == AOP_LIT)
5482 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5486 _moveA (aopGet (AOP (left), offset, FALSE));
5488 aopGet (AOP (right), offset, FALSE));
5489 aopPut (AOP (result), "a", offset);
5494 if (AOP_TYPE (left) == AOP_ACC)
5495 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5498 _moveA (aopGet (AOP (left), offset, FALSE));
5500 aopGet (AOP (right), offset, FALSE));
5501 aopPut (AOP (result), "a", offset);
5508 // left & result in different registers
5509 if (AOP_TYPE (result) == AOP_CRY)
5511 wassertl (0, "Result of OR is in a bit");
5514 for (; (size--); offset++)
5517 // result = left & right
5518 if (AOP_TYPE (right) == AOP_LIT)
5520 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5522 aopPut (AOP (result),
5523 aopGet (AOP (left), offset, FALSE),
5528 // faster than result <- left, anl result,right
5529 // and better if result is SFR
5530 if (AOP_TYPE (left) == AOP_ACC)
5531 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5534 _moveA (aopGet (AOP (left), offset, FALSE));
5536 aopGet (AOP (right), offset, FALSE));
5538 aopPut (AOP (result), "a", offset);
5539 /* PENDING: something weird is going on here. Add exception. */
5540 if (AOP_TYPE (result) == AOP_ACC)
5546 freeAsmop (left, NULL, ic);
5547 freeAsmop (right, NULL, ic);
5548 freeAsmop (result, NULL, ic);
5551 /*-----------------------------------------------------------------*/
5552 /* genXor - code for xclusive or */
5553 /*-----------------------------------------------------------------*/
5555 genXor (iCode * ic, iCode * ifx)
5557 operand *left, *right, *result;
5558 int size, offset = 0;
5559 unsigned long lit = 0L;
5561 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5562 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5563 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5565 /* if left is a literal & right is not then exchange them */
5566 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5567 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5569 operand *tmp = right;
5574 /* if result = right then exchange them */
5575 if (sameRegs (AOP (result), AOP (right)))
5577 operand *tmp = right;
5582 /* if right is bit then exchange them */
5583 if (AOP_TYPE (right) == AOP_CRY &&
5584 AOP_TYPE (left) != AOP_CRY)
5586 operand *tmp = right;
5590 if (AOP_TYPE (right) == AOP_LIT)
5591 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5593 size = AOP_SIZE (result);
5595 if (AOP_TYPE (left) == AOP_CRY)
5597 wassertl (0, "Tried to XOR a bit");
5601 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5602 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5603 if ((AOP_TYPE (right) == AOP_LIT) &&
5604 (AOP_TYPE (result) == AOP_CRY) &&
5605 (AOP_TYPE (left) != AOP_CRY))
5607 symbol *tlbl = newiTempLabel (NULL);
5608 int sizel = AOP_SIZE (left);
5612 /* PENDING: Test case for this. */
5613 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5617 _moveA (aopGet (AOP (left), offset, FALSE));
5618 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5619 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5624 jmpTrueOrFalse (ifx, tlbl);
5628 wassertl (0, "Result of XOR was destined for a bit");
5633 /* if left is same as result */
5634 if (sameRegs (AOP (result), AOP (left)))
5636 for (; size--; offset++)
5638 if (AOP_TYPE (right) == AOP_LIT)
5640 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5644 _moveA (aopGet (AOP (left), offset, FALSE));
5646 aopGet (AOP (right), offset, FALSE));
5647 aopPut (AOP (result), "a", offset);
5652 if (AOP_TYPE (left) == AOP_ACC)
5654 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5658 _moveA (aopGet (AOP (left), offset, FALSE));
5660 aopGet (AOP (right), offset, FALSE));
5661 aopPut (AOP (result), "a", offset);
5668 // left & result in different registers
5669 if (AOP_TYPE (result) == AOP_CRY)
5671 wassertl (0, "Result of XOR is in a bit");
5674 for (; (size--); offset++)
5677 // result = left & right
5678 if (AOP_TYPE (right) == AOP_LIT)
5680 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5682 aopPut (AOP (result),
5683 aopGet (AOP (left), offset, FALSE),
5688 // faster than result <- left, anl result,right
5689 // and better if result is SFR
5690 if (AOP_TYPE (left) == AOP_ACC)
5692 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5696 _moveA (aopGet (AOP (left), offset, FALSE));
5698 aopGet (AOP (right), offset, FALSE));
5700 aopPut (AOP (result), "a", offset);
5705 freeAsmop (left, NULL, ic);
5706 freeAsmop (right, NULL, ic);
5707 freeAsmop (result, NULL, ic);
5710 /*-----------------------------------------------------------------*/
5711 /* genInline - write the inline code out */
5712 /*-----------------------------------------------------------------*/
5714 genInline (iCode * ic)
5716 char *buffer, *bp, *bp1;
5717 bool inComment = FALSE;
5719 _G.lines.isInline += (!options.asmpeep);
5721 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5723 /* emit each line as a code */
5741 /* Add \n for labels, not dirs such as c:\mydir */
5742 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5760 _G.lines.isInline -= (!options.asmpeep);
5764 /*-----------------------------------------------------------------*/
5765 /* genRRC - rotate right with carry */
5766 /*-----------------------------------------------------------------*/
5773 /*-----------------------------------------------------------------*/
5774 /* genRLC - generate code for rotate left with carry */
5775 /*-----------------------------------------------------------------*/
5782 /*-----------------------------------------------------------------*/
5783 /* genGetHbit - generates code get highest order bit */
5784 /*-----------------------------------------------------------------*/
5786 genGetHbit (iCode * ic)
5788 operand *left, *result;
5789 left = IC_LEFT (ic);
5790 result = IC_RESULT (ic);
5792 aopOp (left, ic, FALSE, FALSE);
5793 aopOp (result, ic, FALSE, FALSE);
5795 /* get the highest order byte into a */
5796 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5798 if (AOP_TYPE (result) == AOP_CRY)
5806 emit2 ("and a,!one");
5811 freeAsmop (left, NULL, ic);
5812 freeAsmop (result, NULL, ic);
5816 emitRsh2 (asmop *aop, int size, int is_signed)
5822 const char *l = aopGet (aop, size, FALSE);
5825 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5835 /*-----------------------------------------------------------------*/
5836 /* shiftR2Left2Result - shift right two bytes from left to result */
5837 /*-----------------------------------------------------------------*/
5839 shiftR2Left2Result (operand * left, int offl,
5840 operand * result, int offr,
5841 int shCount, int is_signed)
5846 movLeft2Result (left, offl, result, offr, 0);
5847 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5852 /* if (AOP(result)->type == AOP_REG) { */
5854 tlbl = newiTempLabel (NULL);
5856 /* Left is already in result - so now do the shift */
5857 /* Optimizing for speed by default. */
5858 if (!optimize.codeSize || shCount <= 2)
5862 emitRsh2 (AOP (result), size, is_signed);
5867 emit2 ("ld a,!immedbyte", shCount);
5869 emitLabel (tlbl->key + 100);
5871 emitRsh2 (AOP (result), size, is_signed);
5874 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5878 /*-----------------------------------------------------------------*/
5879 /* shiftL2Left2Result - shift left two bytes from left to result */
5880 /*-----------------------------------------------------------------*/
5882 shiftL2Left2Result (operand * left, int offl,
5883 operand * result, int offr, int shCount)
5885 if (sameRegs (AOP (result), AOP (left)) &&
5886 ((offl + MSB16) == offr))
5892 /* Copy left into result */
5893 movLeft2Result (left, offl, result, offr, 0);
5894 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5900 if (getPairId (AOP (result)) == PAIR_HL)
5904 emit2 ("add hl,hl");
5911 symbol *tlbl, *tlbl1;
5914 tlbl = newiTempLabel (NULL);
5915 tlbl1 = newiTempLabel (NULL);
5917 if (AOP (result)->type == AOP_REG)
5921 for (offset = 0; offset < size; offset++)
5923 l = aopGet (AOP (result), offset, FALSE);
5927 emit2 ("sla %s", l);
5938 /* Left is already in result - so now do the shift */
5941 emit2 ("ld a,!immedbyte+1", shCount);
5942 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5943 emitLabel (tlbl->key + 100);
5948 l = aopGet (AOP (result), offset, FALSE);
5952 emit2 ("sla %s", l);
5963 emitLabel (tlbl1->key + 100);
5965 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5971 /*-----------------------------------------------------------------*/
5972 /* AccRol - rotate left accumulator by known count */
5973 /*-----------------------------------------------------------------*/
5975 AccRol (int shCount)
5977 shCount &= 0x0007; // shCount : 0..7
6054 /*-----------------------------------------------------------------*/
6055 /* AccLsh - left shift accumulator by known count */
6056 /*-----------------------------------------------------------------*/
6058 AccLsh (int shCount)
6060 static const unsigned char SLMask[] =
6062 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6071 else if (shCount == 2)
6078 /* rotate left accumulator */
6080 /* and kill the lower order bits */
6081 emit2 ("and a,!immedbyte", SLMask[shCount]);
6086 /*-----------------------------------------------------------------*/
6087 /* shiftL1Left2Result - shift left one byte from left to result */
6088 /*-----------------------------------------------------------------*/
6090 shiftL1Left2Result (operand * left, int offl,
6091 operand * result, int offr, int shCount)
6095 /* If operand and result are the same we can shift in place.
6096 However shifting in acc using add is cheaper than shifting
6097 in place using sla; when shifting by more than 2 shifting in
6098 acc is worth the additional effort for loading from/to acc. */
6099 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6102 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6106 l = aopGet (AOP (left), offl, FALSE);
6108 /* shift left accumulator */
6110 aopPut (AOP (result), "a", offr);
6114 /*-----------------------------------------------------------------*/
6115 /* genlshTwo - left shift two bytes by known amount */
6116 /*-----------------------------------------------------------------*/
6118 genlshTwo (operand * result, operand * left, int shCount)
6120 int size = AOP_SIZE (result);
6122 wassert (size == 2);
6124 /* if shCount >= 8 */
6132 movLeft2Result (left, LSB, result, MSB16, 0);
6133 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6134 aopPut (AOP (result), "!zero", LSB);
6138 movLeft2Result (left, LSB, result, MSB16, 0);
6139 aopPut (AOP (result), "!zero", 0);
6144 aopPut (AOP (result), "!zero", LSB);
6147 /* 0 <= shCount <= 7 */
6156 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6161 /*-----------------------------------------------------------------*/
6162 /* genlshOne - left shift a one byte quantity by known count */
6163 /*-----------------------------------------------------------------*/
6165 genlshOne (operand * result, operand * left, int shCount)
6167 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6170 /*-----------------------------------------------------------------*/
6171 /* genLeftShiftLiteral - left shifting by known count */
6172 /*-----------------------------------------------------------------*/
6174 genLeftShiftLiteral (operand * left,
6179 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6182 freeAsmop (right, NULL, ic);
6184 aopOp (left, ic, FALSE, FALSE);
6185 aopOp (result, ic, FALSE, FALSE);
6187 size = getSize (operandType (result));
6189 /* I suppose that the left size >= result size */
6191 if (shCount >= (size * 8))
6195 aopPut (AOP (result), "!zero", size);
6203 genlshOne (result, left, shCount);
6206 genlshTwo (result, left, shCount);
6209 wassertl (0, "Shifting of longs is currently unsupported");
6215 freeAsmop (left, NULL, ic);
6216 freeAsmop (result, NULL, ic);
6219 /*-----------------------------------------------------------------*/
6220 /* genLeftShift - generates code for left shifting */
6221 /*-----------------------------------------------------------------*/
6223 genLeftShift (iCode * ic)
6227 symbol *tlbl, *tlbl1;
6228 operand *left, *right, *result;
6230 right = IC_RIGHT (ic);
6231 left = IC_LEFT (ic);
6232 result = IC_RESULT (ic);
6234 aopOp (right, ic, FALSE, FALSE);
6236 /* if the shift count is known then do it
6237 as efficiently as possible */
6238 if (AOP_TYPE (right) == AOP_LIT)
6240 genLeftShiftLiteral (left, right, result, ic);
6244 /* shift count is unknown then we have to form a loop get the loop
6245 count in B : Note: we take only the lower order byte since
6246 shifting more that 32 bits make no sense anyway, ( the largest
6247 size of an object can be only 32 bits ) */
6248 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6250 freeAsmop (right, NULL, ic);
6251 aopOp (left, ic, FALSE, FALSE);
6252 aopOp (result, ic, FALSE, FALSE);
6254 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6257 /* now move the left to the result if they are not the
6260 if (!sameRegs (AOP (left), AOP (result)))
6263 size = AOP_SIZE (result);
6267 l = aopGet (AOP (left), offset, FALSE);
6268 aopPut (AOP (result), l, offset);
6273 tlbl = newiTempLabel (NULL);
6274 size = AOP_SIZE (result);
6276 tlbl1 = newiTempLabel (NULL);
6278 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6281 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6282 emitLabel (tlbl->key + 100);
6283 l = aopGet (AOP (result), offset, FALSE);
6287 l = aopGet (AOP (result), offset, FALSE);
6291 emit2 ("sla %s", l);
6299 emitLabel (tlbl1->key + 100);
6301 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6303 freeAsmop (left, NULL, ic);
6304 freeAsmop (result, NULL, ic);
6307 /*-----------------------------------------------------------------*/
6308 /* genrshOne - left shift two bytes by known amount != 0 */
6309 /*-----------------------------------------------------------------*/
6311 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6314 int size = AOP_SIZE (result);
6317 wassert (size == 1);
6318 wassert (shCount < 8);
6320 l = aopGet (AOP (left), 0, FALSE);
6322 if (AOP (result)->type == AOP_REG)
6324 aopPut (AOP (result), l, 0);
6325 l = aopGet (AOP (result), 0, FALSE);
6328 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6336 emit2 ("%s a", is_signed ? "sra" : "srl");
6338 aopPut (AOP (result), "a", 0);
6342 /*-----------------------------------------------------------------*/
6343 /* AccRsh - right shift accumulator by known count */
6344 /*-----------------------------------------------------------------*/
6346 AccRsh (int shCount)
6348 static const unsigned char SRMask[] =
6350 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6355 /* rotate right accumulator */
6356 AccRol (8 - shCount);
6357 /* and kill the higher order bits */
6358 emit2 ("and a,!immedbyte", SRMask[shCount]);
6362 /*-----------------------------------------------------------------*/
6363 /* shiftR1Left2Result - shift right one byte from left to result */
6364 /*-----------------------------------------------------------------*/
6366 shiftR1Left2Result (operand * left, int offl,
6367 operand * result, int offr,
6368 int shCount, int sign)
6370 _moveA (aopGet (AOP (left), offl, FALSE));
6375 emit2 ("%s a", sign ? "sra" : "srl");
6382 aopPut (AOP (result), "a", offr);
6385 /*-----------------------------------------------------------------*/
6386 /* genrshTwo - right shift two bytes by known amount */
6387 /*-----------------------------------------------------------------*/
6389 genrshTwo (operand * result, operand * left,
6390 int shCount, int sign)
6392 /* if shCount >= 8 */
6398 shiftR1Left2Result (left, MSB16, result, LSB,
6403 movLeft2Result (left, MSB16, result, LSB, sign);
6407 /* Sign extend the result */
6408 _moveA(aopGet (AOP (result), 0, FALSE));
6412 aopPut (AOP (result), ACC_NAME, MSB16);
6416 aopPut (AOP (result), "!zero", 1);
6419 /* 0 <= shCount <= 7 */
6422 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6426 /*-----------------------------------------------------------------*/
6427 /* genRightShiftLiteral - left shifting by known count */
6428 /*-----------------------------------------------------------------*/
6430 genRightShiftLiteral (operand * left,
6436 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6439 freeAsmop (right, NULL, ic);
6441 aopOp (left, ic, FALSE, FALSE);
6442 aopOp (result, ic, FALSE, FALSE);
6444 size = getSize (operandType (result));
6446 /* I suppose that the left size >= result size */
6448 if (shCount >= (size * 8)) {
6450 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6451 _moveA(aopGet (AOP (left), 0, FALSE));
6459 aopPut (AOP (result), s, size);
6466 genrshOne (result, left, shCount, sign);
6469 genrshTwo (result, left, shCount, sign);
6472 wassertl (0, "Asked to shift right a long which should be a function call");
6475 wassertl (0, "Entered default case in right shift delegate");
6478 freeAsmop (left, NULL, ic);
6479 freeAsmop (result, NULL, ic);
6482 /*-----------------------------------------------------------------*/
6483 /* genRightShift - generate code for right shifting */
6484 /*-----------------------------------------------------------------*/
6486 genRightShift (iCode * ic)
6488 operand *right, *left, *result;
6490 int size, offset, first = 1;
6494 symbol *tlbl, *tlbl1;
6496 /* if signed then we do it the hard way preserve the
6497 sign bit moving it inwards */
6498 retype = getSpec (operandType (IC_RESULT (ic)));
6500 is_signed = !SPEC_USIGN (retype);
6502 /* signed & unsigned types are treated the same : i.e. the
6503 signed is NOT propagated inwards : quoting from the
6504 ANSI - standard : "for E1 >> E2, is equivalent to division
6505 by 2**E2 if unsigned or if it has a non-negative value,
6506 otherwise the result is implementation defined ", MY definition
6507 is that the sign does not get propagated */
6509 right = IC_RIGHT (ic);
6510 left = IC_LEFT (ic);
6511 result = IC_RESULT (ic);
6513 aopOp (right, ic, FALSE, FALSE);
6515 /* if the shift count is known then do it
6516 as efficiently as possible */
6517 if (AOP_TYPE (right) == AOP_LIT)
6519 genRightShiftLiteral (left, right, result, ic, is_signed);
6523 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6525 freeAsmop (right, NULL, ic);
6527 aopOp (left, ic, FALSE, FALSE);
6528 aopOp (result, ic, FALSE, FALSE);
6530 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6533 /* now move the left to the result if they are not the
6535 if (!sameRegs (AOP (left), AOP (result)))
6538 size = AOP_SIZE (result);
6542 l = aopGet (AOP (left), offset, FALSE);
6543 aopPut (AOP (result), l, offset);
6548 tlbl = newiTempLabel (NULL);
6549 tlbl1 = newiTempLabel (NULL);
6550 size = AOP_SIZE (result);
6553 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6556 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6557 emitLabel (tlbl->key + 100);
6560 l = aopGet (AOP (result), offset--, FALSE);
6563 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6571 emitLabel (tlbl1->key + 100);
6573 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6575 freeAsmop (left, NULL, ic);
6576 freeAsmop (result, NULL, ic);
6580 /*-----------------------------------------------------------------*/
6581 /* genUnpackBits - generates code for unpacking bits */
6582 /*-----------------------------------------------------------------*/
6584 genUnpackBits (operand * result, int pair)
6586 int offset = 0; /* result byte offset */
6587 int rsize; /* result size */
6588 int rlen = 0; /* remaining bitfield length */
6589 sym_link *etype; /* bitfield type information */
6590 int blen; /* bitfield length */
6591 int bstr; /* bitfield starting bit within byte */
6593 emitDebug ("; genUnpackBits");
6595 etype = getSpec (operandType (result));
6596 rsize = getSize (operandType (result));
6597 blen = SPEC_BLEN (etype);
6598 bstr = SPEC_BSTR (etype);
6600 /* If the bitfield length is less than a byte */
6603 emit2 ("ld a,!*pair", _pairs[pair].name);
6605 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6606 if (!SPEC_USIGN (etype))
6608 /* signed bitfield */
6609 symbol *tlbl = newiTempLabel (NULL);
6611 emit2 ("bit %d,a", blen - 1);
6612 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6613 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6614 emitLabel (tlbl->key + 100);
6616 aopPut (AOP (result), "a", offset++);
6620 /* TODO: what if pair == PAIR_DE ? */
6621 if (getPairId (AOP (result)) == PAIR_HL)
6623 wassertl (rsize == 2, "HL must be of size 2");
6624 emit2 ("ld a,!*hl");
6626 emit2 ("ld h,!*hl");
6629 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6630 if (!SPEC_USIGN (etype))
6632 /* signed bitfield */
6633 symbol *tlbl = newiTempLabel (NULL);
6635 emit2 ("bit %d,a", blen - 1);
6636 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6637 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6638 emitLabel (tlbl->key + 100);
6641 spillPair (PAIR_HL);
6645 /* Bit field did not fit in a byte. Copy all
6646 but the partial byte at the end. */
6647 for (rlen=blen;rlen>=8;rlen-=8)
6649 emit2 ("ld a,!*pair", _pairs[pair].name);
6650 aopPut (AOP (result), "a", offset++);
6653 emit2 ("inc %s", _pairs[pair].name);
6654 _G.pairs[pair].offset++;
6658 /* Handle the partial byte at the end */
6661 emit2 ("ld a,!*pair", _pairs[pair].name);
6662 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6663 if (!SPEC_USIGN (etype))
6665 /* signed bitfield */
6666 symbol *tlbl = newiTempLabel (NULL);
6668 emit2 ("bit %d,a", rlen - 1);
6669 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6670 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6671 emitLabel (tlbl->key + 100);
6673 aopPut (AOP (result), "a", offset++);
6681 if (SPEC_USIGN (etype))
6685 /* signed bitfield: sign extension with 0x00 or 0xff */
6693 aopPut (AOP (result), source, offset++);
6697 /*-----------------------------------------------------------------*/
6698 /* genGenPointerGet - get value from generic pointer space */
6699 /*-----------------------------------------------------------------*/
6701 genGenPointerGet (operand * left,
6702 operand * result, iCode * ic)
6705 sym_link *retype = getSpec (operandType (result));
6711 aopOp (left, ic, FALSE, FALSE);
6712 aopOp (result, ic, FALSE, FALSE);
6714 size = AOP_SIZE (result);
6716 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6719 if (isPtrPair (AOP (left)))
6721 tsprintf (buffer, sizeof(buffer),
6722 "!*pair", getPairName (AOP (left)));
6723 aopPut (AOP (result), buffer, 0);
6727 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6728 aopPut (AOP (result), "a", 0);
6730 freeAsmop (left, NULL, ic);
6734 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6741 tsprintf (at, sizeof(at), "!*iyx", offset);
6742 aopPut (AOP (result), at, offset);
6746 freeAsmop (left, NULL, ic);
6750 /* For now we always load into IY */
6751 /* if this is remateriazable */
6752 fetchPair (pair, AOP (left));
6754 /* if bit then unpack */
6755 if (IS_BITVAR (retype))
6757 genUnpackBits (result, pair);
6758 freeAsmop (left, NULL, ic);
6762 else if (getPairId (AOP (result)) == PAIR_HL)
6764 wassertl (size == 2, "HL must be of size 2");
6765 emit2 ("ld a,!*hl");
6767 emit2 ("ld h,!*hl");
6769 spillPair (PAIR_HL);
6771 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6773 size = AOP_SIZE (result);
6778 /* PENDING: make this better */
6779 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6781 aopPut (AOP (result), "!*hl", offset++);
6785 emit2 ("ld a,!*pair", _pairs[pair].name);
6786 aopPut (AOP (result), "a", offset++);
6790 emit2 ("inc %s", _pairs[pair].name);
6791 _G.pairs[pair].offset++;
6794 /* Fixup HL back down */
6795 for (size = AOP_SIZE (result)-1; size; size--)
6797 emit2 ("dec %s", _pairs[pair].name);
6802 size = AOP_SIZE (result);
6807 /* PENDING: make this better */
6809 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6811 aopPut (AOP (result), "!*hl", offset++);
6815 emit2 ("ld a,!*pair", _pairs[pair].name);
6816 aopPut (AOP (result), "a", offset++);
6820 emit2 ("inc %s", _pairs[pair].name);
6821 _G.pairs[pair].offset++;
6826 freeAsmop (left, NULL, ic);
6829 freeAsmop (result, NULL, ic);
6832 /*-----------------------------------------------------------------*/
6833 /* genPointerGet - generate code for pointer get */
6834 /*-----------------------------------------------------------------*/
6836 genPointerGet (iCode * ic)
6838 operand *left, *result;
6839 sym_link *type, *etype;
6841 left = IC_LEFT (ic);
6842 result = IC_RESULT (ic);
6844 /* depending on the type of pointer we need to
6845 move it to the correct pointer register */
6846 type = operandType (left);
6847 etype = getSpec (type);
6849 genGenPointerGet (left, result, ic);
6853 isRegOrLit (asmop * aop)
6855 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6861 /*-----------------------------------------------------------------*/
6862 /* genPackBits - generates code for packed bit storage */
6863 /*-----------------------------------------------------------------*/
6865 genPackBits (sym_link * etype,
6870 int offset = 0; /* source byte offset */
6871 int rlen = 0; /* remaining bitfield length */
6872 int blen; /* bitfield length */
6873 int bstr; /* bitfield starting bit within byte */
6874 int litval; /* source literal value (if AOP_LIT) */
6875 unsigned char mask; /* bitmask within current byte */
6876 int extraPair; /* a tempory register */
6877 bool needPopExtra=0; /* need to restore original value of temp reg */
6879 emitDebug ("; genPackBits","");
6881 blen = SPEC_BLEN (etype);
6882 bstr = SPEC_BSTR (etype);
6884 /* If the bitfield length is less than a byte */
6887 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6888 (unsigned char) (0xFF >> (8 - bstr)));
6890 if (AOP_TYPE (right) == AOP_LIT)
6892 /* Case with a bitfield length <8 and literal source
6894 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6896 litval &= (~mask) & 0xff;
6897 emit2 ("ld a,!*pair", _pairs[pair].name);
6898 if ((mask|litval)!=0xff)
6899 emit2 ("and a,!immedbyte", mask);
6901 emit2 ("or a,!immedbyte", litval);
6902 emit2 ("ld !*pair,a", _pairs[pair].name);
6907 /* Case with a bitfield length <8 and arbitrary source
6909 _moveA (aopGet (AOP (right), 0, FALSE));
6910 /* shift and mask source value */
6912 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6914 extraPair = getFreePairId(ic);
6915 if (extraPair == PAIR_INVALID)
6917 extraPair = PAIR_BC;
6918 if (getPairId (AOP (right)) != PAIR_BC
6919 || !isLastUse (ic, right))
6925 emit2 ("ld %s,a", _pairs[extraPair].l);
6926 emit2 ("ld a,!*pair", _pairs[pair].name);
6928 emit2 ("and a,!immedbyte", mask);
6929 emit2 ("or a,%s", _pairs[extraPair].l);
6930 emit2 ("ld !*pair,a", _pairs[pair].name);
6937 /* Bit length is greater than 7 bits. In this case, copy */
6938 /* all except the partial byte at the end */
6939 for (rlen=blen;rlen>=8;rlen-=8)
6941 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6942 emit2 ("ld !*pair,a", _pairs[pair].name);
6945 emit2 ("inc %s", _pairs[pair].name);
6946 _G.pairs[pair].offset++;
6950 /* If there was a partial byte at the end */
6953 mask = (((unsigned char) -1 << rlen) & 0xff);
6955 if (AOP_TYPE (right) == AOP_LIT)
6957 /* Case with partial byte and literal source
6959 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6960 litval >>= (blen-rlen);
6961 litval &= (~mask) & 0xff;
6962 emit2 ("ld a,!*pair", _pairs[pair].name);
6963 if ((mask|litval)!=0xff)
6964 emit2 ("and a,!immedbyte", mask);
6966 emit2 ("or a,!immedbyte", litval);
6970 /* Case with partial byte and arbitrary source
6972 _moveA (aopGet (AOP (right), offset++, FALSE));
6973 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6975 extraPair = getFreePairId(ic);
6976 if (extraPair == PAIR_INVALID)
6978 extraPair = getPairId (AOP (right));
6979 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6980 extraPair = PAIR_BC;
6982 if (getPairId (AOP (right)) != PAIR_BC
6983 || !isLastUse (ic, right))
6989 emit2 ("ld %s,a", _pairs[extraPair].l);
6990 emit2 ("ld a,!*pair", _pairs[pair].name);
6992 emit2 ("and a,!immedbyte", mask);
6993 emit2 ("or a,%s", _pairs[extraPair].l);
6998 emit2 ("ld !*pair,a", _pairs[pair].name);
7003 /*-----------------------------------------------------------------*/
7004 /* genGenPointerSet - stores the value into a pointer location */
7005 /*-----------------------------------------------------------------*/
7007 genGenPointerSet (operand * right,
7008 operand * result, iCode * ic)
7011 sym_link *retype = getSpec (operandType (right));
7012 sym_link *letype = getSpec (operandType (result));
7013 PAIR_ID pairId = PAIR_HL;
7016 aopOp (result, ic, FALSE, FALSE);
7017 aopOp (right, ic, FALSE, FALSE);
7022 size = AOP_SIZE (right);
7024 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
7025 emitDebug("; isBitvar = %d", isBitvar);
7027 /* Handle the exceptions first */
7028 if (isPair (AOP (result)) && size == 1 && !isBitvar)
7031 const char *l = aopGet (AOP (right), 0, FALSE);
7032 const char *pair = getPairName (AOP (result));
7033 if (canAssignToPtr (l) && isPtr (pair))
7035 emit2 ("ld !*pair,%s", pair, l);
7040 emit2 ("ld !*pair,a", pair);
7045 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7048 const char *l = aopGet (AOP (right), 0, FALSE);
7053 if (canAssignToPtr (l))
7055 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7059 _moveA (aopGet (AOP (right), offset, FALSE));
7060 emit2 ("ld !*iyx,a", offset);
7066 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7073 const char *l = aopGet (AOP (right), offset, FALSE);
7074 if (isRegOrLit (AOP (right)) && !IS_GB)
7076 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7081 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7085 emit2 ("inc %s", _pairs[PAIR_HL].name);
7086 _G.pairs[PAIR_HL].offset++;
7091 /* Fixup HL back down */
7092 for (size = AOP_SIZE (right)-1; size; size--)
7094 emit2 ("dec %s", _pairs[PAIR_HL].name);
7099 /* if the operand is already in dptr
7100 then we do nothing else we move the value to dptr */
7101 if (AOP_TYPE (result) != AOP_STR)
7103 fetchPair (pairId, AOP (result));
7105 /* so hl now contains the address */
7106 freeAsmop (result, NULL, ic);
7108 /* if bit then unpack */
7111 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7121 const char *l = aopGet (AOP (right), offset, FALSE);
7122 if (isRegOrLit (AOP (right)) && !IS_GB)
7124 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7129 emit2 ("ld !*pair,a", _pairs[pairId].name);
7133 emit2 ("inc %s", _pairs[pairId].name);
7134 _G.pairs[pairId].offset++;
7140 freeAsmop (right, NULL, ic);
7143 /*-----------------------------------------------------------------*/
7144 /* genPointerSet - stores the value into a pointer location */
7145 /*-----------------------------------------------------------------*/
7147 genPointerSet (iCode * ic)
7149 operand *right, *result;
7150 sym_link *type, *etype;
7152 right = IC_RIGHT (ic);
7153 result = IC_RESULT (ic);
7155 /* depending on the type of pointer we need to
7156 move it to the correct pointer register */
7157 type = operandType (result);
7158 etype = getSpec (type);
7160 genGenPointerSet (right, result, ic);
7163 /*-----------------------------------------------------------------*/
7164 /* genIfx - generate code for Ifx statement */
7165 /*-----------------------------------------------------------------*/
7167 genIfx (iCode * ic, iCode * popIc)
7169 operand *cond = IC_COND (ic);
7172 aopOp (cond, ic, FALSE, TRUE);
7174 /* get the value into acc */
7175 if (AOP_TYPE (cond) != AOP_CRY)
7179 /* the result is now in the accumulator */
7180 freeAsmop (cond, NULL, ic);
7182 /* if there was something to be popped then do it */
7186 /* if the condition is a bit variable */
7187 if (isbit && IS_ITEMP (cond) &&
7189 genIfxJump (ic, SPIL_LOC (cond)->rname);
7190 else if (isbit && !IS_ITEMP (cond))
7191 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7193 genIfxJump (ic, "a");
7198 /*-----------------------------------------------------------------*/
7199 /* genAddrOf - generates code for address of */
7200 /*-----------------------------------------------------------------*/
7202 genAddrOf (iCode * ic)
7204 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7206 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7208 /* if the operand is on the stack then we
7209 need to get the stack offset of this
7215 spillPair (PAIR_HL);
7216 if (sym->stack <= 0)
7218 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7222 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7224 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7228 emit2 ("ld de,!hashedstr", sym->rname);
7229 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7234 spillPair (PAIR_HL);
7237 /* if it has an offset then we need to compute it */
7239 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7241 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7242 emit2 ("add hl,sp");
7246 emit2 ("ld hl,!hashedstr", sym->rname);
7248 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7250 freeAsmop (IC_RESULT (ic), NULL, ic);
7253 /*-----------------------------------------------------------------*/
7254 /* genAssign - generate code for assignment */
7255 /*-----------------------------------------------------------------*/
7257 genAssign (iCode * ic)
7259 operand *result, *right;
7261 unsigned long lit = 0L;
7263 result = IC_RESULT (ic);
7264 right = IC_RIGHT (ic);
7266 /* Dont bother assigning if they are the same */
7267 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7269 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7273 aopOp (right, ic, FALSE, FALSE);
7274 aopOp (result, ic, TRUE, FALSE);
7276 /* if they are the same registers */
7277 if (sameRegs (AOP (right), AOP (result)))
7279 emitDebug ("; (registers are the same)");
7283 /* if the result is a bit */
7284 if (AOP_TYPE (result) == AOP_CRY)
7286 wassertl (0, "Tried to assign to a bit");
7290 size = AOP_SIZE (result);
7293 if (AOP_TYPE (right) == AOP_LIT)
7295 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7298 if (isPair (AOP (result)))
7300 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7302 else if ((size > 1) &&
7303 (AOP_TYPE (result) != AOP_REG) &&
7304 (AOP_TYPE (right) == AOP_LIT) &&
7305 !IS_FLOAT (operandType (right)) &&
7308 bool fXored = FALSE;
7310 /* Work from the top down.
7311 Done this way so that we can use the cached copy of 0
7312 in A for a fast clear */
7315 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7317 if (!fXored && size > 1)
7324 aopPut (AOP (result), "a", offset);
7328 aopPut (AOP (result), "!zero", offset);
7332 aopPut (AOP (result),
7333 aopGet (AOP (right), offset, FALSE),
7338 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7340 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7341 aopPut (AOP (result), "l", LSB);
7342 aopPut (AOP (result), "h", MSB16);
7344 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7346 /* Special case. Load into a and d, then load out. */
7347 _moveA (aopGet (AOP (right), 0, FALSE));
7348 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7349 aopPut (AOP (result), "a", 0);
7350 aopPut (AOP (result), "e", 1);
7352 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7354 /* Special case - simple memcpy */
7355 aopGet (AOP (right), LSB, FALSE);
7358 aopGet (AOP (result), LSB, FALSE);
7362 emit2 ("ld a,(de)");
7363 /* Peephole will optimise this. */
7364 emit2 ("ld (hl),a");
7372 spillPair (PAIR_HL);
7378 /* PENDING: do this check better */
7379 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7381 _moveA (aopGet (AOP (right), offset, FALSE));
7382 aopPut (AOP (result), "a", offset);
7385 aopPut (AOP (result),
7386 aopGet (AOP (right), offset, FALSE),
7393 freeAsmop (right, NULL, ic);
7394 freeAsmop (result, NULL, ic);
7397 /*-----------------------------------------------------------------*/
7398 /* genJumpTab - genrates code for jump table */
7399 /*-----------------------------------------------------------------*/
7401 genJumpTab (iCode * ic)
7406 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7407 /* get the condition into accumulator */
7408 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7411 emit2 ("ld e,%s", l);
7412 emit2 ("ld d,!zero");
7413 jtab = newiTempLabel (NULL);
7414 spillPair (PAIR_HL);
7415 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7416 emit2 ("add hl,de");
7417 emit2 ("add hl,de");
7418 emit2 ("add hl,de");
7419 freeAsmop (IC_JTCOND (ic), NULL, ic);
7423 emitLabel (jtab->key + 100);
7424 /* now generate the jump labels */
7425 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7426 jtab = setNextItem (IC_JTLABELS (ic)))
7427 emit2 ("jp !tlabel", jtab->key + 100);
7430 /*-----------------------------------------------------------------*/
7431 /* genCast - gen code for casting */
7432 /*-----------------------------------------------------------------*/
7434 genCast (iCode * ic)
7436 operand *result = IC_RESULT (ic);
7437 sym_link *rtype = operandType (IC_RIGHT (ic));
7438 operand *right = IC_RIGHT (ic);
7441 /* if they are equivalent then do nothing */
7442 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7445 aopOp (right, ic, FALSE, FALSE);
7446 aopOp (result, ic, FALSE, FALSE);
7448 /* if the result is a bit */
7449 if (AOP_TYPE (result) == AOP_CRY)
7451 wassertl (0, "Tried to cast to a bit");
7454 /* if they are the same size : or less */
7455 if (AOP_SIZE (result) <= AOP_SIZE (right))
7458 /* if they are in the same place */
7459 if (sameRegs (AOP (right), AOP (result)))
7462 /* if they in different places then copy */
7463 size = AOP_SIZE (result);
7467 aopPut (AOP (result),
7468 aopGet (AOP (right), offset, FALSE),
7475 /* So we now know that the size of destination is greater
7476 than the size of the source */
7477 /* we move to result for the size of source */
7478 size = AOP_SIZE (right);
7482 aopPut (AOP (result),
7483 aopGet (AOP (right), offset, FALSE),
7488 /* now depending on the sign of the destination */
7489 size = AOP_SIZE (result) - AOP_SIZE (right);
7490 /* Unsigned or not an integral type - right fill with zeros */
7491 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7494 aopPut (AOP (result), "!zero", offset++);
7498 /* we need to extend the sign :{ */
7499 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7505 aopPut (AOP (result), "a", offset++);
7509 freeAsmop (right, NULL, ic);
7510 freeAsmop (result, NULL, ic);
7513 /*-----------------------------------------------------------------*/
7514 /* genReceive - generate code for a receive iCode */
7515 /*-----------------------------------------------------------------*/
7517 genReceive (iCode * ic)
7519 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7520 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7521 IS_TRUE_SYMOP (IC_RESULT (ic))))
7531 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7532 size = AOP_SIZE(IC_RESULT(ic));
7534 for (i = 0; i < size; i++) {
7535 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7539 freeAsmop (IC_RESULT (ic), NULL, ic);
7542 /*-----------------------------------------------------------------*/
7543 /* genDummyRead - generate code for dummy read of volatiles */
7544 /*-----------------------------------------------------------------*/
7546 genDummyRead (iCode * ic)
7552 if (op && IS_SYMOP (op))
7554 aopOp (op, ic, FALSE, FALSE);
7557 size = AOP_SIZE (op);
7562 _moveA (aopGet (AOP (op), offset, FALSE));
7566 freeAsmop (op, NULL, ic);
7570 if (op && IS_SYMOP (op))
7572 aopOp (op, ic, FALSE, FALSE);
7575 size = AOP_SIZE (op);
7580 _moveA (aopGet (AOP (op), offset, FALSE));
7584 freeAsmop (op, NULL, ic);
7588 /*-----------------------------------------------------------------*/
7589 /* genCritical - generate code for start of a critical sequence */
7590 /*-----------------------------------------------------------------*/
7592 genCritical (iCode *ic)
7594 symbol *tlbl = newiTempLabel (NULL);
7600 else if (IC_RESULT (ic))
7602 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7603 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7604 //get interrupt enable flag IFF2 into P/O
7608 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7609 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7610 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7611 emit2 ("!tlabeldef", (tlbl->key + 100));
7612 _G.lines.current->isLabel = 1;
7613 freeAsmop (IC_RESULT (ic), NULL, ic);
7617 //get interrupt enable flag IFF2 into P/O
7626 /*-----------------------------------------------------------------*/
7627 /* genEndCritical - generate code for end of a critical sequence */
7628 /*-----------------------------------------------------------------*/
7630 genEndCritical (iCode *ic)
7632 symbol *tlbl = newiTempLabel (NULL);
7638 else if (IC_RIGHT (ic))
7640 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7641 _toBoolean (IC_RIGHT (ic));
7642 //don't enable interrupts if they were off before
7643 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7645 emitLabel (tlbl->key + 100);
7646 freeAsmop (IC_RIGHT (ic), NULL, ic);
7652 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7653 //don't enable interrupts as they were off before
7654 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7656 emit2 ("!tlabeldef", (tlbl->key + 100));
7657 _G.lines.current->isLabel = 1;
7663 /** Maximum number of bytes to emit per line. */
7667 /** Context for the byte output chunker. */
7670 unsigned char buffer[DBEMIT_MAX_RUN];
7675 /** Flushes a byte chunker by writing out all in the buffer and
7679 _dbFlush(DBEMITCTX *self)
7686 sprintf(line, ".db 0x%02X", self->buffer[0]);
7688 for (i = 1; i < self->pos; i++)
7690 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7697 /** Write out another byte, buffering until a decent line is
7701 _dbEmit(DBEMITCTX *self, int c)
7703 if (self->pos == DBEMIT_MAX_RUN)
7707 self->buffer[self->pos++] = c;
7710 /** Context for a simple run length encoder. */
7714 unsigned char buffer[128];
7716 /** runLen may be equivalent to pos. */
7722 RLE_CHANGE_COST = 4,
7726 /** Flush the buffer of a run length encoder by writing out the run or
7727 data that it currently contains.
7730 _rleCommit(RLECTX *self)
7736 memset(&db, 0, sizeof(db));
7738 emit2(".db %u", self->pos);
7740 for (i = 0; i < self->pos; i++)
7742 _dbEmit(&db, self->buffer[i]);
7751 Can get either a run or a block of random stuff.
7752 Only want to change state if a good run comes in or a run ends.
7753 Detecting run end is easy.
7756 Say initial state is in run, len zero, last zero. Then if you get a
7757 few zeros then something else then a short run will be output.
7758 Seems OK. While in run mode, keep counting. While in random mode,
7759 keep a count of the run. If run hits margin, output all up to run,
7760 restart, enter run mode.
7763 /** Add another byte into the run length encoder, flushing as
7764 required. The run length encoder uses the Amiga IFF style, where
7765 a block is prefixed by its run length. A positive length means
7766 the next n bytes pass straight through. A negative length means
7767 that the next byte is repeated -n times. A zero terminates the
7771 _rleAppend(RLECTX *self, unsigned c)
7775 if (c != self->last)
7777 /* The run has stopped. See if it is worthwhile writing it out
7778 as a run. Note that the random data comes in as runs of
7781 if (self->runLen > RLE_CHANGE_COST)
7783 /* Yes, worthwhile. */
7784 /* Commit whatever was in the buffer. */
7786 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7790 /* Not worthwhile. Append to the end of the random list. */
7791 for (i = 0; i < self->runLen; i++)
7793 if (self->pos >= RLE_MAX_BLOCK)
7798 self->buffer[self->pos++] = self->last;
7806 if (self->runLen >= RLE_MAX_BLOCK)
7808 /* Commit whatever was in the buffer. */
7811 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7819 _rleFlush(RLECTX *self)
7821 _rleAppend(self, -1);
7828 /** genArrayInit - Special code for initialising an array with constant
7832 genArrayInit (iCode * ic)
7836 int elementSize = 0, eIndex, i;
7837 unsigned val, lastVal;
7841 memset(&rle, 0, sizeof(rle));
7843 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7845 _saveRegsForCall(ic, 0);
7847 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7848 emit2 ("call __initrleblock");
7850 type = operandType(IC_LEFT(ic));
7852 if (type && type->next)
7854 if (IS_SPEC(type->next) || IS_PTR(type->next))
7856 elementSize = getSize(type->next);
7858 else if (IS_ARRAY(type->next) && type->next->next)
7860 elementSize = getSize(type->next->next);
7864 printTypeChainRaw (type, NULL);
7865 wassertl (0, "Can't determine element size in genArrayInit.");
7870 wassertl (0, "Can't determine element size in genArrayInit.");
7873 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7875 iLoop = IC_ARRAYILIST(ic);
7876 lastVal = (unsigned)-1;
7878 /* Feed all the bytes into the run length encoder which will handle
7880 This works well for mixed char data, and for random int and long
7887 for (i = 0; i < ix; i++)
7889 for (eIndex = 0; eIndex < elementSize; eIndex++)
7891 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7892 _rleAppend(&rle, val);
7896 iLoop = iLoop->next;
7900 /* Mark the end of the run. */
7903 _restoreRegsAfterCall();
7907 freeAsmop (IC_LEFT(ic), NULL, ic);
7911 _swap (PAIR_ID one, PAIR_ID two)
7913 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7919 emit2 ("ld a,%s", _pairs[one].l);
7920 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7921 emit2 ("ld %s,a", _pairs[two].l);
7922 emit2 ("ld a,%s", _pairs[one].h);
7923 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7924 emit2 ("ld %s,a", _pairs[two].h);
7928 /* The problem is that we may have all three pairs used and they may
7929 be needed in a different order.
7934 hl = hl => unity, fine
7938 hl = hl hl = hl, swap de <=> bc
7946 hl = bc de = de, swap bc <=> hl
7954 hl = de bc = bc, swap hl <=> de
7959 * Any pair = pair are done last
7960 * Any pair = iTemp are done last
7961 * Any swaps can be done any time
7969 So how do we detect the cases?
7970 How about a 3x3 matrix?
7974 x x x x (Fourth for iTemp/other)
7976 First determin which mode to use by counting the number of unity and
7979 Two - Assign the pair first, then the rest
7980 One - Swap the two, then the rest
7984 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7986 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7988 PAIR_BC, PAIR_HL, PAIR_DE
7990 int i, j, nunity = 0;
7991 memset (ids, PAIR_INVALID, sizeof (ids));
7994 wassert (nparams == 3);
7996 /* First save everything that needs to be saved. */
7997 _saveRegsForCall (ic, 0);
7999 /* Loading HL first means that DE is always fine. */
8000 for (i = 0; i < nparams; i++)
8002 aopOp (pparams[i], ic, FALSE, FALSE);
8003 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
8006 /* Count the number of unity or iTemp assigns. */
8007 for (i = 0; i < 3; i++)
8009 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
8017 /* Any order, fall through. */
8019 else if (nunity == 2)
8021 /* One is assigned. Pull it out and assign. */
8022 for (i = 0; i < 3; i++)
8024 for (j = 0; j < NUM_PAIRS; j++)
8026 if (ids[dest[i]][j] == TRUE)
8028 /* Found it. See if it's the right one. */
8029 if (j == PAIR_INVALID || j == dest[i])
8035 fetchPair(dest[i], AOP (pparams[i]));
8042 else if (nunity == 1)
8044 /* Find the pairs to swap. */
8045 for (i = 0; i < 3; i++)
8047 for (j = 0; j < NUM_PAIRS; j++)
8049 if (ids[dest[i]][j] == TRUE)
8051 if (j == PAIR_INVALID || j == dest[i])
8066 int next = getPairId (AOP (pparams[0]));
8067 emit2 ("push %s", _pairs[next].name);
8069 if (next == dest[1])
8071 fetchPair (dest[1], AOP (pparams[1]));
8072 fetchPair (dest[2], AOP (pparams[2]));
8076 fetchPair (dest[2], AOP (pparams[2]));
8077 fetchPair (dest[1], AOP (pparams[1]));
8079 emit2 ("pop %s", _pairs[dest[0]].name);
8082 /* Finally pull out all of the iTemps */
8083 for (i = 0; i < 3; i++)
8085 if (ids[dest[i]][PAIR_INVALID] == 1)
8087 fetchPair (dest[i], AOP (pparams[i]));
8093 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8099 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8103 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8105 setupForBuiltin3 (ic, nParams, pparams);
8107 label = newiTempLabel(NULL);
8109 emitLabel (label->key);
8110 emit2 ("ld a,(hl)");
8113 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8115 freeAsmop (from, NULL, ic->next);
8116 freeAsmop (to, NULL, ic);
8120 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8122 operand *from, *to, *count;
8125 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8130 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8132 setupForBuiltin3 (ic, nParams, pparams);
8136 freeAsmop (count, NULL, ic->next->next);
8137 freeAsmop (from, NULL, ic);
8139 _restoreRegsAfterCall();
8141 /* if we need assign a result value */
8142 if ((IS_ITEMP (IC_RESULT (ic)) &&
8143 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8144 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8145 IS_TRUE_SYMOP (IC_RESULT (ic)))
8147 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8148 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8149 freeAsmop (IC_RESULT (ic), NULL, ic);
8152 freeAsmop (to, NULL, ic->next);
8155 /*-----------------------------------------------------------------*/
8156 /* genBuiltIn - calls the appropriate function to generating code */
8157 /* for a built in function */
8158 /*-----------------------------------------------------------------*/
8159 static void genBuiltIn (iCode *ic)
8161 operand *bi_parms[MAX_BUILTIN_ARGS];
8166 /* get all the arguments for a built in function */
8167 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8169 /* which function is it */
8170 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8172 if (strcmp(bif->name,"__builtin_strcpy")==0)
8174 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8176 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8178 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8182 wassertl (0, "Unknown builtin function encountered");
8186 /*-----------------------------------------------------------------*/
8187 /* genZ80Code - generate code for Z80 based controllers */
8188 /*-----------------------------------------------------------------*/
8190 genZ80Code (iCode * lic)
8198 _fReturn = _gbz80_return;
8199 _fTmp = _gbz80_return;
8203 _fReturn = _z80_return;
8204 _fTmp = _z80_return;
8207 _G.lines.head = _G.lines.current = NULL;
8209 /* if debug information required */
8210 if (options.debug && currFunc)
8212 debugFile->writeFunction (currFunc, lic);
8215 for (ic = lic; ic; ic = ic->next)
8217 _G.current_iCode = ic;
8219 if (ic->lineno && cln != ic->lineno)
8223 debugFile->writeCLine (ic);
8225 if (!options.noCcodeInAsm)
8227 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8228 printCLine(ic->filename, ic->lineno));
8232 if (options.iCodeInAsm)
8234 const char *iLine = printILine(ic);
8235 emit2 (";ic:%d: %s", ic->key, iLine);
8238 /* if the result is marked as
8239 spilt and rematerializable or code for
8240 this has already been generated then
8242 if (resultRemat (ic) || ic->generated)
8245 /* depending on the operation */
8249 emitDebug ("; genNot");
8254 emitDebug ("; genCpl");
8259 emitDebug ("; genUminus");
8264 emitDebug ("; genIpush");
8269 /* IPOP happens only when trying to restore a
8270 spilt live range, if there is an ifx statement
8271 following this pop then the if statement might
8272 be using some of the registers being popped which
8273 would destroy the contents of the register so
8274 we need to check for this condition and handle it */
8276 ic->next->op == IFX &&
8277 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8279 emitDebug ("; genIfx");
8280 genIfx (ic->next, ic);
8284 emitDebug ("; genIpop");
8290 emitDebug ("; genCall");
8295 emitDebug ("; genPcall");
8300 emitDebug ("; genFunction");
8305 emitDebug ("; genEndFunction");
8306 genEndFunction (ic);
8310 emitDebug ("; genRet");
8315 emitDebug ("; genLabel");
8320 emitDebug ("; genGoto");
8325 emitDebug ("; genPlus");
8330 emitDebug ("; genMinus");
8335 emitDebug ("; genMult");
8340 emitDebug ("; genDiv");
8345 emitDebug ("; genMod");
8350 emitDebug ("; genCmpGt");
8351 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8355 emitDebug ("; genCmpLt");
8356 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8363 /* note these two are xlated by algebraic equivalence
8364 during parsing SDCC.y */
8365 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8366 "got '>=' or '<=' shouldn't have come here");
8370 emitDebug ("; genCmpEq");
8371 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8375 emitDebug ("; genAndOp");
8380 emitDebug ("; genOrOp");
8385 emitDebug ("; genXor");
8386 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8390 emitDebug ("; genOr");
8391 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8395 emitDebug ("; genAnd");
8396 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8400 emitDebug ("; genInline");
8405 emitDebug ("; genRRC");
8410 emitDebug ("; genRLC");
8415 emitDebug ("; genGetHBIT");
8420 emitDebug ("; genLeftShift");
8425 emitDebug ("; genRightShift");
8429 case GET_VALUE_AT_ADDRESS:
8430 emitDebug ("; genPointerGet");
8436 if (POINTER_SET (ic))
8438 emitDebug ("; genAssign (pointer)");
8443 emitDebug ("; genAssign");
8449 emitDebug ("; genIfx");
8454 emitDebug ("; genAddrOf");
8459 emitDebug ("; genJumpTab");
8464 emitDebug ("; genCast");
8469 emitDebug ("; genReceive");
8474 if (ic->builtinSEND)
8476 emitDebug ("; genBuiltIn");
8481 emitDebug ("; addSet");
8482 addSet (&_G.sendSet, ic);
8487 emitDebug ("; genArrayInit");
8491 case DUMMY_READ_VOLATILE:
8492 emitDebug ("; genDummyRead");
8497 emitDebug ("; genCritical");
8502 emitDebug ("; genEndCritical");
8503 genEndCritical (ic);
8512 /* now we are ready to call the
8513 peep hole optimizer */
8514 if (!options.nopeep)
8515 peepHole (&_G.lines.head);
8517 /* This is unfortunate */
8518 /* now do the actual printing */
8520 struct dbuf_s *buf = codeOutBuf;
8521 if (isInHome () && codeOutBuf == &code->oBuf)
8522 codeOutBuf = &home->oBuf;
8523 printLine (_G.lines.head, codeOutBuf);
8524 if (_G.flushStatics)
8527 _G.flushStatics = 0;
8532 freeTrace(&_G.lines.trace);
8533 freeTrace(&_G.trace.aops);
8539 _isPairUsed (iCode * ic, PAIR_ID pairId)
8545 if (bitVectBitValue (ic->rMask, D_IDX))
8547 if (bitVectBitValue (ic->rMask, E_IDX))
8557 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8560 value *val = aop->aopu.aop_lit;
8562 wassert (aop->type == AOP_LIT);
8563 wassert (!IS_FLOAT (val->type));
8565 v = ulFromVal (val);
8573 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8574 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));