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 if (size || ifx) /* emit jmp only, if it is actually used */
5390 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5394 // bit = left & literal
5398 emit2 ("!tlabeldef", tlbl->key + 100);
5399 _G.lines.current->isLabel = 1;
5401 // if(left & literal)
5406 jmpTrueOrFalse (ifx, tlbl);
5414 /* if left is same as result */
5415 if (sameRegs (AOP (result), AOP (left)))
5417 for (; size--; offset++)
5419 if (AOP_TYPE (right) == AOP_LIT)
5421 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5426 aopPut (AOP (result), "!zero", offset);
5429 _moveA (aopGet (AOP (left), offset, FALSE));
5431 aopGet (AOP (right), offset, FALSE));
5432 aopPut (AOP (left), "a", offset);
5439 if (AOP_TYPE (left) == AOP_ACC)
5441 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5445 _moveA (aopGet (AOP (left), offset, FALSE));
5447 aopGet (AOP (right), offset, FALSE));
5448 aopPut (AOP (left), "a", offset);
5455 // left & result in different registers
5456 if (AOP_TYPE (result) == AOP_CRY)
5458 wassertl (0, "Tried to AND where the result is in carry");
5462 for (; (size--); offset++)
5465 // result = left & right
5466 if (AOP_TYPE (right) == AOP_LIT)
5468 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5470 aopPut (AOP (result),
5471 aopGet (AOP (left), offset, FALSE),
5475 else if (bytelit == 0)
5477 aopPut (AOP (result), "!zero", offset);
5481 // faster than result <- left, anl result,right
5482 // and better if result is SFR
5483 if (AOP_TYPE (left) == AOP_ACC)
5484 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5487 _moveA (aopGet (AOP (left), offset, FALSE));
5489 aopGet (AOP (right), offset, FALSE));
5491 aopPut (AOP (result), "a", offset);
5498 freeAsmop (left, NULL, ic);
5499 freeAsmop (right, NULL, ic);
5500 freeAsmop (result, NULL, ic);
5503 /*-----------------------------------------------------------------*/
5504 /* genOr - code for or */
5505 /*-----------------------------------------------------------------*/
5507 genOr (iCode * ic, iCode * ifx)
5509 operand *left, *right, *result;
5510 int size, offset = 0;
5511 unsigned long lit = 0L;
5514 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5515 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5516 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5518 /* if left is a literal & right is not then exchange them */
5519 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5520 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5522 operand *tmp = right;
5527 /* if result = right then exchange them */
5528 if (sameRegs (AOP (result), AOP (right)))
5530 operand *tmp = right;
5535 /* if right is bit then exchange them */
5536 if (AOP_TYPE (right) == AOP_CRY &&
5537 AOP_TYPE (left) != AOP_CRY)
5539 operand *tmp = right;
5543 if (AOP_TYPE (right) == AOP_LIT)
5544 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5546 size = AOP_SIZE (result);
5548 if (AOP_TYPE (left) == AOP_CRY)
5550 wassertl (0, "Tried to OR where left is a bit");
5554 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5555 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5556 if ((AOP_TYPE (right) == AOP_LIT) &&
5557 (AOP_TYPE (result) == AOP_CRY) &&
5558 (AOP_TYPE (left) != AOP_CRY))
5560 symbol *tlbl = newiTempLabel (NULL);
5561 int sizel = AOP_SIZE (left);
5565 wassertl (0, "Result is assigned to a bit");
5567 /* PENDING: Modeled after the AND code which is inefficient. */
5570 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5572 _moveA (aopGet (AOP (left), offset, FALSE));
5575 { /* FIXME, allways true, shortcut possible */
5576 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5584 if (ifx) /* emit jmp only, if it is actually used */
5585 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5591 jmpTrueOrFalse (ifx, tlbl);
5596 /* if left is same as result */
5597 if (sameRegs (AOP (result), AOP (left)))
5599 for (; size--; offset++)
5601 if (AOP_TYPE (right) == AOP_LIT)
5603 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5607 _moveA (aopGet (AOP (left), offset, FALSE));
5609 aopGet (AOP (right), offset, FALSE));
5610 aopPut (AOP (result), "a", offset);
5615 if (AOP_TYPE (left) == AOP_ACC)
5616 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5619 _moveA (aopGet (AOP (left), offset, FALSE));
5621 aopGet (AOP (right), offset, FALSE));
5622 aopPut (AOP (result), "a", offset);
5629 // left & result in different registers
5630 if (AOP_TYPE (result) == AOP_CRY)
5632 wassertl (0, "Result of OR is in a bit");
5635 for (; (size--); offset++)
5638 // result = left & right
5639 if (AOP_TYPE (right) == AOP_LIT)
5641 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5643 aopPut (AOP (result),
5644 aopGet (AOP (left), offset, FALSE),
5649 // faster than result <- left, anl result,right
5650 // and better if result is SFR
5651 if (AOP_TYPE (left) == AOP_ACC)
5652 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5655 _moveA (aopGet (AOP (left), offset, FALSE));
5657 aopGet (AOP (right), offset, FALSE));
5659 aopPut (AOP (result), "a", offset);
5660 /* PENDING: something weird is going on here. Add exception. */
5661 if (AOP_TYPE (result) == AOP_ACC)
5667 freeAsmop (left, NULL, ic);
5668 freeAsmop (right, NULL, ic);
5669 freeAsmop (result, NULL, ic);
5672 /*-----------------------------------------------------------------*/
5673 /* genXor - code for xclusive or */
5674 /*-----------------------------------------------------------------*/
5676 genXor (iCode * ic, iCode * ifx)
5678 operand *left, *right, *result;
5679 int size, offset = 0;
5680 unsigned long lit = 0L;
5682 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5683 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5684 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5686 /* if left is a literal & right is not then exchange them */
5687 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5688 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5690 operand *tmp = right;
5695 /* if result = right then exchange them */
5696 if (sameRegs (AOP (result), AOP (right)))
5698 operand *tmp = right;
5703 /* if right is bit then exchange them */
5704 if (AOP_TYPE (right) == AOP_CRY &&
5705 AOP_TYPE (left) != AOP_CRY)
5707 operand *tmp = right;
5711 if (AOP_TYPE (right) == AOP_LIT)
5712 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5714 size = AOP_SIZE (result);
5716 if (AOP_TYPE (left) == AOP_CRY)
5718 wassertl (0, "Tried to XOR a bit");
5722 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5723 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5724 if ((AOP_TYPE (right) == AOP_LIT) &&
5725 (AOP_TYPE (result) == AOP_CRY) &&
5726 (AOP_TYPE (left) != AOP_CRY))
5728 symbol *tlbl = newiTempLabel (NULL);
5729 int sizel = AOP_SIZE (left);
5733 /* PENDING: Test case for this. */
5734 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5738 _moveA (aopGet (AOP (left), offset, FALSE));
5739 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5740 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5745 jmpTrueOrFalse (ifx, tlbl);
5749 wassertl (0, "Result of XOR was destined for a bit");
5754 /* if left is same as result */
5755 if (sameRegs (AOP (result), AOP (left)))
5757 for (; size--; offset++)
5759 if (AOP_TYPE (right) == AOP_LIT)
5761 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5765 _moveA (aopGet (AOP (left), offset, FALSE));
5767 aopGet (AOP (right), offset, FALSE));
5768 aopPut (AOP (result), "a", offset);
5773 if (AOP_TYPE (left) == AOP_ACC)
5775 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5779 _moveA (aopGet (AOP (left), offset, FALSE));
5781 aopGet (AOP (right), offset, FALSE));
5782 aopPut (AOP (result), "a", offset);
5789 // left & result in different registers
5790 if (AOP_TYPE (result) == AOP_CRY)
5792 wassertl (0, "Result of XOR is in a bit");
5795 for (; (size--); offset++)
5798 // result = left & right
5799 if (AOP_TYPE (right) == AOP_LIT)
5801 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5803 aopPut (AOP (result),
5804 aopGet (AOP (left), offset, FALSE),
5809 // faster than result <- left, anl result,right
5810 // and better if result is SFR
5811 if (AOP_TYPE (left) == AOP_ACC)
5813 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5817 _moveA (aopGet (AOP (left), offset, FALSE));
5819 aopGet (AOP (right), offset, FALSE));
5821 aopPut (AOP (result), "a", offset);
5826 freeAsmop (left, NULL, ic);
5827 freeAsmop (right, NULL, ic);
5828 freeAsmop (result, NULL, ic);
5831 /*-----------------------------------------------------------------*/
5832 /* genInline - write the inline code out */
5833 /*-----------------------------------------------------------------*/
5835 genInline (iCode * ic)
5837 char *buffer, *bp, *bp1;
5838 bool inComment = FALSE;
5840 _G.lines.isInline += (!options.asmpeep);
5842 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5844 /* emit each line as a code */
5862 /* Add \n for labels, not dirs such as c:\mydir */
5863 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5881 _G.lines.isInline -= (!options.asmpeep);
5885 /*-----------------------------------------------------------------*/
5886 /* genRRC - rotate right with carry */
5887 /*-----------------------------------------------------------------*/
5894 /*-----------------------------------------------------------------*/
5895 /* genRLC - generate code for rotate left with carry */
5896 /*-----------------------------------------------------------------*/
5903 /*-----------------------------------------------------------------*/
5904 /* genGetHbit - generates code get highest order bit */
5905 /*-----------------------------------------------------------------*/
5907 genGetHbit (iCode * ic)
5909 operand *left, *result;
5910 left = IC_LEFT (ic);
5911 result = IC_RESULT (ic);
5913 aopOp (left, ic, FALSE, FALSE);
5914 aopOp (result, ic, FALSE, FALSE);
5916 /* get the highest order byte into a */
5917 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5919 if (AOP_TYPE (result) == AOP_CRY)
5927 emit2 ("and a,!one");
5932 freeAsmop (left, NULL, ic);
5933 freeAsmop (result, NULL, ic);
5937 emitRsh2 (asmop *aop, int size, int is_signed)
5943 const char *l = aopGet (aop, size, FALSE);
5946 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5956 /*-----------------------------------------------------------------*/
5957 /* shiftR2Left2Result - shift right two bytes from left to result */
5958 /*-----------------------------------------------------------------*/
5960 shiftR2Left2Result (operand * left, int offl,
5961 operand * result, int offr,
5962 int shCount, int is_signed)
5967 movLeft2Result (left, offl, result, offr, 0);
5968 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5973 /* if (AOP(result)->type == AOP_REG) { */
5975 tlbl = newiTempLabel (NULL);
5977 /* Left is already in result - so now do the shift */
5978 /* Optimizing for speed by default. */
5979 if (!optimize.codeSize || shCount <= 2)
5983 emitRsh2 (AOP (result), size, is_signed);
5988 emit2 ("ld a,!immedbyte", shCount);
5990 emitLabel (tlbl->key + 100);
5992 emitRsh2 (AOP (result), size, is_signed);
5995 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5999 /*-----------------------------------------------------------------*/
6000 /* shiftL2Left2Result - shift left two bytes from left to result */
6001 /*-----------------------------------------------------------------*/
6003 shiftL2Left2Result (operand * left, int offl,
6004 operand * result, int offr, int shCount)
6006 if (sameRegs (AOP (result), AOP (left)) &&
6007 ((offl + MSB16) == offr))
6013 /* Copy left into result */
6014 movLeft2Result (left, offl, result, offr, 0);
6015 movLeft2Result (left, offl + 1, result, offr + 1, 0);
6021 if (getPairId (AOP (result)) == PAIR_HL)
6025 emit2 ("add hl,hl");
6032 symbol *tlbl, *tlbl1;
6035 tlbl = newiTempLabel (NULL);
6036 tlbl1 = newiTempLabel (NULL);
6038 if (AOP (result)->type == AOP_REG)
6042 for (offset = 0; offset < size; offset++)
6044 l = aopGet (AOP (result), offset, FALSE);
6048 emit2 ("sla %s", l);
6059 /* Left is already in result - so now do the shift */
6062 emit2 ("ld a,!immedbyte+1", shCount);
6063 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6064 emitLabel (tlbl->key + 100);
6069 l = aopGet (AOP (result), offset, FALSE);
6073 emit2 ("sla %s", l);
6084 emitLabel (tlbl1->key + 100);
6086 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6092 /*-----------------------------------------------------------------*/
6093 /* AccRol - rotate left accumulator by known count */
6094 /*-----------------------------------------------------------------*/
6096 AccRol (int shCount)
6098 shCount &= 0x0007; // shCount : 0..7
6175 /*-----------------------------------------------------------------*/
6176 /* AccLsh - left shift accumulator by known count */
6177 /*-----------------------------------------------------------------*/
6179 AccLsh (int shCount)
6181 static const unsigned char SLMask[] =
6183 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6192 else if (shCount == 2)
6199 /* rotate left accumulator */
6201 /* and kill the lower order bits */
6202 emit2 ("and a,!immedbyte", SLMask[shCount]);
6207 /*-----------------------------------------------------------------*/
6208 /* shiftL1Left2Result - shift left one byte from left to result */
6209 /*-----------------------------------------------------------------*/
6211 shiftL1Left2Result (operand * left, int offl,
6212 operand * result, int offr, int shCount)
6216 /* If operand and result are the same we can shift in place.
6217 However shifting in acc using add is cheaper than shifting
6218 in place using sla; when shifting by more than 2 shifting in
6219 acc is worth the additional effort for loading from/to acc. */
6220 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6223 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6227 l = aopGet (AOP (left), offl, FALSE);
6229 /* shift left accumulator */
6231 aopPut (AOP (result), "a", offr);
6235 /*-----------------------------------------------------------------*/
6236 /* genlshTwo - left shift two bytes by known amount */
6237 /*-----------------------------------------------------------------*/
6239 genlshTwo (operand * result, operand * left, int shCount)
6241 int size = AOP_SIZE (result);
6243 wassert (size == 2);
6245 /* if shCount >= 8 */
6253 movLeft2Result (left, LSB, result, MSB16, 0);
6254 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6255 aopPut (AOP (result), "!zero", LSB);
6259 movLeft2Result (left, LSB, result, MSB16, 0);
6260 aopPut (AOP (result), "!zero", 0);
6265 aopPut (AOP (result), "!zero", LSB);
6268 /* 0 <= shCount <= 7 */
6277 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6282 /*-----------------------------------------------------------------*/
6283 /* genlshOne - left shift a one byte quantity by known count */
6284 /*-----------------------------------------------------------------*/
6286 genlshOne (operand * result, operand * left, int shCount)
6288 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6291 /*-----------------------------------------------------------------*/
6292 /* genLeftShiftLiteral - left shifting by known count */
6293 /*-----------------------------------------------------------------*/
6295 genLeftShiftLiteral (operand * left,
6300 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6303 freeAsmop (right, NULL, ic);
6305 aopOp (left, ic, FALSE, FALSE);
6306 aopOp (result, ic, FALSE, FALSE);
6308 size = getSize (operandType (result));
6310 /* I suppose that the left size >= result size */
6312 if (shCount >= (size * 8))
6316 aopPut (AOP (result), "!zero", size);
6324 genlshOne (result, left, shCount);
6327 genlshTwo (result, left, shCount);
6330 wassertl (0, "Shifting of longs is currently unsupported");
6336 freeAsmop (left, NULL, ic);
6337 freeAsmop (result, NULL, ic);
6340 /*-----------------------------------------------------------------*/
6341 /* genLeftShift - generates code for left shifting */
6342 /*-----------------------------------------------------------------*/
6344 genLeftShift (iCode * ic)
6348 symbol *tlbl, *tlbl1;
6349 operand *left, *right, *result;
6351 right = IC_RIGHT (ic);
6352 left = IC_LEFT (ic);
6353 result = IC_RESULT (ic);
6355 aopOp (right, ic, FALSE, FALSE);
6357 /* if the shift count is known then do it
6358 as efficiently as possible */
6359 if (AOP_TYPE (right) == AOP_LIT)
6361 genLeftShiftLiteral (left, right, result, ic);
6365 /* shift count is unknown then we have to form a loop get the loop
6366 count in B : Note: we take only the lower order byte since
6367 shifting more that 32 bits make no sense anyway, ( the largest
6368 size of an object can be only 32 bits ) */
6369 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6371 freeAsmop (right, NULL, ic);
6372 aopOp (left, ic, FALSE, FALSE);
6373 aopOp (result, ic, FALSE, FALSE);
6375 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6378 /* now move the left to the result if they are not the
6381 if (!sameRegs (AOP (left), AOP (result)))
6384 size = AOP_SIZE (result);
6388 l = aopGet (AOP (left), offset, FALSE);
6389 aopPut (AOP (result), l, offset);
6394 tlbl = newiTempLabel (NULL);
6395 size = AOP_SIZE (result);
6397 tlbl1 = newiTempLabel (NULL);
6399 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6402 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6403 emitLabel (tlbl->key + 100);
6404 l = aopGet (AOP (result), offset, FALSE);
6408 l = aopGet (AOP (result), offset, FALSE);
6412 emit2 ("sla %s", l);
6420 emitLabel (tlbl1->key + 100);
6422 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6424 freeAsmop (left, NULL, ic);
6425 freeAsmop (result, NULL, ic);
6428 /*-----------------------------------------------------------------*/
6429 /* genrshOne - left shift two bytes by known amount != 0 */
6430 /*-----------------------------------------------------------------*/
6432 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6435 int size = AOP_SIZE (result);
6438 wassert (size == 1);
6439 wassert (shCount < 8);
6441 l = aopGet (AOP (left), 0, FALSE);
6443 if (AOP (result)->type == AOP_REG)
6445 aopPut (AOP (result), l, 0);
6446 l = aopGet (AOP (result), 0, FALSE);
6449 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6457 emit2 ("%s a", is_signed ? "sra" : "srl");
6459 aopPut (AOP (result), "a", 0);
6463 /*-----------------------------------------------------------------*/
6464 /* AccRsh - right shift accumulator by known count */
6465 /*-----------------------------------------------------------------*/
6467 AccRsh (int shCount)
6469 static const unsigned char SRMask[] =
6471 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6476 /* rotate right accumulator */
6477 AccRol (8 - shCount);
6478 /* and kill the higher order bits */
6479 emit2 ("and a,!immedbyte", SRMask[shCount]);
6483 /*-----------------------------------------------------------------*/
6484 /* shiftR1Left2Result - shift right one byte from left to result */
6485 /*-----------------------------------------------------------------*/
6487 shiftR1Left2Result (operand * left, int offl,
6488 operand * result, int offr,
6489 int shCount, int sign)
6491 _moveA (aopGet (AOP (left), offl, FALSE));
6496 emit2 ("%s a", sign ? "sra" : "srl");
6503 aopPut (AOP (result), "a", offr);
6506 /*-----------------------------------------------------------------*/
6507 /* genrshTwo - right shift two bytes by known amount */
6508 /*-----------------------------------------------------------------*/
6510 genrshTwo (operand * result, operand * left,
6511 int shCount, int sign)
6513 /* if shCount >= 8 */
6519 shiftR1Left2Result (left, MSB16, result, LSB,
6524 movLeft2Result (left, MSB16, result, LSB, sign);
6528 /* Sign extend the result */
6529 _moveA(aopGet (AOP (result), 0, FALSE));
6533 aopPut (AOP (result), ACC_NAME, MSB16);
6537 aopPut (AOP (result), "!zero", 1);
6540 /* 0 <= shCount <= 7 */
6543 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6547 /*-----------------------------------------------------------------*/
6548 /* genRightShiftLiteral - left shifting by known count */
6549 /*-----------------------------------------------------------------*/
6551 genRightShiftLiteral (operand * left,
6557 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6560 freeAsmop (right, NULL, ic);
6562 aopOp (left, ic, FALSE, FALSE);
6563 aopOp (result, ic, FALSE, FALSE);
6565 size = getSize (operandType (result));
6567 /* I suppose that the left size >= result size */
6569 if (shCount >= (size * 8)) {
6571 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6572 _moveA(aopGet (AOP (left), 0, FALSE));
6580 aopPut (AOP (result), s, size);
6587 genrshOne (result, left, shCount, sign);
6590 genrshTwo (result, left, shCount, sign);
6593 wassertl (0, "Asked to shift right a long which should be a function call");
6596 wassertl (0, "Entered default case in right shift delegate");
6599 freeAsmop (left, NULL, ic);
6600 freeAsmop (result, NULL, ic);
6603 /*-----------------------------------------------------------------*/
6604 /* genRightShift - generate code for right shifting */
6605 /*-----------------------------------------------------------------*/
6607 genRightShift (iCode * ic)
6609 operand *right, *left, *result;
6611 int size, offset, first = 1;
6615 symbol *tlbl, *tlbl1;
6617 /* if signed then we do it the hard way preserve the
6618 sign bit moving it inwards */
6619 retype = getSpec (operandType (IC_RESULT (ic)));
6621 is_signed = !SPEC_USIGN (retype);
6623 /* signed & unsigned types are treated the same : i.e. the
6624 signed is NOT propagated inwards : quoting from the
6625 ANSI - standard : "for E1 >> E2, is equivalent to division
6626 by 2**E2 if unsigned or if it has a non-negative value,
6627 otherwise the result is implementation defined ", MY definition
6628 is that the sign does not get propagated */
6630 right = IC_RIGHT (ic);
6631 left = IC_LEFT (ic);
6632 result = IC_RESULT (ic);
6634 aopOp (right, ic, FALSE, FALSE);
6636 /* if the shift count is known then do it
6637 as efficiently as possible */
6638 if (AOP_TYPE (right) == AOP_LIT)
6640 genRightShiftLiteral (left, right, result, ic, is_signed);
6644 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6646 freeAsmop (right, NULL, ic);
6648 aopOp (left, ic, FALSE, FALSE);
6649 aopOp (result, ic, FALSE, FALSE);
6651 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6654 /* now move the left to the result if they are not the
6656 if (!sameRegs (AOP (left), AOP (result)))
6659 size = AOP_SIZE (result);
6663 l = aopGet (AOP (left), offset, FALSE);
6664 aopPut (AOP (result), l, offset);
6669 tlbl = newiTempLabel (NULL);
6670 tlbl1 = newiTempLabel (NULL);
6671 size = AOP_SIZE (result);
6674 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6677 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6678 emitLabel (tlbl->key + 100);
6681 l = aopGet (AOP (result), offset--, FALSE);
6684 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6692 emitLabel (tlbl1->key + 100);
6694 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6696 freeAsmop (left, NULL, ic);
6697 freeAsmop (result, NULL, ic);
6701 /*-----------------------------------------------------------------*/
6702 /* genUnpackBits - generates code for unpacking bits */
6703 /*-----------------------------------------------------------------*/
6705 genUnpackBits (operand * result, int pair)
6707 int offset = 0; /* result byte offset */
6708 int rsize; /* result size */
6709 int rlen = 0; /* remaining bitfield length */
6710 sym_link *etype; /* bitfield type information */
6711 int blen; /* bitfield length */
6712 int bstr; /* bitfield starting bit within byte */
6714 emitDebug ("; genUnpackBits");
6716 etype = getSpec (operandType (result));
6717 rsize = getSize (operandType (result));
6718 blen = SPEC_BLEN (etype);
6719 bstr = SPEC_BSTR (etype);
6721 /* If the bitfield length is less than a byte */
6724 emit2 ("ld a,!*pair", _pairs[pair].name);
6726 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6727 if (!SPEC_USIGN (etype))
6729 /* signed bitfield */
6730 symbol *tlbl = newiTempLabel (NULL);
6732 emit2 ("bit %d,a", blen - 1);
6733 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6734 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6735 emitLabel (tlbl->key + 100);
6737 aopPut (AOP (result), "a", offset++);
6741 /* TODO: what if pair == PAIR_DE ? */
6742 if (getPairId (AOP (result)) == PAIR_HL)
6744 wassertl (rsize == 2, "HL must be of size 2");
6745 emit2 ("ld a,!*hl");
6747 emit2 ("ld h,!*hl");
6750 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6751 if (!SPEC_USIGN (etype))
6753 /* signed bitfield */
6754 symbol *tlbl = newiTempLabel (NULL);
6756 emit2 ("bit %d,a", blen - 1);
6757 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6758 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6759 emitLabel (tlbl->key + 100);
6762 spillPair (PAIR_HL);
6766 /* Bit field did not fit in a byte. Copy all
6767 but the partial byte at the end. */
6768 for (rlen=blen;rlen>=8;rlen-=8)
6770 emit2 ("ld a,!*pair", _pairs[pair].name);
6771 aopPut (AOP (result), "a", offset++);
6774 emit2 ("inc %s", _pairs[pair].name);
6775 _G.pairs[pair].offset++;
6779 /* Handle the partial byte at the end */
6782 emit2 ("ld a,!*pair", _pairs[pair].name);
6783 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6784 if (!SPEC_USIGN (etype))
6786 /* signed bitfield */
6787 symbol *tlbl = newiTempLabel (NULL);
6789 emit2 ("bit %d,a", rlen - 1);
6790 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6791 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6792 emitLabel (tlbl->key + 100);
6794 aopPut (AOP (result), "a", offset++);
6802 if (SPEC_USIGN (etype))
6806 /* signed bitfield: sign extension with 0x00 or 0xff */
6814 aopPut (AOP (result), source, offset++);
6818 /*-----------------------------------------------------------------*/
6819 /* genGenPointerGet - get value from generic pointer space */
6820 /*-----------------------------------------------------------------*/
6822 genGenPointerGet (operand * left,
6823 operand * result, iCode * ic)
6826 sym_link *retype = getSpec (operandType (result));
6832 aopOp (left, ic, FALSE, FALSE);
6833 aopOp (result, ic, FALSE, FALSE);
6835 size = AOP_SIZE (result);
6837 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6840 if (isPtrPair (AOP (left)))
6842 tsprintf (buffer, sizeof(buffer),
6843 "!*pair", getPairName (AOP (left)));
6844 aopPut (AOP (result), buffer, 0);
6848 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6849 aopPut (AOP (result), "a", 0);
6851 freeAsmop (left, NULL, ic);
6855 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6862 tsprintf (at, sizeof(at), "!*iyx", offset);
6863 aopPut (AOP (result), at, offset);
6867 freeAsmop (left, NULL, ic);
6871 /* For now we always load into IY */
6872 /* if this is remateriazable */
6873 fetchPair (pair, AOP (left));
6875 /* if bit then unpack */
6876 if (IS_BITVAR (retype))
6878 genUnpackBits (result, pair);
6879 freeAsmop (left, NULL, ic);
6883 else if (getPairId (AOP (result)) == PAIR_HL)
6885 wassertl (size == 2, "HL must be of size 2");
6886 emit2 ("ld a,!*hl");
6888 emit2 ("ld h,!*hl");
6890 spillPair (PAIR_HL);
6892 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6894 size = AOP_SIZE (result);
6899 /* PENDING: make this better */
6900 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6902 aopPut (AOP (result), "!*hl", offset++);
6906 emit2 ("ld a,!*pair", _pairs[pair].name);
6907 aopPut (AOP (result), "a", offset++);
6911 emit2 ("inc %s", _pairs[pair].name);
6912 _G.pairs[pair].offset++;
6915 /* Fixup HL back down */
6916 for (size = AOP_SIZE (result)-1; size; size--)
6918 emit2 ("dec %s", _pairs[pair].name);
6923 size = AOP_SIZE (result);
6928 /* PENDING: make this better */
6930 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6932 aopPut (AOP (result), "!*hl", offset++);
6936 emit2 ("ld a,!*pair", _pairs[pair].name);
6937 aopPut (AOP (result), "a", offset++);
6941 emit2 ("inc %s", _pairs[pair].name);
6942 _G.pairs[pair].offset++;
6947 freeAsmop (left, NULL, ic);
6950 freeAsmop (result, NULL, ic);
6953 /*-----------------------------------------------------------------*/
6954 /* genPointerGet - generate code for pointer get */
6955 /*-----------------------------------------------------------------*/
6957 genPointerGet (iCode * ic)
6959 operand *left, *result;
6960 sym_link *type, *etype;
6962 left = IC_LEFT (ic);
6963 result = IC_RESULT (ic);
6965 /* depending on the type of pointer we need to
6966 move it to the correct pointer register */
6967 type = operandType (left);
6968 etype = getSpec (type);
6970 genGenPointerGet (left, result, ic);
6974 isRegOrLit (asmop * aop)
6976 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6982 /*-----------------------------------------------------------------*/
6983 /* genPackBits - generates code for packed bit storage */
6984 /*-----------------------------------------------------------------*/
6986 genPackBits (sym_link * etype,
6991 int offset = 0; /* source byte offset */
6992 int rlen = 0; /* remaining bitfield length */
6993 int blen; /* bitfield length */
6994 int bstr; /* bitfield starting bit within byte */
6995 int litval; /* source literal value (if AOP_LIT) */
6996 unsigned char mask; /* bitmask within current byte */
6997 int extraPair; /* a tempory register */
6998 bool needPopExtra=0; /* need to restore original value of temp reg */
7000 emitDebug ("; genPackBits","");
7002 blen = SPEC_BLEN (etype);
7003 bstr = SPEC_BSTR (etype);
7005 /* If the bitfield length is less than a byte */
7008 mask = ((unsigned char) (0xFF << (blen + bstr)) |
7009 (unsigned char) (0xFF >> (8 - bstr)));
7011 if (AOP_TYPE (right) == AOP_LIT)
7013 /* Case with a bitfield length <8 and literal source
7015 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7017 litval &= (~mask) & 0xff;
7018 emit2 ("ld a,!*pair", _pairs[pair].name);
7019 if ((mask|litval)!=0xff)
7020 emit2 ("and a,!immedbyte", mask);
7022 emit2 ("or a,!immedbyte", litval);
7023 emit2 ("ld !*pair,a", _pairs[pair].name);
7028 /* Case with a bitfield length <8 and arbitrary source
7030 _moveA (aopGet (AOP (right), 0, FALSE));
7031 /* shift and mask source value */
7033 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7035 extraPair = getFreePairId(ic);
7036 if (extraPair == PAIR_INVALID)
7038 extraPair = PAIR_BC;
7039 if (getPairId (AOP (right)) != PAIR_BC
7040 || !isLastUse (ic, right))
7046 emit2 ("ld %s,a", _pairs[extraPair].l);
7047 emit2 ("ld a,!*pair", _pairs[pair].name);
7049 emit2 ("and a,!immedbyte", mask);
7050 emit2 ("or a,%s", _pairs[extraPair].l);
7051 emit2 ("ld !*pair,a", _pairs[pair].name);
7058 /* Bit length is greater than 7 bits. In this case, copy */
7059 /* all except the partial byte at the end */
7060 for (rlen=blen;rlen>=8;rlen-=8)
7062 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
7063 emit2 ("ld !*pair,a", _pairs[pair].name);
7066 emit2 ("inc %s", _pairs[pair].name);
7067 _G.pairs[pair].offset++;
7071 /* If there was a partial byte at the end */
7074 mask = (((unsigned char) -1 << rlen) & 0xff);
7076 if (AOP_TYPE (right) == AOP_LIT)
7078 /* Case with partial byte and literal source
7080 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7081 litval >>= (blen-rlen);
7082 litval &= (~mask) & 0xff;
7083 emit2 ("ld a,!*pair", _pairs[pair].name);
7084 if ((mask|litval)!=0xff)
7085 emit2 ("and a,!immedbyte", mask);
7087 emit2 ("or a,!immedbyte", litval);
7091 /* Case with partial byte and arbitrary source
7093 _moveA (aopGet (AOP (right), offset++, FALSE));
7094 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7096 extraPair = getFreePairId(ic);
7097 if (extraPair == PAIR_INVALID)
7099 extraPair = getPairId (AOP (right));
7100 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
7101 extraPair = PAIR_BC;
7103 if (getPairId (AOP (right)) != PAIR_BC
7104 || !isLastUse (ic, right))
7110 emit2 ("ld %s,a", _pairs[extraPair].l);
7111 emit2 ("ld a,!*pair", _pairs[pair].name);
7113 emit2 ("and a,!immedbyte", mask);
7114 emit2 ("or a,%s", _pairs[extraPair].l);
7119 emit2 ("ld !*pair,a", _pairs[pair].name);
7124 /*-----------------------------------------------------------------*/
7125 /* genGenPointerSet - stores the value into a pointer location */
7126 /*-----------------------------------------------------------------*/
7128 genGenPointerSet (operand * right,
7129 operand * result, iCode * ic)
7132 sym_link *retype = getSpec (operandType (right));
7133 sym_link *letype = getSpec (operandType (result));
7134 PAIR_ID pairId = PAIR_HL;
7137 aopOp (result, ic, FALSE, FALSE);
7138 aopOp (right, ic, FALSE, FALSE);
7143 size = AOP_SIZE (right);
7145 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
7146 emitDebug("; isBitvar = %d", isBitvar);
7148 /* Handle the exceptions first */
7149 if (isPair (AOP (result)) && size == 1 && !isBitvar)
7152 const char *l = aopGet (AOP (right), 0, FALSE);
7153 const char *pair = getPairName (AOP (result));
7154 if (canAssignToPtr (l) && isPtr (pair))
7156 emit2 ("ld !*pair,%s", pair, l);
7161 emit2 ("ld !*pair,a", pair);
7166 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7169 const char *l = aopGet (AOP (right), 0, FALSE);
7174 if (canAssignToPtr (l))
7176 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7180 _moveA (aopGet (AOP (right), offset, FALSE));
7181 emit2 ("ld !*iyx,a", offset);
7187 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7194 const char *l = aopGet (AOP (right), offset, FALSE);
7195 if (isRegOrLit (AOP (right)) && !IS_GB)
7197 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7202 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7206 emit2 ("inc %s", _pairs[PAIR_HL].name);
7207 _G.pairs[PAIR_HL].offset++;
7212 /* Fixup HL back down */
7213 for (size = AOP_SIZE (right)-1; size; size--)
7215 emit2 ("dec %s", _pairs[PAIR_HL].name);
7220 /* if the operand is already in dptr
7221 then we do nothing else we move the value to dptr */
7222 if (AOP_TYPE (result) != AOP_STR)
7224 fetchPair (pairId, AOP (result));
7226 /* so hl now contains the address */
7227 freeAsmop (result, NULL, ic);
7229 /* if bit then unpack */
7232 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7242 const char *l = aopGet (AOP (right), offset, FALSE);
7243 if (isRegOrLit (AOP (right)) && !IS_GB)
7245 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7250 emit2 ("ld !*pair,a", _pairs[pairId].name);
7254 emit2 ("inc %s", _pairs[pairId].name);
7255 _G.pairs[pairId].offset++;
7261 freeAsmop (right, NULL, ic);
7264 /*-----------------------------------------------------------------*/
7265 /* genPointerSet - stores the value into a pointer location */
7266 /*-----------------------------------------------------------------*/
7268 genPointerSet (iCode * ic)
7270 operand *right, *result;
7271 sym_link *type, *etype;
7273 right = IC_RIGHT (ic);
7274 result = IC_RESULT (ic);
7276 /* depending on the type of pointer we need to
7277 move it to the correct pointer register */
7278 type = operandType (result);
7279 etype = getSpec (type);
7281 genGenPointerSet (right, result, ic);
7284 /*-----------------------------------------------------------------*/
7285 /* genIfx - generate code for Ifx statement */
7286 /*-----------------------------------------------------------------*/
7288 genIfx (iCode * ic, iCode * popIc)
7290 operand *cond = IC_COND (ic);
7293 aopOp (cond, ic, FALSE, TRUE);
7295 /* get the value into acc */
7296 if (AOP_TYPE (cond) != AOP_CRY)
7300 /* the result is now in the accumulator */
7301 freeAsmop (cond, NULL, ic);
7303 /* if there was something to be popped then do it */
7307 /* if the condition is a bit variable */
7308 if (isbit && IS_ITEMP (cond) &&
7310 genIfxJump (ic, SPIL_LOC (cond)->rname);
7311 else if (isbit && !IS_ITEMP (cond))
7312 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7314 genIfxJump (ic, "a");
7319 /*-----------------------------------------------------------------*/
7320 /* genAddrOf - generates code for address of */
7321 /*-----------------------------------------------------------------*/
7323 genAddrOf (iCode * ic)
7325 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7327 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7329 /* if the operand is on the stack then we
7330 need to get the stack offset of this
7336 spillPair (PAIR_HL);
7337 if (sym->stack <= 0)
7339 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7343 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7345 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7349 emit2 ("ld de,!hashedstr", sym->rname);
7350 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7355 spillPair (PAIR_HL);
7358 /* if it has an offset then we need to compute it */
7360 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7362 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7363 emit2 ("add hl,sp");
7367 emit2 ("ld hl,!hashedstr", sym->rname);
7369 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7371 freeAsmop (IC_RESULT (ic), NULL, ic);
7374 /*-----------------------------------------------------------------*/
7375 /* genAssign - generate code for assignment */
7376 /*-----------------------------------------------------------------*/
7378 genAssign (iCode * ic)
7380 operand *result, *right;
7382 unsigned long lit = 0L;
7384 result = IC_RESULT (ic);
7385 right = IC_RIGHT (ic);
7387 /* Dont bother assigning if they are the same */
7388 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7390 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7394 aopOp (right, ic, FALSE, FALSE);
7395 aopOp (result, ic, TRUE, FALSE);
7397 /* if they are the same registers */
7398 if (sameRegs (AOP (right), AOP (result)))
7400 emitDebug ("; (registers are the same)");
7404 /* if the result is a bit */
7405 if (AOP_TYPE (result) == AOP_CRY)
7407 wassertl (0, "Tried to assign to a bit");
7411 size = AOP_SIZE (result);
7414 if (AOP_TYPE (right) == AOP_LIT)
7416 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7419 if (isPair (AOP (result)))
7421 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7423 else if ((size > 1) &&
7424 (AOP_TYPE (result) != AOP_REG) &&
7425 (AOP_TYPE (right) == AOP_LIT) &&
7426 !IS_FLOAT (operandType (right)) &&
7429 bool fXored = FALSE;
7431 /* Work from the top down.
7432 Done this way so that we can use the cached copy of 0
7433 in A for a fast clear */
7436 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7438 if (!fXored && size > 1)
7445 aopPut (AOP (result), "a", offset);
7449 aopPut (AOP (result), "!zero", offset);
7453 aopPut (AOP (result),
7454 aopGet (AOP (right), offset, FALSE),
7459 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7461 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7462 aopPut (AOP (result), "l", LSB);
7463 aopPut (AOP (result), "h", MSB16);
7465 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7467 /* Special case. Load into a and d, then load out. */
7468 _moveA (aopGet (AOP (right), 0, FALSE));
7469 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7470 aopPut (AOP (result), "a", 0);
7471 aopPut (AOP (result), "e", 1);
7473 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7475 /* Special case - simple memcpy */
7476 aopGet (AOP (right), LSB, FALSE);
7479 aopGet (AOP (result), LSB, FALSE);
7483 emit2 ("ld a,(de)");
7484 /* Peephole will optimise this. */
7485 emit2 ("ld (hl),a");
7493 spillPair (PAIR_HL);
7499 /* PENDING: do this check better */
7500 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7502 _moveA (aopGet (AOP (right), offset, FALSE));
7503 aopPut (AOP (result), "a", offset);
7506 aopPut (AOP (result),
7507 aopGet (AOP (right), offset, FALSE),
7514 freeAsmop (right, NULL, ic);
7515 freeAsmop (result, NULL, ic);
7518 /*-----------------------------------------------------------------*/
7519 /* genJumpTab - genrates code for jump table */
7520 /*-----------------------------------------------------------------*/
7522 genJumpTab (iCode * ic)
7527 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7528 /* get the condition into accumulator */
7529 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7532 emit2 ("ld e,%s", l);
7533 emit2 ("ld d,!zero");
7534 jtab = newiTempLabel (NULL);
7535 spillPair (PAIR_HL);
7536 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7537 emit2 ("add hl,de");
7538 emit2 ("add hl,de");
7539 emit2 ("add hl,de");
7540 freeAsmop (IC_JTCOND (ic), NULL, ic);
7544 emitLabel (jtab->key + 100);
7545 /* now generate the jump labels */
7546 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7547 jtab = setNextItem (IC_JTLABELS (ic)))
7548 emit2 ("jp !tlabel", jtab->key + 100);
7551 /*-----------------------------------------------------------------*/
7552 /* genCast - gen code for casting */
7553 /*-----------------------------------------------------------------*/
7555 genCast (iCode * ic)
7557 operand *result = IC_RESULT (ic);
7558 sym_link *rtype = operandType (IC_RIGHT (ic));
7559 operand *right = IC_RIGHT (ic);
7562 /* if they are equivalent then do nothing */
7563 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7566 aopOp (right, ic, FALSE, FALSE);
7567 aopOp (result, ic, FALSE, FALSE);
7569 /* if the result is a bit */
7570 if (AOP_TYPE (result) == AOP_CRY)
7572 wassertl (0, "Tried to cast to a bit");
7575 /* if they are the same size : or less */
7576 if (AOP_SIZE (result) <= AOP_SIZE (right))
7579 /* if they are in the same place */
7580 if (sameRegs (AOP (right), AOP (result)))
7583 /* if they in different places then copy */
7584 size = AOP_SIZE (result);
7588 aopPut (AOP (result),
7589 aopGet (AOP (right), offset, FALSE),
7596 /* So we now know that the size of destination is greater
7597 than the size of the source */
7598 /* we move to result for the size of source */
7599 size = AOP_SIZE (right);
7603 aopPut (AOP (result),
7604 aopGet (AOP (right), offset, FALSE),
7609 /* now depending on the sign of the destination */
7610 size = AOP_SIZE (result) - AOP_SIZE (right);
7611 /* Unsigned or not an integral type - right fill with zeros */
7612 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7615 aopPut (AOP (result), "!zero", offset++);
7619 /* we need to extend the sign :{ */
7620 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE);
7625 aopPut (AOP (result), "a", offset++);
7629 freeAsmop (right, NULL, ic);
7630 freeAsmop (result, NULL, ic);
7633 /*-----------------------------------------------------------------*/
7634 /* genReceive - generate code for a receive iCode */
7635 /*-----------------------------------------------------------------*/
7637 genReceive (iCode * ic)
7639 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7640 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7641 IS_TRUE_SYMOP (IC_RESULT (ic))))
7651 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7652 size = AOP_SIZE(IC_RESULT(ic));
7654 for (i = 0; i < size; i++) {
7655 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7659 freeAsmop (IC_RESULT (ic), NULL, ic);
7662 /*-----------------------------------------------------------------*/
7663 /* genDummyRead - generate code for dummy read of volatiles */
7664 /*-----------------------------------------------------------------*/
7666 genDummyRead (iCode * ic)
7672 if (op && IS_SYMOP (op))
7674 aopOp (op, ic, FALSE, FALSE);
7677 size = AOP_SIZE (op);
7682 _moveA (aopGet (AOP (op), offset, FALSE));
7686 freeAsmop (op, NULL, ic);
7690 if (op && IS_SYMOP (op))
7692 aopOp (op, ic, FALSE, FALSE);
7695 size = AOP_SIZE (op);
7700 _moveA (aopGet (AOP (op), offset, FALSE));
7704 freeAsmop (op, NULL, ic);
7708 /*-----------------------------------------------------------------*/
7709 /* genCritical - generate code for start of a critical sequence */
7710 /*-----------------------------------------------------------------*/
7712 genCritical (iCode *ic)
7714 symbol *tlbl = newiTempLabel (NULL);
7720 else if (IC_RESULT (ic))
7722 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7723 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7724 //get interrupt enable flag IFF2 into P/O
7728 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7729 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7730 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7731 emit2 ("!tlabeldef", (tlbl->key + 100));
7732 _G.lines.current->isLabel = 1;
7733 freeAsmop (IC_RESULT (ic), NULL, ic);
7737 //get interrupt enable flag IFF2 into P/O
7746 /*-----------------------------------------------------------------*/
7747 /* genEndCritical - generate code for end of a critical sequence */
7748 /*-----------------------------------------------------------------*/
7750 genEndCritical (iCode *ic)
7752 symbol *tlbl = newiTempLabel (NULL);
7758 else if (IC_RIGHT (ic))
7760 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7761 _toBoolean (IC_RIGHT (ic));
7762 //don't enable interrupts if they were off before
7763 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7765 emitLabel (tlbl->key + 100);
7766 freeAsmop (IC_RIGHT (ic), NULL, ic);
7772 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7773 //don't enable interrupts as they were off before
7774 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7776 emit2 ("!tlabeldef", (tlbl->key + 100));
7777 _G.lines.current->isLabel = 1;
7783 /** Maximum number of bytes to emit per line. */
7787 /** Context for the byte output chunker. */
7790 unsigned char buffer[DBEMIT_MAX_RUN];
7795 /** Flushes a byte chunker by writing out all in the buffer and
7799 _dbFlush(DBEMITCTX *self)
7806 sprintf(line, ".db 0x%02X", self->buffer[0]);
7808 for (i = 1; i < self->pos; i++)
7810 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7817 /** Write out another byte, buffering until a decent line is
7821 _dbEmit(DBEMITCTX *self, int c)
7823 if (self->pos == DBEMIT_MAX_RUN)
7827 self->buffer[self->pos++] = c;
7830 /** Context for a simple run length encoder. */
7834 unsigned char buffer[128];
7836 /** runLen may be equivalent to pos. */
7842 RLE_CHANGE_COST = 4,
7846 /** Flush the buffer of a run length encoder by writing out the run or
7847 data that it currently contains.
7850 _rleCommit(RLECTX *self)
7856 memset(&db, 0, sizeof(db));
7858 emit2(".db %u", self->pos);
7860 for (i = 0; i < self->pos; i++)
7862 _dbEmit(&db, self->buffer[i]);
7871 Can get either a run or a block of random stuff.
7872 Only want to change state if a good run comes in or a run ends.
7873 Detecting run end is easy.
7876 Say initial state is in run, len zero, last zero. Then if you get a
7877 few zeros then something else then a short run will be output.
7878 Seems OK. While in run mode, keep counting. While in random mode,
7879 keep a count of the run. If run hits margin, output all up to run,
7880 restart, enter run mode.
7883 /** Add another byte into the run length encoder, flushing as
7884 required. The run length encoder uses the Amiga IFF style, where
7885 a block is prefixed by its run length. A positive length means
7886 the next n bytes pass straight through. A negative length means
7887 that the next byte is repeated -n times. A zero terminates the
7891 _rleAppend(RLECTX *self, unsigned c)
7895 if (c != self->last)
7897 /* The run has stopped. See if it is worthwhile writing it out
7898 as a run. Note that the random data comes in as runs of
7901 if (self->runLen > RLE_CHANGE_COST)
7903 /* Yes, worthwhile. */
7904 /* Commit whatever was in the buffer. */
7906 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7910 /* Not worthwhile. Append to the end of the random list. */
7911 for (i = 0; i < self->runLen; i++)
7913 if (self->pos >= RLE_MAX_BLOCK)
7918 self->buffer[self->pos++] = self->last;
7926 if (self->runLen >= RLE_MAX_BLOCK)
7928 /* Commit whatever was in the buffer. */
7931 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7939 _rleFlush(RLECTX *self)
7941 _rleAppend(self, -1);
7948 /** genArrayInit - Special code for initialising an array with constant
7952 genArrayInit (iCode * ic)
7956 int elementSize = 0, eIndex, i;
7957 unsigned val, lastVal;
7961 memset(&rle, 0, sizeof(rle));
7963 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7965 _saveRegsForCall(ic, 0);
7967 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7968 emit2 ("call __initrleblock");
7970 type = operandType(IC_LEFT(ic));
7972 if (type && type->next)
7974 if (IS_SPEC(type->next) || IS_PTR(type->next))
7976 elementSize = getSize(type->next);
7978 else if (IS_ARRAY(type->next) && type->next->next)
7980 elementSize = getSize(type->next->next);
7984 printTypeChainRaw (type, NULL);
7985 wassertl (0, "Can't determine element size in genArrayInit.");
7990 wassertl (0, "Can't determine element size in genArrayInit.");
7993 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7995 iLoop = IC_ARRAYILIST(ic);
7996 lastVal = (unsigned)-1;
7998 /* Feed all the bytes into the run length encoder which will handle
8000 This works well for mixed char data, and for random int and long
8007 for (i = 0; i < ix; i++)
8009 for (eIndex = 0; eIndex < elementSize; eIndex++)
8011 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
8012 _rleAppend(&rle, val);
8016 iLoop = iLoop->next;
8020 /* Mark the end of the run. */
8023 _restoreRegsAfterCall();
8027 freeAsmop (IC_LEFT(ic), NULL, ic);
8031 _swap (PAIR_ID one, PAIR_ID two)
8033 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
8039 emit2 ("ld a,%s", _pairs[one].l);
8040 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
8041 emit2 ("ld %s,a", _pairs[two].l);
8042 emit2 ("ld a,%s", _pairs[one].h);
8043 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
8044 emit2 ("ld %s,a", _pairs[two].h);
8049 setupForMemcpy (iCode *ic, int nparams, operand **pparams)
8051 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
8053 PAIR_DE, PAIR_HL, PAIR_BC
8055 int i, j, nunity = 0;
8056 memset (ids, PAIR_INVALID, sizeof (ids));
8059 wassert (nparams == 3);
8061 for (i = 0; i < nparams; i++)
8063 aopOp (pparams[i], ic, FALSE, FALSE);
8064 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
8067 /* Count the number of unity or iTemp assigns. */
8068 for (i = 0; i < 3; i++)
8070 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
8078 /* Any order, fall through. */
8080 else if (nunity == 2)
8082 /* Two are OK. Assign the other one. */
8083 for (i = 0; i < 3; i++)
8085 for (j = 0; j < NUM_PAIRS; j++)
8087 if (ids[dest[i]][j] == TRUE)
8089 /* Found it. See if it's the right one. */
8090 if (j == PAIR_INVALID || j == dest[i])
8096 fetchPair(dest[i], AOP (pparams[i]));
8103 else if (nunity == 1)
8105 /* One is OK. Find the other two. */
8106 for (i = 0; i < 3; i++)
8108 for (j = 0; j < NUM_PAIRS; j++)
8110 if (ids[dest[i]][j] == TRUE)
8112 if (j == PAIR_INVALID || j == dest[i])
8114 /* This one is OK. */
8119 if(ids[j][dest[i]] == TRUE)
8127 fetchPair (dest[i], AOP (pparams[i]));
8137 int next = getPairId (AOP (pparams[0]));
8138 emit2 ("push %s", _pairs[next].name);
8140 if (next == dest[1])
8142 fetchPair (dest[1], AOP (pparams[1]));
8143 fetchPair (dest[2], AOP (pparams[2]));
8147 fetchPair (dest[2], AOP (pparams[2]));
8148 fetchPair (dest[1], AOP (pparams[1]));
8150 emit2 ("pop %s", _pairs[dest[0]].name);
8153 /* Finally pull out all of the iTemps */
8154 for (i = 0; i < 3; i++)
8156 if (ids[dest[i]][PAIR_INVALID] == 1)
8158 fetchPair (dest[i], AOP (pparams[i]));
8164 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8166 operand *from, *to, *count;
8168 wassertl (nParams == 3, "Built-in memcpy() must have three parameters");
8173 _saveRegsForCall (ic, 0);
8175 setupForMemcpy (ic, nParams, pparams);
8179 freeAsmop (count, NULL, ic->next->next);
8180 freeAsmop (from, NULL, ic);
8182 spillPair (PAIR_HL);
8184 _restoreRegsAfterCall();
8186 /* if we need assign a result value */
8187 if ((IS_ITEMP (IC_RESULT (ic)) &&
8188 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8189 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8190 IS_TRUE_SYMOP (IC_RESULT (ic)))
8192 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8193 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8194 freeAsmop (IC_RESULT (ic), NULL, ic);
8197 freeAsmop (to, NULL, ic->next);
8200 /*-----------------------------------------------------------------*/
8201 /* genBuiltIn - calls the appropriate function to generating code */
8202 /* for a built in function */
8203 /*-----------------------------------------------------------------*/
8204 static void genBuiltIn (iCode *ic)
8206 operand *bi_parms[MAX_BUILTIN_ARGS];
8211 /* get all the arguments for a built in function */
8212 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8214 /* which function is it */
8215 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8217 if (strcmp(bif->name,"__builtin_memcpy")==0)
8219 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8223 wassertl (0, "Unknown builtin function encountered");
8227 /*-----------------------------------------------------------------*/
8228 /* genZ80Code - generate code for Z80 based controllers */
8229 /*-----------------------------------------------------------------*/
8231 genZ80Code (iCode * lic)
8239 _fReturn = _gbz80_return;
8240 _fTmp = _gbz80_return;
8244 _fReturn = _z80_return;
8245 _fTmp = _z80_return;
8248 _G.lines.head = _G.lines.current = NULL;
8250 /* if debug information required */
8251 if (options.debug && currFunc)
8253 debugFile->writeFunction (currFunc, lic);
8256 for (ic = lic; ic; ic = ic->next)
8258 _G.current_iCode = ic;
8260 if (ic->lineno && cln != ic->lineno)
8264 debugFile->writeCLine (ic);
8266 if (!options.noCcodeInAsm)
8268 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8269 printCLine(ic->filename, ic->lineno));
8273 if (options.iCodeInAsm)
8275 const char *iLine = printILine(ic);
8276 emit2 (";ic:%d: %s", ic->key, iLine);
8279 /* if the result is marked as
8280 spilt and rematerializable or code for
8281 this has already been generated then
8283 if (resultRemat (ic) || ic->generated)
8286 /* depending on the operation */
8290 emitDebug ("; genNot");
8295 emitDebug ("; genCpl");
8300 emitDebug ("; genUminus");
8305 emitDebug ("; genIpush");
8310 /* IPOP happens only when trying to restore a
8311 spilt live range, if there is an ifx statement
8312 following this pop then the if statement might
8313 be using some of the registers being popped which
8314 would destroy the contents of the register so
8315 we need to check for this condition and handle it */
8317 ic->next->op == IFX &&
8318 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8320 emitDebug ("; genIfx");
8321 genIfx (ic->next, ic);
8325 emitDebug ("; genIpop");
8331 emitDebug ("; genCall");
8336 emitDebug ("; genPcall");
8341 emitDebug ("; genFunction");
8346 emitDebug ("; genEndFunction");
8347 genEndFunction (ic);
8351 emitDebug ("; genRet");
8356 emitDebug ("; genLabel");
8361 emitDebug ("; genGoto");
8366 emitDebug ("; genPlus");
8371 emitDebug ("; genMinus");
8376 emitDebug ("; genMult");
8381 emitDebug ("; genDiv");
8386 emitDebug ("; genMod");
8391 emitDebug ("; genCmpGt");
8392 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8396 emitDebug ("; genCmpLt");
8397 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8404 /* note these two are xlated by algebraic equivalence
8405 during parsing SDCC.y */
8406 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8407 "got '>=' or '<=' shouldn't have come here");
8411 emitDebug ("; genCmpEq");
8412 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8416 emitDebug ("; genAndOp");
8421 emitDebug ("; genOrOp");
8426 emitDebug ("; genXor");
8427 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8431 emitDebug ("; genOr");
8432 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8436 emitDebug ("; genAnd");
8437 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8441 emitDebug ("; genInline");
8446 emitDebug ("; genRRC");
8451 emitDebug ("; genRLC");
8456 emitDebug ("; genGetHBIT");
8461 emitDebug ("; genLeftShift");
8466 emitDebug ("; genRightShift");
8470 case GET_VALUE_AT_ADDRESS:
8471 emitDebug ("; genPointerGet");
8477 if (POINTER_SET (ic))
8479 emitDebug ("; genAssign (pointer)");
8484 emitDebug ("; genAssign");
8490 emitDebug ("; genIfx");
8495 emitDebug ("; genAddrOf");
8500 emitDebug ("; genJumpTab");
8505 emitDebug ("; genCast");
8510 emitDebug ("; genReceive");
8515 if (ic->builtinSEND)
8517 emitDebug ("; genBuiltIn");
8522 emitDebug ("; addSet");
8523 addSet (&_G.sendSet, ic);
8528 emitDebug ("; genArrayInit");
8532 case DUMMY_READ_VOLATILE:
8533 emitDebug ("; genDummyRead");
8538 emitDebug ("; genCritical");
8543 emitDebug ("; genEndCritical");
8544 genEndCritical (ic);
8553 /* now we are ready to call the
8554 peep hole optimizer */
8555 if (!options.nopeep)
8556 peepHole (&_G.lines.head);
8558 /* This is unfortunate */
8559 /* now do the actual printing */
8561 struct dbuf_s *buf = codeOutBuf;
8562 if (isInHome () && codeOutBuf == &code->oBuf)
8563 codeOutBuf = &home->oBuf;
8564 printLine (_G.lines.head, codeOutBuf);
8565 if (_G.flushStatics)
8568 _G.flushStatics = 0;
8573 freeTrace(&_G.lines.trace);
8574 freeTrace(&_G.trace.aops);
8580 _isPairUsed (iCode * ic, PAIR_ID pairId)
8586 if (bitVectBitValue (ic->rMask, D_IDX))
8588 if (bitVectBitValue (ic->rMask, E_IDX))
8598 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8601 value *val = aop->aopu.aop_lit;
8603 wassert (aop->type == AOP_LIT);
8604 wassert (!IS_FLOAT (val->type));
8606 v = ulFromVal (val);
8614 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8615 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));