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 /* Operand resides (partially) in the pair */
1547 if(!strcmp(aopGet (aop, offset + 1, FALSE), _pairs[pairId].l))
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 a,%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 a,%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);
6755 emit2 ("bit %d,a", blen - 1 - 8);
6756 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6757 emit2 ("or a,!immedbyte", (unsigned char) (0xff << (blen - 8)));
6758 emitLabel (tlbl->key + 100);
6761 spillPair (PAIR_HL);
6765 /* Bit field did not fit in a byte. Copy all
6766 but the partial byte at the end. */
6767 for (rlen=blen;rlen>=8;rlen-=8)
6769 emit2 ("ld a,!*pair", _pairs[pair].name);
6770 aopPut (AOP (result), "a", offset++);
6773 emit2 ("inc %s", _pairs[pair].name);
6774 _G.pairs[pair].offset++;
6778 /* Handle the partial byte at the end */
6781 emit2 ("ld a,!*pair", _pairs[pair].name);
6782 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6783 if (!SPEC_USIGN (etype))
6785 /* signed bitfield */
6786 symbol *tlbl = newiTempLabel (NULL);
6788 emit2 ("bit %d,a", rlen - 1);
6789 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6790 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6791 emitLabel (tlbl->key + 100);
6793 aopPut (AOP (result), "a", offset++);
6801 if (SPEC_USIGN (etype))
6805 /* signed bitfield: sign extension with 0x00 or 0xff */
6813 aopPut (AOP (result), source, offset++);
6817 /*-----------------------------------------------------------------*/
6818 /* genGenPointerGet - get value from generic pointer space */
6819 /*-----------------------------------------------------------------*/
6821 genGenPointerGet (operand * left,
6822 operand * result, iCode * ic)
6825 sym_link *retype = getSpec (operandType (result));
6831 aopOp (left, ic, FALSE, FALSE);
6832 aopOp (result, ic, FALSE, FALSE);
6834 size = AOP_SIZE (result);
6836 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6839 if (isPtrPair (AOP (left)))
6841 tsprintf (buffer, sizeof(buffer),
6842 "!*pair", getPairName (AOP (left)));
6843 aopPut (AOP (result), buffer, 0);
6847 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6848 aopPut (AOP (result), "a", 0);
6850 freeAsmop (left, NULL, ic);
6854 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6861 tsprintf (at, sizeof(at), "!*iyx", offset);
6862 aopPut (AOP (result), at, offset);
6866 freeAsmop (left, NULL, ic);
6870 /* For now we always load into IY */
6871 /* if this is remateriazable */
6872 fetchPair (pair, AOP (left));
6874 /* if bit then unpack */
6875 if (IS_BITVAR (retype))
6877 genUnpackBits (result, pair);
6878 freeAsmop (left, NULL, ic);
6882 else if (getPairId (AOP (result)) == PAIR_HL)
6884 wassertl (size == 2, "HL must be of size 2");
6885 emit2 ("ld a,!*hl");
6887 emit2 ("ld h,!*hl");
6889 spillPair (PAIR_HL);
6891 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6893 size = AOP_SIZE (result);
6898 /* PENDING: make this better */
6899 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6901 aopPut (AOP (result), "!*hl", offset++);
6905 emit2 ("ld a,!*pair", _pairs[pair].name);
6906 aopPut (AOP (result), "a", offset++);
6910 emit2 ("inc %s", _pairs[pair].name);
6911 _G.pairs[pair].offset++;
6914 /* Fixup HL back down */
6915 for (size = AOP_SIZE (result)-1; size; size--)
6917 emit2 ("dec %s", _pairs[pair].name);
6922 size = AOP_SIZE (result);
6927 /* PENDING: make this better */
6929 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6931 aopPut (AOP (result), "!*hl", offset++);
6935 emit2 ("ld a,!*pair", _pairs[pair].name);
6936 aopPut (AOP (result), "a", offset++);
6940 emit2 ("inc %s", _pairs[pair].name);
6941 _G.pairs[pair].offset++;
6946 freeAsmop (left, NULL, ic);
6949 freeAsmop (result, NULL, ic);
6952 /*-----------------------------------------------------------------*/
6953 /* genPointerGet - generate code for pointer get */
6954 /*-----------------------------------------------------------------*/
6956 genPointerGet (iCode * ic)
6958 operand *left, *result;
6959 sym_link *type, *etype;
6961 left = IC_LEFT (ic);
6962 result = IC_RESULT (ic);
6964 /* depending on the type of pointer we need to
6965 move it to the correct pointer register */
6966 type = operandType (left);
6967 etype = getSpec (type);
6969 genGenPointerGet (left, result, ic);
6973 isRegOrLit (asmop * aop)
6975 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6981 /*-----------------------------------------------------------------*/
6982 /* genPackBits - generates code for packed bit storage */
6983 /*-----------------------------------------------------------------*/
6985 genPackBits (sym_link * etype,
6990 int offset = 0; /* source byte offset */
6991 int rlen = 0; /* remaining bitfield length */
6992 int blen; /* bitfield length */
6993 int bstr; /* bitfield starting bit within byte */
6994 int litval; /* source literal value (if AOP_LIT) */
6995 unsigned char mask; /* bitmask within current byte */
6996 int extraPair; /* a tempory register */
6997 bool needPopExtra=0; /* need to restore original value of temp reg */
6999 emitDebug ("; genPackBits","");
7001 blen = SPEC_BLEN (etype);
7002 bstr = SPEC_BSTR (etype);
7004 /* If the bitfield length is less than a byte */
7007 mask = ((unsigned char) (0xFF << (blen + bstr)) |
7008 (unsigned char) (0xFF >> (8 - bstr)));
7010 if (AOP_TYPE (right) == AOP_LIT)
7012 /* Case with a bitfield length <8 and literal source
7014 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7016 litval &= (~mask) & 0xff;
7017 emit2 ("ld a,!*pair", _pairs[pair].name);
7018 if ((mask|litval)!=0xff)
7019 emit2 ("and a,!immedbyte", mask);
7021 emit2 ("or a,!immedbyte", litval);
7022 emit2 ("ld !*pair,a", _pairs[pair].name);
7027 /* Case with a bitfield length <8 and arbitrary source
7029 _moveA (aopGet (AOP (right), 0, FALSE));
7030 /* shift and mask source value */
7032 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7034 extraPair = getFreePairId(ic);
7035 if (extraPair == PAIR_INVALID)
7037 extraPair = PAIR_BC;
7038 if (getPairId (AOP (right)) != PAIR_BC
7039 || !isLastUse (ic, right))
7045 emit2 ("ld %s,a", _pairs[extraPair].l);
7046 emit2 ("ld a,!*pair", _pairs[pair].name);
7048 emit2 ("and a,!immedbyte", mask);
7049 emit2 ("or a,%s", _pairs[extraPair].l);
7050 emit2 ("ld !*pair,a", _pairs[pair].name);
7057 /* Bit length is greater than 7 bits. In this case, copy */
7058 /* all except the partial byte at the end */
7059 for (rlen=blen;rlen>=8;rlen-=8)
7061 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
7062 emit2 ("ld !*pair,a", _pairs[pair].name);
7065 emit2 ("inc %s", _pairs[pair].name);
7066 _G.pairs[pair].offset++;
7070 /* If there was a partial byte at the end */
7073 mask = (((unsigned char) -1 << rlen) & 0xff);
7075 if (AOP_TYPE (right) == AOP_LIT)
7077 /* Case with partial byte and literal source
7079 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7080 litval >>= (blen-rlen);
7081 litval &= (~mask) & 0xff;
7082 emit2 ("ld a,!*pair", _pairs[pair].name);
7083 if ((mask|litval)!=0xff)
7084 emit2 ("and a,!immedbyte", mask);
7086 emit2 ("or a,!immedbyte", litval);
7090 /* Case with partial byte and arbitrary source
7092 _moveA (aopGet (AOP (right), offset++, FALSE));
7093 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7095 extraPair = getFreePairId(ic);
7096 if (extraPair == PAIR_INVALID)
7098 extraPair = getPairId (AOP (right));
7099 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
7100 extraPair = PAIR_BC;
7102 if (getPairId (AOP (right)) != PAIR_BC
7103 || !isLastUse (ic, right))
7109 emit2 ("ld %s,a", _pairs[extraPair].l);
7110 emit2 ("ld a,!*pair", _pairs[pair].name);
7112 emit2 ("and a,!immedbyte", mask);
7113 emit2 ("or a,%s", _pairs[extraPair].l);
7118 emit2 ("ld !*pair,a", _pairs[pair].name);
7123 /*-----------------------------------------------------------------*/
7124 /* genGenPointerSet - stores the value into a pointer location */
7125 /*-----------------------------------------------------------------*/
7127 genGenPointerSet (operand * right,
7128 operand * result, iCode * ic)
7131 sym_link *retype = getSpec (operandType (right));
7132 sym_link *letype = getSpec (operandType (result));
7133 PAIR_ID pairId = PAIR_HL;
7136 aopOp (result, ic, FALSE, FALSE);
7137 aopOp (right, ic, FALSE, FALSE);
7142 size = AOP_SIZE (right);
7144 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
7145 emitDebug("; isBitvar = %d", isBitvar);
7147 /* Handle the exceptions first */
7148 if (isPair (AOP (result)) && size == 1 && !isBitvar)
7151 const char *l = aopGet (AOP (right), 0, FALSE);
7152 const char *pair = getPairName (AOP (result));
7153 if (canAssignToPtr (l) && isPtr (pair))
7155 emit2 ("ld !*pair,%s", pair, l);
7160 emit2 ("ld !*pair,a", pair);
7165 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7168 const char *l = aopGet (AOP (right), 0, FALSE);
7173 if (canAssignToPtr (l))
7175 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7179 _moveA (aopGet (AOP (right), offset, FALSE));
7180 emit2 ("ld !*iyx,a", offset);
7186 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7193 const char *l = aopGet (AOP (right), offset, FALSE);
7194 if (isRegOrLit (AOP (right)) && !IS_GB)
7196 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7201 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7205 emit2 ("inc %s", _pairs[PAIR_HL].name);
7206 _G.pairs[PAIR_HL].offset++;
7211 /* Fixup HL back down */
7212 for (size = AOP_SIZE (right)-1; size; size--)
7214 emit2 ("dec %s", _pairs[PAIR_HL].name);
7219 /* if the operand is already in dptr
7220 then we do nothing else we move the value to dptr */
7221 if (AOP_TYPE (result) != AOP_STR)
7223 fetchPair (pairId, AOP (result));
7225 /* so hl now contains the address */
7226 freeAsmop (result, NULL, ic);
7228 /* if bit then unpack */
7231 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7241 const char *l = aopGet (AOP (right), offset, FALSE);
7242 if (isRegOrLit (AOP (right)) && !IS_GB)
7244 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7249 emit2 ("ld !*pair,a", _pairs[pairId].name);
7253 emit2 ("inc %s", _pairs[pairId].name);
7254 _G.pairs[pairId].offset++;
7260 freeAsmop (right, NULL, ic);
7263 /*-----------------------------------------------------------------*/
7264 /* genPointerSet - stores the value into a pointer location */
7265 /*-----------------------------------------------------------------*/
7267 genPointerSet (iCode * ic)
7269 operand *right, *result;
7270 sym_link *type, *etype;
7272 right = IC_RIGHT (ic);
7273 result = IC_RESULT (ic);
7275 /* depending on the type of pointer we need to
7276 move it to the correct pointer register */
7277 type = operandType (result);
7278 etype = getSpec (type);
7280 genGenPointerSet (right, result, ic);
7283 /*-----------------------------------------------------------------*/
7284 /* genIfx - generate code for Ifx statement */
7285 /*-----------------------------------------------------------------*/
7287 genIfx (iCode * ic, iCode * popIc)
7289 operand *cond = IC_COND (ic);
7292 aopOp (cond, ic, FALSE, TRUE);
7294 /* get the value into acc */
7295 if (AOP_TYPE (cond) != AOP_CRY)
7299 /* the result is now in the accumulator */
7300 freeAsmop (cond, NULL, ic);
7302 /* if there was something to be popped then do it */
7306 /* if the condition is a bit variable */
7307 if (isbit && IS_ITEMP (cond) &&
7309 genIfxJump (ic, SPIL_LOC (cond)->rname);
7310 else if (isbit && !IS_ITEMP (cond))
7311 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7313 genIfxJump (ic, "a");
7318 /*-----------------------------------------------------------------*/
7319 /* genAddrOf - generates code for address of */
7320 /*-----------------------------------------------------------------*/
7322 genAddrOf (iCode * ic)
7324 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7326 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7328 /* if the operand is on the stack then we
7329 need to get the stack offset of this
7335 spillPair (PAIR_HL);
7336 if (sym->stack <= 0)
7338 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7342 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7344 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7348 emit2 ("ld de,!hashedstr", sym->rname);
7349 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7354 spillPair (PAIR_HL);
7357 /* if it has an offset then we need to compute it */
7359 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7361 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7362 emit2 ("add hl,sp");
7366 emit2 ("ld hl,!hashedstr", sym->rname);
7368 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7370 freeAsmop (IC_RESULT (ic), NULL, ic);
7373 /*-----------------------------------------------------------------*/
7374 /* genAssign - generate code for assignment */
7375 /*-----------------------------------------------------------------*/
7377 genAssign (iCode * ic)
7379 operand *result, *right;
7381 unsigned long lit = 0L;
7383 result = IC_RESULT (ic);
7384 right = IC_RIGHT (ic);
7386 /* Dont bother assigning if they are the same */
7387 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7389 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7393 aopOp (right, ic, FALSE, FALSE);
7394 aopOp (result, ic, TRUE, FALSE);
7396 /* if they are the same registers */
7397 if (sameRegs (AOP (right), AOP (result)))
7399 emitDebug ("; (registers are the same)");
7403 /* if the result is a bit */
7404 if (AOP_TYPE (result) == AOP_CRY)
7406 wassertl (0, "Tried to assign to a bit");
7410 size = AOP_SIZE (result);
7413 if (AOP_TYPE (right) == AOP_LIT)
7415 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7418 if (isPair (AOP (result)))
7420 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7422 else if ((size > 1) &&
7423 (AOP_TYPE (result) != AOP_REG) &&
7424 (AOP_TYPE (right) == AOP_LIT) &&
7425 !IS_FLOAT (operandType (right)) &&
7428 bool fXored = FALSE;
7430 /* Work from the top down.
7431 Done this way so that we can use the cached copy of 0
7432 in A for a fast clear */
7435 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7437 if (!fXored && size > 1)
7444 aopPut (AOP (result), "a", offset);
7448 aopPut (AOP (result), "!zero", offset);
7452 aopPut (AOP (result),
7453 aopGet (AOP (right), offset, FALSE),
7458 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7460 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7461 aopPut (AOP (result), "l", LSB);
7462 aopPut (AOP (result), "h", MSB16);
7464 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7466 /* Special case. Load into a and d, then load out. */
7467 _moveA (aopGet (AOP (right), 0, FALSE));
7468 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7469 aopPut (AOP (result), "a", 0);
7470 aopPut (AOP (result), "e", 1);
7472 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7474 /* Special case - simple memcpy */
7475 aopGet (AOP (right), LSB, FALSE);
7478 aopGet (AOP (result), LSB, FALSE);
7482 emit2 ("ld a,(de)");
7483 /* Peephole will optimise this. */
7484 emit2 ("ld (hl),a");
7492 spillPair (PAIR_HL);
7498 /* PENDING: do this check better */
7499 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7501 _moveA (aopGet (AOP (right), offset, FALSE));
7502 aopPut (AOP (result), "a", offset);
7505 aopPut (AOP (result),
7506 aopGet (AOP (right), offset, FALSE),
7513 freeAsmop (right, NULL, ic);
7514 freeAsmop (result, NULL, ic);
7517 /*-----------------------------------------------------------------*/
7518 /* genJumpTab - genrates code for jump table */
7519 /*-----------------------------------------------------------------*/
7521 genJumpTab (iCode * ic)
7526 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7527 /* get the condition into accumulator */
7528 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7531 emit2 ("ld e,%s", l);
7532 emit2 ("ld d,!zero");
7533 jtab = newiTempLabel (NULL);
7534 spillPair (PAIR_HL);
7535 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7536 emit2 ("add hl,de");
7537 emit2 ("add hl,de");
7538 emit2 ("add hl,de");
7539 freeAsmop (IC_JTCOND (ic), NULL, ic);
7543 emitLabel (jtab->key + 100);
7544 /* now generate the jump labels */
7545 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7546 jtab = setNextItem (IC_JTLABELS (ic)))
7547 emit2 ("jp !tlabel", jtab->key + 100);
7550 /*-----------------------------------------------------------------*/
7551 /* genCast - gen code for casting */
7552 /*-----------------------------------------------------------------*/
7554 genCast (iCode * ic)
7556 operand *result = IC_RESULT (ic);
7557 sym_link *rtype = operandType (IC_RIGHT (ic));
7558 operand *right = IC_RIGHT (ic);
7561 /* if they are equivalent then do nothing */
7562 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7565 aopOp (right, ic, FALSE, FALSE);
7566 aopOp (result, ic, FALSE, FALSE);
7568 /* if the result is a bit */
7569 if (AOP_TYPE (result) == AOP_CRY)
7571 wassertl (0, "Tried to cast to a bit");
7574 /* if they are the same size : or less */
7575 if (AOP_SIZE (result) <= AOP_SIZE (right))
7578 /* if they are in the same place */
7579 if (sameRegs (AOP (right), AOP (result)))
7582 /* if they in different places then copy */
7583 size = AOP_SIZE (result);
7587 aopPut (AOP (result),
7588 aopGet (AOP (right), offset, FALSE),
7595 /* So we now know that the size of destination is greater
7596 than the size of the source */
7597 /* we move to result for the size of source */
7598 size = AOP_SIZE (right);
7602 aopPut (AOP (result),
7603 aopGet (AOP (right), offset, FALSE),
7608 /* now depending on the sign of the destination */
7609 size = AOP_SIZE (result) - AOP_SIZE (right);
7610 /* Unsigned or not an integral type - right fill with zeros */
7611 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7614 aopPut (AOP (result), "!zero", offset++);
7618 /* we need to extend the sign :{ */
7619 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE);
7624 aopPut (AOP (result), "a", offset++);
7628 freeAsmop (right, NULL, ic);
7629 freeAsmop (result, NULL, ic);
7632 /*-----------------------------------------------------------------*/
7633 /* genReceive - generate code for a receive iCode */
7634 /*-----------------------------------------------------------------*/
7636 genReceive (iCode * ic)
7638 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7639 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7640 IS_TRUE_SYMOP (IC_RESULT (ic))))
7650 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7651 size = AOP_SIZE(IC_RESULT(ic));
7653 for (i = 0; i < size; i++) {
7654 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7658 freeAsmop (IC_RESULT (ic), NULL, ic);
7661 /*-----------------------------------------------------------------*/
7662 /* genDummyRead - generate code for dummy read of volatiles */
7663 /*-----------------------------------------------------------------*/
7665 genDummyRead (iCode * ic)
7671 if (op && IS_SYMOP (op))
7673 aopOp (op, ic, FALSE, FALSE);
7676 size = AOP_SIZE (op);
7681 _moveA (aopGet (AOP (op), offset, FALSE));
7685 freeAsmop (op, NULL, ic);
7689 if (op && IS_SYMOP (op))
7691 aopOp (op, ic, FALSE, FALSE);
7694 size = AOP_SIZE (op);
7699 _moveA (aopGet (AOP (op), offset, FALSE));
7703 freeAsmop (op, NULL, ic);
7707 /*-----------------------------------------------------------------*/
7708 /* genCritical - generate code for start of a critical sequence */
7709 /*-----------------------------------------------------------------*/
7711 genCritical (iCode *ic)
7713 symbol *tlbl = newiTempLabel (NULL);
7719 else if (IC_RESULT (ic))
7721 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7722 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7723 //get interrupt enable flag IFF2 into P/O
7727 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7728 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7729 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7730 emit2 ("!tlabeldef", (tlbl->key + 100));
7731 _G.lines.current->isLabel = 1;
7732 freeAsmop (IC_RESULT (ic), NULL, ic);
7736 //get interrupt enable flag IFF2 into P/O
7745 /*-----------------------------------------------------------------*/
7746 /* genEndCritical - generate code for end of a critical sequence */
7747 /*-----------------------------------------------------------------*/
7749 genEndCritical (iCode *ic)
7751 symbol *tlbl = newiTempLabel (NULL);
7757 else if (IC_RIGHT (ic))
7759 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7760 _toBoolean (IC_RIGHT (ic));
7761 //don't enable interrupts if they were off before
7762 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7764 emitLabel (tlbl->key + 100);
7765 freeAsmop (IC_RIGHT (ic), NULL, ic);
7771 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7772 //don't enable interrupts as they were off before
7773 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7775 emit2 ("!tlabeldef", (tlbl->key + 100));
7776 _G.lines.current->isLabel = 1;
7782 /** Maximum number of bytes to emit per line. */
7786 /** Context for the byte output chunker. */
7789 unsigned char buffer[DBEMIT_MAX_RUN];
7794 /** Flushes a byte chunker by writing out all in the buffer and
7798 _dbFlush(DBEMITCTX *self)
7805 sprintf(line, ".db 0x%02X", self->buffer[0]);
7807 for (i = 1; i < self->pos; i++)
7809 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7816 /** Write out another byte, buffering until a decent line is
7820 _dbEmit(DBEMITCTX *self, int c)
7822 if (self->pos == DBEMIT_MAX_RUN)
7826 self->buffer[self->pos++] = c;
7829 /** Context for a simple run length encoder. */
7833 unsigned char buffer[128];
7835 /** runLen may be equivalent to pos. */
7841 RLE_CHANGE_COST = 4,
7845 /** Flush the buffer of a run length encoder by writing out the run or
7846 data that it currently contains.
7849 _rleCommit(RLECTX *self)
7855 memset(&db, 0, sizeof(db));
7857 emit2(".db %u", self->pos);
7859 for (i = 0; i < self->pos; i++)
7861 _dbEmit(&db, self->buffer[i]);
7870 Can get either a run or a block of random stuff.
7871 Only want to change state if a good run comes in or a run ends.
7872 Detecting run end is easy.
7875 Say initial state is in run, len zero, last zero. Then if you get a
7876 few zeros then something else then a short run will be output.
7877 Seems OK. While in run mode, keep counting. While in random mode,
7878 keep a count of the run. If run hits margin, output all up to run,
7879 restart, enter run mode.
7882 /** Add another byte into the run length encoder, flushing as
7883 required. The run length encoder uses the Amiga IFF style, where
7884 a block is prefixed by its run length. A positive length means
7885 the next n bytes pass straight through. A negative length means
7886 that the next byte is repeated -n times. A zero terminates the
7890 _rleAppend(RLECTX *self, unsigned c)
7894 if (c != self->last)
7896 /* The run has stopped. See if it is worthwhile writing it out
7897 as a run. Note that the random data comes in as runs of
7900 if (self->runLen > RLE_CHANGE_COST)
7902 /* Yes, worthwhile. */
7903 /* Commit whatever was in the buffer. */
7905 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7909 /* Not worthwhile. Append to the end of the random list. */
7910 for (i = 0; i < self->runLen; i++)
7912 if (self->pos >= RLE_MAX_BLOCK)
7917 self->buffer[self->pos++] = self->last;
7925 if (self->runLen >= RLE_MAX_BLOCK)
7927 /* Commit whatever was in the buffer. */
7930 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7938 _rleFlush(RLECTX *self)
7940 _rleAppend(self, -1);
7947 /** genArrayInit - Special code for initialising an array with constant
7951 genArrayInit (iCode * ic)
7955 int elementSize = 0, eIndex, i;
7956 unsigned val, lastVal;
7960 memset(&rle, 0, sizeof(rle));
7962 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7964 _saveRegsForCall(ic, 0);
7966 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7967 emit2 ("call __initrleblock");
7969 type = operandType(IC_LEFT(ic));
7971 if (type && type->next)
7973 if (IS_SPEC(type->next) || IS_PTR(type->next))
7975 elementSize = getSize(type->next);
7977 else if (IS_ARRAY(type->next) && type->next->next)
7979 elementSize = getSize(type->next->next);
7983 printTypeChainRaw (type, NULL);
7984 wassertl (0, "Can't determine element size in genArrayInit.");
7989 wassertl (0, "Can't determine element size in genArrayInit.");
7992 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7994 iLoop = IC_ARRAYILIST(ic);
7995 lastVal = (unsigned)-1;
7997 /* Feed all the bytes into the run length encoder which will handle
7999 This works well for mixed char data, and for random int and long
8006 for (i = 0; i < ix; i++)
8008 for (eIndex = 0; eIndex < elementSize; eIndex++)
8010 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
8011 _rleAppend(&rle, val);
8015 iLoop = iLoop->next;
8019 /* Mark the end of the run. */
8022 _restoreRegsAfterCall();
8026 freeAsmop (IC_LEFT(ic), NULL, ic);
8030 _swap (PAIR_ID one, PAIR_ID two)
8032 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
8038 emit2 ("ld a,%s", _pairs[one].l);
8039 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
8040 emit2 ("ld %s,a", _pairs[two].l);
8041 emit2 ("ld a,%s", _pairs[one].h);
8042 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
8043 emit2 ("ld %s,a", _pairs[two].h);
8048 setupForMemcpy (iCode *ic, int nparams, operand **pparams)
8050 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
8052 PAIR_DE, PAIR_HL, PAIR_BC
8054 int i, j, nunity = 0;
8055 memset (ids, PAIR_INVALID, sizeof (ids));
8058 wassert (nparams == 3);
8060 for (i = 0; i < nparams; i++)
8062 aopOp (pparams[i], ic, FALSE, FALSE);
8063 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
8066 /* Count the number of unity or iTemp assigns. */
8067 for (i = 0; i < 3; i++)
8069 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
8077 /* Any order, fall through. */
8079 else if (nunity == 2)
8081 /* Two are OK. Assign the other one. */
8082 for (i = 0; i < 3; i++)
8084 for (j = 0; j < NUM_PAIRS; j++)
8086 if (ids[dest[i]][j] == TRUE)
8088 /* Found it. See if it's the right one. */
8089 if (j == PAIR_INVALID || j == dest[i])
8095 fetchPair(dest[i], AOP (pparams[i]));
8102 else if (nunity == 1)
8104 /* One is OK. Find the other two. */
8105 for (i = 0; i < 3; i++)
8107 for (j = 0; j < NUM_PAIRS; j++)
8109 if (ids[dest[i]][j] == TRUE)
8111 if (j == PAIR_INVALID || j == dest[i])
8113 /* This one is OK. */
8118 if(ids[j][dest[i]] == TRUE)
8126 fetchPair (dest[i], AOP (pparams[i]));
8136 int next = getPairId (AOP (pparams[0]));
8137 emit2 ("push %s", _pairs[next].name);
8139 if (next == dest[1])
8141 fetchPair (dest[1], AOP (pparams[1]));
8142 fetchPair (dest[2], AOP (pparams[2]));
8146 fetchPair (dest[2], AOP (pparams[2]));
8147 fetchPair (dest[1], AOP (pparams[1]));
8149 emit2 ("pop %s", _pairs[dest[0]].name);
8152 /* Finally pull out all of the iTemps */
8153 for (i = 0; i < 3; i++)
8155 if (ids[dest[i]][PAIR_INVALID] == 1)
8157 fetchPair (dest[i], AOP (pparams[i]));
8163 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8165 operand *from, *to, *count;
8167 wassertl (nParams == 3, "Built-in memcpy() must have three parameters");
8172 _saveRegsForCall (ic, 0);
8174 setupForMemcpy (ic, nParams, pparams);
8178 freeAsmop (count, NULL, ic->next->next);
8179 freeAsmop (from, NULL, ic);
8181 spillPair (PAIR_HL);
8183 _restoreRegsAfterCall();
8185 /* if we need assign a result value */
8186 if ((IS_ITEMP (IC_RESULT (ic)) &&
8187 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8188 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8189 IS_TRUE_SYMOP (IC_RESULT (ic)))
8191 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8192 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8193 freeAsmop (IC_RESULT (ic), NULL, ic);
8196 freeAsmop (to, NULL, ic->next);
8199 /*-----------------------------------------------------------------*/
8200 /* genBuiltIn - calls the appropriate function to generating code */
8201 /* for a built in function */
8202 /*-----------------------------------------------------------------*/
8203 static void genBuiltIn (iCode *ic)
8205 operand *bi_parms[MAX_BUILTIN_ARGS];
8210 /* get all the arguments for a built in function */
8211 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8213 /* which function is it */
8214 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8216 if (strcmp(bif->name,"__builtin_memcpy")==0)
8218 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8222 wassertl (0, "Unknown builtin function encountered");
8226 /*-----------------------------------------------------------------*/
8227 /* genZ80Code - generate code for Z80 based controllers */
8228 /*-----------------------------------------------------------------*/
8230 genZ80Code (iCode * lic)
8238 _fReturn = _gbz80_return;
8239 _fTmp = _gbz80_return;
8243 _fReturn = _z80_return;
8244 _fTmp = _z80_return;
8247 _G.lines.head = _G.lines.current = NULL;
8249 /* if debug information required */
8250 if (options.debug && currFunc)
8252 debugFile->writeFunction (currFunc, lic);
8255 for (ic = lic; ic; ic = ic->next)
8257 _G.current_iCode = ic;
8259 if (ic->lineno && cln != ic->lineno)
8263 debugFile->writeCLine (ic);
8265 if (!options.noCcodeInAsm)
8267 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8268 printCLine(ic->filename, ic->lineno));
8272 if (options.iCodeInAsm)
8274 const char *iLine = printILine(ic);
8275 emit2 (";ic:%d: %s", ic->key, iLine);
8278 /* if the result is marked as
8279 spilt and rematerializable or code for
8280 this has already been generated then
8282 if (resultRemat (ic) || ic->generated)
8285 /* depending on the operation */
8289 emitDebug ("; genNot");
8294 emitDebug ("; genCpl");
8299 emitDebug ("; genUminus");
8304 emitDebug ("; genIpush");
8309 /* IPOP happens only when trying to restore a
8310 spilt live range, if there is an ifx statement
8311 following this pop then the if statement might
8312 be using some of the registers being popped which
8313 would destroy the contents of the register so
8314 we need to check for this condition and handle it */
8316 ic->next->op == IFX &&
8317 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8319 emitDebug ("; genIfx");
8320 genIfx (ic->next, ic);
8324 emitDebug ("; genIpop");
8330 emitDebug ("; genCall");
8335 emitDebug ("; genPcall");
8340 emitDebug ("; genFunction");
8345 emitDebug ("; genEndFunction");
8346 genEndFunction (ic);
8350 emitDebug ("; genRet");
8355 emitDebug ("; genLabel");
8360 emitDebug ("; genGoto");
8365 emitDebug ("; genPlus");
8370 emitDebug ("; genMinus");
8375 emitDebug ("; genMult");
8380 emitDebug ("; genDiv");
8385 emitDebug ("; genMod");
8390 emitDebug ("; genCmpGt");
8391 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8395 emitDebug ("; genCmpLt");
8396 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8403 /* note these two are xlated by algebraic equivalence
8404 during parsing SDCC.y */
8405 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8406 "got '>=' or '<=' shouldn't have come here");
8410 emitDebug ("; genCmpEq");
8411 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8415 emitDebug ("; genAndOp");
8420 emitDebug ("; genOrOp");
8425 emitDebug ("; genXor");
8426 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8430 emitDebug ("; genOr");
8431 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8435 emitDebug ("; genAnd");
8436 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8440 emitDebug ("; genInline");
8445 emitDebug ("; genRRC");
8450 emitDebug ("; genRLC");
8455 emitDebug ("; genGetHBIT");
8460 emitDebug ("; genLeftShift");
8465 emitDebug ("; genRightShift");
8469 case GET_VALUE_AT_ADDRESS:
8470 emitDebug ("; genPointerGet");
8476 if (POINTER_SET (ic))
8478 emitDebug ("; genAssign (pointer)");
8483 emitDebug ("; genAssign");
8489 emitDebug ("; genIfx");
8494 emitDebug ("; genAddrOf");
8499 emitDebug ("; genJumpTab");
8504 emitDebug ("; genCast");
8509 emitDebug ("; genReceive");
8514 if (ic->builtinSEND)
8516 emitDebug ("; genBuiltIn");
8521 emitDebug ("; addSet");
8522 addSet (&_G.sendSet, ic);
8527 emitDebug ("; genArrayInit");
8531 case DUMMY_READ_VOLATILE:
8532 emitDebug ("; genDummyRead");
8537 emitDebug ("; genCritical");
8542 emitDebug ("; genEndCritical");
8543 genEndCritical (ic);
8552 /* now we are ready to call the
8553 peep hole optimizer */
8554 if (!options.nopeep)
8555 peepHole (&_G.lines.head);
8557 /* This is unfortunate */
8558 /* now do the actual printing */
8560 struct dbuf_s *buf = codeOutBuf;
8561 if (isInHome () && codeOutBuf == &code->oBuf)
8562 codeOutBuf = &home->oBuf;
8563 printLine (_G.lines.head, codeOutBuf);
8564 if (_G.flushStatics)
8567 _G.flushStatics = 0;
8572 freeTrace(&_G.lines.trace);
8573 freeTrace(&_G.trace.aops);
8579 _isPairUsed (iCode * ic, PAIR_ID pairId)
8585 if (bitVectBitValue (ic->rMask, D_IDX))
8587 if (bitVectBitValue (ic->rMask, E_IDX))
8597 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8600 value *val = aop->aopu.aop_lit;
8602 wassert (aop->type == AOP_LIT);
8603 wassert (!IS_FLOAT (val->type));
8605 v = ulFromVal (val);
8613 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8614 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));