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 = (char *)dbuf_c_str(&dbuf);
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 == AOP_IMMD && left->type == AOP_IMMD)
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))
1405 if (pairId == PAIR_HL && left->type == AOP_LIT && _G.pairs[pairId].last_type == AOP_LIT &&
1406 !IS_FLOAT (left->aopu.aop_lit->type) && offset == 0 && _G.pairs[pairId].offset == 0)
1408 unsigned new_low, new_high, old_low, old_high;
1409 unsigned long v_new = ulFromVal (left->aopu.aop_lit);
1410 unsigned long v_old = strtoul (_G.pairs[pairId].base, NULL, 0);
1411 new_low = (v_new >> 0) & 0xff;
1412 new_high = (v_new >> 8) & 0xff;
1413 old_low = (v_old >> 0) & 0xff;
1414 old_high = (v_old >> 8) & 0xff;
1416 /* Change lower byte only. */
1417 if(new_high == old_high)
1419 emit2("ld l, %s", aopGet (left, 0, FALSE));
1422 /* Change upper byte only. */
1423 else if(new_low == old_low)
1425 emit2("ld h, %s", aopGet (left, 1, FALSE));
1431 _G.pairs[pairId].last_type = left->type;
1432 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1433 _G.pairs[pairId].offset = offset;
1435 /* Both a lit on the right and a true symbol on the left */
1436 emit2 ("ld %s,!hashedstr", pair, l);
1440 _G.pairs[pairId].last_type = left->type;
1441 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1442 _G.pairs[pairId].offset = offset;
1446 makeFreePairId (iCode *ic, bool *pisUsed)
1452 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1456 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1474 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1476 /* if this is remateriazable */
1477 if (isLitWord (aop)) {
1478 fetchLitPair (pairId, aop, offset);
1482 if (getPairId (aop) == pairId)
1486 /* we need to get it byte by byte */
1487 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1488 aopGet (aop, offset, FALSE);
1489 switch (aop->size - offset) {
1491 emit2 ("ld l,!*hl");
1492 emit2 ("ld h,!immedbyte", 0);
1495 // PENDING: Requires that you are only fetching two bytes.
1498 emit2 ("ld h,!*hl");
1502 wassertl (0, "Attempted to fetch too much data into HL");
1506 else if (IS_Z80 && aop->type == AOP_IY) {
1507 /* Instead of fetching relative to IY, just grab directly
1508 from the address IY refers to */
1509 char *l = aopGetLitWordLong (aop, offset, FALSE);
1511 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1513 if (aop->size < 2) {
1514 emit2("ld %s,!zero", _pairs[pairId].h);
1517 else if (pairId == PAIR_IY)
1521 emit2 ("push %s", _pairs[getPairId(aop)].name);
1527 PAIR_ID id = makeFreePairId (ic, &isUsed);
1530 /* Can't load into parts, so load into HL then exchange. */
1531 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1532 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1533 emit2 ("push %s", _pairs[id].name);
1539 else if (isUnsplitable(aop))
1541 emit2("push %s", _pairs[getPairId(aop)].name);
1542 emit2("pop %s", _pairs[pairId].name);
1546 /* Swapping register contents within register pair */
1547 if(!strcmp(aopGet (aop, offset, FALSE), _pairs[pairId].h))
1549 emit2 ("ld a,%s",aopGet (aop, offset + 1, FALSE));
1550 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1551 emit2 ("ld %s,a", _pairs[pairId].h);
1555 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1556 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1559 /* PENDING: check? */
1560 if (pairId == PAIR_HL)
1561 spillPair (PAIR_HL);
1566 fetchPair (PAIR_ID pairId, asmop * aop)
1568 fetchPairLong (pairId, aop, NULL, 0);
1572 fetchHL (asmop * aop)
1574 fetchPair (PAIR_HL, aop);
1578 setupPairFromSP (PAIR_ID id, int offset)
1580 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1582 if (_G.preserveCarry)
1588 if (offset < INT8MIN || offset > INT8MAX)
1590 emit2 ("ld hl,!immedword", offset);
1591 emit2 ("add hl,sp");
1595 emit2 ("!ldahlsp", offset);
1598 if (_G.preserveCarry)
1606 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1611 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1612 fetchLitPair (pairId, aop, 0);
1616 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1618 fetchLitPair (pairId, aop, offset);
1619 _G.pairs[pairId].offset = offset;
1623 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1624 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1627 int offset = aop->aopu.aop_stk + _G.stack.offset;
1629 if (_G.pairs[pairId].last_type == aop->type &&
1630 _G.pairs[pairId].offset == offset)
1636 /* PENDING: Do this better. */
1637 if (_G.preserveCarry)
1639 sprintf (buffer, "%d", offset + _G.stack.pushed);
1640 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1641 emit2 ("add %s,sp", _pairs[pairId].name);
1642 _G.pairs[pairId].last_type = aop->type;
1643 _G.pairs[pairId].offset = offset;
1644 if (_G.preserveCarry)
1652 /* Doesnt include _G.stack.pushed */
1653 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1655 if (aop->aopu.aop_stk > 0)
1657 abso += _G.stack.param_offset;
1659 assert (pairId == PAIR_HL);
1660 /* In some cases we can still inc or dec hl */
1661 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1663 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1667 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1669 _G.pairs[pairId].offset = abso;
1674 if (pairId != aop->aopu.aop_pairId)
1675 genMovePairPair(aop->aopu.aop_pairId, pairId);
1676 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1682 _G.pairs[pairId].last_type = aop->type;
1688 emit2 ("!tlabeldef", key);
1689 _G.lines.current->isLabel = 1;
1693 /*-----------------------------------------------------------------*/
1694 /* aopGet - for fetching value of the aop */
1695 /*-----------------------------------------------------------------*/
1697 aopGet (asmop * aop, int offset, bool bit16)
1699 // char *s = buffer;
1701 /* offset is greater than size then zero */
1702 /* PENDING: this seems a bit screwed in some pointer cases. */
1703 if (offset > (aop->size - 1) &&
1704 aop->type != AOP_LIT)
1706 tsprintf (buffer, sizeof(buffer), "!zero");
1707 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1710 /* depending on type */
1714 tsprintf (buffer, sizeof(buffer), "!zero");
1715 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1718 /* PENDING: re-target */
1720 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1725 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1728 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1731 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1734 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1737 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1741 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1742 SNPRINTF (buffer, sizeof(buffer), "a");
1744 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1750 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1751 SNPRINTF (buffer, sizeof(buffer), "a");
1753 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1756 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1759 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1760 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1761 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1763 else if( z80_opts.port_mode == 180 )
1764 { /* z180 in0/out0 mode */
1765 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1769 emit2( "in a,(%s)", aop->aopu.aop_dir );
1772 SNPRINTF (buffer, sizeof(buffer), "a");
1774 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1778 return aop->aopu.aop_reg[offset]->name;
1782 setupPair (PAIR_HL, aop, offset);
1783 tsprintf (buffer, sizeof(buffer), "!*hl");
1785 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1789 setupPair (PAIR_IY, aop, offset);
1790 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1792 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1796 setupPair (PAIR_IY, aop, offset);
1797 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1799 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1804 setupPair (PAIR_HL, aop, offset);
1805 tsprintf (buffer, sizeof(buffer), "!*hl");
1809 if (aop->aopu.aop_stk >= 0)
1810 offset += _G.stack.param_offset;
1811 tsprintf (buffer, sizeof(buffer),
1812 "!*ixx", aop->aopu.aop_stk + offset);
1815 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1818 wassertl (0, "Tried to fetch from a bit variable");
1827 tsprintf(buffer, sizeof(buffer), "!zero");
1828 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1832 wassert (offset < 2);
1833 return aop->aopu.aop_str[offset];
1836 return aopLiteral (aop->aopu.aop_lit, offset);
1840 unsigned long v = aop->aopu.aop_simplelit;
1843 tsprintf (buffer, sizeof(buffer),
1844 "!immedbyte", (unsigned int) v & 0xff);
1846 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1850 return aop->aopu.aop_str[offset];
1853 setupPair (aop->aopu.aop_pairId, aop, offset);
1854 if (aop->aopu.aop_pairId==PAIR_IX)
1855 tsprintf (buffer, sizeof(buffer), "!*ixx", offset);
1856 else if (aop->aopu.aop_pairId==PAIR_IY)
1857 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1859 SNPRINTF (buffer, sizeof(buffer),
1860 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1862 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1867 wassertl (0, "aopget got unsupported aop->type");
1872 isRegString (const char *s)
1874 if (!strcmp (s, "b") ||
1886 isConstant (const char *s)
1888 /* This is a bit of a hack... */
1889 return (*s == '#' || *s == '$');
1893 canAssignToPtr (const char *s)
1895 if (isRegString (s))
1902 /*-----------------------------------------------------------------*/
1903 /* aopPut - puts a string for a aop */
1904 /*-----------------------------------------------------------------*/
1906 aopPut (asmop * aop, const char *s, int offset)
1910 if (aop->size && offset > (aop->size - 1))
1912 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1913 "aopPut got offset > aop->size");
1918 tsprintf(buffer2, sizeof(buffer2), s);
1921 /* will assign value to value */
1922 /* depending on where it is ofcourse */
1926 _moveA (s); /* in case s is volatile */
1932 if (strcmp (s, "a"))
1933 emit2 ("ld a,%s", s);
1934 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1941 if (strcmp (s, "a"))
1942 emit2 ("ld a,%s", s);
1943 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1946 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1953 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1954 && s[0] != 'h' && s[0] != 'l'))
1956 emit2( "ld a,%s", s );
1960 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1961 emit2( "out (c),%s", s );
1966 spillPair (PAIR_BC);
1968 else if( z80_opts.port_mode == 180 )
1969 { /* z180 in0/out0 mode */
1970 emit2( "ld a,%s", s );
1971 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1975 emit2( "ld a,%s", s );
1976 emit2( "out (%s),a", aop->aopu.aop_dir );
1982 if (!strcmp (s, "!*hl"))
1983 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1986 aop->aopu.aop_reg[offset]->name, s);
1987 spillPairReg(aop->aopu.aop_reg[offset]->name);
1992 if (!canAssignToPtr (s))
1994 emit2 ("ld a,%s", s);
1995 setupPair (PAIR_IY, aop, offset);
1996 emit2 ("ld !*iyx,a", offset);
2000 setupPair (PAIR_IY, aop, offset);
2001 emit2 ("ld !*iyx,%s", offset, s);
2007 /* PENDING: for re-target */
2008 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2010 emit2 ("ld a,!*hl");
2013 setupPair (PAIR_HL, aop, offset);
2015 emit2 ("ld !*hl,%s", s);
2020 if (!canAssignToPtr (s))
2022 emit2 ("ld a,%s", s);
2023 setupPair (PAIR_IY, aop, offset);
2024 emit2 ("ld !*iyx,a", offset);
2028 setupPair (PAIR_IY, aop, offset);
2029 emit2 ("ld !*iyx,%s", offset, s);
2036 /* PENDING: re-target */
2037 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2039 emit2 ("ld a,!*hl");
2042 setupPair (PAIR_HL, aop, offset);
2043 if (!canAssignToPtr (s))
2045 emit2 ("ld a,%s", s);
2046 emit2 ("ld !*hl,a");
2049 emit2 ("ld !*hl,%s", s);
2053 if (aop->aopu.aop_stk >= 0)
2054 offset += _G.stack.param_offset;
2055 if (!canAssignToPtr (s))
2057 emit2 ("ld a,%s", s);
2058 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2062 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2068 /* if bit variable */
2069 if (!aop->aopu.aop_dir)
2071 emit2 ("ld a,!zero");
2076 /* In bit space but not in C - cant happen */
2077 wassertl (0, "Tried to write into a bit variable");
2083 if (strcmp (aop->aopu.aop_str[offset], s))
2085 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2087 spillPairReg(aop->aopu.aop_str[offset]);
2092 if (!offset && (strcmp (s, "acc") == 0))
2096 wassertl (0, "Tried to access past the end of A");
2100 if (strcmp (aop->aopu.aop_str[offset], s))
2102 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2103 spillPairReg(aop->aopu.aop_str[offset]);
2109 wassert (offset < 2);
2110 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2111 spillPairReg(aop->aopu.aop_str[offset]);
2115 setupPair (aop->aopu.aop_pairId, aop, offset);
2116 if (aop->aopu.aop_pairId==PAIR_IX)
2117 emit2 ("ld !*ixx,%s", 0, s);
2118 else if (aop->aopu.aop_pairId==PAIR_IY)
2119 emit2 ("ld !*iyx,%s", 0, s);
2121 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2125 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2126 "aopPut got unsupported aop->type");
2131 #define AOP(op) op->aop
2132 #define AOP_TYPE(op) AOP(op)->type
2133 #define AOP_SIZE(op) AOP(op)->size
2134 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2135 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2138 commitPair (asmop * aop, PAIR_ID id)
2140 /* PENDING: Verify this. */
2141 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2145 aopPut (aop, "a", 0);
2146 aopPut (aop, "d", 1);
2151 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2153 char *l = aopGetLitWordLong (aop, 0, FALSE);
2156 emit2 ("ld (%s),%s", l, _pairs[id].name);
2160 aopPut (aop, _pairs[id].l, 0);
2161 aopPut (aop, _pairs[id].h, 1);
2166 /*-----------------------------------------------------------------*/
2167 /* getDataSize - get the operand data size */
2168 /*-----------------------------------------------------------------*/
2170 getDataSize (operand * op)
2173 size = AOP_SIZE (op);
2177 wassertl (0, "Somehow got a three byte data pointer");
2182 /*-----------------------------------------------------------------*/
2183 /* movLeft2Result - move byte from left to result */
2184 /*-----------------------------------------------------------------*/
2186 movLeft2Result (operand * left, int offl,
2187 operand * result, int offr, int sign)
2191 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2193 l = aopGet (AOP (left), offl, FALSE);
2197 aopPut (AOP (result), l, offr);
2201 if (getDataSize (left) == offl + 1)
2203 emit2 ("ld a,%s", l);
2204 aopPut (AOP (result), "a", offr);
2211 movLeft2ResultLong (operand * left, int offl,
2212 operand * result, int offr, int sign,
2217 movLeft2Result (left, offl, result, offr, sign);
2221 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2222 wassertl (size == 2, "Only implemented for two bytes or one");
2224 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2226 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2227 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2229 spillPair (PAIR_HL);
2231 else if ( getPairId ( AOP (result)) == PAIR_IY)
2233 PAIR_ID id = getPairId (AOP (left));
2234 if (id != PAIR_INVALID)
2236 emit2("push %s", _pairs[id].name);
2247 movLeft2Result (left, offl, result, offr, sign);
2248 movLeft2Result (left, offl+1, result, offr+1, sign);
2253 /** Put Acc into a register set
2256 outAcc (operand * result)
2259 size = getDataSize (result);
2262 aopPut (AOP (result), "a", 0);
2265 /* unsigned or positive */
2268 aopPut (AOP (result), "!zero", offset++);
2273 /** Take the value in carry and put it into a register
2276 outBitC (operand * result)
2278 /* if the result is bit */
2279 if (AOP_TYPE (result) == AOP_CRY)
2281 if (!IS_OP_RUONLY (result))
2282 aopPut (AOP (result), "c", 0);
2286 emit2 ("ld a,!zero");
2292 /*-----------------------------------------------------------------*/
2293 /* toBoolean - emit code for orl a,operator(sizeop) */
2294 /*-----------------------------------------------------------------*/
2296 _toBoolean (operand * oper)
2298 int size = AOP_SIZE (oper);
2302 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2305 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2309 if (AOP (oper)->type != AOP_ACC)
2312 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2318 /*-----------------------------------------------------------------*/
2319 /* genNot - generate code for ! operation */
2320 /*-----------------------------------------------------------------*/
2325 /* assign asmOps to operand & result */
2326 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2327 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2329 /* if in bit space then a special case */
2330 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2332 wassertl (0, "Tried to negate a bit");
2335 _toBoolean (IC_LEFT (ic));
2340 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2341 emit2 ("sub a,!one");
2342 outBitC (IC_RESULT (ic));
2344 /* release the aops */
2345 freeAsmop (IC_LEFT (ic), NULL, ic);
2346 freeAsmop (IC_RESULT (ic), NULL, ic);
2349 /*-----------------------------------------------------------------*/
2350 /* genCpl - generate code for complement */
2351 /*-----------------------------------------------------------------*/
2359 /* assign asmOps to operand & result */
2360 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2361 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2363 /* if both are in bit space then
2365 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2366 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2368 wassertl (0, "Left and the result are in bit space");
2371 size = AOP_SIZE (IC_RESULT (ic));
2374 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2377 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2380 /* release the aops */
2381 freeAsmop (IC_LEFT (ic), NULL, ic);
2382 freeAsmop (IC_RESULT (ic), NULL, ic);
2386 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2393 store de into result
2398 store de into result
2400 const char *first = isAdd ? "add" : "sub";
2401 const char *later = isAdd ? "adc" : "sbc";
2403 wassertl (IS_GB, "Code is only relevent to the gbz80");
2404 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2406 fetchPair (PAIR_DE, left);
2409 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2412 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2415 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2416 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2418 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2419 aopGet (right, MSB24, FALSE);
2423 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2426 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2428 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2429 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2433 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2435 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2438 /*-----------------------------------------------------------------*/
2439 /* genUminusFloat - unary minus for floating points */
2440 /*-----------------------------------------------------------------*/
2442 genUminusFloat (operand * op, operand * result)
2444 int size, offset = 0;
2446 emitDebug("; genUminusFloat");
2448 /* for this we just need to flip the
2449 first bit then copy the rest in place */
2450 size = AOP_SIZE (op) - 1;
2452 _moveA(aopGet (AOP (op), MSB32, FALSE));
2454 emit2("xor a,!immedbyte", 0x80);
2455 aopPut (AOP (result), "a", MSB32);
2459 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2464 /*-----------------------------------------------------------------*/
2465 /* genUminus - unary minus code generation */
2466 /*-----------------------------------------------------------------*/
2468 genUminus (iCode * ic)
2471 sym_link *optype, *rtype;
2474 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2475 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2477 /* if both in bit space then special
2479 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2480 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2482 wassertl (0, "Left and right are in bit space");
2486 optype = operandType (IC_LEFT (ic));
2487 rtype = operandType (IC_RESULT (ic));
2489 /* if float then do float stuff */
2490 if (IS_FLOAT (optype))
2492 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2496 /* otherwise subtract from zero */
2497 size = AOP_SIZE (IC_LEFT (ic));
2499 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2501 /* Create a new asmop with value zero */
2502 asmop *azero = newAsmop (AOP_SIMPLELIT);
2503 azero->aopu.aop_simplelit = 0;
2505 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2513 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2514 emit2 ("ld a,!zero");
2515 emit2 ("sbc a,%s", l);
2516 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2519 /* if any remaining bytes in the result */
2520 /* we just need to propagate the sign */
2521 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2526 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2530 /* release the aops */
2531 freeAsmop (IC_LEFT (ic), NULL, ic);
2532 freeAsmop (IC_RESULT (ic), NULL, ic);
2535 /*-----------------------------------------------------------------*/
2536 /* assignResultValue - */
2537 /*-----------------------------------------------------------------*/
2539 assignResultValue (operand * oper)
2541 int size = AOP_SIZE (oper);
2544 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2545 topInA = requiresHL (AOP (oper));
2547 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2549 /* We do it the hard way here. */
2551 aopPut (AOP (oper), _fReturn[0], 0);
2552 aopPut (AOP (oper), _fReturn[1], 1);
2554 aopPut (AOP (oper), _fReturn[0], 2);
2555 aopPut (AOP (oper), _fReturn[1], 3);
2559 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2560 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2563 _emitMove ("a", _fReturn[size-1]);
2564 _emitMove (_fReturn[size-1], _fReturn[size]);
2565 _emitMove (_fReturn[size], "a");
2566 aopPut (AOP (oper), _fReturn[size], size-1);
2571 aopPut (AOP (oper), _fReturn[size], size);
2576 /** Simple restore that doesn't take into account what is used in the
2580 _restoreRegsAfterCall(void)
2582 if (_G.stack.pushedDE)
2585 _G.stack.pushedDE = FALSE;
2587 if (_G.stack.pushedBC)
2590 _G.stack.pushedBC = FALSE;
2592 _G.saves.saved = FALSE;
2596 _saveRegsForCall(iCode *ic, int sendSetSize)
2599 o Stack parameters are pushed before this function enters
2600 o DE and BC may be used in this function.
2601 o HL and DE may be used to return the result.
2602 o HL and DE may be used to send variables.
2603 o DE and BC may be used to store the result value.
2604 o HL may be used in computing the sent value of DE
2605 o The iPushes for other parameters occur before any addSets
2607 Logic: (to be run inside the first iPush or if none, before sending)
2608 o Compute if DE and/or BC are in use over the call
2609 o Compute if DE is used in the send set
2610 o Compute if DE and/or BC are used to hold the result value
2611 o If (DE is used, or in the send set) and is not used in the result, push.
2612 o If BC is used and is not in the result, push
2614 o If DE is used in the send set, fetch
2615 o If HL is used in the send set, fetch
2619 if (_G.saves.saved == FALSE) {
2620 bool deInUse, bcInUse;
2622 bool bcInRet = FALSE, deInRet = FALSE;
2625 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2626 z80_rUmaskForOp (IC_RESULT(ic)));
2628 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2629 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2631 deSending = (sendSetSize > 1);
2633 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2635 if (bcInUse && bcInRet == FALSE) {
2637 _G.stack.pushedBC = TRUE;
2639 if (deInUse && deInRet == FALSE) {
2641 _G.stack.pushedDE = TRUE;
2644 _G.saves.saved = TRUE;
2647 /* Already saved. */
2651 /*-----------------------------------------------------------------*/
2652 /* genIpush - genrate code for pushing this gets a little complex */
2653 /*-----------------------------------------------------------------*/
2655 genIpush (iCode * ic)
2657 int size, offset = 0;
2660 /* if this is not a parm push : ie. it is spill push
2661 and spill push is always done on the local stack */
2664 wassertl(0, "Encountered an unsupported spill push.");
2668 if (_G.saves.saved == FALSE) {
2669 /* Caller saves, and this is the first iPush. */
2670 /* Scan ahead until we find the function that we are pushing parameters to.
2671 Count the number of addSets on the way to figure out what registers
2672 are used in the send set.
2675 iCode *walk = ic->next;
2678 if (walk->op == SEND) {
2681 else if (walk->op == CALL || walk->op == PCALL) {
2690 _saveRegsForCall(walk, nAddSets);
2693 /* Already saved by another iPush. */
2696 /* then do the push */
2697 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2699 size = AOP_SIZE (IC_LEFT (ic));
2701 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2703 _G.stack.pushed += 2;
2704 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2710 fetchHL (AOP (IC_LEFT (ic)));
2712 _G.stack.pushed += 2;
2717 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2719 _G.stack.pushed += 2;
2720 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2722 _G.stack.pushed += 2;
2728 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2730 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2732 emit2 ("ld a,(%s)", l);
2737 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2738 if (!strcmp(l, "b"))
2740 else if (!strcmp(l, "d"))
2742 else if (!strcmp(l, "h"))
2746 emit2 ("ld a,%s", l);
2755 freeAsmop (IC_LEFT (ic), NULL, ic);
2758 /*-----------------------------------------------------------------*/
2759 /* genIpop - recover the registers: can happen only for spilling */
2760 /*-----------------------------------------------------------------*/
2762 genIpop (iCode * ic)
2767 /* if the temp was not pushed then */
2768 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2771 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2772 size = AOP_SIZE (IC_LEFT (ic));
2773 offset = (size - 1);
2774 if (isPair (AOP (IC_LEFT (ic))))
2776 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2784 spillPair (PAIR_HL);
2785 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2789 freeAsmop (IC_LEFT (ic), NULL, ic);
2792 /* This is quite unfortunate */
2794 setArea (int inHome)
2797 static int lastArea = 0;
2799 if (_G.in_home != inHome) {
2801 const char *sz = port->mem.code_name;
2802 port->mem.code_name = "HOME";
2803 emit2("!area", CODE_NAME);
2804 port->mem.code_name = sz;
2807 emit2("!area", CODE_NAME); */
2808 _G.in_home = inHome;
2819 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2823 symbol *sym = OP_SYMBOL (op);
2825 if (sym->isspilt || sym->nRegs == 0)
2828 aopOp (op, ic, FALSE, FALSE);
2831 if (aop->type == AOP_REG)
2834 for (i = 0; i < aop->size; i++)
2836 if (pairId == PAIR_DE)
2838 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2839 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2841 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2844 else if (pairId == PAIR_BC)
2846 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2847 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2849 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2859 freeAsmop (IC_LEFT (ic), NULL, ic);
2863 /** Emit the code for a call statement
2866 emitCall (iCode * ic, bool ispcall)
2868 bool bInRet, cInRet, dInRet, eInRet;
2869 sym_link *dtype = operandType (IC_LEFT (ic));
2871 /* if caller saves & we have not saved then */
2877 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2879 /* if send set is not empty then assign */
2884 int nSend = elementsInSet(_G.sendSet);
2885 bool swapped = FALSE;
2887 int _z80_sendOrder[] = {
2892 /* Check if the parameters are swapped. If so route through hl instead. */
2893 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2895 sic = setFirstItem(_G.sendSet);
2896 sic = setNextItem(_G.sendSet);
2898 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2899 /* The second send value is loaded from one the one that holds the first
2900 send, i.e. it is overwritten. */
2901 /* Cache the first in HL, and load the second from HL instead. */
2902 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2903 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2909 for (sic = setFirstItem (_G.sendSet); sic;
2910 sic = setNextItem (_G.sendSet))
2913 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2915 size = AOP_SIZE (IC_LEFT (sic));
2916 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2917 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2919 // PENDING: Mild hack
2920 if (swapped == TRUE && send == 1) {
2922 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2925 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2927 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2930 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2934 freeAsmop (IC_LEFT (sic), NULL, sic);
2941 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2943 werror (W_INDIR_BANKED);
2945 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2947 if (isLitWord (AOP (IC_LEFT (ic))))
2949 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2953 symbol *rlbl = newiTempLabel (NULL);
2954 spillPair (PAIR_HL);
2955 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2957 _G.stack.pushed += 2;
2959 fetchHL (AOP (IC_LEFT (ic)));
2961 emit2 ("!tlabeldef", (rlbl->key + 100));
2962 _G.lines.current->isLabel = 1;
2963 _G.stack.pushed -= 2;
2965 freeAsmop (IC_LEFT (ic), NULL, ic);
2969 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2970 OP_SYMBOL (IC_LEFT (ic))->rname :
2971 OP_SYMBOL (IC_LEFT (ic))->name;
2972 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2974 emit2 ("call banked_call");
2975 emit2 ("!dws", name);
2976 emit2 ("!dw !bankimmeds", name);
2981 emit2 ("call %s", name);
2986 /* Mark the registers as restored. */
2987 _G.saves.saved = FALSE;
2989 /* adjust the stack for parameters if required */
2992 int i = ic->parmBytes;
2994 _G.stack.pushed -= i;
2997 emit2 ("!ldaspsp", i);
3004 emit2 ("ld iy,!immedword", i);
3005 emit2 ("add iy,sp");
3023 /* if we need assign a result value */
3024 if ((IS_ITEMP (IC_RESULT (ic)) &&
3025 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3026 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3027 IS_TRUE_SYMOP (IC_RESULT (ic)))
3029 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3031 assignResultValue (IC_RESULT (ic));
3033 freeAsmop (IC_RESULT (ic), NULL, ic);
3039 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3040 bInRet = bitVectBitValue(result, B_IDX);
3041 cInRet = bitVectBitValue(result, C_IDX);
3042 dInRet = bitVectBitValue(result, D_IDX);
3043 eInRet = bitVectBitValue(result, E_IDX);
3053 if (_G.stack.pushedDE)
3055 if (dInRet && eInRet)
3057 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3061 /* Only restore E */
3068 /* Only restore D */
3076 _G.stack.pushedDE = FALSE;
3079 if (_G.stack.pushedBC)
3081 if (bInRet && cInRet)
3083 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3087 /* Only restore C */
3094 /* Only restore B */
3102 _G.stack.pushedBC = FALSE;
3106 /*-----------------------------------------------------------------*/
3107 /* genCall - generates a call statement */
3108 /*-----------------------------------------------------------------*/
3110 genCall (iCode * ic)
3112 emitCall (ic, FALSE);
3115 /*-----------------------------------------------------------------*/
3116 /* genPcall - generates a call by pointer statement */
3117 /*-----------------------------------------------------------------*/
3119 genPcall (iCode * ic)
3121 emitCall (ic, TRUE);
3124 /*-----------------------------------------------------------------*/
3125 /* resultRemat - result is rematerializable */
3126 /*-----------------------------------------------------------------*/
3128 resultRemat (iCode * ic)
3130 if (SKIP_IC (ic) || ic->op == IFX)
3133 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3135 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3136 if (sym->remat && !POINTER_SET (ic))
3143 extern set *publics;
3145 /*-----------------------------------------------------------------*/
3146 /* genFunction - generated code for function entry */
3147 /*-----------------------------------------------------------------*/
3149 genFunction (iCode * ic)
3153 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3156 bool bcInUse = FALSE;
3157 bool deInUse = FALSE;
3159 setArea (IFFUNC_NONBANKED (sym->type));
3161 /* PENDING: Reset the receive offset as it
3162 doesn't seem to get reset anywhere else.
3164 _G.receiveOffset = 0;
3166 /* Record the last function name for debugging. */
3167 _G.lastFunctionName = sym->rname;
3169 /* Create the function header */
3170 emit2 ("!functionheader", sym->name);
3171 if (!IS_STATIC(sym->etype))
3173 sprintf (buffer, "%s_start", sym->rname);
3174 emit2 ("!labeldef", buffer);
3175 _G.lines.current->isLabel = 1;
3177 emit2 ("!functionlabeldef", sym->rname);
3178 _G.lines.current->isLabel = 1;
3180 ftype = operandType (IC_LEFT (ic));
3182 if (IFFUNC_ISNAKED(ftype))
3184 emitDebug("; naked function: no prologue.");
3188 /* if this is an interrupt service routine
3189 then save all potentially used registers. */
3190 if (IFFUNC_ISISR (sym->type))
3192 /* If critical function then turn interrupts off */
3193 /* except when no interrupt number is given then it implies the NMI handler */
3194 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3203 /* This is a non-ISR function.
3204 If critical function then turn interrupts off */
3205 if (IFFUNC_ISCRITICAL (sym->type))
3213 //get interrupt enable flag IFF2 into P/O
3222 if (options.profile)
3224 emit2 ("!profileenter");
3227 /* PENDING: callee-save etc */
3229 _G.stack.param_offset = 0;
3231 if (z80_opts.calleeSavesBC)
3236 /* Detect which registers are used. */
3237 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3240 for (i = 0; i < sym->regsUsed->size; i++)
3242 if (bitVectBitValue (sym->regsUsed, i))
3256 /* Other systems use DE as a temporary. */
3267 _G.stack.param_offset += 2;
3270 _G.calleeSaves.pushedBC = bcInUse;
3275 _G.stack.param_offset += 2;
3278 _G.calleeSaves.pushedDE = deInUse;
3280 /* adjust the stack for the function */
3281 _G.stack.last = sym->stack;
3284 for (sym = setFirstItem (istack->syms); sym;
3285 sym = setNextItem (istack->syms))
3287 if (sym->_isparm && !IS_REGPARM (sym->etype))
3293 sym = OP_SYMBOL (IC_LEFT (ic));
3295 _G.omitFramePtr = options.ommitFramePtr;
3296 if (IS_Z80 && !stackParm && !sym->stack)
3298 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3299 /* the above !sym->stack condition can be removed. -- EEP */
3301 emit2 ("!ldaspsp", -sym->stack);
3302 _G.omitFramePtr = TRUE;
3304 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3305 emit2 ("!enterxl", sym->stack);
3306 else if (sym->stack)
3308 if ((optimize.codeSize && sym->stack <= 8) || sym->stack <= 4)
3310 int stack = sym->stack;
3321 emit2 ("!enterx", sym->stack);
3326 _G.stack.offset = sym->stack;
3329 /*-----------------------------------------------------------------*/
3330 /* genEndFunction - generates epilogue for functions */
3331 /*-----------------------------------------------------------------*/
3333 genEndFunction (iCode * ic)
3335 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3337 if (IFFUNC_ISNAKED(sym->type))
3339 emitDebug("; naked function: no epilogue.");
3343 /* PENDING: calleeSave */
3344 if (IS_Z80 && _G.omitFramePtr)
3346 if (_G.stack.offset)
3347 emit2 ("!ldaspsp", _G.stack.offset);
3349 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3351 emit2 ("!leavexl", _G.stack.offset);
3353 else if (_G.stack.offset)
3355 emit2 ("!leavex", _G.stack.offset);
3362 if (_G.calleeSaves.pushedDE)
3365 _G.calleeSaves.pushedDE = FALSE;
3368 if (_G.calleeSaves.pushedBC)
3371 _G.calleeSaves.pushedBC = FALSE;
3374 if (options.profile)
3376 emit2 ("!profileexit");
3379 /* if this is an interrupt service routine
3380 then save all potentially used registers. */
3381 if (IFFUNC_ISISR (sym->type))
3385 /* If critical function then turn interrupts back on */
3386 /* except when no interrupt number is given then it implies the NMI handler */
3387 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3394 /* This is a non-ISR function.
3395 If critical function then turn interrupts back on */
3396 if (IFFUNC_ISCRITICAL (sym->type))
3404 symbol *tlbl = newiTempLabel (NULL);
3407 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3408 //don't enable interrupts as they were off before
3409 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3411 emit2 ("!tlabeldef", (tlbl->key + 100));
3412 _G.lines.current->isLabel = 1;
3417 if (options.debug && currFunc)
3419 debugFile->writeEndFunction (currFunc, ic, 1);
3422 if (IFFUNC_ISISR (sym->type))
3424 /* "critical interrupt" is used to imply NMI handler */
3425 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3432 /* Both banked and non-banked just ret */
3436 if (!IS_STATIC(sym->etype))
3438 sprintf (buffer, "%s_end", sym->rname);
3439 emit2 ("!labeldef", buffer);
3440 _G.lines.current->isLabel = 1;
3443 _G.flushStatics = 1;
3444 _G.stack.pushed = 0;
3445 _G.stack.offset = 0;
3448 /*-----------------------------------------------------------------*/
3449 /* genRet - generate code for return statement */
3450 /*-----------------------------------------------------------------*/
3455 /* Errk. This is a hack until I can figure out how
3456 to cause dehl to spill on a call */
3457 int size, offset = 0;
3459 /* if we have no return value then
3460 just generate the "ret" */
3464 /* we have something to return then
3465 move the return value into place */
3466 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3467 size = AOP_SIZE (IC_LEFT (ic));
3469 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3472 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3476 emit2 ("ld de,%s", l);
3480 emit2 ("ld hl,%s", l);
3486 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3490 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3492 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3493 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3499 l = aopGet (AOP (IC_LEFT (ic)), offset,
3501 if (strcmp (_fReturn[offset], l))
3502 emit2 ("ld %s,%s", _fReturn[offset], l);
3507 freeAsmop (IC_LEFT (ic), NULL, ic);
3510 /* generate a jump to the return label
3511 if the next is not the return statement */
3512 if (!(ic->next && ic->next->op == LABEL &&
3513 IC_LABEL (ic->next) == returnLabel))
3515 emit2 ("jp !tlabel", returnLabel->key + 100);
3518 /*-----------------------------------------------------------------*/
3519 /* genLabel - generates a label */
3520 /*-----------------------------------------------------------------*/
3522 genLabel (iCode * ic)
3524 /* special case never generate */
3525 if (IC_LABEL (ic) == entryLabel)
3528 emitLabel (IC_LABEL (ic)->key + 100);
3531 /*-----------------------------------------------------------------*/
3532 /* genGoto - generates a ljmp */
3533 /*-----------------------------------------------------------------*/
3535 genGoto (iCode * ic)
3537 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3540 /*-----------------------------------------------------------------*/
3541 /* genPlusIncr :- does addition with increment if possible */
3542 /*-----------------------------------------------------------------*/
3544 genPlusIncr (iCode * ic)
3546 unsigned int icount;
3547 unsigned int size = getDataSize (IC_RESULT (ic));
3548 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3550 /* will try to generate an increment */
3551 /* if the right side is not a literal
3553 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3556 emitDebug ("; genPlusIncr");
3558 icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3560 /* If result is a pair */
3561 if (resultId != PAIR_INVALID)
3563 if (isLitWord (AOP (IC_LEFT (ic))))
3565 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3568 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3570 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3572 PAIR_ID freep = getFreePairId (ic);
3573 if (freep != PAIR_INVALID)
3575 fetchPair (freep, AOP (IC_RIGHT (ic)));
3576 emit2 ("add hl,%s", _pairs[freep].name);
3582 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3583 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3590 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3594 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3598 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3603 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3605 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3606 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3610 /* if the literal value of the right hand side
3611 is greater than 4 then it is not worth it */
3615 /* if increment 16 bits in register */
3616 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3622 symbol *tlbl = NULL;
3623 tlbl = newiTempLabel (NULL);
3626 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3629 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3632 emitLabel (tlbl->key + 100);
3636 /* if the sizes are greater than 1 then we cannot */
3637 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3638 AOP_SIZE (IC_LEFT (ic)) > 1)
3641 /* If the result is in a register then we can load then increment.
3643 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3645 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3648 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3653 /* we can if the aops of the left & result match or
3654 if they are in registers and the registers are the
3656 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3660 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3668 /*-----------------------------------------------------------------*/
3669 /* outBitAcc - output a bit in acc */
3670 /*-----------------------------------------------------------------*/
3672 outBitAcc (operand * result)
3674 symbol *tlbl = newiTempLabel (NULL);
3675 /* if the result is a bit */
3676 if (AOP_TYPE (result) == AOP_CRY)
3678 wassertl (0, "Tried to write A into a bit");
3682 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3683 emit2 ("ld a,!one");
3684 emitLabel (tlbl->key + 100);
3690 couldDestroyCarry (asmop *aop)
3694 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3703 shiftIntoPair (int idx, asmop *aop)
3705 PAIR_ID id = PAIR_INVALID;
3707 wassertl (IS_Z80, "Only implemented for the Z80");
3708 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3710 emitDebug ("; Shift into pair idx %u", idx);
3716 setupPair (PAIR_HL, aop, 0);
3721 setupPair (PAIR_IY, aop, 0);
3723 emit2 ("pop %s", _pairs[id].name);
3727 setupPair (PAIR_IY, aop, 0);
3730 wassertl (0, "Internal error - hit default case");
3733 aop->type = AOP_PAIRPTR;
3734 aop->aopu.aop_pairId = id;
3735 _G.pairs[id].offset = 0;
3736 _G.pairs[id].last_type = aop->type;
3740 setupToPreserveCarry (iCode * ic)
3742 asmop *left = AOP (IC_LEFT (ic));
3743 asmop *right = AOP (IC_RIGHT (ic));
3744 asmop *result = AOP (IC_RESULT (ic));
3746 wassert (left && right);
3750 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3752 shiftIntoPair (0, right);
3753 /* check result again, in case right == result */
3754 if (couldDestroyCarry (result))
3756 if (!isPairInUse (PAIR_DE, ic))
3757 shiftIntoPair (1, result);
3759 shiftIntoPair (2, result);
3762 else if (couldDestroyCarry (right))
3764 if (getPairId (result) == PAIR_HL)
3765 _G.preserveCarry = TRUE;
3767 shiftIntoPair (0, right);
3769 else if (couldDestroyCarry (result))
3771 shiftIntoPair (0, result);
3780 /*-----------------------------------------------------------------*/
3781 /* genPlus - generates code for addition */
3782 /*-----------------------------------------------------------------*/
3784 genPlus (iCode * ic)
3786 int size, offset = 0;
3788 /* special cases :- */
3790 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3791 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3792 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3794 /* Swap the left and right operands if:
3796 if literal, literal on the right or
3797 if left requires ACC or right is already
3800 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3801 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3802 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3804 operand *t = IC_RIGHT (ic);
3805 IC_RIGHT (ic) = IC_LEFT (ic);
3809 /* if both left & right are in bit
3811 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3812 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3815 wassertl (0, "Tried to add two bits");
3818 /* if left in bit space & right literal */
3819 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3820 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3822 /* Can happen I guess */
3823 wassertl (0, "Tried to add a bit to a literal");
3826 /* if I can do an increment instead
3827 of add then GOOD for ME */
3828 if (genPlusIncr (ic) == TRUE)
3831 size = getDataSize (IC_RESULT (ic));
3833 /* Special case when left and right are constant */
3834 if (isPair (AOP (IC_RESULT (ic))))
3837 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3838 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3840 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3846 sprintf (buffer, "#(%s + %s)", left, right);
3847 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3852 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3854 /* Fetch into HL then do the add */
3855 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3856 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3858 spillPair (PAIR_HL);
3860 if (left == PAIR_HL && right != PAIR_INVALID)
3862 emit2 ("add hl,%s", _pairs[right].name);
3865 else if (right == PAIR_HL && left != PAIR_INVALID)
3867 emit2 ("add hl,%s", _pairs[left].name);
3870 else if (right != PAIR_INVALID && right != PAIR_HL)
3872 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3873 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3876 else if (left != PAIR_INVALID && left != PAIR_HL)
3878 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3879 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3888 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3890 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3891 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3892 spillPair (PAIR_HL);
3893 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3897 if (isPair (AOP (IC_LEFT (ic))) && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && getPairId (AOP (IC_LEFT (ic))) != PAIR_HL)
3899 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3900 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3901 spillPair (PAIR_HL);
3902 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3907 ld hl,sp+n trashes C so we can't afford to do it during an
3908 add with stack based variables. Worst case is:
3921 So you can't afford to load up hl if either left, right, or result
3922 is on the stack (*sigh*) The alt is:
3930 Combinations in here are:
3931 * If left or right are in bc then the loss is small - trap later
3932 * If the result is in bc then the loss is also small
3936 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3937 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3938 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3940 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3941 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3942 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3943 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3945 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3947 /* Swap left and right */
3948 operand *t = IC_RIGHT (ic);
3949 IC_RIGHT (ic) = IC_LEFT (ic);
3952 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3954 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3955 emit2 ("add hl,bc");
3959 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3960 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3961 emit2 ("add hl,de");
3963 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3969 /* Be paranoid on the GB with 4 byte variables due to how C
3970 can be trashed by lda hl,n(sp).
3972 _gbz80_emitAddSubLong (ic, TRUE);
3977 setupToPreserveCarry (ic);
3979 /* This is ugly, but it fixes the worst code generation bug on Z80. */
3980 /* Probably something similar has to be done for addition of larger numbers, too. */
3983 _moveA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3984 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), 0, FALSE));
3985 if(strcmp (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), aopGet (AOP (IC_LEFT (ic)), 1, FALSE)))
3987 aopPut (AOP (IC_RESULT (ic)), "a", 0);
3988 _moveA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3992 emitDebug ("; Addition result is in same register as operand of next addition.");
3993 if(strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'c') ||
3994 strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'b') )
3998 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
4001 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4009 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
4012 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4018 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), 1, FALSE));
4019 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4025 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4028 if(size == 0 && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) == 1)
4031 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4034 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4035 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4039 _G.preserveCarry = FALSE;
4040 freeAsmop (IC_LEFT (ic), NULL, ic);
4041 freeAsmop (IC_RIGHT (ic), NULL, ic);
4042 freeAsmop (IC_RESULT (ic), NULL, ic);
4045 /*-----------------------------------------------------------------*/
4046 /* genMinusDec :- does subtraction with deccrement if possible */
4047 /*-----------------------------------------------------------------*/
4049 genMinusDec (iCode * ic)
4051 unsigned int icount;
4052 unsigned int size = getDataSize (IC_RESULT (ic));
4054 /* will try to generate an increment */
4055 /* if the right side is not a literal we cannot */
4056 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4059 /* if the literal value of the right hand side
4060 is greater than 4 then it is not worth it */
4061 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
4064 size = getDataSize (IC_RESULT (ic));
4066 /* if decrement 16 bits in register */
4067 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4068 (size > 1) && isPair (AOP (IC_RESULT (ic))))
4071 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4075 /* If result is a pair */
4076 if (isPair (AOP (IC_RESULT (ic))))
4078 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
4080 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4084 /* if increment 16 bits in register */
4085 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4089 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4092 emit2 ("dec %s", _getTempPairName());
4095 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4101 /* if the sizes are greater than 1 then we cannot */
4102 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4103 AOP_SIZE (IC_LEFT (ic)) > 1)
4106 /* we can if the aops of the left & result match or if they are in
4107 registers and the registers are the same */
4108 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4111 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4118 /*-----------------------------------------------------------------*/
4119 /* genMinus - generates code for subtraction */
4120 /*-----------------------------------------------------------------*/
4122 genMinus (iCode * ic)
4124 int size, offset = 0;
4125 unsigned long lit = 0L;
4127 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4128 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4129 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4131 /* special cases :- */
4132 /* if both left & right are in bit space */
4133 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4134 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4136 wassertl (0, "Tried to subtract two bits");
4140 /* if I can do an decrement instead of subtract then GOOD for ME */
4141 if (genMinusDec (ic) == TRUE)
4144 size = getDataSize (IC_RESULT (ic));
4146 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4151 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4155 /* Same logic as genPlus */
4158 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4159 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4160 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4162 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4163 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4164 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4165 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4167 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4168 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4170 if (left == PAIR_INVALID && right == PAIR_INVALID)
4175 else if (right == PAIR_INVALID)
4177 else if (left == PAIR_INVALID)
4180 fetchPair (left, AOP (IC_LEFT (ic)));
4181 /* Order is important. Right may be HL */
4182 fetchPair (right, AOP (IC_RIGHT (ic)));
4184 emit2 ("ld a,%s", _pairs[left].l);
4185 emit2 ("sub a,%s", _pairs[right].l);
4187 emit2 ("ld a,%s", _pairs[left].h);
4188 emit2 ("sbc a,%s", _pairs[right].h);
4190 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4192 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4194 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4200 /* Be paranoid on the GB with 4 byte variables due to how C
4201 can be trashed by lda hl,n(sp).
4203 _gbz80_emitAddSubLong (ic, FALSE);
4208 setupToPreserveCarry (ic);
4210 /* if literal, add a,#-lit, else normal subb */
4213 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4214 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4218 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4221 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4225 /* first add without previous c */
4228 if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
4231 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4234 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4236 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4239 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4240 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4241 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4243 wassertl (0, "Tried to subtract on a long pointer");
4247 _G.preserveCarry = FALSE;
4248 freeAsmop (IC_LEFT (ic), NULL, ic);
4249 freeAsmop (IC_RIGHT (ic), NULL, ic);
4250 freeAsmop (IC_RESULT (ic), NULL, ic);
4253 /*-----------------------------------------------------------------*/
4254 /* genMultChar - generates code for unsigned 8x8 multiplication */
4255 /*-----------------------------------------------------------------*/
4257 genMultOneChar (iCode * ic)
4259 symbol *tlbl1, *tlbl2;
4260 bool savedB = FALSE;
4264 wassertl (0, "Multiplication is handled through support function calls on gbz80");
4268 /* Save b into a if b is in use. */
4269 if (bitVectBitValue (ic->rMask, B_IDX) &&
4270 !(getPairId (AOP (IC_RESULT (ic))) == PAIR_BC))
4275 if (isPairInUse (PAIR_DE, ic) &&
4276 !(getPairId (AOP (IC_RESULT (ic))) == PAIR_DE))
4279 _G.stack.pushedDE = TRUE;
4282 tlbl1 = newiTempLabel (NULL);
4283 tlbl2 = newiTempLabel (NULL);
4285 emit2 ("ld e,%s", aopGet (AOP (IC_RIGHT (ic)), LSB, FALSE));
4286 emit2 ("ld h,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4287 emit2 ("ld l,#0x00");
4289 emit2 ("ld b,#0x08");
4290 emitLabel (tlbl1->key + 100);
4291 emit2 ("add hl,hl");
4292 emit2 ("jp NC,!tlabel", tlbl2->key + 100);
4293 emit2 ("add hl,de");
4294 emitLabel (tlbl2->key + 100);
4295 emit2 ("djnz !tlabel", tlbl1->key + 100);
4299 if (IS_Z80 && _G.stack.pushedDE)
4302 _G.stack.pushedDE = FALSE;
4309 if (AOP_SIZE (IC_RESULT (ic)) == 1)
4310 aopPut (AOP (IC_RESULT (ic)), "l", 0);
4312 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4314 freeAsmop (IC_LEFT (ic), NULL, ic);
4315 freeAsmop (IC_RIGHT (ic), NULL, ic);
4316 freeAsmop (IC_RESULT (ic), NULL, ic);
4319 /*-----------------------------------------------------------------*/
4320 /* genMult - generates code for multiplication */
4321 /*-----------------------------------------------------------------*/
4323 genMult (iCode * ic)
4327 /* If true then the final operation should be a subtract */
4328 bool active = FALSE;
4331 /* Shouldn't occur - all done through function calls */
4332 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4333 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4334 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4336 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4338 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4339 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4340 AOP_SIZE (IC_RESULT (ic)) > 2)
4342 wassertl (0, "Multiplication is handled through support function calls");
4345 /* Swap left and right such that right is a literal */
4346 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4348 operand *t = IC_RIGHT (ic);
4349 IC_RIGHT (ic) = IC_LEFT (ic);
4353 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4355 genMultOneChar (ic);
4359 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4361 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4362 // wassertl (val > 0, "Multiply must be positive");
4363 wassertl (val != 1, "Can't multiply by 1");
4365 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4367 _G.stack.pushedDE = TRUE;
4371 emit2 ("ld a,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4372 else if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4374 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4385 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4390 for (count = 0; count < 16; count++)
4392 if (count != 0 && active)
4397 emit2 ("add hl,hl");
4401 if (active == FALSE)
4416 emit2 ("add hl,de");
4425 if (IS_Z80 && _G.stack.pushedDE)
4428 _G.stack.pushedDE = FALSE;
4432 aopPut (AOP (IC_RESULT (ic)), "a", 0);
4434 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4436 freeAsmop (IC_LEFT (ic), NULL, ic);
4437 freeAsmop (IC_RIGHT (ic), NULL, ic);
4438 freeAsmop (IC_RESULT (ic), NULL, ic);
4441 /*-----------------------------------------------------------------*/
4442 /* genDiv - generates code for division */
4443 /*-----------------------------------------------------------------*/
4447 /* Shouldn't occur - all done through function calls */
4448 wassertl (0, "Division is handled through support function calls");
4451 /*-----------------------------------------------------------------*/
4452 /* genMod - generates code for division */
4453 /*-----------------------------------------------------------------*/
4457 /* Shouldn't occur - all done through function calls */
4461 /*-----------------------------------------------------------------*/
4462 /* genIfxJump :- will create a jump depending on the ifx */
4463 /*-----------------------------------------------------------------*/
4465 genIfxJump (iCode * ic, char *jval)
4470 /* if true label then we jump if condition
4474 jlbl = IC_TRUE (ic);
4475 if (!strcmp (jval, "a"))
4479 else if (!strcmp (jval, "c"))
4483 else if (!strcmp (jval, "nc"))
4487 else if (!strcmp (jval, "m"))
4491 else if (!strcmp (jval, "p"))
4497 /* The buffer contains the bit on A that we should test */
4503 /* false label is present */
4504 jlbl = IC_FALSE (ic);
4505 if (!strcmp (jval, "a"))
4509 else if (!strcmp (jval, "c"))
4513 else if (!strcmp (jval, "nc"))
4517 else if (!strcmp (jval, "m"))
4521 else if (!strcmp (jval, "p"))
4527 /* The buffer contains the bit on A that we should test */
4531 /* Z80 can do a conditional long jump */
4532 if (!strcmp (jval, "a"))
4536 else if (!strcmp (jval, "c"))
4539 else if (!strcmp (jval, "nc"))
4542 else if (!strcmp (jval, "m"))
4545 else if (!strcmp (jval, "p"))
4550 emit2 ("bit %s,a", jval);
4552 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4554 /* mark the icode as generated */
4560 _getPairIdName (PAIR_ID id)
4562 return _pairs[id].name;
4567 /* if unsigned char cmp with lit, just compare */
4569 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4571 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4574 emit2 ("xor a,!immedbyte", 0x80);
4575 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4578 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4580 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4582 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4583 // Pull left into DE and right into HL
4584 aopGet (AOP(left), LSB, FALSE);
4587 aopGet (AOP(right), LSB, FALSE);
4591 if (size == 0 && sign)
4593 // Highest byte when signed needs the bits flipped
4596 emit2 ("ld a,(de)");
4597 emit2 ("xor !immedbyte", 0x80);
4599 emit2 ("ld a,(hl)");
4600 emit2 ("xor !immedbyte", 0x80);
4604 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4608 emit2 ("ld a,(de)");
4609 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4619 spillPair (PAIR_HL);
4621 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4623 setupPair (PAIR_HL, AOP (left), 0);
4624 aopGet (AOP(right), LSB, FALSE);
4628 if (size == 0 && sign)
4630 // Highest byte when signed needs the bits flipped
4633 emit2 ("ld a,(hl)");
4634 emit2 ("xor !immedbyte", 0x80);
4636 emit2 ("ld a,%d(iy)", offset);
4637 emit2 ("xor !immedbyte", 0x80);
4641 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4645 emit2 ("ld a,(hl)");
4646 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4655 spillPair (PAIR_HL);
4656 spillPair (PAIR_IY);
4660 if (AOP_TYPE (right) == AOP_LIT)
4662 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4663 /* optimize if(x < 0) or if(x >= 0) */
4668 /* No sign so it's always false */
4673 /* Just load in the top most bit */
4674 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4675 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4677 genIfxJump (ifx, "7");
4689 /* First setup h and l contaning the top most bytes XORed */
4690 bool fDidXor = FALSE;
4691 if (AOP_TYPE (left) == AOP_LIT)
4693 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4694 emit2 ("ld %s,!immedbyte", _fTmp[0],
4695 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4699 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4700 emit2 ("xor a,!immedbyte", 0x80);
4701 emit2 ("ld %s,a", _fTmp[0]);
4704 if (AOP_TYPE (right) == AOP_LIT)
4706 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4707 emit2 ("ld %s,!immedbyte", _fTmp[1],
4708 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4712 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4713 emit2 ("xor a,!immedbyte", 0x80);
4714 emit2 ("ld %s,a", _fTmp[1]);
4720 /* Do a long subtract */
4723 _moveA (aopGet (AOP (left), offset, FALSE));
4725 if (sign && size == 0)
4727 emit2 ("ld a,%s", _fTmp[0]);
4728 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4732 /* Subtract through, propagating the carry */
4733 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4741 /** Generic compare for > or <
4744 genCmp (operand * left, operand * right,
4745 operand * result, iCode * ifx, int sign)
4747 int size, offset = 0;
4748 unsigned long lit = 0L;
4750 /* if left & right are bit variables */
4751 if (AOP_TYPE (left) == AOP_CRY &&
4752 AOP_TYPE (right) == AOP_CRY)
4754 /* Cant happen on the Z80 */
4755 wassertl (0, "Tried to compare two bits");
4759 /* Do a long subtract of right from left. */
4760 size = max (AOP_SIZE (left), AOP_SIZE (right));
4762 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4764 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4765 // Pull left into DE and right into HL
4766 aopGet (AOP(left), LSB, FALSE);
4769 aopGet (AOP(right), LSB, FALSE);
4773 emit2 ("ld a,(de)");
4774 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4783 spillPair (PAIR_HL);
4787 if (AOP_TYPE (right) == AOP_LIT)
4789 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4790 /* optimize if(x < 0) or if(x >= 0) */
4795 /* No sign so it's always false */
4800 /* Just load in the top most bit */
4801 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4802 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4804 genIfxJump (ifx, "7");
4815 genIfxJump (ifx, "nc");
4826 _moveA (aopGet (AOP (left), offset, FALSE));
4827 /* Subtract through, propagating the carry */
4828 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4834 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4838 /* Shift the sign bit up into carry */
4845 /* if the result is used in the next
4846 ifx conditional branch then generate
4847 code a little differently */
4855 genIfxJump (ifx, "c");
4859 genIfxJump (ifx, "m");
4864 genIfxJump (ifx, "c");
4871 /* Shift the sign bit up into carry */
4876 /* leave the result in acc */
4880 /*-----------------------------------------------------------------*/
4881 /* genCmpGt :- greater than comparison */
4882 /*-----------------------------------------------------------------*/
4884 genCmpGt (iCode * ic, iCode * ifx)
4886 operand *left, *right, *result;
4887 sym_link *letype, *retype;
4890 left = IC_LEFT (ic);
4891 right = IC_RIGHT (ic);
4892 result = IC_RESULT (ic);
4894 letype = getSpec (operandType (left));
4895 retype = getSpec (operandType (right));
4896 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4897 /* assign the asmops */
4898 aopOp (left, ic, FALSE, FALSE);
4899 aopOp (right, ic, FALSE, FALSE);
4900 aopOp (result, ic, TRUE, FALSE);
4902 setupToPreserveCarry (ic);
4904 genCmp (right, left, result, ifx, sign);
4906 _G.preserveCarry = FALSE;
4907 freeAsmop (left, NULL, ic);
4908 freeAsmop (right, NULL, ic);
4909 freeAsmop (result, NULL, ic);
4912 /*-----------------------------------------------------------------*/
4913 /* genCmpLt - less than comparisons */
4914 /*-----------------------------------------------------------------*/
4916 genCmpLt (iCode * ic, iCode * ifx)
4918 operand *left, *right, *result;
4919 sym_link *letype, *retype;
4922 left = IC_LEFT (ic);
4923 right = IC_RIGHT (ic);
4924 result = IC_RESULT (ic);
4926 letype = getSpec (operandType (left));
4927 retype = getSpec (operandType (right));
4928 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4930 /* assign the asmops */
4931 aopOp (left, ic, FALSE, FALSE);
4932 aopOp (right, ic, FALSE, FALSE);
4933 aopOp (result, ic, TRUE, FALSE);
4935 setupToPreserveCarry (ic);
4937 genCmp (left, right, result, ifx, sign);
4939 _G.preserveCarry = FALSE;
4940 freeAsmop (left, NULL, ic);
4941 freeAsmop (right, NULL, ic);
4942 freeAsmop (result, NULL, ic);
4945 /*-----------------------------------------------------------------*/
4946 /* gencjneshort - compare and jump if not equal */
4947 /* returns pair that still needs to be popped */
4948 /*-----------------------------------------------------------------*/
4950 gencjneshort (operand * left, operand * right, symbol * lbl)
4952 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4954 unsigned long lit = 0L;
4956 /* Swap the left and right if it makes the computation easier */
4957 if (AOP_TYPE (left) == AOP_LIT)
4964 /* if the right side is a literal then anything goes */
4965 if (AOP_TYPE (right) == AOP_LIT)
4967 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4970 _moveA (aopGet (AOP (left), offset, FALSE));
4975 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4982 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4988 _moveA (aopGet (AOP (left), offset, FALSE));
4989 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4992 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4993 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4998 /* if the right side is in a register or
4999 pointed to by HL, IX or IY */
5000 else if (AOP_TYPE (right) == AOP_REG ||
5001 AOP_TYPE (right) == AOP_HL ||
5002 AOP_TYPE (right) == AOP_IY ||
5003 AOP_TYPE (right) == AOP_STK ||
5004 AOP_IS_PAIRPTR (right, PAIR_HL) ||
5005 AOP_IS_PAIRPTR (right, PAIR_IX) ||
5006 AOP_IS_PAIRPTR (right, PAIR_IY))
5010 _moveA (aopGet (AOP (left), offset, FALSE));
5011 if (AOP_TYPE (right) == AOP_LIT &&
5012 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5015 emit2 ("jp NZ,!tlabel", lbl->key + 100);
5019 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
5020 emit2 ("jp NZ,!tlabel", lbl->key + 100);
5025 /* right is in direct space or a pointer reg, need both a & b */
5029 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
5031 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
5032 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
5040 emit2 ("; direct compare");
5041 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
5042 _moveA (aopGet (AOP (right), offset, FALSE));
5043 emit2 ("sub %s", _pairs[pair].l);
5044 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
5049 return PAIR_INVALID;
5052 /*-----------------------------------------------------------------*/
5053 /* gencjne - compare and jump if not equal */
5054 /*-----------------------------------------------------------------*/
5056 gencjne (operand * left, operand * right, symbol * lbl)
5058 symbol *tlbl = newiTempLabel (NULL);
5060 PAIR_ID pop = gencjneshort (left, right, lbl);
5063 emit2 ("ld a,!one");
5064 emit2 ("!shortjp !tlabel", tlbl->key + 100);
5065 emitLabel (lbl->key + 100);
5067 emitLabel (tlbl->key + 100);
5071 /*-----------------------------------------------------------------*/
5072 /* genCmpEq - generates code for equal to */
5073 /*-----------------------------------------------------------------*/
5075 genCmpEq (iCode * ic, iCode * ifx)
5077 operand *left, *right, *result;
5079 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5080 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5081 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5083 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
5085 /* Swap operands if it makes the operation easier. ie if:
5086 1. Left is a literal.
5088 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
5090 operand *t = IC_RIGHT (ic);
5091 IC_RIGHT (ic) = IC_LEFT (ic);
5095 if (ifx && !AOP_SIZE (result))
5098 /* if they are both bit variables */
5099 if (AOP_TYPE (left) == AOP_CRY &&
5100 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5102 wassertl (0, "Tried to compare two bits");
5107 tlbl = newiTempLabel (NULL);
5108 pop = gencjneshort (left, right, tlbl);
5112 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
5113 emitLabel (tlbl->key + 100);
5118 /* PENDING: do this better */
5119 symbol *lbl = newiTempLabel (NULL);
5121 emit2 ("!shortjp !tlabel", lbl->key + 100);
5122 emitLabel (tlbl->key + 100);
5124 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
5125 emitLabel (lbl->key + 100);
5128 /* mark the icode as generated */
5133 /* if they are both bit variables */
5134 if (AOP_TYPE (left) == AOP_CRY &&
5135 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5137 wassertl (0, "Tried to compare a bit to either a literal or another bit");
5143 gencjne (left, right, newiTempLabel (NULL));
5144 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5151 genIfxJump (ifx, "a");
5154 /* if the result is used in an arithmetic operation
5155 then put the result in place */
5156 if (AOP_TYPE (result) != AOP_CRY)
5161 /* leave the result in acc */
5165 freeAsmop (left, NULL, ic);
5166 freeAsmop (right, NULL, ic);
5167 freeAsmop (result, NULL, ic);
5170 /*-----------------------------------------------------------------*/
5171 /* ifxForOp - returns the icode containing the ifx for operand */
5172 /*-----------------------------------------------------------------*/
5174 ifxForOp (operand * op, iCode * ic)
5176 /* if true symbol then needs to be assigned */
5177 if (IS_TRUE_SYMOP (op))
5180 /* if this has register type condition and
5181 the next instruction is ifx with the same operand
5182 and live to of the operand is upto the ifx only then */
5184 ic->next->op == IFX &&
5185 IC_COND (ic->next)->key == op->key &&
5186 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5192 /*-----------------------------------------------------------------*/
5193 /* genAndOp - for && operation */
5194 /*-----------------------------------------------------------------*/
5196 genAndOp (iCode * ic)
5198 operand *left, *right, *result;
5201 /* note here that && operations that are in an if statement are
5202 taken away by backPatchLabels only those used in arthmetic
5203 operations remain */
5204 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5205 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5206 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5208 /* if both are bit variables */
5209 if (AOP_TYPE (left) == AOP_CRY &&
5210 AOP_TYPE (right) == AOP_CRY)
5212 wassertl (0, "Tried to and two bits");
5216 tlbl = newiTempLabel (NULL);
5218 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5220 emitLabel (tlbl->key + 100);
5224 freeAsmop (left, NULL, ic);
5225 freeAsmop (right, NULL, ic);
5226 freeAsmop (result, NULL, ic);
5229 /*-----------------------------------------------------------------*/
5230 /* genOrOp - for || operation */
5231 /*-----------------------------------------------------------------*/
5233 genOrOp (iCode * ic)
5235 operand *left, *right, *result;
5238 /* note here that || operations that are in an
5239 if statement are taken away by backPatchLabels
5240 only those used in arthmetic operations remain */
5241 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5242 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5243 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5245 /* if both are bit variables */
5246 if (AOP_TYPE (left) == AOP_CRY &&
5247 AOP_TYPE (right) == AOP_CRY)
5249 wassertl (0, "Tried to OR two bits");
5253 tlbl = newiTempLabel (NULL);
5255 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5257 emitLabel (tlbl->key + 100);
5261 freeAsmop (left, NULL, ic);
5262 freeAsmop (right, NULL, ic);
5263 freeAsmop (result, NULL, ic);
5266 /*-----------------------------------------------------------------*/
5267 /* isLiteralBit - test if lit == 2^n */
5268 /*-----------------------------------------------------------------*/
5270 isLiteralBit (unsigned long lit)
5272 unsigned long pw[32] =
5273 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5274 0x100L, 0x200L, 0x400L, 0x800L,
5275 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5276 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5277 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5278 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5279 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5282 for (idx = 0; idx < 32; idx++)
5288 /*-----------------------------------------------------------------*/
5289 /* jmpTrueOrFalse - */
5290 /*-----------------------------------------------------------------*/
5292 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5294 // ugly but optimized by peephole
5297 symbol *nlbl = newiTempLabel (NULL);
5298 emit2 ("jp !tlabel", nlbl->key + 100);
5299 emitLabel (tlbl->key + 100);
5300 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5301 emitLabel (nlbl->key + 100);
5305 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5306 emitLabel (tlbl->key + 100);
5311 /*-----------------------------------------------------------------*/
5312 /* genAnd - code for and */
5313 /*-----------------------------------------------------------------*/
5315 genAnd (iCode * ic, iCode * ifx)
5317 operand *left, *right, *result;
5318 int size, offset = 0;
5319 unsigned long lit = 0L;
5322 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5323 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5324 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5326 /* if left is a literal & right is not then exchange them */
5327 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5328 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5330 operand *tmp = right;
5335 /* if result = right then exchange them */
5336 if (sameRegs (AOP (result), AOP (right)))
5338 operand *tmp = right;
5343 /* if right is bit then exchange them */
5344 if (AOP_TYPE (right) == AOP_CRY &&
5345 AOP_TYPE (left) != AOP_CRY)
5347 operand *tmp = right;
5351 if (AOP_TYPE (right) == AOP_LIT)
5352 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5354 size = AOP_SIZE (result);
5356 if (AOP_TYPE (left) == AOP_CRY)
5358 wassertl (0, "Tried to perform an AND with a bit as an operand");
5362 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5363 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5364 if ((AOP_TYPE (right) == AOP_LIT) &&
5365 (AOP_TYPE (result) == AOP_CRY) &&
5366 (AOP_TYPE (left) != AOP_CRY))
5368 symbol *tlbl = newiTempLabel (NULL);
5369 int sizel = AOP_SIZE (left);
5372 /* PENDING: Test case for this. */
5377 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5379 _moveA (aopGet (AOP (left), offset, FALSE));
5380 if (bytelit != 0x0FFL)
5382 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5389 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5393 // bit = left & literal
5397 emit2 ("!tlabeldef", tlbl->key + 100);
5398 _G.lines.current->isLabel = 1;
5400 // if(left & literal)
5405 jmpTrueOrFalse (ifx, tlbl);
5413 /* if left is same as result */
5414 if (sameRegs (AOP (result), AOP (left)))
5416 for (; size--; offset++)
5418 if (AOP_TYPE (right) == AOP_LIT)
5420 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5425 aopPut (AOP (result), "!zero", offset);
5428 _moveA (aopGet (AOP (left), offset, FALSE));
5430 aopGet (AOP (right), offset, FALSE));
5431 aopPut (AOP (left), "a", offset);
5438 if (AOP_TYPE (left) == AOP_ACC)
5440 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5444 _moveA (aopGet (AOP (left), offset, FALSE));
5446 aopGet (AOP (right), offset, FALSE));
5447 aopPut (AOP (left), "a", offset);
5454 // left & result in different registers
5455 if (AOP_TYPE (result) == AOP_CRY)
5457 wassertl (0, "Tried to AND where the result is in carry");
5461 for (; (size--); offset++)
5464 // result = left & right
5465 if (AOP_TYPE (right) == AOP_LIT)
5467 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5469 aopPut (AOP (result),
5470 aopGet (AOP (left), offset, FALSE),
5474 else if (bytelit == 0)
5476 aopPut (AOP (result), "!zero", offset);
5480 // faster than result <- left, anl result,right
5481 // and better if result is SFR
5482 if (AOP_TYPE (left) == AOP_ACC)
5483 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5486 _moveA (aopGet (AOP (left), offset, FALSE));
5488 aopGet (AOP (right), offset, FALSE));
5490 aopPut (AOP (result), "a", offset);
5497 freeAsmop (left, NULL, ic);
5498 freeAsmop (right, NULL, ic);
5499 freeAsmop (result, NULL, ic);
5502 /*-----------------------------------------------------------------*/
5503 /* genOr - code for or */
5504 /*-----------------------------------------------------------------*/
5506 genOr (iCode * ic, iCode * ifx)
5508 operand *left, *right, *result;
5509 int size, offset = 0;
5510 unsigned long lit = 0L;
5513 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5514 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5515 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5517 /* if left is a literal & right is not then exchange them */
5518 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5519 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5521 operand *tmp = right;
5526 /* if result = right then exchange them */
5527 if (sameRegs (AOP (result), AOP (right)))
5529 operand *tmp = right;
5534 /* if right is bit then exchange them */
5535 if (AOP_TYPE (right) == AOP_CRY &&
5536 AOP_TYPE (left) != AOP_CRY)
5538 operand *tmp = right;
5542 if (AOP_TYPE (right) == AOP_LIT)
5543 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5545 size = AOP_SIZE (result);
5547 if (AOP_TYPE (left) == AOP_CRY)
5549 wassertl (0, "Tried to OR where left is a bit");
5553 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5554 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5555 if ((AOP_TYPE (right) == AOP_LIT) &&
5556 (AOP_TYPE (result) == AOP_CRY) &&
5557 (AOP_TYPE (left) != AOP_CRY))
5559 symbol *tlbl = newiTempLabel (NULL);
5560 int sizel = AOP_SIZE (left);
5564 wassertl (0, "Result is assigned to a bit");
5566 /* PENDING: Modeled after the AND code which is inefficient. */
5569 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5571 _moveA (aopGet (AOP (left), offset, FALSE));
5572 /* OR with any literal is the same as OR with itself. */
5574 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5580 jmpTrueOrFalse (ifx, tlbl);
5585 /* if left is same as result */
5586 if (sameRegs (AOP (result), AOP (left)))
5588 for (; size--; offset++)
5590 if (AOP_TYPE (right) == AOP_LIT)
5592 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5596 _moveA (aopGet (AOP (left), offset, FALSE));
5598 aopGet (AOP (right), offset, FALSE));
5599 aopPut (AOP (result), "a", offset);
5604 if (AOP_TYPE (left) == AOP_ACC)
5605 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5608 _moveA (aopGet (AOP (left), offset, FALSE));
5610 aopGet (AOP (right), offset, FALSE));
5611 aopPut (AOP (result), "a", offset);
5618 // left & result in different registers
5619 if (AOP_TYPE (result) == AOP_CRY)
5621 wassertl (0, "Result of OR is in a bit");
5624 for (; (size--); offset++)
5627 // result = left & right
5628 if (AOP_TYPE (right) == AOP_LIT)
5630 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5632 aopPut (AOP (result),
5633 aopGet (AOP (left), offset, FALSE),
5638 // faster than result <- left, anl result,right
5639 // and better if result is SFR
5640 if (AOP_TYPE (left) == AOP_ACC)
5641 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5644 _moveA (aopGet (AOP (left), offset, FALSE));
5646 aopGet (AOP (right), offset, FALSE));
5648 aopPut (AOP (result), "a", offset);
5649 /* PENDING: something weird is going on here. Add exception. */
5650 if (AOP_TYPE (result) == AOP_ACC)
5656 freeAsmop (left, NULL, ic);
5657 freeAsmop (right, NULL, ic);
5658 freeAsmop (result, NULL, ic);
5661 /*-----------------------------------------------------------------*/
5662 /* genXor - code for xclusive or */
5663 /*-----------------------------------------------------------------*/
5665 genXor (iCode * ic, iCode * ifx)
5667 operand *left, *right, *result;
5668 int size, offset = 0;
5669 unsigned long lit = 0L;
5671 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5672 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5673 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5675 /* if left is a literal & right is not then exchange them */
5676 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5677 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5679 operand *tmp = right;
5684 /* if result = right then exchange them */
5685 if (sameRegs (AOP (result), AOP (right)))
5687 operand *tmp = right;
5692 /* if right is bit then exchange them */
5693 if (AOP_TYPE (right) == AOP_CRY &&
5694 AOP_TYPE (left) != AOP_CRY)
5696 operand *tmp = right;
5700 if (AOP_TYPE (right) == AOP_LIT)
5701 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5703 size = AOP_SIZE (result);
5705 if (AOP_TYPE (left) == AOP_CRY)
5707 wassertl (0, "Tried to XOR a bit");
5711 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5712 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5713 if ((AOP_TYPE (right) == AOP_LIT) &&
5714 (AOP_TYPE (result) == AOP_CRY) &&
5715 (AOP_TYPE (left) != AOP_CRY))
5717 symbol *tlbl = newiTempLabel (NULL);
5718 int sizel = AOP_SIZE (left);
5722 /* PENDING: Test case for this. */
5723 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5727 _moveA (aopGet (AOP (left), offset, FALSE));
5728 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5729 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5734 jmpTrueOrFalse (ifx, tlbl);
5738 wassertl (0, "Result of XOR was destined for a bit");
5743 /* if left is same as result */
5744 if (sameRegs (AOP (result), AOP (left)))
5746 for (; size--; offset++)
5748 if (AOP_TYPE (right) == AOP_LIT)
5750 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5754 _moveA (aopGet (AOP (left), offset, FALSE));
5756 aopGet (AOP (right), offset, FALSE));
5757 aopPut (AOP (result), "a", offset);
5762 if (AOP_TYPE (left) == AOP_ACC)
5764 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5768 _moveA (aopGet (AOP (left), offset, FALSE));
5770 aopGet (AOP (right), offset, FALSE));
5771 aopPut (AOP (result), "a", offset);
5778 // left & result in different registers
5779 if (AOP_TYPE (result) == AOP_CRY)
5781 wassertl (0, "Result of XOR is in a bit");
5784 for (; (size--); offset++)
5787 // result = left & right
5788 if (AOP_TYPE (right) == AOP_LIT)
5790 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5792 aopPut (AOP (result),
5793 aopGet (AOP (left), offset, FALSE),
5798 // faster than result <- left, anl result,right
5799 // and better if result is SFR
5800 if (AOP_TYPE (left) == AOP_ACC)
5802 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5806 _moveA (aopGet (AOP (left), offset, FALSE));
5808 aopGet (AOP (right), offset, FALSE));
5810 aopPut (AOP (result), "a", offset);
5815 freeAsmop (left, NULL, ic);
5816 freeAsmop (right, NULL, ic);
5817 freeAsmop (result, NULL, ic);
5820 /*-----------------------------------------------------------------*/
5821 /* genInline - write the inline code out */
5822 /*-----------------------------------------------------------------*/
5824 genInline (iCode * ic)
5826 char *buffer, *bp, *bp1;
5827 bool inComment = FALSE;
5829 _G.lines.isInline += (!options.asmpeep);
5831 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5833 /* emit each line as a code */
5851 /* Add \n for labels, not dirs such as c:\mydir */
5852 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5870 _G.lines.isInline -= (!options.asmpeep);
5874 /*-----------------------------------------------------------------*/
5875 /* genRRC - rotate right with carry */
5876 /*-----------------------------------------------------------------*/
5883 /*-----------------------------------------------------------------*/
5884 /* genRLC - generate code for rotate left with carry */
5885 /*-----------------------------------------------------------------*/
5892 /*-----------------------------------------------------------------*/
5893 /* genGetHbit - generates code get highest order bit */
5894 /*-----------------------------------------------------------------*/
5896 genGetHbit (iCode * ic)
5898 operand *left, *result;
5899 left = IC_LEFT (ic);
5900 result = IC_RESULT (ic);
5902 aopOp (left, ic, FALSE, FALSE);
5903 aopOp (result, ic, FALSE, FALSE);
5905 /* get the highest order byte into a */
5906 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5908 if (AOP_TYPE (result) == AOP_CRY)
5916 emit2 ("and a,!one");
5921 freeAsmop (left, NULL, ic);
5922 freeAsmop (result, NULL, ic);
5926 emitRsh2 (asmop *aop, int size, int is_signed)
5932 const char *l = aopGet (aop, size, FALSE);
5935 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5945 /*-----------------------------------------------------------------*/
5946 /* shiftR2Left2Result - shift right two bytes from left to result */
5947 /*-----------------------------------------------------------------*/
5949 shiftR2Left2Result (operand * left, int offl,
5950 operand * result, int offr,
5951 int shCount, int is_signed)
5956 movLeft2Result (left, offl, result, offr, 0);
5957 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5962 /* if (AOP(result)->type == AOP_REG) { */
5964 tlbl = newiTempLabel (NULL);
5966 /* Left is already in result - so now do the shift */
5967 /* Optimizing for speed by default. */
5968 if (!optimize.codeSize || shCount <= 2)
5972 emitRsh2 (AOP (result), size, is_signed);
5977 emit2 ("ld a,!immedbyte", shCount);
5979 emitLabel (tlbl->key + 100);
5981 emitRsh2 (AOP (result), size, is_signed);
5984 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5988 /*-----------------------------------------------------------------*/
5989 /* shiftL2Left2Result - shift left two bytes from left to result */
5990 /*-----------------------------------------------------------------*/
5992 shiftL2Left2Result (operand * left, int offl,
5993 operand * result, int offr, int shCount)
5995 if (sameRegs (AOP (result), AOP (left)) &&
5996 ((offl + MSB16) == offr))
6002 /* Copy left into result */
6003 movLeft2Result (left, offl, result, offr, 0);
6004 movLeft2Result (left, offl + 1, result, offr + 1, 0);
6010 if (getPairId (AOP (result)) == PAIR_HL)
6014 emit2 ("add hl,hl");
6021 symbol *tlbl, *tlbl1;
6024 tlbl = newiTempLabel (NULL);
6025 tlbl1 = newiTempLabel (NULL);
6027 if (AOP (result)->type == AOP_REG)
6031 for (offset = 0; offset < size; offset++)
6033 l = aopGet (AOP (result), offset, FALSE);
6037 emit2 ("sla %s", l);
6048 /* Left is already in result - so now do the shift */
6051 emit2 ("ld a,!immedbyte+1", shCount);
6052 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6053 emitLabel (tlbl->key + 100);
6058 l = aopGet (AOP (result), offset, FALSE);
6062 emit2 ("sla %s", l);
6073 emitLabel (tlbl1->key + 100);
6075 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6081 /*-----------------------------------------------------------------*/
6082 /* AccRol - rotate left accumulator by known count */
6083 /*-----------------------------------------------------------------*/
6085 AccRol (int shCount)
6087 shCount &= 0x0007; // shCount : 0..7
6164 /*-----------------------------------------------------------------*/
6165 /* AccLsh - left shift accumulator by known count */
6166 /*-----------------------------------------------------------------*/
6168 AccLsh (int shCount)
6170 static const unsigned char SLMask[] =
6172 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6181 else if (shCount == 2)
6188 /* rotate left accumulator */
6190 /* and kill the lower order bits */
6191 emit2 ("and a,!immedbyte", SLMask[shCount]);
6196 /*-----------------------------------------------------------------*/
6197 /* shiftL1Left2Result - shift left one byte from left to result */
6198 /*-----------------------------------------------------------------*/
6200 shiftL1Left2Result (operand * left, int offl,
6201 operand * result, int offr, int shCount)
6205 /* If operand and result are the same we can shift in place.
6206 However shifting in acc using add is cheaper than shifting
6207 in place using sla; when shifting by more than 2 shifting in
6208 acc is worth the additional effort for loading from/to acc. */
6209 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6212 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6216 l = aopGet (AOP (left), offl, FALSE);
6218 /* shift left accumulator */
6220 aopPut (AOP (result), "a", offr);
6224 /*-----------------------------------------------------------------*/
6225 /* genlshTwo - left shift two bytes by known amount */
6226 /*-----------------------------------------------------------------*/
6228 genlshTwo (operand * result, operand * left, int shCount)
6230 int size = AOP_SIZE (result);
6232 wassert (size == 2);
6234 /* if shCount >= 8 */
6242 movLeft2Result (left, LSB, result, MSB16, 0);
6243 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6244 aopPut (AOP (result), "!zero", LSB);
6248 movLeft2Result (left, LSB, result, MSB16, 0);
6249 aopPut (AOP (result), "!zero", 0);
6254 aopPut (AOP (result), "!zero", LSB);
6257 /* 0 <= shCount <= 7 */
6266 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6271 /*-----------------------------------------------------------------*/
6272 /* genlshOne - left shift a one byte quantity by known count */
6273 /*-----------------------------------------------------------------*/
6275 genlshOne (operand * result, operand * left, int shCount)
6277 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6280 /*-----------------------------------------------------------------*/
6281 /* genLeftShiftLiteral - left shifting by known count */
6282 /*-----------------------------------------------------------------*/
6284 genLeftShiftLiteral (operand * left,
6289 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6292 freeAsmop (right, NULL, ic);
6294 aopOp (left, ic, FALSE, FALSE);
6295 aopOp (result, ic, FALSE, FALSE);
6297 size = getSize (operandType (result));
6299 /* I suppose that the left size >= result size */
6301 if (shCount >= (size * 8))
6305 aopPut (AOP (result), "!zero", size);
6313 genlshOne (result, left, shCount);
6316 genlshTwo (result, left, shCount);
6319 wassertl (0, "Shifting of longs is currently unsupported");
6325 freeAsmop (left, NULL, ic);
6326 freeAsmop (result, NULL, ic);
6329 /*-----------------------------------------------------------------*/
6330 /* genLeftShift - generates code for left shifting */
6331 /*-----------------------------------------------------------------*/
6333 genLeftShift (iCode * ic)
6337 symbol *tlbl, *tlbl1;
6338 operand *left, *right, *result;
6340 right = IC_RIGHT (ic);
6341 left = IC_LEFT (ic);
6342 result = IC_RESULT (ic);
6344 aopOp (right, ic, FALSE, FALSE);
6346 /* if the shift count is known then do it
6347 as efficiently as possible */
6348 if (AOP_TYPE (right) == AOP_LIT)
6350 genLeftShiftLiteral (left, right, result, ic);
6354 /* shift count is unknown then we have to form a loop get the loop
6355 count in B : Note: we take only the lower order byte since
6356 shifting more that 32 bits make no sense anyway, ( the largest
6357 size of an object can be only 32 bits ) */
6358 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6360 freeAsmop (right, NULL, ic);
6361 aopOp (left, ic, FALSE, FALSE);
6362 aopOp (result, ic, FALSE, FALSE);
6364 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6367 /* now move the left to the result if they are not the
6370 if (!sameRegs (AOP (left), AOP (result)))
6373 size = AOP_SIZE (result);
6377 l = aopGet (AOP (left), offset, FALSE);
6378 aopPut (AOP (result), l, offset);
6383 tlbl = newiTempLabel (NULL);
6384 size = AOP_SIZE (result);
6386 tlbl1 = newiTempLabel (NULL);
6388 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6391 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6392 emitLabel (tlbl->key + 100);
6393 l = aopGet (AOP (result), offset, FALSE);
6397 l = aopGet (AOP (result), offset, FALSE);
6401 emit2 ("sla %s", l);
6409 emitLabel (tlbl1->key + 100);
6411 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6413 freeAsmop (left, NULL, ic);
6414 freeAsmop (result, NULL, ic);
6417 /*-----------------------------------------------------------------*/
6418 /* genrshOne - left shift two bytes by known amount != 0 */
6419 /*-----------------------------------------------------------------*/
6421 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6424 int size = AOP_SIZE (result);
6427 wassert (size == 1);
6428 wassert (shCount < 8);
6430 l = aopGet (AOP (left), 0, FALSE);
6432 if (AOP (result)->type == AOP_REG)
6434 aopPut (AOP (result), l, 0);
6435 l = aopGet (AOP (result), 0, FALSE);
6438 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6446 emit2 ("%s a", is_signed ? "sra" : "srl");
6448 aopPut (AOP (result), "a", 0);
6452 /*-----------------------------------------------------------------*/
6453 /* AccRsh - right shift accumulator by known count */
6454 /*-----------------------------------------------------------------*/
6456 AccRsh (int shCount)
6458 static const unsigned char SRMask[] =
6460 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6465 /* rotate right accumulator */
6466 AccRol (8 - shCount);
6467 /* and kill the higher order bits */
6468 emit2 ("and a,!immedbyte", SRMask[shCount]);
6472 /*-----------------------------------------------------------------*/
6473 /* shiftR1Left2Result - shift right one byte from left to result */
6474 /*-----------------------------------------------------------------*/
6476 shiftR1Left2Result (operand * left, int offl,
6477 operand * result, int offr,
6478 int shCount, int sign)
6480 _moveA (aopGet (AOP (left), offl, FALSE));
6485 emit2 ("%s a", sign ? "sra" : "srl");
6492 aopPut (AOP (result), "a", offr);
6495 /*-----------------------------------------------------------------*/
6496 /* genrshTwo - right shift two bytes by known amount */
6497 /*-----------------------------------------------------------------*/
6499 genrshTwo (operand * result, operand * left,
6500 int shCount, int sign)
6502 /* if shCount >= 8 */
6508 shiftR1Left2Result (left, MSB16, result, LSB,
6513 movLeft2Result (left, MSB16, result, LSB, sign);
6517 /* Sign extend the result */
6518 _moveA(aopGet (AOP (result), 0, FALSE));
6522 aopPut (AOP (result), ACC_NAME, MSB16);
6526 aopPut (AOP (result), "!zero", 1);
6529 /* 0 <= shCount <= 7 */
6532 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6536 /*-----------------------------------------------------------------*/
6537 /* genRightShiftLiteral - left shifting by known count */
6538 /*-----------------------------------------------------------------*/
6540 genRightShiftLiteral (operand * left,
6546 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6549 freeAsmop (right, NULL, ic);
6551 aopOp (left, ic, FALSE, FALSE);
6552 aopOp (result, ic, FALSE, FALSE);
6554 size = getSize (operandType (result));
6556 /* I suppose that the left size >= result size */
6558 if (shCount >= (size * 8)) {
6560 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6561 _moveA(aopGet (AOP (left), 0, FALSE));
6569 aopPut (AOP (result), s, size);
6576 genrshOne (result, left, shCount, sign);
6579 genrshTwo (result, left, shCount, sign);
6582 wassertl (0, "Asked to shift right a long which should be a function call");
6585 wassertl (0, "Entered default case in right shift delegate");
6588 freeAsmop (left, NULL, ic);
6589 freeAsmop (result, NULL, ic);
6592 /*-----------------------------------------------------------------*/
6593 /* genRightShift - generate code for right shifting */
6594 /*-----------------------------------------------------------------*/
6596 genRightShift (iCode * ic)
6598 operand *right, *left, *result;
6600 int size, offset, first = 1;
6604 symbol *tlbl, *tlbl1;
6606 /* if signed then we do it the hard way preserve the
6607 sign bit moving it inwards */
6608 retype = getSpec (operandType (IC_RESULT (ic)));
6610 is_signed = !SPEC_USIGN (retype);
6612 /* signed & unsigned types are treated the same : i.e. the
6613 signed is NOT propagated inwards : quoting from the
6614 ANSI - standard : "for E1 >> E2, is equivalent to division
6615 by 2**E2 if unsigned or if it has a non-negative value,
6616 otherwise the result is implementation defined ", MY definition
6617 is that the sign does not get propagated */
6619 right = IC_RIGHT (ic);
6620 left = IC_LEFT (ic);
6621 result = IC_RESULT (ic);
6623 aopOp (right, ic, FALSE, FALSE);
6625 /* if the shift count is known then do it
6626 as efficiently as possible */
6627 if (AOP_TYPE (right) == AOP_LIT)
6629 genRightShiftLiteral (left, right, result, ic, is_signed);
6633 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6635 freeAsmop (right, NULL, ic);
6637 aopOp (left, ic, FALSE, FALSE);
6638 aopOp (result, ic, FALSE, FALSE);
6640 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6643 /* now move the left to the result if they are not the
6645 if (!sameRegs (AOP (left), AOP (result)))
6648 size = AOP_SIZE (result);
6652 l = aopGet (AOP (left), offset, FALSE);
6653 aopPut (AOP (result), l, offset);
6658 tlbl = newiTempLabel (NULL);
6659 tlbl1 = newiTempLabel (NULL);
6660 size = AOP_SIZE (result);
6663 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6666 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6667 emitLabel (tlbl->key + 100);
6670 l = aopGet (AOP (result), offset--, FALSE);
6673 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6681 emitLabel (tlbl1->key + 100);
6683 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6685 freeAsmop (left, NULL, ic);
6686 freeAsmop (result, NULL, ic);
6690 /*-----------------------------------------------------------------*/
6691 /* genUnpackBits - generates code for unpacking bits */
6692 /*-----------------------------------------------------------------*/
6694 genUnpackBits (operand * result, int pair)
6696 int offset = 0; /* result byte offset */
6697 int rsize; /* result size */
6698 int rlen = 0; /* remaining bitfield length */
6699 sym_link *etype; /* bitfield type information */
6700 int blen; /* bitfield length */
6701 int bstr; /* bitfield starting bit within byte */
6703 emitDebug ("; genUnpackBits");
6705 etype = getSpec (operandType (result));
6706 rsize = getSize (operandType (result));
6707 blen = SPEC_BLEN (etype);
6708 bstr = SPEC_BSTR (etype);
6710 /* If the bitfield length is less than a byte */
6713 emit2 ("ld a,!*pair", _pairs[pair].name);
6715 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6716 if (!SPEC_USIGN (etype))
6718 /* signed bitfield */
6719 symbol *tlbl = newiTempLabel (NULL);
6721 emit2 ("bit %d,a", blen - 1);
6722 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6723 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6724 emitLabel (tlbl->key + 100);
6726 aopPut (AOP (result), "a", offset++);
6730 /* TODO: what if pair == PAIR_DE ? */
6731 if (getPairId (AOP (result)) == PAIR_HL)
6733 wassertl (rsize == 2, "HL must be of size 2");
6734 emit2 ("ld a,!*hl");
6736 emit2 ("ld h,!*hl");
6739 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6740 if (!SPEC_USIGN (etype))
6742 /* signed bitfield */
6743 symbol *tlbl = newiTempLabel (NULL);
6745 emit2 ("bit %d,a", blen - 1);
6746 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6747 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6748 emitLabel (tlbl->key + 100);
6751 spillPair (PAIR_HL);
6755 /* Bit field did not fit in a byte. Copy all
6756 but the partial byte at the end. */
6757 for (rlen=blen;rlen>=8;rlen-=8)
6759 emit2 ("ld a,!*pair", _pairs[pair].name);
6760 aopPut (AOP (result), "a", offset++);
6763 emit2 ("inc %s", _pairs[pair].name);
6764 _G.pairs[pair].offset++;
6768 /* Handle the partial byte at the end */
6771 emit2 ("ld a,!*pair", _pairs[pair].name);
6772 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6773 if (!SPEC_USIGN (etype))
6775 /* signed bitfield */
6776 symbol *tlbl = newiTempLabel (NULL);
6778 emit2 ("bit %d,a", rlen - 1);
6779 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6780 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6781 emitLabel (tlbl->key + 100);
6783 aopPut (AOP (result), "a", offset++);
6791 if (SPEC_USIGN (etype))
6795 /* signed bitfield: sign extension with 0x00 or 0xff */
6803 aopPut (AOP (result), source, offset++);
6807 /*-----------------------------------------------------------------*/
6808 /* genGenPointerGet - get value from generic pointer space */
6809 /*-----------------------------------------------------------------*/
6811 genGenPointerGet (operand * left,
6812 operand * result, iCode * ic)
6815 sym_link *retype = getSpec (operandType (result));
6821 aopOp (left, ic, FALSE, FALSE);
6822 aopOp (result, ic, FALSE, FALSE);
6824 size = AOP_SIZE (result);
6826 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6829 if (isPtrPair (AOP (left)))
6831 tsprintf (buffer, sizeof(buffer),
6832 "!*pair", getPairName (AOP (left)));
6833 aopPut (AOP (result), buffer, 0);
6837 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6838 aopPut (AOP (result), "a", 0);
6840 freeAsmop (left, NULL, ic);
6844 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6851 tsprintf (at, sizeof(at), "!*iyx", offset);
6852 aopPut (AOP (result), at, offset);
6856 freeAsmop (left, NULL, ic);
6860 /* For now we always load into IY */
6861 /* if this is remateriazable */
6862 fetchPair (pair, AOP (left));
6864 /* if bit then unpack */
6865 if (IS_BITVAR (retype))
6867 genUnpackBits (result, pair);
6868 freeAsmop (left, NULL, ic);
6872 else if (getPairId (AOP (result)) == PAIR_HL)
6874 wassertl (size == 2, "HL must be of size 2");
6875 emit2 ("ld a,!*hl");
6877 emit2 ("ld h,!*hl");
6879 spillPair (PAIR_HL);
6881 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6883 size = AOP_SIZE (result);
6888 /* PENDING: make this better */
6889 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6891 aopPut (AOP (result), "!*hl", offset++);
6895 emit2 ("ld a,!*pair", _pairs[pair].name);
6896 aopPut (AOP (result), "a", offset++);
6900 emit2 ("inc %s", _pairs[pair].name);
6901 _G.pairs[pair].offset++;
6904 /* Fixup HL back down */
6905 for (size = AOP_SIZE (result)-1; size; size--)
6907 emit2 ("dec %s", _pairs[pair].name);
6912 size = AOP_SIZE (result);
6917 /* PENDING: make this better */
6919 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6921 aopPut (AOP (result), "!*hl", offset++);
6925 emit2 ("ld a,!*pair", _pairs[pair].name);
6926 aopPut (AOP (result), "a", offset++);
6930 emit2 ("inc %s", _pairs[pair].name);
6931 _G.pairs[pair].offset++;
6936 freeAsmop (left, NULL, ic);
6939 freeAsmop (result, NULL, ic);
6942 /*-----------------------------------------------------------------*/
6943 /* genPointerGet - generate code for pointer get */
6944 /*-----------------------------------------------------------------*/
6946 genPointerGet (iCode * ic)
6948 operand *left, *result;
6949 sym_link *type, *etype;
6951 left = IC_LEFT (ic);
6952 result = IC_RESULT (ic);
6954 /* depending on the type of pointer we need to
6955 move it to the correct pointer register */
6956 type = operandType (left);
6957 etype = getSpec (type);
6959 genGenPointerGet (left, result, ic);
6963 isRegOrLit (asmop * aop)
6965 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6971 /*-----------------------------------------------------------------*/
6972 /* genPackBits - generates code for packed bit storage */
6973 /*-----------------------------------------------------------------*/
6975 genPackBits (sym_link * etype,
6980 int offset = 0; /* source byte offset */
6981 int rlen = 0; /* remaining bitfield length */
6982 int blen; /* bitfield length */
6983 int bstr; /* bitfield starting bit within byte */
6984 int litval; /* source literal value (if AOP_LIT) */
6985 unsigned char mask; /* bitmask within current byte */
6986 int extraPair; /* a tempory register */
6987 bool needPopExtra=0; /* need to restore original value of temp reg */
6989 emitDebug ("; genPackBits","");
6991 blen = SPEC_BLEN (etype);
6992 bstr = SPEC_BSTR (etype);
6994 /* If the bitfield length is less than a byte */
6997 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6998 (unsigned char) (0xFF >> (8 - bstr)));
7000 if (AOP_TYPE (right) == AOP_LIT)
7002 /* Case with a bitfield length <8 and literal source
7004 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7006 litval &= (~mask) & 0xff;
7007 emit2 ("ld a,!*pair", _pairs[pair].name);
7008 if ((mask|litval)!=0xff)
7009 emit2 ("and a,!immedbyte", mask);
7011 emit2 ("or a,!immedbyte", litval);
7012 emit2 ("ld !*pair,a", _pairs[pair].name);
7017 /* Case with a bitfield length <8 and arbitrary source
7019 _moveA (aopGet (AOP (right), 0, FALSE));
7020 /* shift and mask source value */
7022 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7024 extraPair = getFreePairId(ic);
7025 if (extraPair == PAIR_INVALID)
7027 extraPair = PAIR_BC;
7028 if (getPairId (AOP (right)) != PAIR_BC
7029 || !isLastUse (ic, right))
7035 emit2 ("ld %s,a", _pairs[extraPair].l);
7036 emit2 ("ld a,!*pair", _pairs[pair].name);
7038 emit2 ("and a,!immedbyte", mask);
7039 emit2 ("or a,%s", _pairs[extraPair].l);
7040 emit2 ("ld !*pair,a", _pairs[pair].name);
7047 /* Bit length is greater than 7 bits. In this case, copy */
7048 /* all except the partial byte at the end */
7049 for (rlen=blen;rlen>=8;rlen-=8)
7051 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
7052 emit2 ("ld !*pair,a", _pairs[pair].name);
7055 emit2 ("inc %s", _pairs[pair].name);
7056 _G.pairs[pair].offset++;
7060 /* If there was a partial byte at the end */
7063 mask = (((unsigned char) -1 << rlen) & 0xff);
7065 if (AOP_TYPE (right) == AOP_LIT)
7067 /* Case with partial byte and literal source
7069 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7070 litval >>= (blen-rlen);
7071 litval &= (~mask) & 0xff;
7072 emit2 ("ld a,!*pair", _pairs[pair].name);
7073 if ((mask|litval)!=0xff)
7074 emit2 ("and a,!immedbyte", mask);
7076 emit2 ("or a,!immedbyte", litval);
7080 /* Case with partial byte and arbitrary source
7082 _moveA (aopGet (AOP (right), offset++, FALSE));
7083 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7085 extraPair = getFreePairId(ic);
7086 if (extraPair == PAIR_INVALID)
7088 extraPair = getPairId (AOP (right));
7089 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
7090 extraPair = PAIR_BC;
7092 if (getPairId (AOP (right)) != PAIR_BC
7093 || !isLastUse (ic, right))
7099 emit2 ("ld %s,a", _pairs[extraPair].l);
7100 emit2 ("ld a,!*pair", _pairs[pair].name);
7102 emit2 ("and a,!immedbyte", mask);
7103 emit2 ("or a,%s", _pairs[extraPair].l);
7108 emit2 ("ld !*pair,a", _pairs[pair].name);
7113 /*-----------------------------------------------------------------*/
7114 /* genGenPointerSet - stores the value into a pointer location */
7115 /*-----------------------------------------------------------------*/
7117 genGenPointerSet (operand * right,
7118 operand * result, iCode * ic)
7121 sym_link *retype = getSpec (operandType (right));
7122 sym_link *letype = getSpec (operandType (result));
7123 PAIR_ID pairId = PAIR_HL;
7126 aopOp (result, ic, FALSE, FALSE);
7127 aopOp (right, ic, FALSE, FALSE);
7132 size = AOP_SIZE (right);
7134 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
7135 emitDebug("; isBitvar = %d", isBitvar);
7137 /* Handle the exceptions first */
7138 if (isPair (AOP (result)) && size == 1 && !isBitvar)
7141 const char *l = aopGet (AOP (right), 0, FALSE);
7142 const char *pair = getPairName (AOP (result));
7143 if (canAssignToPtr (l) && isPtr (pair))
7145 emit2 ("ld !*pair,%s", pair, l);
7150 emit2 ("ld !*pair,a", pair);
7155 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7158 const char *l = aopGet (AOP (right), 0, FALSE);
7163 if (canAssignToPtr (l))
7165 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7169 _moveA (aopGet (AOP (right), offset, FALSE));
7170 emit2 ("ld !*iyx,a", offset);
7176 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7183 const char *l = aopGet (AOP (right), offset, FALSE);
7184 if (isRegOrLit (AOP (right)) && !IS_GB)
7186 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7191 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7195 emit2 ("inc %s", _pairs[PAIR_HL].name);
7196 _G.pairs[PAIR_HL].offset++;
7201 /* Fixup HL back down */
7202 for (size = AOP_SIZE (right)-1; size; size--)
7204 emit2 ("dec %s", _pairs[PAIR_HL].name);
7209 /* if the operand is already in dptr
7210 then we do nothing else we move the value to dptr */
7211 if (AOP_TYPE (result) != AOP_STR)
7213 fetchPair (pairId, AOP (result));
7215 /* so hl now contains the address */
7216 freeAsmop (result, NULL, ic);
7218 /* if bit then unpack */
7221 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7231 const char *l = aopGet (AOP (right), offset, FALSE);
7232 if (isRegOrLit (AOP (right)) && !IS_GB)
7234 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7239 emit2 ("ld !*pair,a", _pairs[pairId].name);
7243 emit2 ("inc %s", _pairs[pairId].name);
7244 _G.pairs[pairId].offset++;
7250 freeAsmop (right, NULL, ic);
7253 /*-----------------------------------------------------------------*/
7254 /* genPointerSet - stores the value into a pointer location */
7255 /*-----------------------------------------------------------------*/
7257 genPointerSet (iCode * ic)
7259 operand *right, *result;
7260 sym_link *type, *etype;
7262 right = IC_RIGHT (ic);
7263 result = IC_RESULT (ic);
7265 /* depending on the type of pointer we need to
7266 move it to the correct pointer register */
7267 type = operandType (result);
7268 etype = getSpec (type);
7270 genGenPointerSet (right, result, ic);
7273 /*-----------------------------------------------------------------*/
7274 /* genIfx - generate code for Ifx statement */
7275 /*-----------------------------------------------------------------*/
7277 genIfx (iCode * ic, iCode * popIc)
7279 operand *cond = IC_COND (ic);
7282 aopOp (cond, ic, FALSE, TRUE);
7284 /* get the value into acc */
7285 if (AOP_TYPE (cond) != AOP_CRY)
7289 /* the result is now in the accumulator */
7290 freeAsmop (cond, NULL, ic);
7292 /* if there was something to be popped then do it */
7296 /* if the condition is a bit variable */
7297 if (isbit && IS_ITEMP (cond) &&
7299 genIfxJump (ic, SPIL_LOC (cond)->rname);
7300 else if (isbit && !IS_ITEMP (cond))
7301 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7303 genIfxJump (ic, "a");
7308 /*-----------------------------------------------------------------*/
7309 /* genAddrOf - generates code for address of */
7310 /*-----------------------------------------------------------------*/
7312 genAddrOf (iCode * ic)
7314 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7316 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7318 /* if the operand is on the stack then we
7319 need to get the stack offset of this
7325 spillPair (PAIR_HL);
7326 if (sym->stack <= 0)
7328 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7332 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7334 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7338 emit2 ("ld de,!hashedstr", sym->rname);
7339 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7344 spillPair (PAIR_HL);
7347 /* if it has an offset then we need to compute it */
7349 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7351 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7352 emit2 ("add hl,sp");
7356 emit2 ("ld hl,!hashedstr", sym->rname);
7358 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7360 freeAsmop (IC_RESULT (ic), NULL, ic);
7363 /*-----------------------------------------------------------------*/
7364 /* genAssign - generate code for assignment */
7365 /*-----------------------------------------------------------------*/
7367 genAssign (iCode * ic)
7369 operand *result, *right;
7371 unsigned long lit = 0L;
7373 result = IC_RESULT (ic);
7374 right = IC_RIGHT (ic);
7376 /* Dont bother assigning if they are the same */
7377 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7379 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7383 aopOp (right, ic, FALSE, FALSE);
7384 aopOp (result, ic, TRUE, FALSE);
7386 /* if they are the same registers */
7387 if (sameRegs (AOP (right), AOP (result)))
7389 emitDebug ("; (registers are the same)");
7393 /* if the result is a bit */
7394 if (AOP_TYPE (result) == AOP_CRY)
7396 wassertl (0, "Tried to assign to a bit");
7400 size = AOP_SIZE (result);
7403 if (AOP_TYPE (right) == AOP_LIT)
7405 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7408 if (isPair (AOP (result)))
7410 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7412 else if ((size > 1) &&
7413 (AOP_TYPE (result) != AOP_REG) &&
7414 (AOP_TYPE (right) == AOP_LIT) &&
7415 !IS_FLOAT (operandType (right)) &&
7418 bool fXored = FALSE;
7420 /* Work from the top down.
7421 Done this way so that we can use the cached copy of 0
7422 in A for a fast clear */
7425 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7427 if (!fXored && size > 1)
7434 aopPut (AOP (result), "a", offset);
7438 aopPut (AOP (result), "!zero", offset);
7442 aopPut (AOP (result),
7443 aopGet (AOP (right), offset, FALSE),
7448 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7450 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7451 aopPut (AOP (result), "l", LSB);
7452 aopPut (AOP (result), "h", MSB16);
7454 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7456 /* Special case. Load into a and d, then load out. */
7457 _moveA (aopGet (AOP (right), 0, FALSE));
7458 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7459 aopPut (AOP (result), "a", 0);
7460 aopPut (AOP (result), "e", 1);
7462 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7464 /* Special case - simple memcpy */
7465 aopGet (AOP (right), LSB, FALSE);
7468 aopGet (AOP (result), LSB, FALSE);
7472 emit2 ("ld a,(de)");
7473 /* Peephole will optimise this. */
7474 emit2 ("ld (hl),a");
7482 spillPair (PAIR_HL);
7488 /* PENDING: do this check better */
7489 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7491 _moveA (aopGet (AOP (right), offset, FALSE));
7492 aopPut (AOP (result), "a", offset);
7495 aopPut (AOP (result),
7496 aopGet (AOP (right), offset, FALSE),
7503 freeAsmop (right, NULL, ic);
7504 freeAsmop (result, NULL, ic);
7507 /*-----------------------------------------------------------------*/
7508 /* genJumpTab - genrates code for jump table */
7509 /*-----------------------------------------------------------------*/
7511 genJumpTab (iCode * ic)
7516 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7517 /* get the condition into accumulator */
7518 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7521 emit2 ("ld e,%s", l);
7522 emit2 ("ld d,!zero");
7523 jtab = newiTempLabel (NULL);
7524 spillPair (PAIR_HL);
7525 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7526 emit2 ("add hl,de");
7527 emit2 ("add hl,de");
7528 emit2 ("add hl,de");
7529 freeAsmop (IC_JTCOND (ic), NULL, ic);
7533 emitLabel (jtab->key + 100);
7534 /* now generate the jump labels */
7535 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7536 jtab = setNextItem (IC_JTLABELS (ic)))
7537 emit2 ("jp !tlabel", jtab->key + 100);
7540 /*-----------------------------------------------------------------*/
7541 /* genCast - gen code for casting */
7542 /*-----------------------------------------------------------------*/
7544 genCast (iCode * ic)
7546 operand *result = IC_RESULT (ic);
7547 sym_link *rtype = operandType (IC_RIGHT (ic));
7548 operand *right = IC_RIGHT (ic);
7551 /* if they are equivalent then do nothing */
7552 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7555 aopOp (right, ic, FALSE, FALSE);
7556 aopOp (result, ic, FALSE, FALSE);
7558 /* if the result is a bit */
7559 if (AOP_TYPE (result) == AOP_CRY)
7561 wassertl (0, "Tried to cast to a bit");
7564 /* if they are the same size : or less */
7565 if (AOP_SIZE (result) <= AOP_SIZE (right))
7568 /* if they are in the same place */
7569 if (sameRegs (AOP (right), AOP (result)))
7572 /* if they in different places then copy */
7573 size = AOP_SIZE (result);
7577 aopPut (AOP (result),
7578 aopGet (AOP (right), offset, FALSE),
7585 /* So we now know that the size of destination is greater
7586 than the size of the source */
7587 /* we move to result for the size of source */
7588 size = AOP_SIZE (right);
7592 aopPut (AOP (result),
7593 aopGet (AOP (right), offset, FALSE),
7598 /* now depending on the sign of the destination */
7599 size = AOP_SIZE (result) - AOP_SIZE (right);
7600 /* Unsigned or not an integral type - right fill with zeros */
7601 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7604 aopPut (AOP (result), "!zero", offset++);
7608 /* we need to extend the sign :{ */
7609 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE);
7614 aopPut (AOP (result), "a", offset++);
7618 freeAsmop (right, NULL, ic);
7619 freeAsmop (result, NULL, ic);
7622 /*-----------------------------------------------------------------*/
7623 /* genReceive - generate code for a receive iCode */
7624 /*-----------------------------------------------------------------*/
7626 genReceive (iCode * ic)
7628 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7629 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7630 IS_TRUE_SYMOP (IC_RESULT (ic))))
7640 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7641 size = AOP_SIZE(IC_RESULT(ic));
7643 for (i = 0; i < size; i++) {
7644 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7648 freeAsmop (IC_RESULT (ic), NULL, ic);
7651 /*-----------------------------------------------------------------*/
7652 /* genDummyRead - generate code for dummy read of volatiles */
7653 /*-----------------------------------------------------------------*/
7655 genDummyRead (iCode * ic)
7661 if (op && IS_SYMOP (op))
7663 aopOp (op, ic, FALSE, FALSE);
7666 size = AOP_SIZE (op);
7671 _moveA (aopGet (AOP (op), offset, FALSE));
7675 freeAsmop (op, NULL, ic);
7679 if (op && IS_SYMOP (op))
7681 aopOp (op, ic, FALSE, FALSE);
7684 size = AOP_SIZE (op);
7689 _moveA (aopGet (AOP (op), offset, FALSE));
7693 freeAsmop (op, NULL, ic);
7697 /*-----------------------------------------------------------------*/
7698 /* genCritical - generate code for start of a critical sequence */
7699 /*-----------------------------------------------------------------*/
7701 genCritical (iCode *ic)
7703 symbol *tlbl = newiTempLabel (NULL);
7709 else if (IC_RESULT (ic))
7711 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7712 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7713 //get interrupt enable flag IFF2 into P/O
7717 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7718 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7719 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7720 emit2 ("!tlabeldef", (tlbl->key + 100));
7721 _G.lines.current->isLabel = 1;
7722 freeAsmop (IC_RESULT (ic), NULL, ic);
7726 //get interrupt enable flag IFF2 into P/O
7735 /*-----------------------------------------------------------------*/
7736 /* genEndCritical - generate code for end of a critical sequence */
7737 /*-----------------------------------------------------------------*/
7739 genEndCritical (iCode *ic)
7741 symbol *tlbl = newiTempLabel (NULL);
7747 else if (IC_RIGHT (ic))
7749 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7750 _toBoolean (IC_RIGHT (ic));
7751 //don't enable interrupts if they were off before
7752 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7754 emitLabel (tlbl->key + 100);
7755 freeAsmop (IC_RIGHT (ic), NULL, ic);
7761 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7762 //don't enable interrupts as they were off before
7763 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7765 emit2 ("!tlabeldef", (tlbl->key + 100));
7766 _G.lines.current->isLabel = 1;
7772 /** Maximum number of bytes to emit per line. */
7776 /** Context for the byte output chunker. */
7779 unsigned char buffer[DBEMIT_MAX_RUN];
7784 /** Flushes a byte chunker by writing out all in the buffer and
7788 _dbFlush(DBEMITCTX *self)
7795 sprintf(line, ".db 0x%02X", self->buffer[0]);
7797 for (i = 1; i < self->pos; i++)
7799 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7806 /** Write out another byte, buffering until a decent line is
7810 _dbEmit(DBEMITCTX *self, int c)
7812 if (self->pos == DBEMIT_MAX_RUN)
7816 self->buffer[self->pos++] = c;
7819 /** Context for a simple run length encoder. */
7823 unsigned char buffer[128];
7825 /** runLen may be equivalent to pos. */
7831 RLE_CHANGE_COST = 4,
7835 /** Flush the buffer of a run length encoder by writing out the run or
7836 data that it currently contains.
7839 _rleCommit(RLECTX *self)
7845 memset(&db, 0, sizeof(db));
7847 emit2(".db %u", self->pos);
7849 for (i = 0; i < self->pos; i++)
7851 _dbEmit(&db, self->buffer[i]);
7860 Can get either a run or a block of random stuff.
7861 Only want to change state if a good run comes in or a run ends.
7862 Detecting run end is easy.
7865 Say initial state is in run, len zero, last zero. Then if you get a
7866 few zeros then something else then a short run will be output.
7867 Seems OK. While in run mode, keep counting. While in random mode,
7868 keep a count of the run. If run hits margin, output all up to run,
7869 restart, enter run mode.
7872 /** Add another byte into the run length encoder, flushing as
7873 required. The run length encoder uses the Amiga IFF style, where
7874 a block is prefixed by its run length. A positive length means
7875 the next n bytes pass straight through. A negative length means
7876 that the next byte is repeated -n times. A zero terminates the
7880 _rleAppend(RLECTX *self, unsigned c)
7884 if (c != self->last)
7886 /* The run has stopped. See if it is worthwhile writing it out
7887 as a run. Note that the random data comes in as runs of
7890 if (self->runLen > RLE_CHANGE_COST)
7892 /* Yes, worthwhile. */
7893 /* Commit whatever was in the buffer. */
7895 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7899 /* Not worthwhile. Append to the end of the random list. */
7900 for (i = 0; i < self->runLen; i++)
7902 if (self->pos >= RLE_MAX_BLOCK)
7907 self->buffer[self->pos++] = self->last;
7915 if (self->runLen >= RLE_MAX_BLOCK)
7917 /* Commit whatever was in the buffer. */
7920 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7928 _rleFlush(RLECTX *self)
7930 _rleAppend(self, -1);
7937 /** genArrayInit - Special code for initialising an array with constant
7941 genArrayInit (iCode * ic)
7945 int elementSize = 0, eIndex, i;
7946 unsigned val, lastVal;
7950 memset(&rle, 0, sizeof(rle));
7952 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7954 _saveRegsForCall(ic, 0);
7956 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7957 emit2 ("call __initrleblock");
7959 type = operandType(IC_LEFT(ic));
7961 if (type && type->next)
7963 if (IS_SPEC(type->next) || IS_PTR(type->next))
7965 elementSize = getSize(type->next);
7967 else if (IS_ARRAY(type->next) && type->next->next)
7969 elementSize = getSize(type->next->next);
7973 printTypeChainRaw (type, NULL);
7974 wassertl (0, "Can't determine element size in genArrayInit.");
7979 wassertl (0, "Can't determine element size in genArrayInit.");
7982 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7984 iLoop = IC_ARRAYILIST(ic);
7985 lastVal = (unsigned)-1;
7987 /* Feed all the bytes into the run length encoder which will handle
7989 This works well for mixed char data, and for random int and long
7996 for (i = 0; i < ix; i++)
7998 for (eIndex = 0; eIndex < elementSize; eIndex++)
8000 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
8001 _rleAppend(&rle, val);
8005 iLoop = iLoop->next;
8009 /* Mark the end of the run. */
8012 _restoreRegsAfterCall();
8016 freeAsmop (IC_LEFT(ic), NULL, ic);
8020 _swap (PAIR_ID one, PAIR_ID two)
8022 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
8028 emit2 ("ld a,%s", _pairs[one].l);
8029 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
8030 emit2 ("ld %s,a", _pairs[two].l);
8031 emit2 ("ld a,%s", _pairs[one].h);
8032 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
8033 emit2 ("ld %s,a", _pairs[two].h);
8038 setupForMemcpy (iCode *ic, int nparams, operand **pparams)
8040 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
8042 PAIR_DE, PAIR_HL, PAIR_BC
8044 int i, j, nunity = 0;
8045 memset (ids, PAIR_INVALID, sizeof (ids));
8048 wassert (nparams == 3);
8050 for (i = 0; i < nparams; i++)
8052 aopOp (pparams[i], ic, FALSE, FALSE);
8053 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
8056 /* Count the number of unity or iTemp assigns. */
8057 for (i = 0; i < 3; i++)
8059 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
8067 /* Any order, fall through. */
8069 else if (nunity == 2)
8071 /* Two are OK. Assign the other one. */
8072 for (i = 0; i < 3; i++)
8074 for (j = 0; j < NUM_PAIRS; j++)
8076 if (ids[dest[i]][j] == TRUE)
8078 /* Found it. See if it's the right one. */
8079 if (j == PAIR_INVALID || j == dest[i])
8085 fetchPair(dest[i], AOP (pparams[i]));
8092 else if (nunity == 1)
8094 /* One is OK. Find the other two. */
8095 for (i = 0; i < 3; i++)
8097 for (j = 0; j < NUM_PAIRS; j++)
8099 if (ids[dest[i]][j] == TRUE)
8101 if (j == PAIR_INVALID || j == dest[i])
8103 /* This one is OK. */
8108 if(ids[j][dest[i]] == TRUE)
8116 fetchPair (dest[i], AOP (pparams[i]));
8126 int next = getPairId (AOP (pparams[0]));
8127 emit2 ("push %s", _pairs[next].name);
8129 if (next == dest[1])
8131 fetchPair (dest[1], AOP (pparams[1]));
8132 fetchPair (dest[2], AOP (pparams[2]));
8136 fetchPair (dest[2], AOP (pparams[2]));
8137 fetchPair (dest[1], AOP (pparams[1]));
8139 emit2 ("pop %s", _pairs[dest[0]].name);
8142 /* Finally pull out all of the iTemps */
8143 for (i = 0; i < 3; i++)
8145 if (ids[dest[i]][PAIR_INVALID] == 1)
8147 fetchPair (dest[i], AOP (pparams[i]));
8153 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8155 operand *from, *to, *count;
8157 wassertl (nParams == 3, "Built-in memcpy() must have three parameters");
8162 _saveRegsForCall (ic, 0);
8164 setupForMemcpy (ic, nParams, pparams);
8168 freeAsmop (count, NULL, ic->next->next);
8169 freeAsmop (from, NULL, ic);
8171 spillPair (PAIR_HL);
8173 _restoreRegsAfterCall();
8175 /* if we need assign a result value */
8176 if ((IS_ITEMP (IC_RESULT (ic)) &&
8177 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8178 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8179 IS_TRUE_SYMOP (IC_RESULT (ic)))
8181 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8182 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8183 freeAsmop (IC_RESULT (ic), NULL, ic);
8186 freeAsmop (to, NULL, ic->next);
8189 /*-----------------------------------------------------------------*/
8190 /* genBuiltIn - calls the appropriate function to generating code */
8191 /* for a built in function */
8192 /*-----------------------------------------------------------------*/
8193 static void genBuiltIn (iCode *ic)
8195 operand *bi_parms[MAX_BUILTIN_ARGS];
8200 /* get all the arguments for a built in function */
8201 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8203 /* which function is it */
8204 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8206 if (strcmp(bif->name,"__builtin_memcpy")==0)
8208 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8212 wassertl (0, "Unknown builtin function encountered");
8216 /*-----------------------------------------------------------------*/
8217 /* genZ80Code - generate code for Z80 based controllers */
8218 /*-----------------------------------------------------------------*/
8220 genZ80Code (iCode * lic)
8228 _fReturn = _gbz80_return;
8229 _fTmp = _gbz80_return;
8233 _fReturn = _z80_return;
8234 _fTmp = _z80_return;
8237 _G.lines.head = _G.lines.current = NULL;
8239 /* if debug information required */
8240 if (options.debug && currFunc)
8242 debugFile->writeFunction (currFunc, lic);
8245 for (ic = lic; ic; ic = ic->next)
8247 _G.current_iCode = ic;
8249 if (ic->lineno && cln != ic->lineno)
8253 debugFile->writeCLine (ic);
8255 if (!options.noCcodeInAsm)
8257 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8258 printCLine(ic->filename, ic->lineno));
8262 if (options.iCodeInAsm)
8264 const char *iLine = printILine(ic);
8265 emit2 (";ic:%d: %s", ic->key, iLine);
8268 /* if the result is marked as
8269 spilt and rematerializable or code for
8270 this has already been generated then
8272 if (resultRemat (ic) || ic->generated)
8275 /* depending on the operation */
8279 emitDebug ("; genNot");
8284 emitDebug ("; genCpl");
8289 emitDebug ("; genUminus");
8294 emitDebug ("; genIpush");
8299 /* IPOP happens only when trying to restore a
8300 spilt live range, if there is an ifx statement
8301 following this pop then the if statement might
8302 be using some of the registers being popped which
8303 would destroy the contents of the register so
8304 we need to check for this condition and handle it */
8306 ic->next->op == IFX &&
8307 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8309 emitDebug ("; genIfx");
8310 genIfx (ic->next, ic);
8314 emitDebug ("; genIpop");
8320 emitDebug ("; genCall");
8325 emitDebug ("; genPcall");
8330 emitDebug ("; genFunction");
8335 emitDebug ("; genEndFunction");
8336 genEndFunction (ic);
8340 emitDebug ("; genRet");
8345 emitDebug ("; genLabel");
8350 emitDebug ("; genGoto");
8355 emitDebug ("; genPlus");
8360 emitDebug ("; genMinus");
8365 emitDebug ("; genMult");
8370 emitDebug ("; genDiv");
8375 emitDebug ("; genMod");
8380 emitDebug ("; genCmpGt");
8381 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8385 emitDebug ("; genCmpLt");
8386 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8393 /* note these two are xlated by algebraic equivalence
8394 during parsing SDCC.y */
8395 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8396 "got '>=' or '<=' shouldn't have come here");
8400 emitDebug ("; genCmpEq");
8401 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8405 emitDebug ("; genAndOp");
8410 emitDebug ("; genOrOp");
8415 emitDebug ("; genXor");
8416 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8420 emitDebug ("; genOr");
8421 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8425 emitDebug ("; genAnd");
8426 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8430 emitDebug ("; genInline");
8435 emitDebug ("; genRRC");
8440 emitDebug ("; genRLC");
8445 emitDebug ("; genGetHBIT");
8450 emitDebug ("; genLeftShift");
8455 emitDebug ("; genRightShift");
8459 case GET_VALUE_AT_ADDRESS:
8460 emitDebug ("; genPointerGet");
8466 if (POINTER_SET (ic))
8468 emitDebug ("; genAssign (pointer)");
8473 emitDebug ("; genAssign");
8479 emitDebug ("; genIfx");
8484 emitDebug ("; genAddrOf");
8489 emitDebug ("; genJumpTab");
8494 emitDebug ("; genCast");
8499 emitDebug ("; genReceive");
8504 if (ic->builtinSEND)
8506 emitDebug ("; genBuiltIn");
8511 emitDebug ("; addSet");
8512 addSet (&_G.sendSet, ic);
8517 emitDebug ("; genArrayInit");
8521 case DUMMY_READ_VOLATILE:
8522 emitDebug ("; genDummyRead");
8527 emitDebug ("; genCritical");
8532 emitDebug ("; genEndCritical");
8533 genEndCritical (ic);
8542 /* now we are ready to call the
8543 peep hole optimizer */
8544 if (!options.nopeep)
8545 peepHole (&_G.lines.head);
8547 /* This is unfortunate */
8548 /* now do the actual printing */
8550 struct dbuf_s *buf = codeOutBuf;
8551 if (isInHome () && codeOutBuf == &code->oBuf)
8552 codeOutBuf = &home->oBuf;
8553 printLine (_G.lines.head, codeOutBuf);
8554 if (_G.flushStatics)
8557 _G.flushStatics = 0;
8562 freeTrace(&_G.lines.trace);
8563 freeTrace(&_G.trace.aops);
8569 _isPairUsed (iCode * ic, PAIR_ID pairId)
8575 if (bitVectBitValue (ic->rMask, D_IDX))
8577 if (bitVectBitValue (ic->rMask, E_IDX))
8587 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8590 value *val = aop->aopu.aop_lit;
8592 wassert (aop->type == AOP_LIT);
8593 wassert (!IS_FLOAT (val->type));
8595 v = ulFromVal (val);
8603 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8604 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));