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);
2513 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2514 topInA = requiresHL (AOP (oper));
2516 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2518 /* We do it the hard way here. */
2520 aopPut (AOP (oper), _fReturn[0], 0);
2521 aopPut (AOP (oper), _fReturn[1], 1);
2523 aopPut (AOP (oper), _fReturn[0], 2);
2524 aopPut (AOP (oper), _fReturn[1], 3);
2528 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2529 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2532 _emitMove ("a", _fReturn[size-1]);
2533 _emitMove (_fReturn[size-1], _fReturn[size]);
2534 _emitMove (_fReturn[size], "a");
2535 aopPut (AOP (oper), _fReturn[size], size-1);
2540 aopPut (AOP (oper), _fReturn[size], size);
2545 /** Simple restore that doesn't take into account what is used in the
2549 _restoreRegsAfterCall(void)
2551 if (_G.stack.pushedDE)
2554 _G.stack.pushedDE = FALSE;
2556 if (_G.stack.pushedBC)
2559 _G.stack.pushedBC = FALSE;
2561 _G.saves.saved = FALSE;
2565 _saveRegsForCall(iCode *ic, int sendSetSize)
2568 o Stack parameters are pushed before this function enters
2569 o DE and BC may be used in this function.
2570 o HL and DE may be used to return the result.
2571 o HL and DE may be used to send variables.
2572 o DE and BC may be used to store the result value.
2573 o HL may be used in computing the sent value of DE
2574 o The iPushes for other parameters occur before any addSets
2576 Logic: (to be run inside the first iPush or if none, before sending)
2577 o Compute if DE and/or BC are in use over the call
2578 o Compute if DE is used in the send set
2579 o Compute if DE and/or BC are used to hold the result value
2580 o If (DE is used, or in the send set) and is not used in the result, push.
2581 o If BC is used and is not in the result, push
2583 o If DE is used in the send set, fetch
2584 o If HL is used in the send set, fetch
2588 if (_G.saves.saved == FALSE) {
2589 bool deInUse, bcInUse;
2591 bool bcInRet = FALSE, deInRet = FALSE;
2594 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2595 z80_rUmaskForOp (IC_RESULT(ic)));
2597 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2598 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2600 deSending = (sendSetSize > 1);
2602 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2604 if (bcInUse && bcInRet == FALSE) {
2606 _G.stack.pushedBC = TRUE;
2608 if (deInUse && deInRet == FALSE) {
2610 _G.stack.pushedDE = TRUE;
2613 _G.saves.saved = TRUE;
2616 /* Already saved. */
2620 /*-----------------------------------------------------------------*/
2621 /* genIpush - genrate code for pushing this gets a little complex */
2622 /*-----------------------------------------------------------------*/
2624 genIpush (iCode * ic)
2626 int size, offset = 0;
2629 /* if this is not a parm push : ie. it is spill push
2630 and spill push is always done on the local stack */
2633 wassertl(0, "Encountered an unsupported spill push.");
2637 if (_G.saves.saved == FALSE) {
2638 /* Caller saves, and this is the first iPush. */
2639 /* Scan ahead until we find the function that we are pushing parameters to.
2640 Count the number of addSets on the way to figure out what registers
2641 are used in the send set.
2644 iCode *walk = ic->next;
2647 if (walk->op == SEND) {
2650 else if (walk->op == CALL || walk->op == PCALL) {
2659 _saveRegsForCall(walk, nAddSets);
2662 /* Already saved by another iPush. */
2665 /* then do the push */
2666 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2668 size = AOP_SIZE (IC_LEFT (ic));
2670 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2672 _G.stack.pushed += 2;
2673 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2679 fetchHL (AOP (IC_LEFT (ic)));
2681 spillPair (PAIR_HL);
2682 _G.stack.pushed += 2;
2687 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2689 spillPair (PAIR_HL);
2690 _G.stack.pushed += 2;
2691 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2693 spillPair (PAIR_HL);
2694 _G.stack.pushed += 2;
2700 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2702 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2704 emit2 ("ld a,(%s)", l);
2709 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2710 if (!strcmp(l, "b"))
2712 else if (!strcmp(l, "d"))
2714 else if (!strcmp(l, "h"))
2718 emit2 ("ld a,%s", l);
2727 freeAsmop (IC_LEFT (ic), NULL, ic);
2730 /*-----------------------------------------------------------------*/
2731 /* genIpop - recover the registers: can happen only for spilling */
2732 /*-----------------------------------------------------------------*/
2734 genIpop (iCode * ic)
2739 /* if the temp was not pushed then */
2740 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2743 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2744 size = AOP_SIZE (IC_LEFT (ic));
2745 offset = (size - 1);
2746 if (isPair (AOP (IC_LEFT (ic))))
2748 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2756 spillPair (PAIR_HL);
2757 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2761 freeAsmop (IC_LEFT (ic), NULL, ic);
2764 /* This is quite unfortunate */
2766 setArea (int inHome)
2769 static int lastArea = 0;
2771 if (_G.in_home != inHome) {
2773 const char *sz = port->mem.code_name;
2774 port->mem.code_name = "HOME";
2775 emit2("!area", CODE_NAME);
2776 port->mem.code_name = sz;
2779 emit2("!area", CODE_NAME); */
2780 _G.in_home = inHome;
2791 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2795 symbol *sym = OP_SYMBOL (op);
2797 if (sym->isspilt || sym->nRegs == 0)
2800 aopOp (op, ic, FALSE, FALSE);
2803 if (aop->type == AOP_REG)
2806 for (i = 0; i < aop->size; i++)
2808 if (pairId == PAIR_DE)
2810 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2811 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2813 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2816 else if (pairId == PAIR_BC)
2818 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2819 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2821 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2831 freeAsmop (IC_LEFT (ic), NULL, ic);
2835 /** Emit the code for a call statement
2838 emitCall (iCode * ic, bool ispcall)
2840 bool bInRet, cInRet, dInRet, eInRet;
2841 sym_link *dtype = operandType (IC_LEFT (ic));
2843 /* if caller saves & we have not saved then */
2849 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2851 /* if send set is not empty then assign */
2856 int nSend = elementsInSet(_G.sendSet);
2857 bool swapped = FALSE;
2859 int _z80_sendOrder[] = {
2864 /* Check if the parameters are swapped. If so route through hl instead. */
2865 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2867 sic = setFirstItem(_G.sendSet);
2868 sic = setNextItem(_G.sendSet);
2870 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2871 /* The second send value is loaded from one the one that holds the first
2872 send, i.e. it is overwritten. */
2873 /* Cache the first in HL, and load the second from HL instead. */
2874 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2875 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2881 for (sic = setFirstItem (_G.sendSet); sic;
2882 sic = setNextItem (_G.sendSet))
2885 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2887 size = AOP_SIZE (IC_LEFT (sic));
2888 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2889 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2891 // PENDING: Mild hack
2892 if (swapped == TRUE && send == 1) {
2894 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2897 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2899 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2902 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2906 freeAsmop (IC_LEFT (sic), NULL, sic);
2913 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2915 werror (W_INDIR_BANKED);
2917 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2919 if (isLitWord (AOP (IC_LEFT (ic))))
2921 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2925 symbol *rlbl = newiTempLabel (NULL);
2926 spillPair (PAIR_HL);
2927 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2929 _G.stack.pushed += 2;
2931 fetchHL (AOP (IC_LEFT (ic)));
2933 emit2 ("!tlabeldef", (rlbl->key + 100));
2934 _G.lines.current->isLabel = 1;
2935 _G.stack.pushed -= 2;
2937 freeAsmop (IC_LEFT (ic), NULL, ic);
2941 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2942 OP_SYMBOL (IC_LEFT (ic))->rname :
2943 OP_SYMBOL (IC_LEFT (ic))->name;
2944 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2946 emit2 ("call banked_call");
2947 emit2 ("!dws", name);
2948 emit2 ("!dw !bankimmeds", name);
2953 emit2 ("call %s", name);
2958 /* Mark the registers as restored. */
2959 _G.saves.saved = FALSE;
2961 /* adjust the stack for parameters if required */
2964 int i = ic->parmBytes;
2966 _G.stack.pushed -= i;
2969 emit2 ("!ldaspsp", i);
2976 emit2 ("ld iy,!immedword", i);
2977 emit2 ("add iy,sp");
2995 /* if we need assign a result value */
2996 if ((IS_ITEMP (IC_RESULT (ic)) &&
2997 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2998 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2999 IS_TRUE_SYMOP (IC_RESULT (ic)))
3001 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3003 assignResultValue (IC_RESULT (ic));
3005 freeAsmop (IC_RESULT (ic), NULL, ic);
3011 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3012 bInRet = bitVectBitValue(result, B_IDX);
3013 cInRet = bitVectBitValue(result, C_IDX);
3014 dInRet = bitVectBitValue(result, D_IDX);
3015 eInRet = bitVectBitValue(result, E_IDX);
3025 if (_G.stack.pushedDE)
3027 if (dInRet && eInRet)
3029 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3033 /* Only restore E */
3040 /* Only restore D */
3048 _G.stack.pushedDE = FALSE;
3051 if (_G.stack.pushedBC)
3053 if (bInRet && cInRet)
3055 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3059 /* Only restore C */
3066 /* Only restore B */
3074 _G.stack.pushedBC = FALSE;
3078 /*-----------------------------------------------------------------*/
3079 /* genCall - generates a call statement */
3080 /*-----------------------------------------------------------------*/
3082 genCall (iCode * ic)
3084 emitCall (ic, FALSE);
3087 /*-----------------------------------------------------------------*/
3088 /* genPcall - generates a call by pointer statement */
3089 /*-----------------------------------------------------------------*/
3091 genPcall (iCode * ic)
3093 emitCall (ic, TRUE);
3096 /*-----------------------------------------------------------------*/
3097 /* resultRemat - result is rematerializable */
3098 /*-----------------------------------------------------------------*/
3100 resultRemat (iCode * ic)
3102 if (SKIP_IC (ic) || ic->op == IFX)
3105 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3107 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3108 if (sym->remat && !POINTER_SET (ic))
3115 extern set *publics;
3117 /*-----------------------------------------------------------------*/
3118 /* genFunction - generated code for function entry */
3119 /*-----------------------------------------------------------------*/
3121 genFunction (iCode * ic)
3125 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3128 bool bcInUse = FALSE;
3129 bool deInUse = FALSE;
3131 setArea (IFFUNC_NONBANKED (sym->type));
3133 /* PENDING: Reset the receive offset as it
3134 doesn't seem to get reset anywhere else.
3136 _G.receiveOffset = 0;
3138 /* Record the last function name for debugging. */
3139 _G.lastFunctionName = sym->rname;
3141 /* Create the function header */
3142 emit2 ("!functionheader", sym->name);
3143 if (!IS_STATIC(sym->etype))
3145 sprintf (buffer, "%s_start", sym->rname);
3146 emit2 ("!labeldef", buffer);
3147 _G.lines.current->isLabel = 1;
3149 emit2 ("!functionlabeldef", sym->rname);
3150 _G.lines.current->isLabel = 1;
3152 ftype = operandType (IC_LEFT (ic));
3154 if (IFFUNC_ISNAKED(ftype))
3156 emitDebug("; naked function: no prologue.");
3160 /* if this is an interrupt service routine
3161 then save all potentially used registers. */
3162 if (IFFUNC_ISISR (sym->type))
3164 /* If critical function then turn interrupts off */
3165 /* except when no interrupt number is given then it implies the NMI handler */
3166 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3175 /* This is a non-ISR function.
3176 If critical function then turn interrupts off */
3177 if (IFFUNC_ISCRITICAL (sym->type))
3185 //get interrupt enable flag IFF2 into P/O
3194 if (options.profile)
3196 emit2 ("!profileenter");
3199 /* PENDING: callee-save etc */
3201 _G.stack.param_offset = 0;
3203 if (z80_opts.calleeSavesBC)
3208 /* Detect which registers are used. */
3209 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3212 for (i = 0; i < sym->regsUsed->size; i++)
3214 if (bitVectBitValue (sym->regsUsed, i))
3228 /* Other systems use DE as a temporary. */
3239 _G.stack.param_offset += 2;
3242 _G.calleeSaves.pushedBC = bcInUse;
3247 _G.stack.param_offset += 2;
3250 _G.calleeSaves.pushedDE = deInUse;
3252 /* adjust the stack for the function */
3253 _G.stack.last = sym->stack;
3256 for (sym = setFirstItem (istack->syms); sym;
3257 sym = setNextItem (istack->syms))
3259 if (sym->_isparm && !IS_REGPARM (sym->etype))
3265 sym = OP_SYMBOL (IC_LEFT (ic));
3267 _G.omitFramePtr = options.ommitFramePtr;
3268 if (IS_Z80 && !stackParm && !sym->stack)
3270 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3271 /* the above !sym->stack condition can be removed. -- EEP */
3273 emit2 ("!ldaspsp", -sym->stack);
3274 _G.omitFramePtr = TRUE;
3276 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3277 emit2 ("!enterxl", sym->stack);
3278 else if (sym->stack)
3280 if ((optimize.codeSize && sym->stack <= 8) || sym->stack <= 4)
3282 int stack = sym->stack;
3293 emit2 ("!enterx", sym->stack);
3298 _G.stack.offset = sym->stack;
3301 /*-----------------------------------------------------------------*/
3302 /* genEndFunction - generates epilogue for functions */
3303 /*-----------------------------------------------------------------*/
3305 genEndFunction (iCode * ic)
3307 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3309 if (IFFUNC_ISNAKED(sym->type))
3311 emitDebug("; naked function: no epilogue.");
3315 /* PENDING: calleeSave */
3316 if (IS_Z80 && _G.omitFramePtr)
3318 if (_G.stack.offset)
3319 emit2 ("!ldaspsp", _G.stack.offset);
3321 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3323 emit2 ("!leavexl", _G.stack.offset);
3325 else if (_G.stack.offset)
3327 emit2 ("!leavex", _G.stack.offset);
3334 if (_G.calleeSaves.pushedDE)
3337 _G.calleeSaves.pushedDE = FALSE;
3340 if (_G.calleeSaves.pushedBC)
3343 _G.calleeSaves.pushedBC = FALSE;
3346 if (options.profile)
3348 emit2 ("!profileexit");
3351 /* if this is an interrupt service routine
3352 then save all potentially used registers. */
3353 if (IFFUNC_ISISR (sym->type))
3357 /* If critical function then turn interrupts back on */
3358 /* except when no interrupt number is given then it implies the NMI handler */
3359 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3366 /* This is a non-ISR function.
3367 If critical function then turn interrupts back on */
3368 if (IFFUNC_ISCRITICAL (sym->type))
3376 symbol *tlbl = newiTempLabel (NULL);
3379 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3380 //don't enable interrupts as they were off before
3381 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3383 emit2 ("!tlabeldef", (tlbl->key + 100));
3384 _G.lines.current->isLabel = 1;
3389 if (options.debug && currFunc)
3391 debugFile->writeEndFunction (currFunc, ic, 1);
3394 if (IFFUNC_ISISR (sym->type))
3396 /* "critical interrupt" is used to imply NMI handler */
3397 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3404 /* Both banked and non-banked just ret */
3408 if (!IS_STATIC(sym->etype))
3410 sprintf (buffer, "%s_end", sym->rname);
3411 emit2 ("!labeldef", buffer);
3412 _G.lines.current->isLabel = 1;
3415 _G.flushStatics = 1;
3416 _G.stack.pushed = 0;
3417 _G.stack.offset = 0;
3420 /*-----------------------------------------------------------------*/
3421 /* genRet - generate code for return statement */
3422 /*-----------------------------------------------------------------*/
3427 /* Errk. This is a hack until I can figure out how
3428 to cause dehl to spill on a call */
3429 int size, offset = 0;
3431 /* if we have no return value then
3432 just generate the "ret" */
3436 /* we have something to return then
3437 move the return value into place */
3438 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3439 size = AOP_SIZE (IC_LEFT (ic));
3441 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3444 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3448 emit2 ("ld de,%s", l);
3452 emit2 ("ld hl,%s", l);
3458 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3462 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3464 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3465 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3471 l = aopGet (AOP (IC_LEFT (ic)), offset,
3473 if (strcmp (_fReturn[offset], l))
3474 emit2 ("ld %s,%s", _fReturn[offset], l);
3479 freeAsmop (IC_LEFT (ic), NULL, ic);
3482 /* generate a jump to the return label
3483 if the next is not the return statement */
3484 if (!(ic->next && ic->next->op == LABEL &&
3485 IC_LABEL (ic->next) == returnLabel))
3487 emit2 ("jp !tlabel", returnLabel->key + 100);
3490 /*-----------------------------------------------------------------*/
3491 /* genLabel - generates a label */
3492 /*-----------------------------------------------------------------*/
3494 genLabel (iCode * ic)
3496 /* special case never generate */
3497 if (IC_LABEL (ic) == entryLabel)
3500 emitLabel (IC_LABEL (ic)->key + 100);
3503 /*-----------------------------------------------------------------*/
3504 /* genGoto - generates a ljmp */
3505 /*-----------------------------------------------------------------*/
3507 genGoto (iCode * ic)
3509 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3512 /*-----------------------------------------------------------------*/
3513 /* genPlusIncr :- does addition with increment if possible */
3514 /*-----------------------------------------------------------------*/
3516 genPlusIncr (iCode * ic)
3518 unsigned int icount;
3519 unsigned int size = getDataSize (IC_RESULT (ic));
3520 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3522 /* will try to generate an increment */
3523 /* if the right side is not a literal
3525 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3528 emitDebug ("; genPlusIncr");
3530 icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3532 /* If result is a pair */
3533 if (resultId != PAIR_INVALID)
3535 if (isLitWord (AOP (IC_LEFT (ic))))
3537 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3540 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3542 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3544 PAIR_ID freep = getFreePairId (ic);
3545 if (freep != PAIR_INVALID)
3547 fetchPair (freep, AOP (IC_RIGHT (ic)));
3548 emit2 ("add hl,%s", _pairs[freep].name);
3554 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3555 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3562 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3566 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3570 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3575 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3577 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3578 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3582 /* if the literal value of the right hand side
3583 is greater than 4 then it is not worth it */
3587 /* if increment 16 bits in register */
3588 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3594 symbol *tlbl = NULL;
3595 tlbl = newiTempLabel (NULL);
3598 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3601 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3604 emitLabel (tlbl->key + 100);
3608 /* if the sizes are greater than 1 then we cannot */
3609 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3610 AOP_SIZE (IC_LEFT (ic)) > 1)
3613 /* If the result is in a register then we can load then increment.
3615 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3617 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3620 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3625 /* we can if the aops of the left & result match or
3626 if they are in registers and the registers are the
3628 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3632 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3640 /*-----------------------------------------------------------------*/
3641 /* outBitAcc - output a bit in acc */
3642 /*-----------------------------------------------------------------*/
3644 outBitAcc (operand * result)
3646 symbol *tlbl = newiTempLabel (NULL);
3647 /* if the result is a bit */
3648 if (AOP_TYPE (result) == AOP_CRY)
3650 wassertl (0, "Tried to write A into a bit");
3654 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3655 emit2 ("ld a,!one");
3656 emitLabel (tlbl->key + 100);
3662 couldDestroyCarry (asmop *aop)
3666 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3675 shiftIntoPair (int idx, asmop *aop)
3677 PAIR_ID id = PAIR_INVALID;
3679 wassertl (IS_Z80, "Only implemented for the Z80");
3680 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3682 emitDebug ("; Shift into pair idx %u", idx);
3688 setupPair (PAIR_HL, aop, 0);
3693 setupPair (PAIR_IY, aop, 0);
3695 emit2 ("pop %s", _pairs[id].name);
3699 setupPair (PAIR_IY, aop, 0);
3702 wassertl (0, "Internal error - hit default case");
3705 aop->type = AOP_PAIRPTR;
3706 aop->aopu.aop_pairId = id;
3707 _G.pairs[id].offset = 0;
3708 _G.pairs[id].last_type = aop->type;
3712 setupToPreserveCarry (iCode * ic)
3714 asmop *left = AOP (IC_LEFT (ic));
3715 asmop *right = AOP (IC_RIGHT (ic));
3716 asmop *result = AOP (IC_RESULT (ic));
3718 wassert (left && right);
3722 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3724 shiftIntoPair (0, right);
3725 /* check result again, in case right == result */
3726 if (couldDestroyCarry (result))
3728 if (!isPairInUse (PAIR_DE, ic))
3729 shiftIntoPair (1, result);
3731 shiftIntoPair (2, result);
3734 else if (couldDestroyCarry (right))
3736 if (getPairId (result) == PAIR_HL)
3737 _G.preserveCarry = TRUE;
3739 shiftIntoPair (0, right);
3741 else if (couldDestroyCarry (result))
3743 shiftIntoPair (0, result);
3752 /*-----------------------------------------------------------------*/
3753 /* genPlus - generates code for addition */
3754 /*-----------------------------------------------------------------*/
3756 genPlus (iCode * ic)
3758 int size, offset = 0;
3760 /* special cases :- */
3762 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3763 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3764 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3766 /* Swap the left and right operands if:
3768 if literal, literal on the right or
3769 if left requires ACC or right is already
3772 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3773 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3774 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3776 operand *t = IC_RIGHT (ic);
3777 IC_RIGHT (ic) = IC_LEFT (ic);
3781 /* if both left & right are in bit
3783 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3784 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3787 wassertl (0, "Tried to add two bits");
3790 /* if left in bit space & right literal */
3791 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3792 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3794 /* Can happen I guess */
3795 wassertl (0, "Tried to add a bit to a literal");
3798 /* if I can do an increment instead
3799 of add then GOOD for ME */
3800 if (genPlusIncr (ic) == TRUE)
3803 size = getDataSize (IC_RESULT (ic));
3805 /* Special case when left and right are constant */
3806 if (isPair (AOP (IC_RESULT (ic))))
3809 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3810 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3812 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3818 sprintf (buffer, "#(%s + %s)", left, right);
3819 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3824 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3826 /* Fetch into HL then do the add */
3827 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3828 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3830 spillPair (PAIR_HL);
3832 if (left == PAIR_HL && right != PAIR_INVALID)
3834 emit2 ("add hl,%s", _pairs[right].name);
3837 else if (right == PAIR_HL && left != PAIR_INVALID)
3839 emit2 ("add hl,%s", _pairs[left].name);
3842 else if (right != PAIR_INVALID && right != PAIR_HL)
3844 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3845 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3848 else if (left != PAIR_INVALID && left != PAIR_HL)
3850 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3851 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3860 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3862 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3863 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3864 spillPair (PAIR_HL);
3865 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3869 if (isPair (AOP (IC_LEFT (ic))) && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && getPairId (AOP (IC_LEFT (ic))) != PAIR_HL)
3871 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3872 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3873 spillPair (PAIR_HL);
3874 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3879 ld hl,sp+n trashes C so we can't afford to do it during an
3880 add with stack based variables. Worst case is:
3893 So you can't afford to load up hl if either left, right, or result
3894 is on the stack (*sigh*) The alt is:
3902 Combinations in here are:
3903 * If left or right are in bc then the loss is small - trap later
3904 * If the result is in bc then the loss is also small
3908 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3909 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3910 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3912 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3913 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3914 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3915 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3917 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3919 /* Swap left and right */
3920 operand *t = IC_RIGHT (ic);
3921 IC_RIGHT (ic) = IC_LEFT (ic);
3924 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3926 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3927 emit2 ("add hl,bc");
3931 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3932 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3933 emit2 ("add hl,de");
3935 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3941 /* Be paranoid on the GB with 4 byte variables due to how C
3942 can be trashed by lda hl,n(sp).
3944 _gbz80_emitAddSubLong (ic, TRUE);
3949 setupToPreserveCarry (ic);
3951 /* This is ugly, but it fixes the worst code generation bug on Z80. */
3952 /* Probably something similar has to be done for addition of larger numbers, too. */
3955 _moveA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3956 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), 0, FALSE));
3957 if(strcmp (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), aopGet (AOP (IC_LEFT (ic)), 1, FALSE)))
3959 aopPut (AOP (IC_RESULT (ic)), "a", 0);
3960 _moveA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3964 emitDebug ("; Addition result is in same register as operand of next addition.");
3965 if(strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'c') ||
3966 strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'b') )
3970 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3973 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3981 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3984 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3990 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), 1, FALSE));
3991 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3997 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3999 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4001 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4002 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4006 _G.preserveCarry = FALSE;
4007 freeAsmop (IC_LEFT (ic), NULL, ic);
4008 freeAsmop (IC_RIGHT (ic), NULL, ic);
4009 freeAsmop (IC_RESULT (ic), NULL, ic);
4012 /*-----------------------------------------------------------------*/
4013 /* genMinusDec :- does subtraction with deccrement if possible */
4014 /*-----------------------------------------------------------------*/
4016 genMinusDec (iCode * ic)
4018 unsigned int icount;
4019 unsigned int size = getDataSize (IC_RESULT (ic));
4021 /* will try to generate an increment */
4022 /* if the right side is not a literal we cannot */
4023 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4026 /* if the literal value of the right hand side
4027 is greater than 4 then it is not worth it */
4028 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
4031 size = getDataSize (IC_RESULT (ic));
4033 /* if decrement 16 bits in register */
4034 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4035 (size > 1) && isPair (AOP (IC_RESULT (ic))))
4038 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4042 /* If result is a pair */
4043 if (isPair (AOP (IC_RESULT (ic))))
4045 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
4047 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4051 /* if increment 16 bits in register */
4052 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4056 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4059 emit2 ("dec %s", _getTempPairName());
4062 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4068 /* if the sizes are greater than 1 then we cannot */
4069 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4070 AOP_SIZE (IC_LEFT (ic)) > 1)
4073 /* we can if the aops of the left & result match or if they are in
4074 registers and the registers are the same */
4075 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4078 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4085 /*-----------------------------------------------------------------*/
4086 /* genMinus - generates code for subtraction */
4087 /*-----------------------------------------------------------------*/
4089 genMinus (iCode * ic)
4091 int size, offset = 0;
4092 unsigned long lit = 0L;
4094 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4095 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4096 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4098 /* special cases :- */
4099 /* if both left & right are in bit space */
4100 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4101 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4103 wassertl (0, "Tried to subtract two bits");
4107 /* if I can do an decrement instead of subtract then GOOD for ME */
4108 if (genMinusDec (ic) == TRUE)
4111 size = getDataSize (IC_RESULT (ic));
4113 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4118 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4122 /* Same logic as genPlus */
4125 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4126 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4127 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4129 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4130 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4131 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4132 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4134 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4135 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4137 if (left == PAIR_INVALID && right == PAIR_INVALID)
4142 else if (right == PAIR_INVALID)
4144 else if (left == PAIR_INVALID)
4147 fetchPair (left, AOP (IC_LEFT (ic)));
4148 /* Order is important. Right may be HL */
4149 fetchPair (right, AOP (IC_RIGHT (ic)));
4151 emit2 ("ld a,%s", _pairs[left].l);
4152 emit2 ("sub a,%s", _pairs[right].l);
4154 emit2 ("ld a,%s", _pairs[left].h);
4155 emit2 ("sbc a,%s", _pairs[right].h);
4157 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4159 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4161 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4167 /* Be paranoid on the GB with 4 byte variables due to how C
4168 can be trashed by lda hl,n(sp).
4170 _gbz80_emitAddSubLong (ic, FALSE);
4175 setupToPreserveCarry (ic);
4177 /* if literal, add a,#-lit, else normal subb */
4180 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4181 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4185 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4188 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4192 /* first add without previous c */
4195 if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
4198 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4201 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4203 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4206 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4207 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4208 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4210 wassertl (0, "Tried to subtract on a long pointer");
4214 _G.preserveCarry = FALSE;
4215 freeAsmop (IC_LEFT (ic), NULL, ic);
4216 freeAsmop (IC_RIGHT (ic), NULL, ic);
4217 freeAsmop (IC_RESULT (ic), NULL, ic);
4220 /*-----------------------------------------------------------------*/
4221 /* genMult - generates code for multiplication */
4222 /*-----------------------------------------------------------------*/
4224 genMult (iCode * ic)
4228 /* If true then the final operation should be a subtract */
4229 bool active = FALSE;
4232 /* Shouldn't occur - all done through function calls */
4233 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4234 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4235 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4237 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4239 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4240 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4241 AOP_SIZE (IC_RESULT (ic)) > 2)
4243 wassertl (0, "Multiplication is handled through support function calls");
4246 /* Swap left and right such that right is a literal */
4247 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4249 operand *t = IC_RIGHT (ic);
4250 IC_RIGHT (ic) = IC_LEFT (ic);
4254 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4256 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4257 // wassertl (val > 0, "Multiply must be positive");
4258 wassertl (val != 1, "Can't multiply by 1");
4260 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4262 _G.stack.pushedDE = TRUE;
4266 emit2 ("ld a,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4267 else if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4269 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4280 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4285 for (count = 0; count < 16; count++)
4287 if (count != 0 && active)
4292 emit2 ("add hl,hl");
4296 if (active == FALSE)
4311 emit2 ("add hl,de");
4320 if (IS_Z80 && _G.stack.pushedDE)
4323 _G.stack.pushedDE = FALSE;
4327 aopPut (AOP (IC_RESULT (ic)), "a", 0);
4329 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4331 freeAsmop (IC_LEFT (ic), NULL, ic);
4332 freeAsmop (IC_RIGHT (ic), NULL, ic);
4333 freeAsmop (IC_RESULT (ic), NULL, ic);
4336 /*-----------------------------------------------------------------*/
4337 /* genDiv - generates code for division */
4338 /*-----------------------------------------------------------------*/
4342 /* Shouldn't occur - all done through function calls */
4343 wassertl (0, "Division is handled through support function calls");
4346 /*-----------------------------------------------------------------*/
4347 /* genMod - generates code for division */
4348 /*-----------------------------------------------------------------*/
4352 /* Shouldn't occur - all done through function calls */
4356 /*-----------------------------------------------------------------*/
4357 /* genIfxJump :- will create a jump depending on the ifx */
4358 /*-----------------------------------------------------------------*/
4360 genIfxJump (iCode * ic, char *jval)
4365 /* if true label then we jump if condition
4369 jlbl = IC_TRUE (ic);
4370 if (!strcmp (jval, "a"))
4374 else if (!strcmp (jval, "c"))
4378 else if (!strcmp (jval, "nc"))
4382 else if (!strcmp (jval, "m"))
4386 else if (!strcmp (jval, "p"))
4392 /* The buffer contains the bit on A that we should test */
4398 /* false label is present */
4399 jlbl = IC_FALSE (ic);
4400 if (!strcmp (jval, "a"))
4404 else if (!strcmp (jval, "c"))
4408 else if (!strcmp (jval, "nc"))
4412 else if (!strcmp (jval, "m"))
4416 else if (!strcmp (jval, "p"))
4422 /* The buffer contains the bit on A that we should test */
4426 /* Z80 can do a conditional long jump */
4427 if (!strcmp (jval, "a"))
4431 else if (!strcmp (jval, "c"))
4434 else if (!strcmp (jval, "nc"))
4437 else if (!strcmp (jval, "m"))
4440 else if (!strcmp (jval, "p"))
4445 emit2 ("bit %s,a", jval);
4447 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4449 /* mark the icode as generated */
4455 _getPairIdName (PAIR_ID id)
4457 return _pairs[id].name;
4462 /* if unsigned char cmp with lit, just compare */
4464 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4466 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4469 emit2 ("xor a,!immedbyte", 0x80);
4470 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4473 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4475 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4477 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4478 // Pull left into DE and right into HL
4479 aopGet (AOP(left), LSB, FALSE);
4482 aopGet (AOP(right), LSB, FALSE);
4486 if (size == 0 && sign)
4488 // Highest byte when signed needs the bits flipped
4491 emit2 ("ld a,(de)");
4492 emit2 ("xor !immedbyte", 0x80);
4494 emit2 ("ld a,(hl)");
4495 emit2 ("xor !immedbyte", 0x80);
4499 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4503 emit2 ("ld a,(de)");
4504 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4514 spillPair (PAIR_HL);
4516 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4518 setupPair (PAIR_HL, AOP (left), 0);
4519 aopGet (AOP(right), LSB, FALSE);
4523 if (size == 0 && sign)
4525 // Highest byte when signed needs the bits flipped
4528 emit2 ("ld a,(hl)");
4529 emit2 ("xor !immedbyte", 0x80);
4531 emit2 ("ld a,%d(iy)", offset);
4532 emit2 ("xor !immedbyte", 0x80);
4536 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4540 emit2 ("ld a,(hl)");
4541 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4550 spillPair (PAIR_HL);
4551 spillPair (PAIR_IY);
4555 if (AOP_TYPE (right) == AOP_LIT)
4557 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4558 /* optimize if(x < 0) or if(x >= 0) */
4563 /* No sign so it's always false */
4568 /* Just load in the top most bit */
4569 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4570 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4572 genIfxJump (ifx, "7");
4584 /* First setup h and l contaning the top most bytes XORed */
4585 bool fDidXor = FALSE;
4586 if (AOP_TYPE (left) == AOP_LIT)
4588 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4589 emit2 ("ld %s,!immedbyte", _fTmp[0],
4590 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4594 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4595 emit2 ("xor a,!immedbyte", 0x80);
4596 emit2 ("ld %s,a", _fTmp[0]);
4599 if (AOP_TYPE (right) == AOP_LIT)
4601 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4602 emit2 ("ld %s,!immedbyte", _fTmp[1],
4603 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4607 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4608 emit2 ("xor a,!immedbyte", 0x80);
4609 emit2 ("ld %s,a", _fTmp[1]);
4615 /* Do a long subtract */
4618 _moveA (aopGet (AOP (left), offset, FALSE));
4620 if (sign && size == 0)
4622 emit2 ("ld a,%s", _fTmp[0]);
4623 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4627 /* Subtract through, propagating the carry */
4628 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4636 /** Generic compare for > or <
4639 genCmp (operand * left, operand * right,
4640 operand * result, iCode * ifx, int sign)
4642 int size, offset = 0;
4643 unsigned long lit = 0L;
4645 /* if left & right are bit variables */
4646 if (AOP_TYPE (left) == AOP_CRY &&
4647 AOP_TYPE (right) == AOP_CRY)
4649 /* Cant happen on the Z80 */
4650 wassertl (0, "Tried to compare two bits");
4654 /* Do a long subtract of right from left. */
4655 size = max (AOP_SIZE (left), AOP_SIZE (right));
4657 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4659 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4660 // Pull left into DE and right into HL
4661 aopGet (AOP(left), LSB, FALSE);
4664 aopGet (AOP(right), LSB, FALSE);
4668 emit2 ("ld a,(de)");
4669 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4678 spillPair (PAIR_HL);
4682 if (AOP_TYPE (right) == AOP_LIT)
4684 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4685 /* optimize if(x < 0) or if(x >= 0) */
4690 /* No sign so it's always false */
4695 /* Just load in the top most bit */
4696 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4697 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4699 genIfxJump (ifx, "7");
4710 genIfxJump (ifx, "nc");
4721 _moveA (aopGet (AOP (left), offset, FALSE));
4722 /* Subtract through, propagating the carry */
4723 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4729 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4733 /* Shift the sign bit up into carry */
4740 /* if the result is used in the next
4741 ifx conditional branch then generate
4742 code a little differently */
4750 genIfxJump (ifx, "c");
4754 genIfxJump (ifx, "m");
4759 genIfxJump (ifx, "c");
4766 /* Shift the sign bit up into carry */
4771 /* leave the result in acc */
4775 /*-----------------------------------------------------------------*/
4776 /* genCmpGt :- greater than comparison */
4777 /*-----------------------------------------------------------------*/
4779 genCmpGt (iCode * ic, iCode * ifx)
4781 operand *left, *right, *result;
4782 sym_link *letype, *retype;
4785 left = IC_LEFT (ic);
4786 right = IC_RIGHT (ic);
4787 result = IC_RESULT (ic);
4789 letype = getSpec (operandType (left));
4790 retype = getSpec (operandType (right));
4791 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4792 /* assign the amsops */
4793 aopOp (left, ic, FALSE, FALSE);
4794 aopOp (right, ic, FALSE, FALSE);
4795 aopOp (result, ic, TRUE, FALSE);
4797 genCmp (right, left, result, ifx, sign);
4799 freeAsmop (left, NULL, ic);
4800 freeAsmop (right, NULL, ic);
4801 freeAsmop (result, NULL, ic);
4804 /*-----------------------------------------------------------------*/
4805 /* genCmpLt - less than comparisons */
4806 /*-----------------------------------------------------------------*/
4808 genCmpLt (iCode * ic, iCode * ifx)
4810 operand *left, *right, *result;
4811 sym_link *letype, *retype;
4814 left = IC_LEFT (ic);
4815 right = IC_RIGHT (ic);
4816 result = IC_RESULT (ic);
4818 letype = getSpec (operandType (left));
4819 retype = getSpec (operandType (right));
4820 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4822 /* assign the amsops */
4823 aopOp (left, ic, FALSE, FALSE);
4824 aopOp (right, ic, FALSE, FALSE);
4825 aopOp (result, ic, TRUE, FALSE);
4827 genCmp (left, right, result, ifx, sign);
4829 freeAsmop (left, NULL, ic);
4830 freeAsmop (right, NULL, ic);
4831 freeAsmop (result, NULL, ic);
4834 /*-----------------------------------------------------------------*/
4835 /* gencjneshort - compare and jump if not equal */
4836 /* returns pair that still needs to be popped */
4837 /*-----------------------------------------------------------------*/
4839 gencjneshort (operand * left, operand * right, symbol * lbl)
4841 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4843 unsigned long lit = 0L;
4845 /* Swap the left and right if it makes the computation easier */
4846 if (AOP_TYPE (left) == AOP_LIT)
4853 /* if the right side is a literal then anything goes */
4854 if (AOP_TYPE (right) == AOP_LIT)
4856 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4859 _moveA (aopGet (AOP (left), offset, FALSE));
4864 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4871 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4877 _moveA (aopGet (AOP (left), offset, FALSE));
4878 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4881 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4882 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4887 /* if the right side is in a register or
4888 pointed to by HL, IX or IY */
4889 else if (AOP_TYPE (right) == AOP_REG ||
4890 AOP_TYPE (right) == AOP_HL ||
4891 AOP_TYPE (right) == AOP_IY ||
4892 AOP_TYPE (right) == AOP_STK ||
4893 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4894 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4895 AOP_IS_PAIRPTR (right, PAIR_IY))
4899 _moveA (aopGet (AOP (left), offset, FALSE));
4900 if (AOP_TYPE (right) == AOP_LIT &&
4901 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4904 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4908 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4909 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4914 /* right is in direct space or a pointer reg, need both a & b */
4918 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4920 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4921 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4929 emit2 ("; direct compare");
4930 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4931 _moveA (aopGet (AOP (right), offset, FALSE));
4932 emit2 ("sub %s", _pairs[pair].l);
4933 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4938 return PAIR_INVALID;
4941 /*-----------------------------------------------------------------*/
4942 /* gencjne - compare and jump if not equal */
4943 /*-----------------------------------------------------------------*/
4945 gencjne (operand * left, operand * right, symbol * lbl)
4947 symbol *tlbl = newiTempLabel (NULL);
4949 PAIR_ID pop = gencjneshort (left, right, lbl);
4952 emit2 ("ld a,!one");
4953 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4954 emitLabel (lbl->key + 100);
4956 emitLabel (tlbl->key + 100);
4960 /*-----------------------------------------------------------------*/
4961 /* genCmpEq - generates code for equal to */
4962 /*-----------------------------------------------------------------*/
4964 genCmpEq (iCode * ic, iCode * ifx)
4966 operand *left, *right, *result;
4968 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4969 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4970 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4972 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4974 /* Swap operands if it makes the operation easier. ie if:
4975 1. Left is a literal.
4977 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4979 operand *t = IC_RIGHT (ic);
4980 IC_RIGHT (ic) = IC_LEFT (ic);
4984 if (ifx && !AOP_SIZE (result))
4987 /* if they are both bit variables */
4988 if (AOP_TYPE (left) == AOP_CRY &&
4989 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4991 wassertl (0, "Tried to compare two bits");
4996 tlbl = newiTempLabel (NULL);
4997 pop = gencjneshort (left, right, tlbl);
5001 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
5002 emitLabel (tlbl->key + 100);
5007 /* PENDING: do this better */
5008 symbol *lbl = newiTempLabel (NULL);
5010 emit2 ("!shortjp !tlabel", lbl->key + 100);
5011 emitLabel (tlbl->key + 100);
5013 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
5014 emitLabel (lbl->key + 100);
5017 /* mark the icode as generated */
5022 /* if they are both bit variables */
5023 if (AOP_TYPE (left) == AOP_CRY &&
5024 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5026 wassertl (0, "Tried to compare a bit to either a literal or another bit");
5032 gencjne (left, right, newiTempLabel (NULL));
5033 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5040 genIfxJump (ifx, "a");
5043 /* if the result is used in an arithmetic operation
5044 then put the result in place */
5045 if (AOP_TYPE (result) != AOP_CRY)
5050 /* leave the result in acc */
5054 freeAsmop (left, NULL, ic);
5055 freeAsmop (right, NULL, ic);
5056 freeAsmop (result, NULL, ic);
5059 /*-----------------------------------------------------------------*/
5060 /* ifxForOp - returns the icode containing the ifx for operand */
5061 /*-----------------------------------------------------------------*/
5063 ifxForOp (operand * op, iCode * ic)
5065 /* if true symbol then needs to be assigned */
5066 if (IS_TRUE_SYMOP (op))
5069 /* if this has register type condition and
5070 the next instruction is ifx with the same operand
5071 and live to of the operand is upto the ifx only then */
5073 ic->next->op == IFX &&
5074 IC_COND (ic->next)->key == op->key &&
5075 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5081 /*-----------------------------------------------------------------*/
5082 /* genAndOp - for && operation */
5083 /*-----------------------------------------------------------------*/
5085 genAndOp (iCode * ic)
5087 operand *left, *right, *result;
5090 /* note here that && operations that are in an if statement are
5091 taken away by backPatchLabels only those used in arthmetic
5092 operations remain */
5093 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5094 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5095 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5097 /* if both are bit variables */
5098 if (AOP_TYPE (left) == AOP_CRY &&
5099 AOP_TYPE (right) == AOP_CRY)
5101 wassertl (0, "Tried to and two bits");
5105 tlbl = newiTempLabel (NULL);
5107 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5109 emitLabel (tlbl->key + 100);
5113 freeAsmop (left, NULL, ic);
5114 freeAsmop (right, NULL, ic);
5115 freeAsmop (result, NULL, ic);
5118 /*-----------------------------------------------------------------*/
5119 /* genOrOp - for || operation */
5120 /*-----------------------------------------------------------------*/
5122 genOrOp (iCode * ic)
5124 operand *left, *right, *result;
5127 /* note here that || operations that are in an
5128 if statement are taken away by backPatchLabels
5129 only those used in arthmetic operations remain */
5130 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5131 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5132 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5134 /* if both are bit variables */
5135 if (AOP_TYPE (left) == AOP_CRY &&
5136 AOP_TYPE (right) == AOP_CRY)
5138 wassertl (0, "Tried to OR two bits");
5142 tlbl = newiTempLabel (NULL);
5144 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5146 emitLabel (tlbl->key + 100);
5150 freeAsmop (left, NULL, ic);
5151 freeAsmop (right, NULL, ic);
5152 freeAsmop (result, NULL, ic);
5155 /*-----------------------------------------------------------------*/
5156 /* isLiteralBit - test if lit == 2^n */
5157 /*-----------------------------------------------------------------*/
5159 isLiteralBit (unsigned long lit)
5161 unsigned long pw[32] =
5162 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5163 0x100L, 0x200L, 0x400L, 0x800L,
5164 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5165 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5166 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5167 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5168 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5171 for (idx = 0; idx < 32; idx++)
5177 /*-----------------------------------------------------------------*/
5178 /* jmpTrueOrFalse - */
5179 /*-----------------------------------------------------------------*/
5181 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5183 // ugly but optimized by peephole
5186 symbol *nlbl = newiTempLabel (NULL);
5187 emit2 ("jp !tlabel", nlbl->key + 100);
5188 emitLabel (tlbl->key + 100);
5189 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5190 emitLabel (nlbl->key + 100);
5194 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5195 emitLabel (tlbl->key + 100);
5200 /*-----------------------------------------------------------------*/
5201 /* genAnd - code for and */
5202 /*-----------------------------------------------------------------*/
5204 genAnd (iCode * ic, iCode * ifx)
5206 operand *left, *right, *result;
5207 int size, offset = 0;
5208 unsigned long lit = 0L;
5211 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5212 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5213 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5215 /* if left is a literal & right is not then exchange them */
5216 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5217 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5219 operand *tmp = right;
5224 /* if result = right then exchange them */
5225 if (sameRegs (AOP (result), AOP (right)))
5227 operand *tmp = right;
5232 /* if right is bit then exchange them */
5233 if (AOP_TYPE (right) == AOP_CRY &&
5234 AOP_TYPE (left) != AOP_CRY)
5236 operand *tmp = right;
5240 if (AOP_TYPE (right) == AOP_LIT)
5241 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5243 size = AOP_SIZE (result);
5245 if (AOP_TYPE (left) == AOP_CRY)
5247 wassertl (0, "Tried to perform an AND with a bit as an operand");
5251 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5252 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5253 if ((AOP_TYPE (right) == AOP_LIT) &&
5254 (AOP_TYPE (result) == AOP_CRY) &&
5255 (AOP_TYPE (left) != AOP_CRY))
5257 symbol *tlbl = newiTempLabel (NULL);
5258 int sizel = AOP_SIZE (left);
5261 /* PENDING: Test case for this. */
5266 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5268 _moveA (aopGet (AOP (left), offset, FALSE));
5269 if (bytelit != 0x0FFL)
5271 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5278 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5282 // bit = left & literal
5286 emit2 ("!tlabeldef", tlbl->key + 100);
5287 _G.lines.current->isLabel = 1;
5289 // if(left & literal)
5294 jmpTrueOrFalse (ifx, tlbl);
5302 /* if left is same as result */
5303 if (sameRegs (AOP (result), AOP (left)))
5305 for (; size--; offset++)
5307 if (AOP_TYPE (right) == AOP_LIT)
5309 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5314 aopPut (AOP (result), "!zero", offset);
5317 _moveA (aopGet (AOP (left), offset, FALSE));
5319 aopGet (AOP (right), offset, FALSE));
5320 aopPut (AOP (left), "a", offset);
5327 if (AOP_TYPE (left) == AOP_ACC)
5329 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5333 _moveA (aopGet (AOP (left), offset, FALSE));
5335 aopGet (AOP (right), offset, FALSE));
5336 aopPut (AOP (left), "a", offset);
5343 // left & result in different registers
5344 if (AOP_TYPE (result) == AOP_CRY)
5346 wassertl (0, "Tried to AND where the result is in carry");
5350 for (; (size--); offset++)
5353 // result = left & right
5354 if (AOP_TYPE (right) == AOP_LIT)
5356 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5358 aopPut (AOP (result),
5359 aopGet (AOP (left), offset, FALSE),
5363 else if (bytelit == 0)
5365 aopPut (AOP (result), "!zero", offset);
5369 // faster than result <- left, anl result,right
5370 // and better if result is SFR
5371 if (AOP_TYPE (left) == AOP_ACC)
5372 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5375 _moveA (aopGet (AOP (left), offset, FALSE));
5377 aopGet (AOP (right), offset, FALSE));
5379 aopPut (AOP (result), "a", offset);
5386 freeAsmop (left, NULL, ic);
5387 freeAsmop (right, NULL, ic);
5388 freeAsmop (result, NULL, ic);
5391 /*-----------------------------------------------------------------*/
5392 /* genOr - code for or */
5393 /*-----------------------------------------------------------------*/
5395 genOr (iCode * ic, iCode * ifx)
5397 operand *left, *right, *result;
5398 int size, offset = 0;
5399 unsigned long lit = 0L;
5402 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5403 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5404 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5406 /* if left is a literal & right is not then exchange them */
5407 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5408 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5410 operand *tmp = right;
5415 /* if result = right then exchange them */
5416 if (sameRegs (AOP (result), AOP (right)))
5418 operand *tmp = right;
5423 /* if right is bit then exchange them */
5424 if (AOP_TYPE (right) == AOP_CRY &&
5425 AOP_TYPE (left) != AOP_CRY)
5427 operand *tmp = right;
5431 if (AOP_TYPE (right) == AOP_LIT)
5432 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5434 size = AOP_SIZE (result);
5436 if (AOP_TYPE (left) == AOP_CRY)
5438 wassertl (0, "Tried to OR where left is a bit");
5442 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5443 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5444 if ((AOP_TYPE (right) == AOP_LIT) &&
5445 (AOP_TYPE (result) == AOP_CRY) &&
5446 (AOP_TYPE (left) != AOP_CRY))
5448 symbol *tlbl = newiTempLabel (NULL);
5449 int sizel = AOP_SIZE (left);
5453 wassertl (0, "Result is assigned to a bit");
5455 /* PENDING: Modeled after the AND code which is inefficient. */
5458 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5460 _moveA (aopGet (AOP (left), offset, FALSE));
5461 /* OR with any literal is the same as OR with itself. */
5463 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5469 jmpTrueOrFalse (ifx, tlbl);
5474 /* if left is same as result */
5475 if (sameRegs (AOP (result), AOP (left)))
5477 for (; size--; offset++)
5479 if (AOP_TYPE (right) == AOP_LIT)
5481 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5485 _moveA (aopGet (AOP (left), offset, FALSE));
5487 aopGet (AOP (right), offset, FALSE));
5488 aopPut (AOP (result), "a", offset);
5493 if (AOP_TYPE (left) == AOP_ACC)
5494 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5497 _moveA (aopGet (AOP (left), offset, FALSE));
5499 aopGet (AOP (right), offset, FALSE));
5500 aopPut (AOP (result), "a", offset);
5507 // left & result in different registers
5508 if (AOP_TYPE (result) == AOP_CRY)
5510 wassertl (0, "Result of OR is in a bit");
5513 for (; (size--); offset++)
5516 // result = left & right
5517 if (AOP_TYPE (right) == AOP_LIT)
5519 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5521 aopPut (AOP (result),
5522 aopGet (AOP (left), offset, FALSE),
5527 // faster than result <- left, anl result,right
5528 // and better if result is SFR
5529 if (AOP_TYPE (left) == AOP_ACC)
5530 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5533 _moveA (aopGet (AOP (left), offset, FALSE));
5535 aopGet (AOP (right), offset, FALSE));
5537 aopPut (AOP (result), "a", offset);
5538 /* PENDING: something weird is going on here. Add exception. */
5539 if (AOP_TYPE (result) == AOP_ACC)
5545 freeAsmop (left, NULL, ic);
5546 freeAsmop (right, NULL, ic);
5547 freeAsmop (result, NULL, ic);
5550 /*-----------------------------------------------------------------*/
5551 /* genXor - code for xclusive or */
5552 /*-----------------------------------------------------------------*/
5554 genXor (iCode * ic, iCode * ifx)
5556 operand *left, *right, *result;
5557 int size, offset = 0;
5558 unsigned long lit = 0L;
5560 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5561 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5562 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5564 /* if left is a literal & right is not then exchange them */
5565 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5566 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5568 operand *tmp = right;
5573 /* if result = right then exchange them */
5574 if (sameRegs (AOP (result), AOP (right)))
5576 operand *tmp = right;
5581 /* if right is bit then exchange them */
5582 if (AOP_TYPE (right) == AOP_CRY &&
5583 AOP_TYPE (left) != AOP_CRY)
5585 operand *tmp = right;
5589 if (AOP_TYPE (right) == AOP_LIT)
5590 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5592 size = AOP_SIZE (result);
5594 if (AOP_TYPE (left) == AOP_CRY)
5596 wassertl (0, "Tried to XOR a bit");
5600 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5601 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5602 if ((AOP_TYPE (right) == AOP_LIT) &&
5603 (AOP_TYPE (result) == AOP_CRY) &&
5604 (AOP_TYPE (left) != AOP_CRY))
5606 symbol *tlbl = newiTempLabel (NULL);
5607 int sizel = AOP_SIZE (left);
5611 /* PENDING: Test case for this. */
5612 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5616 _moveA (aopGet (AOP (left), offset, FALSE));
5617 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5618 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5623 jmpTrueOrFalse (ifx, tlbl);
5627 wassertl (0, "Result of XOR was destined for a bit");
5632 /* if left is same as result */
5633 if (sameRegs (AOP (result), AOP (left)))
5635 for (; size--; offset++)
5637 if (AOP_TYPE (right) == AOP_LIT)
5639 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5643 _moveA (aopGet (AOP (left), offset, FALSE));
5645 aopGet (AOP (right), offset, FALSE));
5646 aopPut (AOP (result), "a", offset);
5651 if (AOP_TYPE (left) == AOP_ACC)
5653 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5657 _moveA (aopGet (AOP (left), offset, FALSE));
5659 aopGet (AOP (right), offset, FALSE));
5660 aopPut (AOP (result), "a", offset);
5667 // left & result in different registers
5668 if (AOP_TYPE (result) == AOP_CRY)
5670 wassertl (0, "Result of XOR is in a bit");
5673 for (; (size--); offset++)
5676 // result = left & right
5677 if (AOP_TYPE (right) == AOP_LIT)
5679 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5681 aopPut (AOP (result),
5682 aopGet (AOP (left), offset, FALSE),
5687 // faster than result <- left, anl result,right
5688 // and better if result is SFR
5689 if (AOP_TYPE (left) == AOP_ACC)
5691 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5695 _moveA (aopGet (AOP (left), offset, FALSE));
5697 aopGet (AOP (right), offset, FALSE));
5699 aopPut (AOP (result), "a", offset);
5704 freeAsmop (left, NULL, ic);
5705 freeAsmop (right, NULL, ic);
5706 freeAsmop (result, NULL, ic);
5709 /*-----------------------------------------------------------------*/
5710 /* genInline - write the inline code out */
5711 /*-----------------------------------------------------------------*/
5713 genInline (iCode * ic)
5715 char *buffer, *bp, *bp1;
5716 bool inComment = FALSE;
5718 _G.lines.isInline += (!options.asmpeep);
5720 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5722 /* emit each line as a code */
5740 /* Add \n for labels, not dirs such as c:\mydir */
5741 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5759 _G.lines.isInline -= (!options.asmpeep);
5763 /*-----------------------------------------------------------------*/
5764 /* genRRC - rotate right with carry */
5765 /*-----------------------------------------------------------------*/
5772 /*-----------------------------------------------------------------*/
5773 /* genRLC - generate code for rotate left with carry */
5774 /*-----------------------------------------------------------------*/
5781 /*-----------------------------------------------------------------*/
5782 /* genGetHbit - generates code get highest order bit */
5783 /*-----------------------------------------------------------------*/
5785 genGetHbit (iCode * ic)
5787 operand *left, *result;
5788 left = IC_LEFT (ic);
5789 result = IC_RESULT (ic);
5791 aopOp (left, ic, FALSE, FALSE);
5792 aopOp (result, ic, FALSE, FALSE);
5794 /* get the highest order byte into a */
5795 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5797 if (AOP_TYPE (result) == AOP_CRY)
5805 emit2 ("and a,!one");
5810 freeAsmop (left, NULL, ic);
5811 freeAsmop (result, NULL, ic);
5815 emitRsh2 (asmop *aop, int size, int is_signed)
5821 const char *l = aopGet (aop, size, FALSE);
5824 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5834 /*-----------------------------------------------------------------*/
5835 /* shiftR2Left2Result - shift right two bytes from left to result */
5836 /*-----------------------------------------------------------------*/
5838 shiftR2Left2Result (operand * left, int offl,
5839 operand * result, int offr,
5840 int shCount, int is_signed)
5845 movLeft2Result (left, offl, result, offr, 0);
5846 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5851 /* if (AOP(result)->type == AOP_REG) { */
5853 tlbl = newiTempLabel (NULL);
5855 /* Left is already in result - so now do the shift */
5856 /* Optimizing for speed by default. */
5857 if (!optimize.codeSize || shCount <= 2)
5861 emitRsh2 (AOP (result), size, is_signed);
5866 emit2 ("ld a,!immedbyte", shCount);
5868 emitLabel (tlbl->key + 100);
5870 emitRsh2 (AOP (result), size, is_signed);
5873 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5877 /*-----------------------------------------------------------------*/
5878 /* shiftL2Left2Result - shift left two bytes from left to result */
5879 /*-----------------------------------------------------------------*/
5881 shiftL2Left2Result (operand * left, int offl,
5882 operand * result, int offr, int shCount)
5884 if (sameRegs (AOP (result), AOP (left)) &&
5885 ((offl + MSB16) == offr))
5891 /* Copy left into result */
5892 movLeft2Result (left, offl, result, offr, 0);
5893 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5899 if (getPairId (AOP (result)) == PAIR_HL)
5903 emit2 ("add hl,hl");
5910 symbol *tlbl, *tlbl1;
5913 tlbl = newiTempLabel (NULL);
5914 tlbl1 = newiTempLabel (NULL);
5916 if (AOP (result)->type == AOP_REG)
5920 for (offset = 0; offset < size; offset++)
5922 l = aopGet (AOP (result), offset, FALSE);
5926 emit2 ("sla %s", l);
5937 /* Left is already in result - so now do the shift */
5940 emit2 ("ld a,!immedbyte+1", shCount);
5941 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5942 emitLabel (tlbl->key + 100);
5947 l = aopGet (AOP (result), offset, FALSE);
5951 emit2 ("sla %s", l);
5962 emitLabel (tlbl1->key + 100);
5964 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5970 /*-----------------------------------------------------------------*/
5971 /* AccRol - rotate left accumulator by known count */
5972 /*-----------------------------------------------------------------*/
5974 AccRol (int shCount)
5976 shCount &= 0x0007; // shCount : 0..7
6053 /*-----------------------------------------------------------------*/
6054 /* AccLsh - left shift accumulator by known count */
6055 /*-----------------------------------------------------------------*/
6057 AccLsh (int shCount)
6059 static const unsigned char SLMask[] =
6061 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6070 else if (shCount == 2)
6077 /* rotate left accumulator */
6079 /* and kill the lower order bits */
6080 emit2 ("and a,!immedbyte", SLMask[shCount]);
6085 /*-----------------------------------------------------------------*/
6086 /* shiftL1Left2Result - shift left one byte from left to result */
6087 /*-----------------------------------------------------------------*/
6089 shiftL1Left2Result (operand * left, int offl,
6090 operand * result, int offr, int shCount)
6094 /* If operand and result are the same we can shift in place.
6095 However shifting in acc using add is cheaper than shifting
6096 in place using sla; when shifting by more than 2 shifting in
6097 acc is worth the additional effort for loading from/to acc. */
6098 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6101 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6105 l = aopGet (AOP (left), offl, FALSE);
6107 /* shift left accumulator */
6109 aopPut (AOP (result), "a", offr);
6113 /*-----------------------------------------------------------------*/
6114 /* genlshTwo - left shift two bytes by known amount */
6115 /*-----------------------------------------------------------------*/
6117 genlshTwo (operand * result, operand * left, int shCount)
6119 int size = AOP_SIZE (result);
6121 wassert (size == 2);
6123 /* if shCount >= 8 */
6131 movLeft2Result (left, LSB, result, MSB16, 0);
6132 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6133 aopPut (AOP (result), "!zero", LSB);
6137 movLeft2Result (left, LSB, result, MSB16, 0);
6138 aopPut (AOP (result), "!zero", 0);
6143 aopPut (AOP (result), "!zero", LSB);
6146 /* 0 <= shCount <= 7 */
6155 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6160 /*-----------------------------------------------------------------*/
6161 /* genlshOne - left shift a one byte quantity by known count */
6162 /*-----------------------------------------------------------------*/
6164 genlshOne (operand * result, operand * left, int shCount)
6166 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6169 /*-----------------------------------------------------------------*/
6170 /* genLeftShiftLiteral - left shifting by known count */
6171 /*-----------------------------------------------------------------*/
6173 genLeftShiftLiteral (operand * left,
6178 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6181 freeAsmop (right, NULL, ic);
6183 aopOp (left, ic, FALSE, FALSE);
6184 aopOp (result, ic, FALSE, FALSE);
6186 size = getSize (operandType (result));
6188 /* I suppose that the left size >= result size */
6190 if (shCount >= (size * 8))
6194 aopPut (AOP (result), "!zero", size);
6202 genlshOne (result, left, shCount);
6205 genlshTwo (result, left, shCount);
6208 wassertl (0, "Shifting of longs is currently unsupported");
6214 freeAsmop (left, NULL, ic);
6215 freeAsmop (result, NULL, ic);
6218 /*-----------------------------------------------------------------*/
6219 /* genLeftShift - generates code for left shifting */
6220 /*-----------------------------------------------------------------*/
6222 genLeftShift (iCode * ic)
6226 symbol *tlbl, *tlbl1;
6227 operand *left, *right, *result;
6229 right = IC_RIGHT (ic);
6230 left = IC_LEFT (ic);
6231 result = IC_RESULT (ic);
6233 aopOp (right, ic, FALSE, FALSE);
6235 /* if the shift count is known then do it
6236 as efficiently as possible */
6237 if (AOP_TYPE (right) == AOP_LIT)
6239 genLeftShiftLiteral (left, right, result, ic);
6243 /* shift count is unknown then we have to form a loop get the loop
6244 count in B : Note: we take only the lower order byte since
6245 shifting more that 32 bits make no sense anyway, ( the largest
6246 size of an object can be only 32 bits ) */
6247 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6249 freeAsmop (right, NULL, ic);
6250 aopOp (left, ic, FALSE, FALSE);
6251 aopOp (result, ic, FALSE, FALSE);
6253 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6256 /* now move the left to the result if they are not the
6259 if (!sameRegs (AOP (left), AOP (result)))
6262 size = AOP_SIZE (result);
6266 l = aopGet (AOP (left), offset, FALSE);
6267 aopPut (AOP (result), l, offset);
6272 tlbl = newiTempLabel (NULL);
6273 size = AOP_SIZE (result);
6275 tlbl1 = newiTempLabel (NULL);
6277 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6280 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6281 emitLabel (tlbl->key + 100);
6282 l = aopGet (AOP (result), offset, FALSE);
6286 l = aopGet (AOP (result), offset, FALSE);
6290 emit2 ("sla %s", l);
6298 emitLabel (tlbl1->key + 100);
6300 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6302 freeAsmop (left, NULL, ic);
6303 freeAsmop (result, NULL, ic);
6306 /*-----------------------------------------------------------------*/
6307 /* genrshOne - left shift two bytes by known amount != 0 */
6308 /*-----------------------------------------------------------------*/
6310 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6313 int size = AOP_SIZE (result);
6316 wassert (size == 1);
6317 wassert (shCount < 8);
6319 l = aopGet (AOP (left), 0, FALSE);
6321 if (AOP (result)->type == AOP_REG)
6323 aopPut (AOP (result), l, 0);
6324 l = aopGet (AOP (result), 0, FALSE);
6327 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6335 emit2 ("%s a", is_signed ? "sra" : "srl");
6337 aopPut (AOP (result), "a", 0);
6341 /*-----------------------------------------------------------------*/
6342 /* AccRsh - right shift accumulator by known count */
6343 /*-----------------------------------------------------------------*/
6345 AccRsh (int shCount)
6347 static const unsigned char SRMask[] =
6349 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6354 /* rotate right accumulator */
6355 AccRol (8 - shCount);
6356 /* and kill the higher order bits */
6357 emit2 ("and a,!immedbyte", SRMask[shCount]);
6361 /*-----------------------------------------------------------------*/
6362 /* shiftR1Left2Result - shift right one byte from left to result */
6363 /*-----------------------------------------------------------------*/
6365 shiftR1Left2Result (operand * left, int offl,
6366 operand * result, int offr,
6367 int shCount, int sign)
6369 _moveA (aopGet (AOP (left), offl, FALSE));
6374 emit2 ("%s a", sign ? "sra" : "srl");
6381 aopPut (AOP (result), "a", offr);
6384 /*-----------------------------------------------------------------*/
6385 /* genrshTwo - right shift two bytes by known amount */
6386 /*-----------------------------------------------------------------*/
6388 genrshTwo (operand * result, operand * left,
6389 int shCount, int sign)
6391 /* if shCount >= 8 */
6397 shiftR1Left2Result (left, MSB16, result, LSB,
6402 movLeft2Result (left, MSB16, result, LSB, sign);
6406 /* Sign extend the result */
6407 _moveA(aopGet (AOP (result), 0, FALSE));
6411 aopPut (AOP (result), ACC_NAME, MSB16);
6415 aopPut (AOP (result), "!zero", 1);
6418 /* 0 <= shCount <= 7 */
6421 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6425 /*-----------------------------------------------------------------*/
6426 /* genRightShiftLiteral - left shifting by known count */
6427 /*-----------------------------------------------------------------*/
6429 genRightShiftLiteral (operand * left,
6435 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6438 freeAsmop (right, NULL, ic);
6440 aopOp (left, ic, FALSE, FALSE);
6441 aopOp (result, ic, FALSE, FALSE);
6443 size = getSize (operandType (result));
6445 /* I suppose that the left size >= result size */
6447 if (shCount >= (size * 8)) {
6449 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6450 _moveA(aopGet (AOP (left), 0, FALSE));
6458 aopPut (AOP (result), s, size);
6465 genrshOne (result, left, shCount, sign);
6468 genrshTwo (result, left, shCount, sign);
6471 wassertl (0, "Asked to shift right a long which should be a function call");
6474 wassertl (0, "Entered default case in right shift delegate");
6477 freeAsmop (left, NULL, ic);
6478 freeAsmop (result, NULL, ic);
6481 /*-----------------------------------------------------------------*/
6482 /* genRightShift - generate code for right shifting */
6483 /*-----------------------------------------------------------------*/
6485 genRightShift (iCode * ic)
6487 operand *right, *left, *result;
6489 int size, offset, first = 1;
6493 symbol *tlbl, *tlbl1;
6495 /* if signed then we do it the hard way preserve the
6496 sign bit moving it inwards */
6497 retype = getSpec (operandType (IC_RESULT (ic)));
6499 is_signed = !SPEC_USIGN (retype);
6501 /* signed & unsigned types are treated the same : i.e. the
6502 signed is NOT propagated inwards : quoting from the
6503 ANSI - standard : "for E1 >> E2, is equivalent to division
6504 by 2**E2 if unsigned or if it has a non-negative value,
6505 otherwise the result is implementation defined ", MY definition
6506 is that the sign does not get propagated */
6508 right = IC_RIGHT (ic);
6509 left = IC_LEFT (ic);
6510 result = IC_RESULT (ic);
6512 aopOp (right, ic, FALSE, FALSE);
6514 /* if the shift count is known then do it
6515 as efficiently as possible */
6516 if (AOP_TYPE (right) == AOP_LIT)
6518 genRightShiftLiteral (left, right, result, ic, is_signed);
6522 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6524 freeAsmop (right, NULL, ic);
6526 aopOp (left, ic, FALSE, FALSE);
6527 aopOp (result, ic, FALSE, FALSE);
6529 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6532 /* now move the left to the result if they are not the
6534 if (!sameRegs (AOP (left), AOP (result)))
6537 size = AOP_SIZE (result);
6541 l = aopGet (AOP (left), offset, FALSE);
6542 aopPut (AOP (result), l, offset);
6547 tlbl = newiTempLabel (NULL);
6548 tlbl1 = newiTempLabel (NULL);
6549 size = AOP_SIZE (result);
6552 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6555 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6556 emitLabel (tlbl->key + 100);
6559 l = aopGet (AOP (result), offset--, FALSE);
6562 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6570 emitLabel (tlbl1->key + 100);
6572 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6574 freeAsmop (left, NULL, ic);
6575 freeAsmop (result, NULL, ic);
6579 /*-----------------------------------------------------------------*/
6580 /* genUnpackBits - generates code for unpacking bits */
6581 /*-----------------------------------------------------------------*/
6583 genUnpackBits (operand * result, int pair)
6585 int offset = 0; /* result byte offset */
6586 int rsize; /* result size */
6587 int rlen = 0; /* remaining bitfield length */
6588 sym_link *etype; /* bitfield type information */
6589 int blen; /* bitfield length */
6590 int bstr; /* bitfield starting bit within byte */
6592 emitDebug ("; genUnpackBits");
6594 etype = getSpec (operandType (result));
6595 rsize = getSize (operandType (result));
6596 blen = SPEC_BLEN (etype);
6597 bstr = SPEC_BSTR (etype);
6599 /* If the bitfield length is less than a byte */
6602 emit2 ("ld a,!*pair", _pairs[pair].name);
6604 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6605 if (!SPEC_USIGN (etype))
6607 /* signed bitfield */
6608 symbol *tlbl = newiTempLabel (NULL);
6610 emit2 ("bit %d,a", blen - 1);
6611 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6612 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6613 emitLabel (tlbl->key + 100);
6615 aopPut (AOP (result), "a", offset++);
6619 /* TODO: what if pair == PAIR_DE ? */
6620 if (getPairId (AOP (result)) == PAIR_HL)
6622 wassertl (rsize == 2, "HL must be of size 2");
6623 emit2 ("ld a,!*hl");
6625 emit2 ("ld h,!*hl");
6628 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6629 if (!SPEC_USIGN (etype))
6631 /* signed bitfield */
6632 symbol *tlbl = newiTempLabel (NULL);
6634 emit2 ("bit %d,a", blen - 1);
6635 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6636 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6637 emitLabel (tlbl->key + 100);
6640 spillPair (PAIR_HL);
6644 /* Bit field did not fit in a byte. Copy all
6645 but the partial byte at the end. */
6646 for (rlen=blen;rlen>=8;rlen-=8)
6648 emit2 ("ld a,!*pair", _pairs[pair].name);
6649 aopPut (AOP (result), "a", offset++);
6652 emit2 ("inc %s", _pairs[pair].name);
6653 _G.pairs[pair].offset++;
6657 /* Handle the partial byte at the end */
6660 emit2 ("ld a,!*pair", _pairs[pair].name);
6661 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6662 if (!SPEC_USIGN (etype))
6664 /* signed bitfield */
6665 symbol *tlbl = newiTempLabel (NULL);
6667 emit2 ("bit %d,a", rlen - 1);
6668 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6669 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6670 emitLabel (tlbl->key + 100);
6672 aopPut (AOP (result), "a", offset++);
6680 if (SPEC_USIGN (etype))
6684 /* signed bitfield: sign extension with 0x00 or 0xff */
6692 aopPut (AOP (result), source, offset++);
6696 /*-----------------------------------------------------------------*/
6697 /* genGenPointerGet - get value from generic pointer space */
6698 /*-----------------------------------------------------------------*/
6700 genGenPointerGet (operand * left,
6701 operand * result, iCode * ic)
6704 sym_link *retype = getSpec (operandType (result));
6710 aopOp (left, ic, FALSE, FALSE);
6711 aopOp (result, ic, FALSE, FALSE);
6713 size = AOP_SIZE (result);
6715 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6718 if (isPtrPair (AOP (left)))
6720 tsprintf (buffer, sizeof(buffer),
6721 "!*pair", getPairName (AOP (left)));
6722 aopPut (AOP (result), buffer, 0);
6726 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6727 aopPut (AOP (result), "a", 0);
6729 freeAsmop (left, NULL, ic);
6733 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6740 tsprintf (at, sizeof(at), "!*iyx", offset);
6741 aopPut (AOP (result), at, offset);
6745 freeAsmop (left, NULL, ic);
6749 /* For now we always load into IY */
6750 /* if this is remateriazable */
6751 fetchPair (pair, AOP (left));
6753 /* if bit then unpack */
6754 if (IS_BITVAR (retype))
6756 genUnpackBits (result, pair);
6757 freeAsmop (left, NULL, ic);
6761 else if (getPairId (AOP (result)) == PAIR_HL)
6763 wassertl (size == 2, "HL must be of size 2");
6764 emit2 ("ld a,!*hl");
6766 emit2 ("ld h,!*hl");
6768 spillPair (PAIR_HL);
6770 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6772 size = AOP_SIZE (result);
6777 /* PENDING: make this better */
6778 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6780 aopPut (AOP (result), "!*hl", offset++);
6784 emit2 ("ld a,!*pair", _pairs[pair].name);
6785 aopPut (AOP (result), "a", offset++);
6789 emit2 ("inc %s", _pairs[pair].name);
6790 _G.pairs[pair].offset++;
6793 /* Fixup HL back down */
6794 for (size = AOP_SIZE (result)-1; size; size--)
6796 emit2 ("dec %s", _pairs[pair].name);
6801 size = AOP_SIZE (result);
6806 /* PENDING: make this better */
6808 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6810 aopPut (AOP (result), "!*hl", offset++);
6814 emit2 ("ld a,!*pair", _pairs[pair].name);
6815 aopPut (AOP (result), "a", offset++);
6819 emit2 ("inc %s", _pairs[pair].name);
6820 _G.pairs[pair].offset++;
6825 freeAsmop (left, NULL, ic);
6828 freeAsmop (result, NULL, ic);
6831 /*-----------------------------------------------------------------*/
6832 /* genPointerGet - generate code for pointer get */
6833 /*-----------------------------------------------------------------*/
6835 genPointerGet (iCode * ic)
6837 operand *left, *result;
6838 sym_link *type, *etype;
6840 left = IC_LEFT (ic);
6841 result = IC_RESULT (ic);
6843 /* depending on the type of pointer we need to
6844 move it to the correct pointer register */
6845 type = operandType (left);
6846 etype = getSpec (type);
6848 genGenPointerGet (left, result, ic);
6852 isRegOrLit (asmop * aop)
6854 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6860 /*-----------------------------------------------------------------*/
6861 /* genPackBits - generates code for packed bit storage */
6862 /*-----------------------------------------------------------------*/
6864 genPackBits (sym_link * etype,
6869 int offset = 0; /* source byte offset */
6870 int rlen = 0; /* remaining bitfield length */
6871 int blen; /* bitfield length */
6872 int bstr; /* bitfield starting bit within byte */
6873 int litval; /* source literal value (if AOP_LIT) */
6874 unsigned char mask; /* bitmask within current byte */
6875 int extraPair; /* a tempory register */
6876 bool needPopExtra=0; /* need to restore original value of temp reg */
6878 emitDebug ("; genPackBits","");
6880 blen = SPEC_BLEN (etype);
6881 bstr = SPEC_BSTR (etype);
6883 /* If the bitfield length is less than a byte */
6886 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6887 (unsigned char) (0xFF >> (8 - bstr)));
6889 if (AOP_TYPE (right) == AOP_LIT)
6891 /* Case with a bitfield length <8 and literal source
6893 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6895 litval &= (~mask) & 0xff;
6896 emit2 ("ld a,!*pair", _pairs[pair].name);
6897 if ((mask|litval)!=0xff)
6898 emit2 ("and a,!immedbyte", mask);
6900 emit2 ("or a,!immedbyte", litval);
6901 emit2 ("ld !*pair,a", _pairs[pair].name);
6906 /* Case with a bitfield length <8 and arbitrary source
6908 _moveA (aopGet (AOP (right), 0, FALSE));
6909 /* shift and mask source value */
6911 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6913 extraPair = getFreePairId(ic);
6914 if (extraPair == PAIR_INVALID)
6916 extraPair = PAIR_BC;
6917 if (getPairId (AOP (right)) != PAIR_BC
6918 || !isLastUse (ic, right))
6924 emit2 ("ld %s,a", _pairs[extraPair].l);
6925 emit2 ("ld a,!*pair", _pairs[pair].name);
6927 emit2 ("and a,!immedbyte", mask);
6928 emit2 ("or a,%s", _pairs[extraPair].l);
6929 emit2 ("ld !*pair,a", _pairs[pair].name);
6936 /* Bit length is greater than 7 bits. In this case, copy */
6937 /* all except the partial byte at the end */
6938 for (rlen=blen;rlen>=8;rlen-=8)
6940 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6941 emit2 ("ld !*pair,a", _pairs[pair].name);
6944 emit2 ("inc %s", _pairs[pair].name);
6945 _G.pairs[pair].offset++;
6949 /* If there was a partial byte at the end */
6952 mask = (((unsigned char) -1 << rlen) & 0xff);
6954 if (AOP_TYPE (right) == AOP_LIT)
6956 /* Case with partial byte and literal source
6958 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6959 litval >>= (blen-rlen);
6960 litval &= (~mask) & 0xff;
6961 emit2 ("ld a,!*pair", _pairs[pair].name);
6962 if ((mask|litval)!=0xff)
6963 emit2 ("and a,!immedbyte", mask);
6965 emit2 ("or a,!immedbyte", litval);
6969 /* Case with partial byte and arbitrary source
6971 _moveA (aopGet (AOP (right), offset++, FALSE));
6972 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6974 extraPair = getFreePairId(ic);
6975 if (extraPair == PAIR_INVALID)
6977 extraPair = getPairId (AOP (right));
6978 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6979 extraPair = PAIR_BC;
6981 if (getPairId (AOP (right)) != PAIR_BC
6982 || !isLastUse (ic, right))
6988 emit2 ("ld %s,a", _pairs[extraPair].l);
6989 emit2 ("ld a,!*pair", _pairs[pair].name);
6991 emit2 ("and a,!immedbyte", mask);
6992 emit2 ("or a,%s", _pairs[extraPair].l);
6997 emit2 ("ld !*pair,a", _pairs[pair].name);
7002 /*-----------------------------------------------------------------*/
7003 /* genGenPointerSet - stores the value into a pointer location */
7004 /*-----------------------------------------------------------------*/
7006 genGenPointerSet (operand * right,
7007 operand * result, iCode * ic)
7010 sym_link *retype = getSpec (operandType (right));
7011 sym_link *letype = getSpec (operandType (result));
7012 PAIR_ID pairId = PAIR_HL;
7015 aopOp (result, ic, FALSE, FALSE);
7016 aopOp (right, ic, FALSE, FALSE);
7021 size = AOP_SIZE (right);
7023 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
7024 emitDebug("; isBitvar = %d", isBitvar);
7026 /* Handle the exceptions first */
7027 if (isPair (AOP (result)) && size == 1 && !isBitvar)
7030 const char *l = aopGet (AOP (right), 0, FALSE);
7031 const char *pair = getPairName (AOP (result));
7032 if (canAssignToPtr (l) && isPtr (pair))
7034 emit2 ("ld !*pair,%s", pair, l);
7039 emit2 ("ld !*pair,a", pair);
7044 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7047 const char *l = aopGet (AOP (right), 0, FALSE);
7052 if (canAssignToPtr (l))
7054 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7058 _moveA (aopGet (AOP (right), offset, FALSE));
7059 emit2 ("ld !*iyx,a", offset);
7065 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7072 const char *l = aopGet (AOP (right), offset, FALSE);
7073 if (isRegOrLit (AOP (right)) && !IS_GB)
7075 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7080 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7084 emit2 ("inc %s", _pairs[PAIR_HL].name);
7085 _G.pairs[PAIR_HL].offset++;
7090 /* Fixup HL back down */
7091 for (size = AOP_SIZE (right)-1; size; size--)
7093 emit2 ("dec %s", _pairs[PAIR_HL].name);
7098 /* if the operand is already in dptr
7099 then we do nothing else we move the value to dptr */
7100 if (AOP_TYPE (result) != AOP_STR)
7102 fetchPair (pairId, AOP (result));
7104 /* so hl now contains the address */
7105 freeAsmop (result, NULL, ic);
7107 /* if bit then unpack */
7110 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7120 const char *l = aopGet (AOP (right), offset, FALSE);
7121 if (isRegOrLit (AOP (right)) && !IS_GB)
7123 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7128 emit2 ("ld !*pair,a", _pairs[pairId].name);
7132 emit2 ("inc %s", _pairs[pairId].name);
7133 _G.pairs[pairId].offset++;
7139 freeAsmop (right, NULL, ic);
7142 /*-----------------------------------------------------------------*/
7143 /* genPointerSet - stores the value into a pointer location */
7144 /*-----------------------------------------------------------------*/
7146 genPointerSet (iCode * ic)
7148 operand *right, *result;
7149 sym_link *type, *etype;
7151 right = IC_RIGHT (ic);
7152 result = IC_RESULT (ic);
7154 /* depending on the type of pointer we need to
7155 move it to the correct pointer register */
7156 type = operandType (result);
7157 etype = getSpec (type);
7159 genGenPointerSet (right, result, ic);
7162 /*-----------------------------------------------------------------*/
7163 /* genIfx - generate code for Ifx statement */
7164 /*-----------------------------------------------------------------*/
7166 genIfx (iCode * ic, iCode * popIc)
7168 operand *cond = IC_COND (ic);
7171 aopOp (cond, ic, FALSE, TRUE);
7173 /* get the value into acc */
7174 if (AOP_TYPE (cond) != AOP_CRY)
7178 /* the result is now in the accumulator */
7179 freeAsmop (cond, NULL, ic);
7181 /* if there was something to be popped then do it */
7185 /* if the condition is a bit variable */
7186 if (isbit && IS_ITEMP (cond) &&
7188 genIfxJump (ic, SPIL_LOC (cond)->rname);
7189 else if (isbit && !IS_ITEMP (cond))
7190 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7192 genIfxJump (ic, "a");
7197 /*-----------------------------------------------------------------*/
7198 /* genAddrOf - generates code for address of */
7199 /*-----------------------------------------------------------------*/
7201 genAddrOf (iCode * ic)
7203 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7205 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7207 /* if the operand is on the stack then we
7208 need to get the stack offset of this
7214 spillPair (PAIR_HL);
7215 if (sym->stack <= 0)
7217 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7221 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7223 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7227 emit2 ("ld de,!hashedstr", sym->rname);
7228 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7233 spillPair (PAIR_HL);
7236 /* if it has an offset then we need to compute it */
7238 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7240 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7241 emit2 ("add hl,sp");
7245 emit2 ("ld hl,!hashedstr", sym->rname);
7247 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7249 freeAsmop (IC_RESULT (ic), NULL, ic);
7252 /*-----------------------------------------------------------------*/
7253 /* genAssign - generate code for assignment */
7254 /*-----------------------------------------------------------------*/
7256 genAssign (iCode * ic)
7258 operand *result, *right;
7260 unsigned long lit = 0L;
7262 result = IC_RESULT (ic);
7263 right = IC_RIGHT (ic);
7265 /* Dont bother assigning if they are the same */
7266 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7268 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7272 aopOp (right, ic, FALSE, FALSE);
7273 aopOp (result, ic, TRUE, FALSE);
7275 /* if they are the same registers */
7276 if (sameRegs (AOP (right), AOP (result)))
7278 emitDebug ("; (registers are the same)");
7282 /* if the result is a bit */
7283 if (AOP_TYPE (result) == AOP_CRY)
7285 wassertl (0, "Tried to assign to a bit");
7289 size = AOP_SIZE (result);
7292 if (AOP_TYPE (right) == AOP_LIT)
7294 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7297 if (isPair (AOP (result)))
7299 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7301 else if ((size > 1) &&
7302 (AOP_TYPE (result) != AOP_REG) &&
7303 (AOP_TYPE (right) == AOP_LIT) &&
7304 !IS_FLOAT (operandType (right)) &&
7307 bool fXored = FALSE;
7309 /* Work from the top down.
7310 Done this way so that we can use the cached copy of 0
7311 in A for a fast clear */
7314 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7316 if (!fXored && size > 1)
7323 aopPut (AOP (result), "a", offset);
7327 aopPut (AOP (result), "!zero", offset);
7331 aopPut (AOP (result),
7332 aopGet (AOP (right), offset, FALSE),
7337 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7339 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7340 aopPut (AOP (result), "l", LSB);
7341 aopPut (AOP (result), "h", MSB16);
7343 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7345 /* Special case. Load into a and d, then load out. */
7346 _moveA (aopGet (AOP (right), 0, FALSE));
7347 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7348 aopPut (AOP (result), "a", 0);
7349 aopPut (AOP (result), "e", 1);
7351 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7353 /* Special case - simple memcpy */
7354 aopGet (AOP (right), LSB, FALSE);
7357 aopGet (AOP (result), LSB, FALSE);
7361 emit2 ("ld a,(de)");
7362 /* Peephole will optimise this. */
7363 emit2 ("ld (hl),a");
7371 spillPair (PAIR_HL);
7377 /* PENDING: do this check better */
7378 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7380 _moveA (aopGet (AOP (right), offset, FALSE));
7381 aopPut (AOP (result), "a", offset);
7384 aopPut (AOP (result),
7385 aopGet (AOP (right), offset, FALSE),
7392 freeAsmop (right, NULL, ic);
7393 freeAsmop (result, NULL, ic);
7396 /*-----------------------------------------------------------------*/
7397 /* genJumpTab - genrates code for jump table */
7398 /*-----------------------------------------------------------------*/
7400 genJumpTab (iCode * ic)
7405 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7406 /* get the condition into accumulator */
7407 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7410 emit2 ("ld e,%s", l);
7411 emit2 ("ld d,!zero");
7412 jtab = newiTempLabel (NULL);
7413 spillPair (PAIR_HL);
7414 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7415 emit2 ("add hl,de");
7416 emit2 ("add hl,de");
7417 emit2 ("add hl,de");
7418 freeAsmop (IC_JTCOND (ic), NULL, ic);
7422 emitLabel (jtab->key + 100);
7423 /* now generate the jump labels */
7424 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7425 jtab = setNextItem (IC_JTLABELS (ic)))
7426 emit2 ("jp !tlabel", jtab->key + 100);
7429 /*-----------------------------------------------------------------*/
7430 /* genCast - gen code for casting */
7431 /*-----------------------------------------------------------------*/
7433 genCast (iCode * ic)
7435 operand *result = IC_RESULT (ic);
7436 sym_link *rtype = operandType (IC_RIGHT (ic));
7437 operand *right = IC_RIGHT (ic);
7440 /* if they are equivalent then do nothing */
7441 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7444 aopOp (right, ic, FALSE, FALSE);
7445 aopOp (result, ic, FALSE, FALSE);
7447 /* if the result is a bit */
7448 if (AOP_TYPE (result) == AOP_CRY)
7450 wassertl (0, "Tried to cast to a bit");
7453 /* if they are the same size : or less */
7454 if (AOP_SIZE (result) <= AOP_SIZE (right))
7457 /* if they are in the same place */
7458 if (sameRegs (AOP (right), AOP (result)))
7461 /* if they in different places then copy */
7462 size = AOP_SIZE (result);
7466 aopPut (AOP (result),
7467 aopGet (AOP (right), offset, FALSE),
7474 /* So we now know that the size of destination is greater
7475 than the size of the source */
7476 /* we move to result for the size of source */
7477 size = AOP_SIZE (right);
7481 aopPut (AOP (result),
7482 aopGet (AOP (right), offset, FALSE),
7487 /* now depending on the sign of the destination */
7488 size = AOP_SIZE (result) - AOP_SIZE (right);
7489 /* Unsigned or not an integral type - right fill with zeros */
7490 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7493 aopPut (AOP (result), "!zero", offset++);
7497 /* we need to extend the sign :{ */
7498 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7504 aopPut (AOP (result), "a", offset++);
7508 freeAsmop (right, NULL, ic);
7509 freeAsmop (result, NULL, ic);
7512 /*-----------------------------------------------------------------*/
7513 /* genReceive - generate code for a receive iCode */
7514 /*-----------------------------------------------------------------*/
7516 genReceive (iCode * ic)
7518 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7519 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7520 IS_TRUE_SYMOP (IC_RESULT (ic))))
7530 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7531 size = AOP_SIZE(IC_RESULT(ic));
7533 for (i = 0; i < size; i++) {
7534 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7538 freeAsmop (IC_RESULT (ic), NULL, ic);
7541 /*-----------------------------------------------------------------*/
7542 /* genDummyRead - generate code for dummy read of volatiles */
7543 /*-----------------------------------------------------------------*/
7545 genDummyRead (iCode * ic)
7551 if (op && IS_SYMOP (op))
7553 aopOp (op, ic, FALSE, FALSE);
7556 size = AOP_SIZE (op);
7561 _moveA (aopGet (AOP (op), offset, FALSE));
7565 freeAsmop (op, NULL, ic);
7569 if (op && IS_SYMOP (op))
7571 aopOp (op, ic, FALSE, FALSE);
7574 size = AOP_SIZE (op);
7579 _moveA (aopGet (AOP (op), offset, FALSE));
7583 freeAsmop (op, NULL, ic);
7587 /*-----------------------------------------------------------------*/
7588 /* genCritical - generate code for start of a critical sequence */
7589 /*-----------------------------------------------------------------*/
7591 genCritical (iCode *ic)
7593 symbol *tlbl = newiTempLabel (NULL);
7599 else if (IC_RESULT (ic))
7601 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7602 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7603 //get interrupt enable flag IFF2 into P/O
7607 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7608 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7609 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7610 emit2 ("!tlabeldef", (tlbl->key + 100));
7611 _G.lines.current->isLabel = 1;
7612 freeAsmop (IC_RESULT (ic), NULL, ic);
7616 //get interrupt enable flag IFF2 into P/O
7625 /*-----------------------------------------------------------------*/
7626 /* genEndCritical - generate code for end of a critical sequence */
7627 /*-----------------------------------------------------------------*/
7629 genEndCritical (iCode *ic)
7631 symbol *tlbl = newiTempLabel (NULL);
7637 else if (IC_RIGHT (ic))
7639 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7640 _toBoolean (IC_RIGHT (ic));
7641 //don't enable interrupts if they were off before
7642 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7644 emitLabel (tlbl->key + 100);
7645 freeAsmop (IC_RIGHT (ic), NULL, ic);
7651 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7652 //don't enable interrupts as they were off before
7653 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7655 emit2 ("!tlabeldef", (tlbl->key + 100));
7656 _G.lines.current->isLabel = 1;
7662 /** Maximum number of bytes to emit per line. */
7666 /** Context for the byte output chunker. */
7669 unsigned char buffer[DBEMIT_MAX_RUN];
7674 /** Flushes a byte chunker by writing out all in the buffer and
7678 _dbFlush(DBEMITCTX *self)
7685 sprintf(line, ".db 0x%02X", self->buffer[0]);
7687 for (i = 1; i < self->pos; i++)
7689 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7696 /** Write out another byte, buffering until a decent line is
7700 _dbEmit(DBEMITCTX *self, int c)
7702 if (self->pos == DBEMIT_MAX_RUN)
7706 self->buffer[self->pos++] = c;
7709 /** Context for a simple run length encoder. */
7713 unsigned char buffer[128];
7715 /** runLen may be equivalent to pos. */
7721 RLE_CHANGE_COST = 4,
7725 /** Flush the buffer of a run length encoder by writing out the run or
7726 data that it currently contains.
7729 _rleCommit(RLECTX *self)
7735 memset(&db, 0, sizeof(db));
7737 emit2(".db %u", self->pos);
7739 for (i = 0; i < self->pos; i++)
7741 _dbEmit(&db, self->buffer[i]);
7750 Can get either a run or a block of random stuff.
7751 Only want to change state if a good run comes in or a run ends.
7752 Detecting run end is easy.
7755 Say initial state is in run, len zero, last zero. Then if you get a
7756 few zeros then something else then a short run will be output.
7757 Seems OK. While in run mode, keep counting. While in random mode,
7758 keep a count of the run. If run hits margin, output all up to run,
7759 restart, enter run mode.
7762 /** Add another byte into the run length encoder, flushing as
7763 required. The run length encoder uses the Amiga IFF style, where
7764 a block is prefixed by its run length. A positive length means
7765 the next n bytes pass straight through. A negative length means
7766 that the next byte is repeated -n times. A zero terminates the
7770 _rleAppend(RLECTX *self, unsigned c)
7774 if (c != self->last)
7776 /* The run has stopped. See if it is worthwhile writing it out
7777 as a run. Note that the random data comes in as runs of
7780 if (self->runLen > RLE_CHANGE_COST)
7782 /* Yes, worthwhile. */
7783 /* Commit whatever was in the buffer. */
7785 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7789 /* Not worthwhile. Append to the end of the random list. */
7790 for (i = 0; i < self->runLen; i++)
7792 if (self->pos >= RLE_MAX_BLOCK)
7797 self->buffer[self->pos++] = self->last;
7805 if (self->runLen >= RLE_MAX_BLOCK)
7807 /* Commit whatever was in the buffer. */
7810 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7818 _rleFlush(RLECTX *self)
7820 _rleAppend(self, -1);
7827 /** genArrayInit - Special code for initialising an array with constant
7831 genArrayInit (iCode * ic)
7835 int elementSize = 0, eIndex, i;
7836 unsigned val, lastVal;
7840 memset(&rle, 0, sizeof(rle));
7842 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7844 _saveRegsForCall(ic, 0);
7846 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7847 emit2 ("call __initrleblock");
7849 type = operandType(IC_LEFT(ic));
7851 if (type && type->next)
7853 if (IS_SPEC(type->next) || IS_PTR(type->next))
7855 elementSize = getSize(type->next);
7857 else if (IS_ARRAY(type->next) && type->next->next)
7859 elementSize = getSize(type->next->next);
7863 printTypeChainRaw (type, NULL);
7864 wassertl (0, "Can't determine element size in genArrayInit.");
7869 wassertl (0, "Can't determine element size in genArrayInit.");
7872 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7874 iLoop = IC_ARRAYILIST(ic);
7875 lastVal = (unsigned)-1;
7877 /* Feed all the bytes into the run length encoder which will handle
7879 This works well for mixed char data, and for random int and long
7886 for (i = 0; i < ix; i++)
7888 for (eIndex = 0; eIndex < elementSize; eIndex++)
7890 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7891 _rleAppend(&rle, val);
7895 iLoop = iLoop->next;
7899 /* Mark the end of the run. */
7902 _restoreRegsAfterCall();
7906 freeAsmop (IC_LEFT(ic), NULL, ic);
7910 _swap (PAIR_ID one, PAIR_ID two)
7912 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7918 emit2 ("ld a,%s", _pairs[one].l);
7919 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7920 emit2 ("ld %s,a", _pairs[two].l);
7921 emit2 ("ld a,%s", _pairs[one].h);
7922 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7923 emit2 ("ld %s,a", _pairs[two].h);
7927 /* The problem is that we may have all three pairs used and they may
7928 be needed in a different order.
7933 hl = hl => unity, fine
7937 hl = hl hl = hl, swap de <=> bc
7945 hl = bc de = de, swap bc <=> hl
7953 hl = de bc = bc, swap hl <=> de
7958 * Any pair = pair are done last
7959 * Any pair = iTemp are done last
7960 * Any swaps can be done any time
7968 So how do we detect the cases?
7969 How about a 3x3 matrix?
7973 x x x x (Fourth for iTemp/other)
7975 First determin which mode to use by counting the number of unity and
7978 Two - Assign the pair first, then the rest
7979 One - Swap the two, then the rest
7983 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7985 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7987 PAIR_BC, PAIR_HL, PAIR_DE
7989 int i, j, nunity = 0;
7990 memset (ids, PAIR_INVALID, sizeof (ids));
7993 wassert (nparams == 3);
7995 /* First save everything that needs to be saved. */
7996 _saveRegsForCall (ic, 0);
7998 /* Loading HL first means that DE is always fine. */
7999 for (i = 0; i < nparams; i++)
8001 aopOp (pparams[i], ic, FALSE, FALSE);
8002 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
8005 /* Count the number of unity or iTemp assigns. */
8006 for (i = 0; i < 3; i++)
8008 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
8016 /* Any order, fall through. */
8018 else if (nunity == 2)
8020 /* One is assigned. Pull it out and assign. */
8021 for (i = 0; i < 3; i++)
8023 for (j = 0; j < NUM_PAIRS; j++)
8025 if (ids[dest[i]][j] == TRUE)
8027 /* Found it. See if it's the right one. */
8028 if (j == PAIR_INVALID || j == dest[i])
8034 fetchPair(dest[i], AOP (pparams[i]));
8041 else if (nunity == 1)
8043 /* Find the pairs to swap. */
8044 for (i = 0; i < 3; i++)
8046 for (j = 0; j < NUM_PAIRS; j++)
8048 if (ids[dest[i]][j] == TRUE)
8050 if (j == PAIR_INVALID || j == dest[i])
8065 int next = getPairId (AOP (pparams[0]));
8066 emit2 ("push %s", _pairs[next].name);
8068 if (next == dest[1])
8070 fetchPair (dest[1], AOP (pparams[1]));
8071 fetchPair (dest[2], AOP (pparams[2]));
8075 fetchPair (dest[2], AOP (pparams[2]));
8076 fetchPair (dest[1], AOP (pparams[1]));
8078 emit2 ("pop %s", _pairs[dest[0]].name);
8081 /* Finally pull out all of the iTemps */
8082 for (i = 0; i < 3; i++)
8084 if (ids[dest[i]][PAIR_INVALID] == 1)
8086 fetchPair (dest[i], AOP (pparams[i]));
8092 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8098 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8102 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8104 setupForBuiltin3 (ic, nParams, pparams);
8106 label = newiTempLabel(NULL);
8108 emitLabel (label->key);
8109 emit2 ("ld a,(hl)");
8112 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8114 freeAsmop (from, NULL, ic->next);
8115 freeAsmop (to, NULL, ic);
8119 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8121 operand *from, *to, *count;
8124 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8129 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8131 setupForBuiltin3 (ic, nParams, pparams);
8135 freeAsmop (count, NULL, ic->next->next);
8136 freeAsmop (from, NULL, ic);
8138 _restoreRegsAfterCall();
8140 /* if we need assign a result value */
8141 if ((IS_ITEMP (IC_RESULT (ic)) &&
8142 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8143 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8144 IS_TRUE_SYMOP (IC_RESULT (ic)))
8146 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8147 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8148 freeAsmop (IC_RESULT (ic), NULL, ic);
8151 freeAsmop (to, NULL, ic->next);
8154 /*-----------------------------------------------------------------*/
8155 /* genBuiltIn - calls the appropriate function to generating code */
8156 /* for a built in function */
8157 /*-----------------------------------------------------------------*/
8158 static void genBuiltIn (iCode *ic)
8160 operand *bi_parms[MAX_BUILTIN_ARGS];
8165 /* get all the arguments for a built in function */
8166 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8168 /* which function is it */
8169 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8171 if (strcmp(bif->name,"__builtin_strcpy")==0)
8173 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8175 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8177 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8181 wassertl (0, "Unknown builtin function encountered");
8185 /*-----------------------------------------------------------------*/
8186 /* genZ80Code - generate code for Z80 based controllers */
8187 /*-----------------------------------------------------------------*/
8189 genZ80Code (iCode * lic)
8197 _fReturn = _gbz80_return;
8198 _fTmp = _gbz80_return;
8202 _fReturn = _z80_return;
8203 _fTmp = _z80_return;
8206 _G.lines.head = _G.lines.current = NULL;
8208 /* if debug information required */
8209 if (options.debug && currFunc)
8211 debugFile->writeFunction (currFunc, lic);
8214 for (ic = lic; ic; ic = ic->next)
8216 _G.current_iCode = ic;
8218 if (ic->lineno && cln != ic->lineno)
8222 debugFile->writeCLine (ic);
8224 if (!options.noCcodeInAsm)
8226 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8227 printCLine(ic->filename, ic->lineno));
8231 if (options.iCodeInAsm)
8233 const char *iLine = printILine(ic);
8234 emit2 (";ic:%d: %s", ic->key, iLine);
8237 /* if the result is marked as
8238 spilt and rematerializable or code for
8239 this has already been generated then
8241 if (resultRemat (ic) || ic->generated)
8244 /* depending on the operation */
8248 emitDebug ("; genNot");
8253 emitDebug ("; genCpl");
8258 emitDebug ("; genUminus");
8263 emitDebug ("; genIpush");
8268 /* IPOP happens only when trying to restore a
8269 spilt live range, if there is an ifx statement
8270 following this pop then the if statement might
8271 be using some of the registers being popped which
8272 would destroy the contents of the register so
8273 we need to check for this condition and handle it */
8275 ic->next->op == IFX &&
8276 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8278 emitDebug ("; genIfx");
8279 genIfx (ic->next, ic);
8283 emitDebug ("; genIpop");
8289 emitDebug ("; genCall");
8294 emitDebug ("; genPcall");
8299 emitDebug ("; genFunction");
8304 emitDebug ("; genEndFunction");
8305 genEndFunction (ic);
8309 emitDebug ("; genRet");
8314 emitDebug ("; genLabel");
8319 emitDebug ("; genGoto");
8324 emitDebug ("; genPlus");
8329 emitDebug ("; genMinus");
8334 emitDebug ("; genMult");
8339 emitDebug ("; genDiv");
8344 emitDebug ("; genMod");
8349 emitDebug ("; genCmpGt");
8350 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8354 emitDebug ("; genCmpLt");
8355 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8362 /* note these two are xlated by algebraic equivalence
8363 during parsing SDCC.y */
8364 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8365 "got '>=' or '<=' shouldn't have come here");
8369 emitDebug ("; genCmpEq");
8370 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8374 emitDebug ("; genAndOp");
8379 emitDebug ("; genOrOp");
8384 emitDebug ("; genXor");
8385 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8389 emitDebug ("; genOr");
8390 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8394 emitDebug ("; genAnd");
8395 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8399 emitDebug ("; genInline");
8404 emitDebug ("; genRRC");
8409 emitDebug ("; genRLC");
8414 emitDebug ("; genGetHBIT");
8419 emitDebug ("; genLeftShift");
8424 emitDebug ("; genRightShift");
8428 case GET_VALUE_AT_ADDRESS:
8429 emitDebug ("; genPointerGet");
8435 if (POINTER_SET (ic))
8437 emitDebug ("; genAssign (pointer)");
8442 emitDebug ("; genAssign");
8448 emitDebug ("; genIfx");
8453 emitDebug ("; genAddrOf");
8458 emitDebug ("; genJumpTab");
8463 emitDebug ("; genCast");
8468 emitDebug ("; genReceive");
8473 if (ic->builtinSEND)
8475 emitDebug ("; genBuiltIn");
8480 emitDebug ("; addSet");
8481 addSet (&_G.sendSet, ic);
8486 emitDebug ("; genArrayInit");
8490 case DUMMY_READ_VOLATILE:
8491 emitDebug ("; genDummyRead");
8496 emitDebug ("; genCritical");
8501 emitDebug ("; genEndCritical");
8502 genEndCritical (ic);
8511 /* now we are ready to call the
8512 peep hole optimizer */
8513 if (!options.nopeep)
8514 peepHole (&_G.lines.head);
8516 /* This is unfortunate */
8517 /* now do the actual printing */
8519 struct dbuf_s *buf = codeOutBuf;
8520 if (isInHome () && codeOutBuf == &code->oBuf)
8521 codeOutBuf = &home->oBuf;
8522 printLine (_G.lines.head, codeOutBuf);
8523 if (_G.flushStatics)
8526 _G.flushStatics = 0;
8531 freeTrace(&_G.lines.trace);
8532 freeTrace(&_G.trace.aops);
8538 _isPairUsed (iCode * ic, PAIR_ID pairId)
8544 if (bitVectBitValue (ic->rMask, D_IDX))
8546 if (bitVectBitValue (ic->rMask, E_IDX))
8556 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8559 value *val = aop->aopu.aop_lit;
8561 wassert (aop->type == AOP_LIT);
8562 wassert (!IS_FLOAT (val->type));
8564 v = ulFromVal (val);
8572 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8573 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));