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 == left->type)
1390 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1392 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1394 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1397 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1404 _G.pairs[pairId].last_type = left->type;
1405 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1406 _G.pairs[pairId].offset = offset;
1408 /* Both a lit on the right and a true symbol on the left */
1409 emit2 ("ld %s,!hashedstr", pair, l);
1413 makeFreePairId (iCode *ic, bool *pisUsed)
1419 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1423 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1441 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1443 /* if this is remateriazable */
1444 if (isLitWord (aop)) {
1445 fetchLitPair (pairId, aop, offset);
1449 if (getPairId (aop) == pairId)
1453 /* we need to get it byte by byte */
1454 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1455 aopGet (aop, offset, FALSE);
1456 switch (aop->size - offset) {
1458 emit2 ("ld l,!*hl");
1459 emit2 ("ld h,!immedbyte", 0);
1462 // PENDING: Requires that you are only fetching two bytes.
1465 emit2 ("ld h,!*hl");
1469 wassertl (0, "Attempted to fetch too much data into HL");
1473 else if (IS_Z80 && aop->type == AOP_IY) {
1474 /* Instead of fetching relative to IY, just grab directly
1475 from the address IY refers to */
1476 char *l = aopGetLitWordLong (aop, offset, FALSE);
1478 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1480 if (aop->size < 2) {
1481 emit2("ld %s,!zero", _pairs[pairId].h);
1484 else if (pairId == PAIR_IY)
1488 emit2 ("push %s", _pairs[getPairId(aop)].name);
1494 PAIR_ID id = makeFreePairId (ic, &isUsed);
1497 /* Can't load into parts, so load into HL then exchange. */
1498 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1499 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1500 emit2 ("push %s", _pairs[id].name);
1506 else if (isUnsplitable(aop))
1508 emit2("push %s", _pairs[getPairId(aop)].name);
1509 emit2("pop %s", _pairs[pairId].name);
1513 /* Swapping register contents within register pair */
1514 if(!strcmp(aopGet (aop, offset, FALSE), _pairs[pairId].h))
1516 emit2 ("ld a,%s",aopGet (aop, offset + 1, FALSE));
1517 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1518 emit2 ("ld %s,a", _pairs[pairId].h);
1522 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1523 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1526 /* PENDING: check? */
1527 if (pairId == PAIR_HL)
1528 spillPair (PAIR_HL);
1533 fetchPair (PAIR_ID pairId, asmop * aop)
1535 fetchPairLong (pairId, aop, NULL, 0);
1539 fetchHL (asmop * aop)
1541 fetchPair (PAIR_HL, aop);
1545 setupPairFromSP (PAIR_ID id, int offset)
1547 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1549 if (_G.preserveCarry)
1555 if (offset < INT8MIN || offset > INT8MAX)
1557 emit2 ("ld hl,!immedword", offset);
1558 emit2 ("add hl,sp");
1562 emit2 ("!ldahlsp", offset);
1565 if (_G.preserveCarry)
1573 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1578 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1579 fetchLitPair (pairId, aop, 0);
1583 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1585 fetchLitPair (pairId, aop, offset);
1586 _G.pairs[pairId].offset = offset;
1590 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1591 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1594 int offset = aop->aopu.aop_stk + _G.stack.offset;
1596 if (_G.pairs[pairId].last_type == aop->type &&
1597 _G.pairs[pairId].offset == offset)
1603 /* PENDING: Do this better. */
1604 if (_G.preserveCarry)
1606 sprintf (buffer, "%d", offset + _G.stack.pushed);
1607 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1608 emit2 ("add %s,sp", _pairs[pairId].name);
1609 _G.pairs[pairId].last_type = aop->type;
1610 _G.pairs[pairId].offset = offset;
1611 if (_G.preserveCarry)
1619 /* Doesnt include _G.stack.pushed */
1620 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1622 if (aop->aopu.aop_stk > 0)
1624 abso += _G.stack.param_offset;
1626 assert (pairId == PAIR_HL);
1627 /* In some cases we can still inc or dec hl */
1628 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1630 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1634 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1636 _G.pairs[pairId].offset = abso;
1641 if (pairId != aop->aopu.aop_pairId)
1642 genMovePairPair(aop->aopu.aop_pairId, pairId);
1643 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1649 _G.pairs[pairId].last_type = aop->type;
1655 emit2 ("!tlabeldef", key);
1656 _G.lines.current->isLabel = 1;
1660 /*-----------------------------------------------------------------*/
1661 /* aopGet - for fetching value of the aop */
1662 /*-----------------------------------------------------------------*/
1664 aopGet (asmop * aop, int offset, bool bit16)
1666 // char *s = buffer;
1668 /* offset is greater than size then zero */
1669 /* PENDING: this seems a bit screwed in some pointer cases. */
1670 if (offset > (aop->size - 1) &&
1671 aop->type != AOP_LIT)
1673 tsprintf (buffer, sizeof(buffer), "!zero");
1674 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1677 /* depending on type */
1681 tsprintf (buffer, sizeof(buffer), "!zero");
1682 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1685 /* PENDING: re-target */
1687 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1692 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1695 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1698 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1701 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1704 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1708 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1709 SNPRINTF (buffer, sizeof(buffer), "a");
1711 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1717 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1718 SNPRINTF (buffer, sizeof(buffer), "a");
1720 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1723 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1726 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1727 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1728 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1730 else if( z80_opts.port_mode == 180 )
1731 { /* z180 in0/out0 mode */
1732 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1736 emit2( "in a,(%s)", aop->aopu.aop_dir );
1739 SNPRINTF (buffer, sizeof(buffer), "a");
1741 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1745 return aop->aopu.aop_reg[offset]->name;
1749 setupPair (PAIR_HL, aop, offset);
1750 tsprintf (buffer, sizeof(buffer), "!*hl");
1752 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1756 setupPair (PAIR_IY, aop, offset);
1757 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1759 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1763 setupPair (PAIR_IY, aop, offset);
1764 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1766 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1771 setupPair (PAIR_HL, aop, offset);
1772 tsprintf (buffer, sizeof(buffer), "!*hl");
1776 if (aop->aopu.aop_stk >= 0)
1777 offset += _G.stack.param_offset;
1778 tsprintf (buffer, sizeof(buffer),
1779 "!*ixx", aop->aopu.aop_stk + offset);
1782 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1785 wassertl (0, "Tried to fetch from a bit variable");
1794 tsprintf(buffer, sizeof(buffer), "!zero");
1795 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1799 wassert (offset < 2);
1800 return aop->aopu.aop_str[offset];
1803 return aopLiteral (aop->aopu.aop_lit, offset);
1807 unsigned long v = aop->aopu.aop_simplelit;
1810 tsprintf (buffer, sizeof(buffer),
1811 "!immedbyte", (unsigned int) v & 0xff);
1813 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1817 return aop->aopu.aop_str[offset];
1820 setupPair (aop->aopu.aop_pairId, aop, offset);
1821 if (aop->aopu.aop_pairId==PAIR_IX)
1822 tsprintf (buffer, sizeof(buffer), "!*ixx", offset);
1823 else if (aop->aopu.aop_pairId==PAIR_IY)
1824 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1826 SNPRINTF (buffer, sizeof(buffer),
1827 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1829 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1834 wassertl (0, "aopget got unsupported aop->type");
1839 isRegString (const char *s)
1841 if (!strcmp (s, "b") ||
1853 isConstant (const char *s)
1855 /* This is a bit of a hack... */
1856 return (*s == '#' || *s == '$');
1860 canAssignToPtr (const char *s)
1862 if (isRegString (s))
1869 /*-----------------------------------------------------------------*/
1870 /* aopPut - puts a string for a aop */
1871 /*-----------------------------------------------------------------*/
1873 aopPut (asmop * aop, const char *s, int offset)
1877 if (aop->size && offset > (aop->size - 1))
1879 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1880 "aopPut got offset > aop->size");
1885 tsprintf(buffer2, sizeof(buffer2), s);
1888 /* will assign value to value */
1889 /* depending on where it is ofcourse */
1893 _moveA (s); /* in case s is volatile */
1899 if (strcmp (s, "a"))
1900 emit2 ("ld a,%s", s);
1901 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1908 if (strcmp (s, "a"))
1909 emit2 ("ld a,%s", s);
1910 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1913 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1920 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1921 && s[0] != 'h' && s[0] != 'l'))
1923 emit2( "ld a,%s", s );
1927 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1928 emit2( "out (c),%s", s );
1933 spillPair (PAIR_BC);
1935 else if( z80_opts.port_mode == 180 )
1936 { /* z180 in0/out0 mode */
1937 emit2( "ld a,%s", s );
1938 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1942 emit2( "ld a,%s", s );
1943 emit2( "out (%s),a", aop->aopu.aop_dir );
1949 if (!strcmp (s, "!*hl"))
1950 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1953 aop->aopu.aop_reg[offset]->name, s);
1954 spillPairReg(aop->aopu.aop_reg[offset]->name);
1959 if (!canAssignToPtr (s))
1961 emit2 ("ld a,%s", s);
1962 setupPair (PAIR_IY, aop, offset);
1963 emit2 ("ld !*iyx,a", offset);
1967 setupPair (PAIR_IY, aop, offset);
1968 emit2 ("ld !*iyx,%s", offset, s);
1974 /* PENDING: for re-target */
1975 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1977 emit2 ("ld a,!*hl");
1980 setupPair (PAIR_HL, aop, offset);
1982 emit2 ("ld !*hl,%s", s);
1987 if (!canAssignToPtr (s))
1989 emit2 ("ld a,%s", s);
1990 setupPair (PAIR_IY, aop, offset);
1991 emit2 ("ld !*iyx,a", offset);
1995 setupPair (PAIR_IY, aop, offset);
1996 emit2 ("ld !*iyx,%s", offset, s);
2003 /* PENDING: re-target */
2004 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2006 emit2 ("ld a,!*hl");
2009 setupPair (PAIR_HL, aop, offset);
2010 if (!canAssignToPtr (s))
2012 emit2 ("ld a,%s", s);
2013 emit2 ("ld !*hl,a");
2016 emit2 ("ld !*hl,%s", s);
2020 if (aop->aopu.aop_stk >= 0)
2021 offset += _G.stack.param_offset;
2022 if (!canAssignToPtr (s))
2024 emit2 ("ld a,%s", s);
2025 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2029 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2035 /* if bit variable */
2036 if (!aop->aopu.aop_dir)
2038 emit2 ("ld a,!zero");
2043 /* In bit space but not in C - cant happen */
2044 wassertl (0, "Tried to write into a bit variable");
2050 if (strcmp (aop->aopu.aop_str[offset], s))
2052 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2054 spillPairReg(aop->aopu.aop_str[offset]);
2059 if (!offset && (strcmp (s, "acc") == 0))
2063 wassertl (0, "Tried to access past the end of A");
2067 if (strcmp (aop->aopu.aop_str[offset], s))
2069 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2070 spillPairReg(aop->aopu.aop_str[offset]);
2076 wassert (offset < 2);
2077 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2078 spillPairReg(aop->aopu.aop_str[offset]);
2082 setupPair (aop->aopu.aop_pairId, aop, offset);
2083 if (aop->aopu.aop_pairId==PAIR_IX)
2084 emit2 ("ld !*ixx,%s", 0, s);
2085 else if (aop->aopu.aop_pairId==PAIR_IY)
2086 emit2 ("ld !*iyx,%s", 0, s);
2088 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2092 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2093 "aopPut got unsupported aop->type");
2098 #define AOP(op) op->aop
2099 #define AOP_TYPE(op) AOP(op)->type
2100 #define AOP_SIZE(op) AOP(op)->size
2101 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2102 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2105 commitPair (asmop * aop, PAIR_ID id)
2107 /* PENDING: Verify this. */
2108 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2112 aopPut (aop, "a", 0);
2113 aopPut (aop, "d", 1);
2118 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2120 char *l = aopGetLitWordLong (aop, 0, FALSE);
2123 emit2 ("ld (%s),%s", l, _pairs[id].name);
2127 aopPut (aop, _pairs[id].l, 0);
2128 aopPut (aop, _pairs[id].h, 1);
2133 /*-----------------------------------------------------------------*/
2134 /* getDataSize - get the operand data size */
2135 /*-----------------------------------------------------------------*/
2137 getDataSize (operand * op)
2140 size = AOP_SIZE (op);
2144 wassertl (0, "Somehow got a three byte data pointer");
2149 /*-----------------------------------------------------------------*/
2150 /* movLeft2Result - move byte from left to result */
2151 /*-----------------------------------------------------------------*/
2153 movLeft2Result (operand * left, int offl,
2154 operand * result, int offr, int sign)
2158 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2160 l = aopGet (AOP (left), offl, FALSE);
2164 aopPut (AOP (result), l, offr);
2168 if (getDataSize (left) == offl + 1)
2170 emit2 ("ld a,%s", l);
2171 aopPut (AOP (result), "a", offr);
2178 movLeft2ResultLong (operand * left, int offl,
2179 operand * result, int offr, int sign,
2184 movLeft2Result (left, offl, result, offr, sign);
2188 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2189 wassertl (size == 2, "Only implemented for two bytes or one");
2191 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2193 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2194 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2196 spillPair (PAIR_HL);
2198 else if ( getPairId ( AOP (result)) == PAIR_IY)
2200 PAIR_ID id = getPairId (AOP (left));
2201 if (id != PAIR_INVALID)
2203 emit2("push %s", _pairs[id].name);
2214 movLeft2Result (left, offl, result, offr, sign);
2215 movLeft2Result (left, offl+1, result, offr+1, sign);
2220 /** Put Acc into a register set
2223 outAcc (operand * result)
2226 size = getDataSize (result);
2229 aopPut (AOP (result), "a", 0);
2232 /* unsigned or positive */
2235 aopPut (AOP (result), "!zero", offset++);
2240 /** Take the value in carry and put it into a register
2243 outBitC (operand * result)
2245 /* if the result is bit */
2246 if (AOP_TYPE (result) == AOP_CRY)
2248 if (!IS_OP_RUONLY (result))
2249 aopPut (AOP (result), "c", 0);
2253 emit2 ("ld a,!zero");
2259 /*-----------------------------------------------------------------*/
2260 /* toBoolean - emit code for orl a,operator(sizeop) */
2261 /*-----------------------------------------------------------------*/
2263 _toBoolean (operand * oper)
2265 int size = AOP_SIZE (oper);
2269 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2272 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2276 if (AOP (oper)->type != AOP_ACC)
2279 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2285 /*-----------------------------------------------------------------*/
2286 /* genNot - generate code for ! operation */
2287 /*-----------------------------------------------------------------*/
2292 /* assign asmOps to operand & result */
2293 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2294 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2296 /* if in bit space then a special case */
2297 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2299 wassertl (0, "Tried to negate a bit");
2302 _toBoolean (IC_LEFT (ic));
2307 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2308 emit2 ("sub a,!one");
2309 outBitC (IC_RESULT (ic));
2311 /* release the aops */
2312 freeAsmop (IC_LEFT (ic), NULL, ic);
2313 freeAsmop (IC_RESULT (ic), NULL, ic);
2316 /*-----------------------------------------------------------------*/
2317 /* genCpl - generate code for complement */
2318 /*-----------------------------------------------------------------*/
2326 /* assign asmOps to operand & result */
2327 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2328 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2330 /* if both are in bit space then
2332 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2333 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2335 wassertl (0, "Left and the result are in bit space");
2338 size = AOP_SIZE (IC_RESULT (ic));
2341 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2344 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2347 /* release the aops */
2348 freeAsmop (IC_LEFT (ic), NULL, ic);
2349 freeAsmop (IC_RESULT (ic), NULL, ic);
2353 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2360 store de into result
2365 store de into result
2367 const char *first = isAdd ? "add" : "sub";
2368 const char *later = isAdd ? "adc" : "sbc";
2370 wassertl (IS_GB, "Code is only relevent to the gbz80");
2371 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2373 fetchPair (PAIR_DE, left);
2376 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2379 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2382 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2383 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2385 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2386 aopGet (right, MSB24, FALSE);
2390 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2393 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2395 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2396 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2400 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2402 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2405 /*-----------------------------------------------------------------*/
2406 /* genUminusFloat - unary minus for floating points */
2407 /*-----------------------------------------------------------------*/
2409 genUminusFloat (operand * op, operand * result)
2411 int size, offset = 0;
2413 emitDebug("; genUminusFloat");
2415 /* for this we just need to flip the
2416 first bit then copy the rest in place */
2417 size = AOP_SIZE (op) - 1;
2419 _moveA(aopGet (AOP (op), MSB32, FALSE));
2421 emit2("xor a,!immedbyte", 0x80);
2422 aopPut (AOP (result), "a", MSB32);
2426 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2431 /*-----------------------------------------------------------------*/
2432 /* genUminus - unary minus code generation */
2433 /*-----------------------------------------------------------------*/
2435 genUminus (iCode * ic)
2438 sym_link *optype, *rtype;
2441 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2442 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2444 /* if both in bit space then special
2446 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2447 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2449 wassertl (0, "Left and right are in bit space");
2453 optype = operandType (IC_LEFT (ic));
2454 rtype = operandType (IC_RESULT (ic));
2456 /* if float then do float stuff */
2457 if (IS_FLOAT (optype))
2459 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2463 /* otherwise subtract from zero */
2464 size = AOP_SIZE (IC_LEFT (ic));
2466 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2468 /* Create a new asmop with value zero */
2469 asmop *azero = newAsmop (AOP_SIMPLELIT);
2470 azero->aopu.aop_simplelit = 0;
2472 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2480 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2481 emit2 ("ld a,!zero");
2482 emit2 ("sbc a,%s", l);
2483 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2486 /* if any remaining bytes in the result */
2487 /* we just need to propagate the sign */
2488 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2493 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2497 /* release the aops */
2498 freeAsmop (IC_LEFT (ic), NULL, ic);
2499 freeAsmop (IC_RESULT (ic), NULL, ic);
2502 /*-----------------------------------------------------------------*/
2503 /* assignResultValue - */
2504 /*-----------------------------------------------------------------*/
2506 assignResultValue (operand * oper)
2508 int size = AOP_SIZE (oper);
2511 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2512 topInA = requiresHL (AOP (oper));
2514 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2516 /* We do it the hard way here. */
2518 aopPut (AOP (oper), _fReturn[0], 0);
2519 aopPut (AOP (oper), _fReturn[1], 1);
2521 aopPut (AOP (oper), _fReturn[0], 2);
2522 aopPut (AOP (oper), _fReturn[1], 3);
2526 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2527 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2530 _emitMove ("a", _fReturn[size-1]);
2531 _emitMove (_fReturn[size-1], _fReturn[size]);
2532 _emitMove (_fReturn[size], "a");
2533 aopPut (AOP (oper), _fReturn[size], size-1);
2538 aopPut (AOP (oper), _fReturn[size], size);
2543 /** Simple restore that doesn't take into account what is used in the
2547 _restoreRegsAfterCall(void)
2549 if (_G.stack.pushedDE)
2552 _G.stack.pushedDE = FALSE;
2554 if (_G.stack.pushedBC)
2557 _G.stack.pushedBC = FALSE;
2559 _G.saves.saved = FALSE;
2563 _saveRegsForCall(iCode *ic, int sendSetSize)
2566 o Stack parameters are pushed before this function enters
2567 o DE and BC may be used in this function.
2568 o HL and DE may be used to return the result.
2569 o HL and DE may be used to send variables.
2570 o DE and BC may be used to store the result value.
2571 o HL may be used in computing the sent value of DE
2572 o The iPushes for other parameters occur before any addSets
2574 Logic: (to be run inside the first iPush or if none, before sending)
2575 o Compute if DE and/or BC are in use over the call
2576 o Compute if DE is used in the send set
2577 o Compute if DE and/or BC are used to hold the result value
2578 o If (DE is used, or in the send set) and is not used in the result, push.
2579 o If BC is used and is not in the result, push
2581 o If DE is used in the send set, fetch
2582 o If HL is used in the send set, fetch
2586 if (_G.saves.saved == FALSE) {
2587 bool deInUse, bcInUse;
2589 bool bcInRet = FALSE, deInRet = FALSE;
2592 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2593 z80_rUmaskForOp (IC_RESULT(ic)));
2595 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2596 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2598 deSending = (sendSetSize > 1);
2600 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2602 if (bcInUse && bcInRet == FALSE) {
2604 _G.stack.pushedBC = TRUE;
2606 if (deInUse && deInRet == FALSE) {
2608 _G.stack.pushedDE = TRUE;
2611 _G.saves.saved = TRUE;
2614 /* Already saved. */
2618 /*-----------------------------------------------------------------*/
2619 /* genIpush - genrate code for pushing this gets a little complex */
2620 /*-----------------------------------------------------------------*/
2622 genIpush (iCode * ic)
2624 int size, offset = 0;
2627 /* if this is not a parm push : ie. it is spill push
2628 and spill push is always done on the local stack */
2631 wassertl(0, "Encountered an unsupported spill push.");
2635 if (_G.saves.saved == FALSE) {
2636 /* Caller saves, and this is the first iPush. */
2637 /* Scan ahead until we find the function that we are pushing parameters to.
2638 Count the number of addSets on the way to figure out what registers
2639 are used in the send set.
2642 iCode *walk = ic->next;
2645 if (walk->op == SEND) {
2648 else if (walk->op == CALL || walk->op == PCALL) {
2657 _saveRegsForCall(walk, nAddSets);
2660 /* Already saved by another iPush. */
2663 /* then do the push */
2664 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2666 size = AOP_SIZE (IC_LEFT (ic));
2668 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2670 _G.stack.pushed += 2;
2671 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2677 fetchHL (AOP (IC_LEFT (ic)));
2679 spillPair (PAIR_HL);
2680 _G.stack.pushed += 2;
2685 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2687 spillPair (PAIR_HL);
2688 _G.stack.pushed += 2;
2689 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2691 spillPair (PAIR_HL);
2692 _G.stack.pushed += 2;
2698 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2700 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2702 emit2 ("ld a,(%s)", l);
2707 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2708 if (!strcmp(l, "b"))
2710 else if (!strcmp(l, "d"))
2712 else if (!strcmp(l, "h"))
2716 emit2 ("ld a,%s", l);
2725 freeAsmop (IC_LEFT (ic), NULL, ic);
2728 /*-----------------------------------------------------------------*/
2729 /* genIpop - recover the registers: can happen only for spilling */
2730 /*-----------------------------------------------------------------*/
2732 genIpop (iCode * ic)
2737 /* if the temp was not pushed then */
2738 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2741 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2742 size = AOP_SIZE (IC_LEFT (ic));
2743 offset = (size - 1);
2744 if (isPair (AOP (IC_LEFT (ic))))
2746 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2754 spillPair (PAIR_HL);
2755 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2759 freeAsmop (IC_LEFT (ic), NULL, ic);
2762 /* This is quite unfortunate */
2764 setArea (int inHome)
2767 static int lastArea = 0;
2769 if (_G.in_home != inHome) {
2771 const char *sz = port->mem.code_name;
2772 port->mem.code_name = "HOME";
2773 emit2("!area", CODE_NAME);
2774 port->mem.code_name = sz;
2777 emit2("!area", CODE_NAME); */
2778 _G.in_home = inHome;
2789 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2793 symbol *sym = OP_SYMBOL (op);
2795 if (sym->isspilt || sym->nRegs == 0)
2798 aopOp (op, ic, FALSE, FALSE);
2801 if (aop->type == AOP_REG)
2804 for (i = 0; i < aop->size; i++)
2806 if (pairId == PAIR_DE)
2808 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2809 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2811 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2814 else if (pairId == PAIR_BC)
2816 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2817 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2819 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2829 freeAsmop (IC_LEFT (ic), NULL, ic);
2833 /** Emit the code for a call statement
2836 emitCall (iCode * ic, bool ispcall)
2838 bool bInRet, cInRet, dInRet, eInRet;
2839 sym_link *dtype = operandType (IC_LEFT (ic));
2841 /* if caller saves & we have not saved then */
2847 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2849 /* if send set is not empty then assign */
2854 int nSend = elementsInSet(_G.sendSet);
2855 bool swapped = FALSE;
2857 int _z80_sendOrder[] = {
2862 /* Check if the parameters are swapped. If so route through hl instead. */
2863 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2865 sic = setFirstItem(_G.sendSet);
2866 sic = setNextItem(_G.sendSet);
2868 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2869 /* The second send value is loaded from one the one that holds the first
2870 send, i.e. it is overwritten. */
2871 /* Cache the first in HL, and load the second from HL instead. */
2872 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2873 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2879 for (sic = setFirstItem (_G.sendSet); sic;
2880 sic = setNextItem (_G.sendSet))
2883 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2885 size = AOP_SIZE (IC_LEFT (sic));
2886 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2887 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2889 // PENDING: Mild hack
2890 if (swapped == TRUE && send == 1) {
2892 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2895 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2897 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2900 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2904 freeAsmop (IC_LEFT (sic), NULL, sic);
2911 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2913 werror (W_INDIR_BANKED);
2915 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2917 if (isLitWord (AOP (IC_LEFT (ic))))
2919 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2923 symbol *rlbl = newiTempLabel (NULL);
2924 spillPair (PAIR_HL);
2925 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2927 _G.stack.pushed += 2;
2929 fetchHL (AOP (IC_LEFT (ic)));
2931 emit2 ("!tlabeldef", (rlbl->key + 100));
2932 _G.lines.current->isLabel = 1;
2933 _G.stack.pushed -= 2;
2935 freeAsmop (IC_LEFT (ic), NULL, ic);
2939 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2940 OP_SYMBOL (IC_LEFT (ic))->rname :
2941 OP_SYMBOL (IC_LEFT (ic))->name;
2942 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2944 emit2 ("call banked_call");
2945 emit2 ("!dws", name);
2946 emit2 ("!dw !bankimmeds", name);
2951 emit2 ("call %s", name);
2956 /* Mark the registers as restored. */
2957 _G.saves.saved = FALSE;
2959 /* adjust the stack for parameters if required */
2962 int i = ic->parmBytes;
2964 _G.stack.pushed -= i;
2967 emit2 ("!ldaspsp", i);
2974 emit2 ("ld iy,!immedword", i);
2975 emit2 ("add iy,sp");
2993 /* if we need assign a result value */
2994 if ((IS_ITEMP (IC_RESULT (ic)) &&
2995 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2996 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2997 IS_TRUE_SYMOP (IC_RESULT (ic)))
2999 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3001 assignResultValue (IC_RESULT (ic));
3003 freeAsmop (IC_RESULT (ic), NULL, ic);
3009 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3010 bInRet = bitVectBitValue(result, B_IDX);
3011 cInRet = bitVectBitValue(result, C_IDX);
3012 dInRet = bitVectBitValue(result, D_IDX);
3013 eInRet = bitVectBitValue(result, E_IDX);
3023 if (_G.stack.pushedDE)
3025 if (dInRet && eInRet)
3027 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3031 /* Only restore E */
3038 /* Only restore D */
3046 _G.stack.pushedDE = FALSE;
3049 if (_G.stack.pushedBC)
3051 if (bInRet && cInRet)
3053 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3057 /* Only restore C */
3064 /* Only restore B */
3072 _G.stack.pushedBC = FALSE;
3076 /*-----------------------------------------------------------------*/
3077 /* genCall - generates a call statement */
3078 /*-----------------------------------------------------------------*/
3080 genCall (iCode * ic)
3082 emitCall (ic, FALSE);
3085 /*-----------------------------------------------------------------*/
3086 /* genPcall - generates a call by pointer statement */
3087 /*-----------------------------------------------------------------*/
3089 genPcall (iCode * ic)
3091 emitCall (ic, TRUE);
3094 /*-----------------------------------------------------------------*/
3095 /* resultRemat - result is rematerializable */
3096 /*-----------------------------------------------------------------*/
3098 resultRemat (iCode * ic)
3100 if (SKIP_IC (ic) || ic->op == IFX)
3103 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3105 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3106 if (sym->remat && !POINTER_SET (ic))
3113 extern set *publics;
3115 /*-----------------------------------------------------------------*/
3116 /* genFunction - generated code for function entry */
3117 /*-----------------------------------------------------------------*/
3119 genFunction (iCode * ic)
3123 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3126 bool bcInUse = FALSE;
3127 bool deInUse = FALSE;
3129 setArea (IFFUNC_NONBANKED (sym->type));
3131 /* PENDING: Reset the receive offset as it
3132 doesn't seem to get reset anywhere else.
3134 _G.receiveOffset = 0;
3136 /* Record the last function name for debugging. */
3137 _G.lastFunctionName = sym->rname;
3139 /* Create the function header */
3140 emit2 ("!functionheader", sym->name);
3141 if (!IS_STATIC(sym->etype))
3143 sprintf (buffer, "%s_start", sym->rname);
3144 emit2 ("!labeldef", buffer);
3145 _G.lines.current->isLabel = 1;
3147 emit2 ("!functionlabeldef", sym->rname);
3148 _G.lines.current->isLabel = 1;
3150 ftype = operandType (IC_LEFT (ic));
3152 if (IFFUNC_ISNAKED(ftype))
3154 emitDebug("; naked function: no prologue.");
3158 /* if this is an interrupt service routine
3159 then save all potentially used registers. */
3160 if (IFFUNC_ISISR (sym->type))
3162 /* If critical function then turn interrupts off */
3163 /* except when no interrupt number is given then it implies the NMI handler */
3164 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3173 /* This is a non-ISR function.
3174 If critical function then turn interrupts off */
3175 if (IFFUNC_ISCRITICAL (sym->type))
3183 //get interrupt enable flag IFF2 into P/O
3192 if (options.profile)
3194 emit2 ("!profileenter");
3197 /* PENDING: callee-save etc */
3199 _G.stack.param_offset = 0;
3201 if (z80_opts.calleeSavesBC)
3206 /* Detect which registers are used. */
3207 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3210 for (i = 0; i < sym->regsUsed->size; i++)
3212 if (bitVectBitValue (sym->regsUsed, i))
3226 /* Other systems use DE as a temporary. */
3237 _G.stack.param_offset += 2;
3240 _G.calleeSaves.pushedBC = bcInUse;
3245 _G.stack.param_offset += 2;
3248 _G.calleeSaves.pushedDE = deInUse;
3250 /* adjust the stack for the function */
3251 _G.stack.last = sym->stack;
3254 for (sym = setFirstItem (istack->syms); sym;
3255 sym = setNextItem (istack->syms))
3257 if (sym->_isparm && !IS_REGPARM (sym->etype))
3263 sym = OP_SYMBOL (IC_LEFT (ic));
3265 _G.omitFramePtr = options.ommitFramePtr;
3266 if (IS_Z80 && !stackParm && !sym->stack)
3268 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3269 /* the above !sym->stack condition can be removed. -- EEP */
3271 emit2 ("!ldaspsp", -sym->stack);
3272 _G.omitFramePtr = TRUE;
3274 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3275 emit2 ("!enterxl", sym->stack);
3276 else if (sym->stack)
3278 if ((optimize.codeSize && sym->stack <= 8) || sym->stack <= 4)
3280 int stack = sym->stack;
3291 emit2 ("!enterx", sym->stack);
3296 _G.stack.offset = sym->stack;
3299 /*-----------------------------------------------------------------*/
3300 /* genEndFunction - generates epilogue for functions */
3301 /*-----------------------------------------------------------------*/
3303 genEndFunction (iCode * ic)
3305 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3307 if (IFFUNC_ISNAKED(sym->type))
3309 emitDebug("; naked function: no epilogue.");
3313 /* PENDING: calleeSave */
3314 if (IS_Z80 && _G.omitFramePtr)
3316 if (_G.stack.offset)
3317 emit2 ("!ldaspsp", _G.stack.offset);
3319 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3321 emit2 ("!leavexl", _G.stack.offset);
3323 else if (_G.stack.offset)
3325 emit2 ("!leavex", _G.stack.offset);
3332 if (_G.calleeSaves.pushedDE)
3335 _G.calleeSaves.pushedDE = FALSE;
3338 if (_G.calleeSaves.pushedBC)
3341 _G.calleeSaves.pushedBC = FALSE;
3344 if (options.profile)
3346 emit2 ("!profileexit");
3349 /* if this is an interrupt service routine
3350 then save all potentially used registers. */
3351 if (IFFUNC_ISISR (sym->type))
3355 /* If critical function then turn interrupts back on */
3356 /* except when no interrupt number is given then it implies the NMI handler */
3357 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3364 /* This is a non-ISR function.
3365 If critical function then turn interrupts back on */
3366 if (IFFUNC_ISCRITICAL (sym->type))
3374 symbol *tlbl = newiTempLabel (NULL);
3377 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3378 //don't enable interrupts as they were off before
3379 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3381 emit2 ("!tlabeldef", (tlbl->key + 100));
3382 _G.lines.current->isLabel = 1;
3387 if (options.debug && currFunc)
3389 debugFile->writeEndFunction (currFunc, ic, 1);
3392 if (IFFUNC_ISISR (sym->type))
3394 /* "critical interrupt" is used to imply NMI handler */
3395 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3402 /* Both banked and non-banked just ret */
3406 if (!IS_STATIC(sym->etype))
3408 sprintf (buffer, "%s_end", sym->rname);
3409 emit2 ("!labeldef", buffer);
3410 _G.lines.current->isLabel = 1;
3413 _G.flushStatics = 1;
3414 _G.stack.pushed = 0;
3415 _G.stack.offset = 0;
3418 /*-----------------------------------------------------------------*/
3419 /* genRet - generate code for return statement */
3420 /*-----------------------------------------------------------------*/
3425 /* Errk. This is a hack until I can figure out how
3426 to cause dehl to spill on a call */
3427 int size, offset = 0;
3429 /* if we have no return value then
3430 just generate the "ret" */
3434 /* we have something to return then
3435 move the return value into place */
3436 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3437 size = AOP_SIZE (IC_LEFT (ic));
3439 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3442 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3446 emit2 ("ld de,%s", l);
3450 emit2 ("ld hl,%s", l);
3456 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3460 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3462 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3463 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3469 l = aopGet (AOP (IC_LEFT (ic)), offset,
3471 if (strcmp (_fReturn[offset], l))
3472 emit2 ("ld %s,%s", _fReturn[offset], l);
3477 freeAsmop (IC_LEFT (ic), NULL, ic);
3480 /* generate a jump to the return label
3481 if the next is not the return statement */
3482 if (!(ic->next && ic->next->op == LABEL &&
3483 IC_LABEL (ic->next) == returnLabel))
3485 emit2 ("jp !tlabel", returnLabel->key + 100);
3488 /*-----------------------------------------------------------------*/
3489 /* genLabel - generates a label */
3490 /*-----------------------------------------------------------------*/
3492 genLabel (iCode * ic)
3494 /* special case never generate */
3495 if (IC_LABEL (ic) == entryLabel)
3498 emitLabel (IC_LABEL (ic)->key + 100);
3501 /*-----------------------------------------------------------------*/
3502 /* genGoto - generates a ljmp */
3503 /*-----------------------------------------------------------------*/
3505 genGoto (iCode * ic)
3507 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3510 /*-----------------------------------------------------------------*/
3511 /* genPlusIncr :- does addition with increment if possible */
3512 /*-----------------------------------------------------------------*/
3514 genPlusIncr (iCode * ic)
3516 unsigned int icount;
3517 unsigned int size = getDataSize (IC_RESULT (ic));
3518 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3520 /* will try to generate an increment */
3521 /* if the right side is not a literal
3523 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3526 emitDebug ("; genPlusIncr");
3528 icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3530 /* If result is a pair */
3531 if (resultId != PAIR_INVALID)
3533 if (isLitWord (AOP (IC_LEFT (ic))))
3535 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3538 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3540 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3542 PAIR_ID freep = getFreePairId (ic);
3543 if (freep != PAIR_INVALID)
3545 fetchPair (freep, AOP (IC_RIGHT (ic)));
3546 emit2 ("add hl,%s", _pairs[freep].name);
3552 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3553 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3560 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3564 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3568 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3573 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3575 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3576 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3580 /* if the literal value of the right hand side
3581 is greater than 4 then it is not worth it */
3585 /* if increment 16 bits in register */
3586 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3592 symbol *tlbl = NULL;
3593 tlbl = newiTempLabel (NULL);
3596 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3599 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3602 emitLabel (tlbl->key + 100);
3606 /* if the sizes are greater than 1 then we cannot */
3607 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3608 AOP_SIZE (IC_LEFT (ic)) > 1)
3611 /* If the result is in a register then we can load then increment.
3613 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3615 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3618 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3623 /* we can if the aops of the left & result match or
3624 if they are in registers and the registers are the
3626 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3630 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3638 /*-----------------------------------------------------------------*/
3639 /* outBitAcc - output a bit in acc */
3640 /*-----------------------------------------------------------------*/
3642 outBitAcc (operand * result)
3644 symbol *tlbl = newiTempLabel (NULL);
3645 /* if the result is a bit */
3646 if (AOP_TYPE (result) == AOP_CRY)
3648 wassertl (0, "Tried to write A into a bit");
3652 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3653 emit2 ("ld a,!one");
3654 emitLabel (tlbl->key + 100);
3660 couldDestroyCarry (asmop *aop)
3664 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3673 shiftIntoPair (int idx, asmop *aop)
3675 PAIR_ID id = PAIR_INVALID;
3677 wassertl (IS_Z80, "Only implemented for the Z80");
3678 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3680 emitDebug ("; Shift into pair idx %u", idx);
3686 setupPair (PAIR_HL, aop, 0);
3691 setupPair (PAIR_IY, aop, 0);
3693 emit2 ("pop %s", _pairs[id].name);
3697 setupPair (PAIR_IY, aop, 0);
3700 wassertl (0, "Internal error - hit default case");
3703 aop->type = AOP_PAIRPTR;
3704 aop->aopu.aop_pairId = id;
3705 _G.pairs[id].offset = 0;
3706 _G.pairs[id].last_type = aop->type;
3710 setupToPreserveCarry (iCode * ic)
3712 asmop *left = AOP (IC_LEFT (ic));
3713 asmop *right = AOP (IC_RIGHT (ic));
3714 asmop *result = AOP (IC_RESULT (ic));
3716 wassert (left && right);
3720 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3722 shiftIntoPair (0, right);
3723 /* check result again, in case right == result */
3724 if (couldDestroyCarry (result))
3726 if (!isPairInUse (PAIR_DE, ic))
3727 shiftIntoPair (1, result);
3729 shiftIntoPair (2, result);
3732 else if (couldDestroyCarry (right))
3734 if (getPairId (result) == PAIR_HL)
3735 _G.preserveCarry = TRUE;
3737 shiftIntoPair (0, right);
3739 else if (couldDestroyCarry (result))
3741 shiftIntoPair (0, result);
3750 /*-----------------------------------------------------------------*/
3751 /* genPlus - generates code for addition */
3752 /*-----------------------------------------------------------------*/
3754 genPlus (iCode * ic)
3756 int size, offset = 0;
3758 /* special cases :- */
3760 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3761 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3762 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3764 /* Swap the left and right operands if:
3766 if literal, literal on the right or
3767 if left requires ACC or right is already
3770 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3771 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3772 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3774 operand *t = IC_RIGHT (ic);
3775 IC_RIGHT (ic) = IC_LEFT (ic);
3779 /* if both left & right are in bit
3781 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3782 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3785 wassertl (0, "Tried to add two bits");
3788 /* if left in bit space & right literal */
3789 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3790 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3792 /* Can happen I guess */
3793 wassertl (0, "Tried to add a bit to a literal");
3796 /* if I can do an increment instead
3797 of add then GOOD for ME */
3798 if (genPlusIncr (ic) == TRUE)
3801 size = getDataSize (IC_RESULT (ic));
3803 /* Special case when left and right are constant */
3804 if (isPair (AOP (IC_RESULT (ic))))
3807 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3808 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3810 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3816 sprintf (buffer, "#(%s + %s)", left, right);
3817 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3822 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3824 /* Fetch into HL then do the add */
3825 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3826 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3828 spillPair (PAIR_HL);
3830 if (left == PAIR_HL && right != PAIR_INVALID)
3832 emit2 ("add hl,%s", _pairs[right].name);
3835 else if (right == PAIR_HL && left != PAIR_INVALID)
3837 emit2 ("add hl,%s", _pairs[left].name);
3840 else if (right != PAIR_INVALID && right != PAIR_HL)
3842 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3843 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3846 else if (left != PAIR_INVALID && left != PAIR_HL)
3848 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3849 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3858 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3860 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3861 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3862 spillPair (PAIR_HL);
3863 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3867 if (isPair (AOP (IC_LEFT (ic))) && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && getPairId (AOP (IC_LEFT (ic))) != PAIR_HL)
3869 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3870 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3871 spillPair (PAIR_HL);
3872 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3877 ld hl,sp+n trashes C so we can't afford to do it during an
3878 add with stack based variables. Worst case is:
3891 So you can't afford to load up hl if either left, right, or result
3892 is on the stack (*sigh*) The alt is:
3900 Combinations in here are:
3901 * If left or right are in bc then the loss is small - trap later
3902 * If the result is in bc then the loss is also small
3906 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3907 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3908 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3910 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3911 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3912 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3913 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3915 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3917 /* Swap left and right */
3918 operand *t = IC_RIGHT (ic);
3919 IC_RIGHT (ic) = IC_LEFT (ic);
3922 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3924 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3925 emit2 ("add hl,bc");
3929 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3930 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3931 emit2 ("add hl,de");
3933 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3939 /* Be paranoid on the GB with 4 byte variables due to how C
3940 can be trashed by lda hl,n(sp).
3942 _gbz80_emitAddSubLong (ic, TRUE);
3947 setupToPreserveCarry (ic);
3949 /* This is ugly, but it fixes the worst code generation bug on Z80. */
3950 /* Probably something similar has to be done for addition of larger numbers, too. */
3953 _moveA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3954 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), 0, FALSE));
3955 if(strcmp (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), aopGet (AOP (IC_LEFT (ic)), 1, FALSE)))
3957 aopPut (AOP (IC_RESULT (ic)), "a", 0);
3958 _moveA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3962 emitDebug ("; Addition result is in same register as operand of next addition.");
3963 if(strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'c') ||
3964 strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'b') )
3968 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3971 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3979 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3982 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3988 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), 1, FALSE));
3989 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3995 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3997 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3999 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4000 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4004 _G.preserveCarry = FALSE;
4005 freeAsmop (IC_LEFT (ic), NULL, ic);
4006 freeAsmop (IC_RIGHT (ic), NULL, ic);
4007 freeAsmop (IC_RESULT (ic), NULL, ic);
4010 /*-----------------------------------------------------------------*/
4011 /* genMinusDec :- does subtraction with deccrement if possible */
4012 /*-----------------------------------------------------------------*/
4014 genMinusDec (iCode * ic)
4016 unsigned int icount;
4017 unsigned int size = getDataSize (IC_RESULT (ic));
4019 /* will try to generate an increment */
4020 /* if the right side is not a literal we cannot */
4021 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4024 /* if the literal value of the right hand side
4025 is greater than 4 then it is not worth it */
4026 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
4029 size = getDataSize (IC_RESULT (ic));
4031 /* if decrement 16 bits in register */
4032 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4033 (size > 1) && isPair (AOP (IC_RESULT (ic))))
4036 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4040 /* If result is a pair */
4041 if (isPair (AOP (IC_RESULT (ic))))
4043 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
4045 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4049 /* if increment 16 bits in register */
4050 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4054 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4057 emit2 ("dec %s", _getTempPairName());
4060 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4066 /* if the sizes are greater than 1 then we cannot */
4067 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4068 AOP_SIZE (IC_LEFT (ic)) > 1)
4071 /* we can if the aops of the left & result match or if they are in
4072 registers and the registers are the same */
4073 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4076 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4083 /*-----------------------------------------------------------------*/
4084 /* genMinus - generates code for subtraction */
4085 /*-----------------------------------------------------------------*/
4087 genMinus (iCode * ic)
4089 int size, offset = 0;
4090 unsigned long lit = 0L;
4092 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4093 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4094 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4096 /* special cases :- */
4097 /* if both left & right are in bit space */
4098 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4099 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4101 wassertl (0, "Tried to subtract two bits");
4105 /* if I can do an decrement instead of subtract then GOOD for ME */
4106 if (genMinusDec (ic) == TRUE)
4109 size = getDataSize (IC_RESULT (ic));
4111 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4116 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4120 /* Same logic as genPlus */
4123 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4124 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4125 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4127 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4128 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4129 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4130 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4132 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4133 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4135 if (left == PAIR_INVALID && right == PAIR_INVALID)
4140 else if (right == PAIR_INVALID)
4142 else if (left == PAIR_INVALID)
4145 fetchPair (left, AOP (IC_LEFT (ic)));
4146 /* Order is important. Right may be HL */
4147 fetchPair (right, AOP (IC_RIGHT (ic)));
4149 emit2 ("ld a,%s", _pairs[left].l);
4150 emit2 ("sub a,%s", _pairs[right].l);
4152 emit2 ("ld a,%s", _pairs[left].h);
4153 emit2 ("sbc a,%s", _pairs[right].h);
4155 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4157 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4159 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4165 /* Be paranoid on the GB with 4 byte variables due to how C
4166 can be trashed by lda hl,n(sp).
4168 _gbz80_emitAddSubLong (ic, FALSE);
4173 setupToPreserveCarry (ic);
4175 /* if literal, add a,#-lit, else normal subb */
4178 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4179 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4183 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4186 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4190 /* first add without previous c */
4193 if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
4196 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4199 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4201 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4204 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4205 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4206 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4208 wassertl (0, "Tried to subtract on a long pointer");
4212 _G.preserveCarry = FALSE;
4213 freeAsmop (IC_LEFT (ic), NULL, ic);
4214 freeAsmop (IC_RIGHT (ic), NULL, ic);
4215 freeAsmop (IC_RESULT (ic), NULL, ic);
4218 /*-----------------------------------------------------------------*/
4219 /* genMult - generates code for multiplication */
4220 /*-----------------------------------------------------------------*/
4222 genMult (iCode * ic)
4226 /* If true then the final operation should be a subtract */
4227 bool active = FALSE;
4230 /* Shouldn't occur - all done through function calls */
4231 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4232 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4233 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4235 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4237 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4238 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4239 AOP_SIZE (IC_RESULT (ic)) > 2)
4241 wassertl (0, "Multiplication is handled through support function calls");
4244 /* Swap left and right such that right is a literal */
4245 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4247 operand *t = IC_RIGHT (ic);
4248 IC_RIGHT (ic) = IC_LEFT (ic);
4252 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4254 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4255 // wassertl (val > 0, "Multiply must be positive");
4256 wassertl (val != 1, "Can't multiply by 1");
4258 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4260 _G.stack.pushedDE = TRUE;
4264 emit2 ("ld a,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4265 else if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4267 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4278 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4283 for (count = 0; count < 16; count++)
4285 if (count != 0 && active)
4290 emit2 ("add hl,hl");
4294 if (active == FALSE)
4309 emit2 ("add hl,de");
4318 if (IS_Z80 && _G.stack.pushedDE)
4321 _G.stack.pushedDE = FALSE;
4325 aopPut (AOP (IC_RESULT (ic)), "a", 0);
4327 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4329 freeAsmop (IC_LEFT (ic), NULL, ic);
4330 freeAsmop (IC_RIGHT (ic), NULL, ic);
4331 freeAsmop (IC_RESULT (ic), NULL, ic);
4334 /*-----------------------------------------------------------------*/
4335 /* genDiv - generates code for division */
4336 /*-----------------------------------------------------------------*/
4340 /* Shouldn't occur - all done through function calls */
4341 wassertl (0, "Division is handled through support function calls");
4344 /*-----------------------------------------------------------------*/
4345 /* genMod - generates code for division */
4346 /*-----------------------------------------------------------------*/
4350 /* Shouldn't occur - all done through function calls */
4354 /*-----------------------------------------------------------------*/
4355 /* genIfxJump :- will create a jump depending on the ifx */
4356 /*-----------------------------------------------------------------*/
4358 genIfxJump (iCode * ic, char *jval)
4363 /* if true label then we jump if condition
4367 jlbl = IC_TRUE (ic);
4368 if (!strcmp (jval, "a"))
4372 else if (!strcmp (jval, "c"))
4376 else if (!strcmp (jval, "nc"))
4380 else if (!strcmp (jval, "m"))
4384 else if (!strcmp (jval, "p"))
4390 /* The buffer contains the bit on A that we should test */
4396 /* false label is present */
4397 jlbl = IC_FALSE (ic);
4398 if (!strcmp (jval, "a"))
4402 else if (!strcmp (jval, "c"))
4406 else if (!strcmp (jval, "nc"))
4410 else if (!strcmp (jval, "m"))
4414 else if (!strcmp (jval, "p"))
4420 /* The buffer contains the bit on A that we should test */
4424 /* Z80 can do a conditional long jump */
4425 if (!strcmp (jval, "a"))
4429 else if (!strcmp (jval, "c"))
4432 else if (!strcmp (jval, "nc"))
4435 else if (!strcmp (jval, "m"))
4438 else if (!strcmp (jval, "p"))
4443 emit2 ("bit %s,a", jval);
4445 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4447 /* mark the icode as generated */
4453 _getPairIdName (PAIR_ID id)
4455 return _pairs[id].name;
4460 /* if unsigned char cmp with lit, just compare */
4462 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4464 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4467 emit2 ("xor a,!immedbyte", 0x80);
4468 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4471 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4473 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4475 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4476 // Pull left into DE and right into HL
4477 aopGet (AOP(left), LSB, FALSE);
4480 aopGet (AOP(right), LSB, FALSE);
4484 if (size == 0 && sign)
4486 // Highest byte when signed needs the bits flipped
4489 emit2 ("ld a,(de)");
4490 emit2 ("xor !immedbyte", 0x80);
4492 emit2 ("ld a,(hl)");
4493 emit2 ("xor !immedbyte", 0x80);
4497 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4501 emit2 ("ld a,(de)");
4502 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4512 spillPair (PAIR_HL);
4514 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4516 setupPair (PAIR_HL, AOP (left), 0);
4517 aopGet (AOP(right), LSB, FALSE);
4521 if (size == 0 && sign)
4523 // Highest byte when signed needs the bits flipped
4526 emit2 ("ld a,(hl)");
4527 emit2 ("xor !immedbyte", 0x80);
4529 emit2 ("ld a,%d(iy)", offset);
4530 emit2 ("xor !immedbyte", 0x80);
4534 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4538 emit2 ("ld a,(hl)");
4539 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4548 spillPair (PAIR_HL);
4549 spillPair (PAIR_IY);
4553 if (AOP_TYPE (right) == AOP_LIT)
4555 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4556 /* optimize if(x < 0) or if(x >= 0) */
4561 /* No sign so it's always false */
4566 /* Just load in the top most bit */
4567 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4568 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4570 genIfxJump (ifx, "7");
4582 /* First setup h and l contaning the top most bytes XORed */
4583 bool fDidXor = FALSE;
4584 if (AOP_TYPE (left) == AOP_LIT)
4586 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4587 emit2 ("ld %s,!immedbyte", _fTmp[0],
4588 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4592 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4593 emit2 ("xor a,!immedbyte", 0x80);
4594 emit2 ("ld %s,a", _fTmp[0]);
4597 if (AOP_TYPE (right) == AOP_LIT)
4599 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4600 emit2 ("ld %s,!immedbyte", _fTmp[1],
4601 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4605 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4606 emit2 ("xor a,!immedbyte", 0x80);
4607 emit2 ("ld %s,a", _fTmp[1]);
4613 /* Do a long subtract */
4616 _moveA (aopGet (AOP (left), offset, FALSE));
4618 if (sign && size == 0)
4620 emit2 ("ld a,%s", _fTmp[0]);
4621 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4625 /* Subtract through, propagating the carry */
4626 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4634 /** Generic compare for > or <
4637 genCmp (operand * left, operand * right,
4638 operand * result, iCode * ifx, int sign)
4640 int size, offset = 0;
4641 unsigned long lit = 0L;
4643 /* if left & right are bit variables */
4644 if (AOP_TYPE (left) == AOP_CRY &&
4645 AOP_TYPE (right) == AOP_CRY)
4647 /* Cant happen on the Z80 */
4648 wassertl (0, "Tried to compare two bits");
4652 /* Do a long subtract of right from left. */
4653 size = max (AOP_SIZE (left), AOP_SIZE (right));
4655 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4657 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4658 // Pull left into DE and right into HL
4659 aopGet (AOP(left), LSB, FALSE);
4662 aopGet (AOP(right), LSB, FALSE);
4666 emit2 ("ld a,(de)");
4667 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4676 spillPair (PAIR_HL);
4680 if (AOP_TYPE (right) == AOP_LIT)
4682 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4683 /* optimize if(x < 0) or if(x >= 0) */
4688 /* No sign so it's always false */
4693 /* Just load in the top most bit */
4694 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4695 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4697 genIfxJump (ifx, "7");
4708 genIfxJump (ifx, "nc");
4719 _moveA (aopGet (AOP (left), offset, FALSE));
4720 /* Subtract through, propagating the carry */
4721 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4727 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4731 /* Shift the sign bit up into carry */
4738 /* if the result is used in the next
4739 ifx conditional branch then generate
4740 code a little differently */
4748 genIfxJump (ifx, "c");
4752 genIfxJump (ifx, "m");
4757 genIfxJump (ifx, "c");
4764 /* Shift the sign bit up into carry */
4769 /* leave the result in acc */
4773 /*-----------------------------------------------------------------*/
4774 /* genCmpGt :- greater than comparison */
4775 /*-----------------------------------------------------------------*/
4777 genCmpGt (iCode * ic, iCode * ifx)
4779 operand *left, *right, *result;
4780 sym_link *letype, *retype;
4783 left = IC_LEFT (ic);
4784 right = IC_RIGHT (ic);
4785 result = IC_RESULT (ic);
4787 letype = getSpec (operandType (left));
4788 retype = getSpec (operandType (right));
4789 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4790 /* assign the asmops */
4791 aopOp (left, ic, FALSE, FALSE);
4792 aopOp (right, ic, FALSE, FALSE);
4793 aopOp (result, ic, TRUE, FALSE);
4795 setupToPreserveCarry (ic);
4797 genCmp (right, left, result, ifx, sign);
4799 _G.preserveCarry = FALSE;
4800 freeAsmop (left, NULL, ic);
4801 freeAsmop (right, NULL, ic);
4802 freeAsmop (result, NULL, ic);
4805 /*-----------------------------------------------------------------*/
4806 /* genCmpLt - less than comparisons */
4807 /*-----------------------------------------------------------------*/
4809 genCmpLt (iCode * ic, iCode * ifx)
4811 operand *left, *right, *result;
4812 sym_link *letype, *retype;
4815 left = IC_LEFT (ic);
4816 right = IC_RIGHT (ic);
4817 result = IC_RESULT (ic);
4819 letype = getSpec (operandType (left));
4820 retype = getSpec (operandType (right));
4821 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4823 /* assign the asmops */
4824 aopOp (left, ic, FALSE, FALSE);
4825 aopOp (right, ic, FALSE, FALSE);
4826 aopOp (result, ic, TRUE, FALSE);
4828 setupToPreserveCarry (ic);
4830 genCmp (left, right, result, ifx, sign);
4832 _G.preserveCarry = FALSE;
4833 freeAsmop (left, NULL, ic);
4834 freeAsmop (right, NULL, ic);
4835 freeAsmop (result, NULL, ic);
4838 /*-----------------------------------------------------------------*/
4839 /* gencjneshort - compare and jump if not equal */
4840 /* returns pair that still needs to be popped */
4841 /*-----------------------------------------------------------------*/
4843 gencjneshort (operand * left, operand * right, symbol * lbl)
4845 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4847 unsigned long lit = 0L;
4849 /* Swap the left and right if it makes the computation easier */
4850 if (AOP_TYPE (left) == AOP_LIT)
4857 /* if the right side is a literal then anything goes */
4858 if (AOP_TYPE (right) == AOP_LIT)
4860 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4863 _moveA (aopGet (AOP (left), offset, FALSE));
4868 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4875 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4881 _moveA (aopGet (AOP (left), offset, FALSE));
4882 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4885 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4886 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4891 /* if the right side is in a register or
4892 pointed to by HL, IX or IY */
4893 else if (AOP_TYPE (right) == AOP_REG ||
4894 AOP_TYPE (right) == AOP_HL ||
4895 AOP_TYPE (right) == AOP_IY ||
4896 AOP_TYPE (right) == AOP_STK ||
4897 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4898 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4899 AOP_IS_PAIRPTR (right, PAIR_IY))
4903 _moveA (aopGet (AOP (left), offset, FALSE));
4904 if (AOP_TYPE (right) == AOP_LIT &&
4905 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4908 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4912 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4913 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4918 /* right is in direct space or a pointer reg, need both a & b */
4922 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4924 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4925 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
4933 emit2 ("; direct compare");
4934 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
4935 _moveA (aopGet (AOP (right), offset, FALSE));
4936 emit2 ("sub %s", _pairs[pair].l);
4937 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4942 return PAIR_INVALID;
4945 /*-----------------------------------------------------------------*/
4946 /* gencjne - compare and jump if not equal */
4947 /*-----------------------------------------------------------------*/
4949 gencjne (operand * left, operand * right, symbol * lbl)
4951 symbol *tlbl = newiTempLabel (NULL);
4953 PAIR_ID pop = gencjneshort (left, right, lbl);
4956 emit2 ("ld a,!one");
4957 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4958 emitLabel (lbl->key + 100);
4960 emitLabel (tlbl->key + 100);
4964 /*-----------------------------------------------------------------*/
4965 /* genCmpEq - generates code for equal to */
4966 /*-----------------------------------------------------------------*/
4968 genCmpEq (iCode * ic, iCode * ifx)
4970 operand *left, *right, *result;
4972 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4973 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4974 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4976 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4978 /* Swap operands if it makes the operation easier. ie if:
4979 1. Left is a literal.
4981 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4983 operand *t = IC_RIGHT (ic);
4984 IC_RIGHT (ic) = IC_LEFT (ic);
4988 if (ifx && !AOP_SIZE (result))
4991 /* if they are both bit variables */
4992 if (AOP_TYPE (left) == AOP_CRY &&
4993 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4995 wassertl (0, "Tried to compare two bits");
5000 tlbl = newiTempLabel (NULL);
5001 pop = gencjneshort (left, right, tlbl);
5005 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
5006 emitLabel (tlbl->key + 100);
5011 /* PENDING: do this better */
5012 symbol *lbl = newiTempLabel (NULL);
5014 emit2 ("!shortjp !tlabel", lbl->key + 100);
5015 emitLabel (tlbl->key + 100);
5017 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
5018 emitLabel (lbl->key + 100);
5021 /* mark the icode as generated */
5026 /* if they are both bit variables */
5027 if (AOP_TYPE (left) == AOP_CRY &&
5028 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5030 wassertl (0, "Tried to compare a bit to either a literal or another bit");
5036 gencjne (left, right, newiTempLabel (NULL));
5037 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5044 genIfxJump (ifx, "a");
5047 /* if the result is used in an arithmetic operation
5048 then put the result in place */
5049 if (AOP_TYPE (result) != AOP_CRY)
5054 /* leave the result in acc */
5058 freeAsmop (left, NULL, ic);
5059 freeAsmop (right, NULL, ic);
5060 freeAsmop (result, NULL, ic);
5063 /*-----------------------------------------------------------------*/
5064 /* ifxForOp - returns the icode containing the ifx for operand */
5065 /*-----------------------------------------------------------------*/
5067 ifxForOp (operand * op, iCode * ic)
5069 /* if true symbol then needs to be assigned */
5070 if (IS_TRUE_SYMOP (op))
5073 /* if this has register type condition and
5074 the next instruction is ifx with the same operand
5075 and live to of the operand is upto the ifx only then */
5077 ic->next->op == IFX &&
5078 IC_COND (ic->next)->key == op->key &&
5079 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5085 /*-----------------------------------------------------------------*/
5086 /* genAndOp - for && operation */
5087 /*-----------------------------------------------------------------*/
5089 genAndOp (iCode * ic)
5091 operand *left, *right, *result;
5094 /* note here that && operations that are in an if statement are
5095 taken away by backPatchLabels only those used in arthmetic
5096 operations remain */
5097 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5098 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5099 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5101 /* if both are bit variables */
5102 if (AOP_TYPE (left) == AOP_CRY &&
5103 AOP_TYPE (right) == AOP_CRY)
5105 wassertl (0, "Tried to and two bits");
5109 tlbl = newiTempLabel (NULL);
5111 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5113 emitLabel (tlbl->key + 100);
5117 freeAsmop (left, NULL, ic);
5118 freeAsmop (right, NULL, ic);
5119 freeAsmop (result, NULL, ic);
5122 /*-----------------------------------------------------------------*/
5123 /* genOrOp - for || operation */
5124 /*-----------------------------------------------------------------*/
5126 genOrOp (iCode * ic)
5128 operand *left, *right, *result;
5131 /* note here that || operations that are in an
5132 if statement are taken away by backPatchLabels
5133 only those used in arthmetic operations remain */
5134 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5135 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5136 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5138 /* if both are bit variables */
5139 if (AOP_TYPE (left) == AOP_CRY &&
5140 AOP_TYPE (right) == AOP_CRY)
5142 wassertl (0, "Tried to OR two bits");
5146 tlbl = newiTempLabel (NULL);
5148 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5150 emitLabel (tlbl->key + 100);
5154 freeAsmop (left, NULL, ic);
5155 freeAsmop (right, NULL, ic);
5156 freeAsmop (result, NULL, ic);
5159 /*-----------------------------------------------------------------*/
5160 /* isLiteralBit - test if lit == 2^n */
5161 /*-----------------------------------------------------------------*/
5163 isLiteralBit (unsigned long lit)
5165 unsigned long pw[32] =
5166 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5167 0x100L, 0x200L, 0x400L, 0x800L,
5168 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5169 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5170 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5171 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5172 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5175 for (idx = 0; idx < 32; idx++)
5181 /*-----------------------------------------------------------------*/
5182 /* jmpTrueOrFalse - */
5183 /*-----------------------------------------------------------------*/
5185 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5187 // ugly but optimized by peephole
5190 symbol *nlbl = newiTempLabel (NULL);
5191 emit2 ("jp !tlabel", nlbl->key + 100);
5192 emitLabel (tlbl->key + 100);
5193 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5194 emitLabel (nlbl->key + 100);
5198 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5199 emitLabel (tlbl->key + 100);
5204 /*-----------------------------------------------------------------*/
5205 /* genAnd - code for and */
5206 /*-----------------------------------------------------------------*/
5208 genAnd (iCode * ic, iCode * ifx)
5210 operand *left, *right, *result;
5211 int size, offset = 0;
5212 unsigned long lit = 0L;
5215 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5216 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5217 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5219 /* if left is a literal & right is not then exchange them */
5220 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5221 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5223 operand *tmp = right;
5228 /* if result = right then exchange them */
5229 if (sameRegs (AOP (result), AOP (right)))
5231 operand *tmp = right;
5236 /* if right is bit then exchange them */
5237 if (AOP_TYPE (right) == AOP_CRY &&
5238 AOP_TYPE (left) != AOP_CRY)
5240 operand *tmp = right;
5244 if (AOP_TYPE (right) == AOP_LIT)
5245 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5247 size = AOP_SIZE (result);
5249 if (AOP_TYPE (left) == AOP_CRY)
5251 wassertl (0, "Tried to perform an AND with a bit as an operand");
5255 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5256 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5257 if ((AOP_TYPE (right) == AOP_LIT) &&
5258 (AOP_TYPE (result) == AOP_CRY) &&
5259 (AOP_TYPE (left) != AOP_CRY))
5261 symbol *tlbl = newiTempLabel (NULL);
5262 int sizel = AOP_SIZE (left);
5265 /* PENDING: Test case for this. */
5270 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5272 _moveA (aopGet (AOP (left), offset, FALSE));
5273 if (bytelit != 0x0FFL)
5275 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5282 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5286 // bit = left & literal
5290 emit2 ("!tlabeldef", tlbl->key + 100);
5291 _G.lines.current->isLabel = 1;
5293 // if(left & literal)
5298 jmpTrueOrFalse (ifx, tlbl);
5306 /* if left is same as result */
5307 if (sameRegs (AOP (result), AOP (left)))
5309 for (; size--; offset++)
5311 if (AOP_TYPE (right) == AOP_LIT)
5313 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5318 aopPut (AOP (result), "!zero", offset);
5321 _moveA (aopGet (AOP (left), offset, FALSE));
5323 aopGet (AOP (right), offset, FALSE));
5324 aopPut (AOP (left), "a", offset);
5331 if (AOP_TYPE (left) == AOP_ACC)
5333 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5337 _moveA (aopGet (AOP (left), offset, FALSE));
5339 aopGet (AOP (right), offset, FALSE));
5340 aopPut (AOP (left), "a", offset);
5347 // left & result in different registers
5348 if (AOP_TYPE (result) == AOP_CRY)
5350 wassertl (0, "Tried to AND where the result is in carry");
5354 for (; (size--); offset++)
5357 // result = left & right
5358 if (AOP_TYPE (right) == AOP_LIT)
5360 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5362 aopPut (AOP (result),
5363 aopGet (AOP (left), offset, FALSE),
5367 else if (bytelit == 0)
5369 aopPut (AOP (result), "!zero", offset);
5373 // faster than result <- left, anl result,right
5374 // and better if result is SFR
5375 if (AOP_TYPE (left) == AOP_ACC)
5376 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5379 _moveA (aopGet (AOP (left), offset, FALSE));
5381 aopGet (AOP (right), offset, FALSE));
5383 aopPut (AOP (result), "a", offset);
5390 freeAsmop (left, NULL, ic);
5391 freeAsmop (right, NULL, ic);
5392 freeAsmop (result, NULL, ic);
5395 /*-----------------------------------------------------------------*/
5396 /* genOr - code for or */
5397 /*-----------------------------------------------------------------*/
5399 genOr (iCode * ic, iCode * ifx)
5401 operand *left, *right, *result;
5402 int size, offset = 0;
5403 unsigned long lit = 0L;
5406 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5407 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5408 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5410 /* if left is a literal & right is not then exchange them */
5411 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5412 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5414 operand *tmp = right;
5419 /* if result = right then exchange them */
5420 if (sameRegs (AOP (result), AOP (right)))
5422 operand *tmp = right;
5427 /* if right is bit then exchange them */
5428 if (AOP_TYPE (right) == AOP_CRY &&
5429 AOP_TYPE (left) != AOP_CRY)
5431 operand *tmp = right;
5435 if (AOP_TYPE (right) == AOP_LIT)
5436 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5438 size = AOP_SIZE (result);
5440 if (AOP_TYPE (left) == AOP_CRY)
5442 wassertl (0, "Tried to OR where left is a bit");
5446 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5447 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5448 if ((AOP_TYPE (right) == AOP_LIT) &&
5449 (AOP_TYPE (result) == AOP_CRY) &&
5450 (AOP_TYPE (left) != AOP_CRY))
5452 symbol *tlbl = newiTempLabel (NULL);
5453 int sizel = AOP_SIZE (left);
5457 wassertl (0, "Result is assigned to a bit");
5459 /* PENDING: Modeled after the AND code which is inefficient. */
5462 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5464 _moveA (aopGet (AOP (left), offset, FALSE));
5465 /* OR with any literal is the same as OR with itself. */
5467 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5473 jmpTrueOrFalse (ifx, tlbl);
5478 /* if left is same as result */
5479 if (sameRegs (AOP (result), AOP (left)))
5481 for (; size--; offset++)
5483 if (AOP_TYPE (right) == AOP_LIT)
5485 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5489 _moveA (aopGet (AOP (left), offset, FALSE));
5491 aopGet (AOP (right), offset, FALSE));
5492 aopPut (AOP (result), "a", offset);
5497 if (AOP_TYPE (left) == AOP_ACC)
5498 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5501 _moveA (aopGet (AOP (left), offset, FALSE));
5503 aopGet (AOP (right), offset, FALSE));
5504 aopPut (AOP (result), "a", offset);
5511 // left & result in different registers
5512 if (AOP_TYPE (result) == AOP_CRY)
5514 wassertl (0, "Result of OR is in a bit");
5517 for (; (size--); offset++)
5520 // result = left & right
5521 if (AOP_TYPE (right) == AOP_LIT)
5523 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5525 aopPut (AOP (result),
5526 aopGet (AOP (left), offset, FALSE),
5531 // faster than result <- left, anl result,right
5532 // and better if result is SFR
5533 if (AOP_TYPE (left) == AOP_ACC)
5534 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5537 _moveA (aopGet (AOP (left), offset, FALSE));
5539 aopGet (AOP (right), offset, FALSE));
5541 aopPut (AOP (result), "a", offset);
5542 /* PENDING: something weird is going on here. Add exception. */
5543 if (AOP_TYPE (result) == AOP_ACC)
5549 freeAsmop (left, NULL, ic);
5550 freeAsmop (right, NULL, ic);
5551 freeAsmop (result, NULL, ic);
5554 /*-----------------------------------------------------------------*/
5555 /* genXor - code for xclusive or */
5556 /*-----------------------------------------------------------------*/
5558 genXor (iCode * ic, iCode * ifx)
5560 operand *left, *right, *result;
5561 int size, offset = 0;
5562 unsigned long lit = 0L;
5564 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5565 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5566 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5568 /* if left is a literal & right is not then exchange them */
5569 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5570 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5572 operand *tmp = right;
5577 /* if result = right then exchange them */
5578 if (sameRegs (AOP (result), AOP (right)))
5580 operand *tmp = right;
5585 /* if right is bit then exchange them */
5586 if (AOP_TYPE (right) == AOP_CRY &&
5587 AOP_TYPE (left) != AOP_CRY)
5589 operand *tmp = right;
5593 if (AOP_TYPE (right) == AOP_LIT)
5594 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5596 size = AOP_SIZE (result);
5598 if (AOP_TYPE (left) == AOP_CRY)
5600 wassertl (0, "Tried to XOR a bit");
5604 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5605 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5606 if ((AOP_TYPE (right) == AOP_LIT) &&
5607 (AOP_TYPE (result) == AOP_CRY) &&
5608 (AOP_TYPE (left) != AOP_CRY))
5610 symbol *tlbl = newiTempLabel (NULL);
5611 int sizel = AOP_SIZE (left);
5615 /* PENDING: Test case for this. */
5616 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5620 _moveA (aopGet (AOP (left), offset, FALSE));
5621 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5622 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5627 jmpTrueOrFalse (ifx, tlbl);
5631 wassertl (0, "Result of XOR was destined for a bit");
5636 /* if left is same as result */
5637 if (sameRegs (AOP (result), AOP (left)))
5639 for (; size--; offset++)
5641 if (AOP_TYPE (right) == AOP_LIT)
5643 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5647 _moveA (aopGet (AOP (left), offset, FALSE));
5649 aopGet (AOP (right), offset, FALSE));
5650 aopPut (AOP (result), "a", offset);
5655 if (AOP_TYPE (left) == AOP_ACC)
5657 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5661 _moveA (aopGet (AOP (left), offset, FALSE));
5663 aopGet (AOP (right), offset, FALSE));
5664 aopPut (AOP (result), "a", offset);
5671 // left & result in different registers
5672 if (AOP_TYPE (result) == AOP_CRY)
5674 wassertl (0, "Result of XOR is in a bit");
5677 for (; (size--); offset++)
5680 // result = left & right
5681 if (AOP_TYPE (right) == AOP_LIT)
5683 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5685 aopPut (AOP (result),
5686 aopGet (AOP (left), offset, FALSE),
5691 // faster than result <- left, anl result,right
5692 // and better if result is SFR
5693 if (AOP_TYPE (left) == AOP_ACC)
5695 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5699 _moveA (aopGet (AOP (left), offset, FALSE));
5701 aopGet (AOP (right), offset, FALSE));
5703 aopPut (AOP (result), "a", offset);
5708 freeAsmop (left, NULL, ic);
5709 freeAsmop (right, NULL, ic);
5710 freeAsmop (result, NULL, ic);
5713 /*-----------------------------------------------------------------*/
5714 /* genInline - write the inline code out */
5715 /*-----------------------------------------------------------------*/
5717 genInline (iCode * ic)
5719 char *buffer, *bp, *bp1;
5720 bool inComment = FALSE;
5722 _G.lines.isInline += (!options.asmpeep);
5724 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5726 /* emit each line as a code */
5744 /* Add \n for labels, not dirs such as c:\mydir */
5745 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5763 _G.lines.isInline -= (!options.asmpeep);
5767 /*-----------------------------------------------------------------*/
5768 /* genRRC - rotate right with carry */
5769 /*-----------------------------------------------------------------*/
5776 /*-----------------------------------------------------------------*/
5777 /* genRLC - generate code for rotate left with carry */
5778 /*-----------------------------------------------------------------*/
5785 /*-----------------------------------------------------------------*/
5786 /* genGetHbit - generates code get highest order bit */
5787 /*-----------------------------------------------------------------*/
5789 genGetHbit (iCode * ic)
5791 operand *left, *result;
5792 left = IC_LEFT (ic);
5793 result = IC_RESULT (ic);
5795 aopOp (left, ic, FALSE, FALSE);
5796 aopOp (result, ic, FALSE, FALSE);
5798 /* get the highest order byte into a */
5799 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5801 if (AOP_TYPE (result) == AOP_CRY)
5809 emit2 ("and a,!one");
5814 freeAsmop (left, NULL, ic);
5815 freeAsmop (result, NULL, ic);
5819 emitRsh2 (asmop *aop, int size, int is_signed)
5825 const char *l = aopGet (aop, size, FALSE);
5828 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5838 /*-----------------------------------------------------------------*/
5839 /* shiftR2Left2Result - shift right two bytes from left to result */
5840 /*-----------------------------------------------------------------*/
5842 shiftR2Left2Result (operand * left, int offl,
5843 operand * result, int offr,
5844 int shCount, int is_signed)
5849 movLeft2Result (left, offl, result, offr, 0);
5850 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5855 /* if (AOP(result)->type == AOP_REG) { */
5857 tlbl = newiTempLabel (NULL);
5859 /* Left is already in result - so now do the shift */
5860 /* Optimizing for speed by default. */
5861 if (!optimize.codeSize || shCount <= 2)
5865 emitRsh2 (AOP (result), size, is_signed);
5870 emit2 ("ld a,!immedbyte", shCount);
5872 emitLabel (tlbl->key + 100);
5874 emitRsh2 (AOP (result), size, is_signed);
5877 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5881 /*-----------------------------------------------------------------*/
5882 /* shiftL2Left2Result - shift left two bytes from left to result */
5883 /*-----------------------------------------------------------------*/
5885 shiftL2Left2Result (operand * left, int offl,
5886 operand * result, int offr, int shCount)
5888 if (sameRegs (AOP (result), AOP (left)) &&
5889 ((offl + MSB16) == offr))
5895 /* Copy left into result */
5896 movLeft2Result (left, offl, result, offr, 0);
5897 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5903 if (getPairId (AOP (result)) == PAIR_HL)
5907 emit2 ("add hl,hl");
5914 symbol *tlbl, *tlbl1;
5917 tlbl = newiTempLabel (NULL);
5918 tlbl1 = newiTempLabel (NULL);
5920 if (AOP (result)->type == AOP_REG)
5924 for (offset = 0; offset < size; offset++)
5926 l = aopGet (AOP (result), offset, FALSE);
5930 emit2 ("sla %s", l);
5941 /* Left is already in result - so now do the shift */
5944 emit2 ("ld a,!immedbyte+1", shCount);
5945 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5946 emitLabel (tlbl->key + 100);
5951 l = aopGet (AOP (result), offset, FALSE);
5955 emit2 ("sla %s", l);
5966 emitLabel (tlbl1->key + 100);
5968 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5974 /*-----------------------------------------------------------------*/
5975 /* AccRol - rotate left accumulator by known count */
5976 /*-----------------------------------------------------------------*/
5978 AccRol (int shCount)
5980 shCount &= 0x0007; // shCount : 0..7
6057 /*-----------------------------------------------------------------*/
6058 /* AccLsh - left shift accumulator by known count */
6059 /*-----------------------------------------------------------------*/
6061 AccLsh (int shCount)
6063 static const unsigned char SLMask[] =
6065 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6074 else if (shCount == 2)
6081 /* rotate left accumulator */
6083 /* and kill the lower order bits */
6084 emit2 ("and a,!immedbyte", SLMask[shCount]);
6089 /*-----------------------------------------------------------------*/
6090 /* shiftL1Left2Result - shift left one byte from left to result */
6091 /*-----------------------------------------------------------------*/
6093 shiftL1Left2Result (operand * left, int offl,
6094 operand * result, int offr, int shCount)
6098 /* If operand and result are the same we can shift in place.
6099 However shifting in acc using add is cheaper than shifting
6100 in place using sla; when shifting by more than 2 shifting in
6101 acc is worth the additional effort for loading from/to acc. */
6102 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6105 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6109 l = aopGet (AOP (left), offl, FALSE);
6111 /* shift left accumulator */
6113 aopPut (AOP (result), "a", offr);
6117 /*-----------------------------------------------------------------*/
6118 /* genlshTwo - left shift two bytes by known amount */
6119 /*-----------------------------------------------------------------*/
6121 genlshTwo (operand * result, operand * left, int shCount)
6123 int size = AOP_SIZE (result);
6125 wassert (size == 2);
6127 /* if shCount >= 8 */
6135 movLeft2Result (left, LSB, result, MSB16, 0);
6136 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6137 aopPut (AOP (result), "!zero", LSB);
6141 movLeft2Result (left, LSB, result, MSB16, 0);
6142 aopPut (AOP (result), "!zero", 0);
6147 aopPut (AOP (result), "!zero", LSB);
6150 /* 0 <= shCount <= 7 */
6159 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6164 /*-----------------------------------------------------------------*/
6165 /* genlshOne - left shift a one byte quantity by known count */
6166 /*-----------------------------------------------------------------*/
6168 genlshOne (operand * result, operand * left, int shCount)
6170 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6173 /*-----------------------------------------------------------------*/
6174 /* genLeftShiftLiteral - left shifting by known count */
6175 /*-----------------------------------------------------------------*/
6177 genLeftShiftLiteral (operand * left,
6182 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6185 freeAsmop (right, NULL, ic);
6187 aopOp (left, ic, FALSE, FALSE);
6188 aopOp (result, ic, FALSE, FALSE);
6190 size = getSize (operandType (result));
6192 /* I suppose that the left size >= result size */
6194 if (shCount >= (size * 8))
6198 aopPut (AOP (result), "!zero", size);
6206 genlshOne (result, left, shCount);
6209 genlshTwo (result, left, shCount);
6212 wassertl (0, "Shifting of longs is currently unsupported");
6218 freeAsmop (left, NULL, ic);
6219 freeAsmop (result, NULL, ic);
6222 /*-----------------------------------------------------------------*/
6223 /* genLeftShift - generates code for left shifting */
6224 /*-----------------------------------------------------------------*/
6226 genLeftShift (iCode * ic)
6230 symbol *tlbl, *tlbl1;
6231 operand *left, *right, *result;
6233 right = IC_RIGHT (ic);
6234 left = IC_LEFT (ic);
6235 result = IC_RESULT (ic);
6237 aopOp (right, ic, FALSE, FALSE);
6239 /* if the shift count is known then do it
6240 as efficiently as possible */
6241 if (AOP_TYPE (right) == AOP_LIT)
6243 genLeftShiftLiteral (left, right, result, ic);
6247 /* shift count is unknown then we have to form a loop get the loop
6248 count in B : Note: we take only the lower order byte since
6249 shifting more that 32 bits make no sense anyway, ( the largest
6250 size of an object can be only 32 bits ) */
6251 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6253 freeAsmop (right, NULL, ic);
6254 aopOp (left, ic, FALSE, FALSE);
6255 aopOp (result, ic, FALSE, FALSE);
6257 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6260 /* now move the left to the result if they are not the
6263 if (!sameRegs (AOP (left), AOP (result)))
6266 size = AOP_SIZE (result);
6270 l = aopGet (AOP (left), offset, FALSE);
6271 aopPut (AOP (result), l, offset);
6276 tlbl = newiTempLabel (NULL);
6277 size = AOP_SIZE (result);
6279 tlbl1 = newiTempLabel (NULL);
6281 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6284 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6285 emitLabel (tlbl->key + 100);
6286 l = aopGet (AOP (result), offset, FALSE);
6290 l = aopGet (AOP (result), offset, FALSE);
6294 emit2 ("sla %s", l);
6302 emitLabel (tlbl1->key + 100);
6304 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6306 freeAsmop (left, NULL, ic);
6307 freeAsmop (result, NULL, ic);
6310 /*-----------------------------------------------------------------*/
6311 /* genrshOne - left shift two bytes by known amount != 0 */
6312 /*-----------------------------------------------------------------*/
6314 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6317 int size = AOP_SIZE (result);
6320 wassert (size == 1);
6321 wassert (shCount < 8);
6323 l = aopGet (AOP (left), 0, FALSE);
6325 if (AOP (result)->type == AOP_REG)
6327 aopPut (AOP (result), l, 0);
6328 l = aopGet (AOP (result), 0, FALSE);
6331 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6339 emit2 ("%s a", is_signed ? "sra" : "srl");
6341 aopPut (AOP (result), "a", 0);
6345 /*-----------------------------------------------------------------*/
6346 /* AccRsh - right shift accumulator by known count */
6347 /*-----------------------------------------------------------------*/
6349 AccRsh (int shCount)
6351 static const unsigned char SRMask[] =
6353 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6358 /* rotate right accumulator */
6359 AccRol (8 - shCount);
6360 /* and kill the higher order bits */
6361 emit2 ("and a,!immedbyte", SRMask[shCount]);
6365 /*-----------------------------------------------------------------*/
6366 /* shiftR1Left2Result - shift right one byte from left to result */
6367 /*-----------------------------------------------------------------*/
6369 shiftR1Left2Result (operand * left, int offl,
6370 operand * result, int offr,
6371 int shCount, int sign)
6373 _moveA (aopGet (AOP (left), offl, FALSE));
6378 emit2 ("%s a", sign ? "sra" : "srl");
6385 aopPut (AOP (result), "a", offr);
6388 /*-----------------------------------------------------------------*/
6389 /* genrshTwo - right shift two bytes by known amount */
6390 /*-----------------------------------------------------------------*/
6392 genrshTwo (operand * result, operand * left,
6393 int shCount, int sign)
6395 /* if shCount >= 8 */
6401 shiftR1Left2Result (left, MSB16, result, LSB,
6406 movLeft2Result (left, MSB16, result, LSB, sign);
6410 /* Sign extend the result */
6411 _moveA(aopGet (AOP (result), 0, FALSE));
6415 aopPut (AOP (result), ACC_NAME, MSB16);
6419 aopPut (AOP (result), "!zero", 1);
6422 /* 0 <= shCount <= 7 */
6425 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6429 /*-----------------------------------------------------------------*/
6430 /* genRightShiftLiteral - left shifting by known count */
6431 /*-----------------------------------------------------------------*/
6433 genRightShiftLiteral (operand * left,
6439 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6442 freeAsmop (right, NULL, ic);
6444 aopOp (left, ic, FALSE, FALSE);
6445 aopOp (result, ic, FALSE, FALSE);
6447 size = getSize (operandType (result));
6449 /* I suppose that the left size >= result size */
6451 if (shCount >= (size * 8)) {
6453 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6454 _moveA(aopGet (AOP (left), 0, FALSE));
6462 aopPut (AOP (result), s, size);
6469 genrshOne (result, left, shCount, sign);
6472 genrshTwo (result, left, shCount, sign);
6475 wassertl (0, "Asked to shift right a long which should be a function call");
6478 wassertl (0, "Entered default case in right shift delegate");
6481 freeAsmop (left, NULL, ic);
6482 freeAsmop (result, NULL, ic);
6485 /*-----------------------------------------------------------------*/
6486 /* genRightShift - generate code for right shifting */
6487 /*-----------------------------------------------------------------*/
6489 genRightShift (iCode * ic)
6491 operand *right, *left, *result;
6493 int size, offset, first = 1;
6497 symbol *tlbl, *tlbl1;
6499 /* if signed then we do it the hard way preserve the
6500 sign bit moving it inwards */
6501 retype = getSpec (operandType (IC_RESULT (ic)));
6503 is_signed = !SPEC_USIGN (retype);
6505 /* signed & unsigned types are treated the same : i.e. the
6506 signed is NOT propagated inwards : quoting from the
6507 ANSI - standard : "for E1 >> E2, is equivalent to division
6508 by 2**E2 if unsigned or if it has a non-negative value,
6509 otherwise the result is implementation defined ", MY definition
6510 is that the sign does not get propagated */
6512 right = IC_RIGHT (ic);
6513 left = IC_LEFT (ic);
6514 result = IC_RESULT (ic);
6516 aopOp (right, ic, FALSE, FALSE);
6518 /* if the shift count is known then do it
6519 as efficiently as possible */
6520 if (AOP_TYPE (right) == AOP_LIT)
6522 genRightShiftLiteral (left, right, result, ic, is_signed);
6526 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6528 freeAsmop (right, NULL, ic);
6530 aopOp (left, ic, FALSE, FALSE);
6531 aopOp (result, ic, FALSE, FALSE);
6533 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6536 /* now move the left to the result if they are not the
6538 if (!sameRegs (AOP (left), AOP (result)))
6541 size = AOP_SIZE (result);
6545 l = aopGet (AOP (left), offset, FALSE);
6546 aopPut (AOP (result), l, offset);
6551 tlbl = newiTempLabel (NULL);
6552 tlbl1 = newiTempLabel (NULL);
6553 size = AOP_SIZE (result);
6556 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6559 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6560 emitLabel (tlbl->key + 100);
6563 l = aopGet (AOP (result), offset--, FALSE);
6566 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6574 emitLabel (tlbl1->key + 100);
6576 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6578 freeAsmop (left, NULL, ic);
6579 freeAsmop (result, NULL, ic);
6583 /*-----------------------------------------------------------------*/
6584 /* genUnpackBits - generates code for unpacking bits */
6585 /*-----------------------------------------------------------------*/
6587 genUnpackBits (operand * result, int pair)
6589 int offset = 0; /* result byte offset */
6590 int rsize; /* result size */
6591 int rlen = 0; /* remaining bitfield length */
6592 sym_link *etype; /* bitfield type information */
6593 int blen; /* bitfield length */
6594 int bstr; /* bitfield starting bit within byte */
6596 emitDebug ("; genUnpackBits");
6598 etype = getSpec (operandType (result));
6599 rsize = getSize (operandType (result));
6600 blen = SPEC_BLEN (etype);
6601 bstr = SPEC_BSTR (etype);
6603 /* If the bitfield length is less than a byte */
6606 emit2 ("ld a,!*pair", _pairs[pair].name);
6608 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6609 if (!SPEC_USIGN (etype))
6611 /* signed bitfield */
6612 symbol *tlbl = newiTempLabel (NULL);
6614 emit2 ("bit %d,a", blen - 1);
6615 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6616 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6617 emitLabel (tlbl->key + 100);
6619 aopPut (AOP (result), "a", offset++);
6623 /* TODO: what if pair == PAIR_DE ? */
6624 if (getPairId (AOP (result)) == PAIR_HL)
6626 wassertl (rsize == 2, "HL must be of size 2");
6627 emit2 ("ld a,!*hl");
6629 emit2 ("ld h,!*hl");
6632 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6633 if (!SPEC_USIGN (etype))
6635 /* signed bitfield */
6636 symbol *tlbl = newiTempLabel (NULL);
6638 emit2 ("bit %d,a", blen - 1);
6639 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6640 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6641 emitLabel (tlbl->key + 100);
6644 spillPair (PAIR_HL);
6648 /* Bit field did not fit in a byte. Copy all
6649 but the partial byte at the end. */
6650 for (rlen=blen;rlen>=8;rlen-=8)
6652 emit2 ("ld a,!*pair", _pairs[pair].name);
6653 aopPut (AOP (result), "a", offset++);
6656 emit2 ("inc %s", _pairs[pair].name);
6657 _G.pairs[pair].offset++;
6661 /* Handle the partial byte at the end */
6664 emit2 ("ld a,!*pair", _pairs[pair].name);
6665 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6666 if (!SPEC_USIGN (etype))
6668 /* signed bitfield */
6669 symbol *tlbl = newiTempLabel (NULL);
6671 emit2 ("bit %d,a", rlen - 1);
6672 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6673 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6674 emitLabel (tlbl->key + 100);
6676 aopPut (AOP (result), "a", offset++);
6684 if (SPEC_USIGN (etype))
6688 /* signed bitfield: sign extension with 0x00 or 0xff */
6696 aopPut (AOP (result), source, offset++);
6700 /*-----------------------------------------------------------------*/
6701 /* genGenPointerGet - get value from generic pointer space */
6702 /*-----------------------------------------------------------------*/
6704 genGenPointerGet (operand * left,
6705 operand * result, iCode * ic)
6708 sym_link *retype = getSpec (operandType (result));
6714 aopOp (left, ic, FALSE, FALSE);
6715 aopOp (result, ic, FALSE, FALSE);
6717 size = AOP_SIZE (result);
6719 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6722 if (isPtrPair (AOP (left)))
6724 tsprintf (buffer, sizeof(buffer),
6725 "!*pair", getPairName (AOP (left)));
6726 aopPut (AOP (result), buffer, 0);
6730 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6731 aopPut (AOP (result), "a", 0);
6733 freeAsmop (left, NULL, ic);
6737 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6744 tsprintf (at, sizeof(at), "!*iyx", offset);
6745 aopPut (AOP (result), at, offset);
6749 freeAsmop (left, NULL, ic);
6753 /* For now we always load into IY */
6754 /* if this is remateriazable */
6755 fetchPair (pair, AOP (left));
6757 /* if bit then unpack */
6758 if (IS_BITVAR (retype))
6760 genUnpackBits (result, pair);
6761 freeAsmop (left, NULL, ic);
6765 else if (getPairId (AOP (result)) == PAIR_HL)
6767 wassertl (size == 2, "HL must be of size 2");
6768 emit2 ("ld a,!*hl");
6770 emit2 ("ld h,!*hl");
6772 spillPair (PAIR_HL);
6774 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6776 size = AOP_SIZE (result);
6781 /* PENDING: make this better */
6782 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6784 aopPut (AOP (result), "!*hl", offset++);
6788 emit2 ("ld a,!*pair", _pairs[pair].name);
6789 aopPut (AOP (result), "a", offset++);
6793 emit2 ("inc %s", _pairs[pair].name);
6794 _G.pairs[pair].offset++;
6797 /* Fixup HL back down */
6798 for (size = AOP_SIZE (result)-1; size; size--)
6800 emit2 ("dec %s", _pairs[pair].name);
6805 size = AOP_SIZE (result);
6810 /* PENDING: make this better */
6812 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6814 aopPut (AOP (result), "!*hl", offset++);
6818 emit2 ("ld a,!*pair", _pairs[pair].name);
6819 aopPut (AOP (result), "a", offset++);
6823 emit2 ("inc %s", _pairs[pair].name);
6824 _G.pairs[pair].offset++;
6829 freeAsmop (left, NULL, ic);
6832 freeAsmop (result, NULL, ic);
6835 /*-----------------------------------------------------------------*/
6836 /* genPointerGet - generate code for pointer get */
6837 /*-----------------------------------------------------------------*/
6839 genPointerGet (iCode * ic)
6841 operand *left, *result;
6842 sym_link *type, *etype;
6844 left = IC_LEFT (ic);
6845 result = IC_RESULT (ic);
6847 /* depending on the type of pointer we need to
6848 move it to the correct pointer register */
6849 type = operandType (left);
6850 etype = getSpec (type);
6852 genGenPointerGet (left, result, ic);
6856 isRegOrLit (asmop * aop)
6858 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6864 /*-----------------------------------------------------------------*/
6865 /* genPackBits - generates code for packed bit storage */
6866 /*-----------------------------------------------------------------*/
6868 genPackBits (sym_link * etype,
6873 int offset = 0; /* source byte offset */
6874 int rlen = 0; /* remaining bitfield length */
6875 int blen; /* bitfield length */
6876 int bstr; /* bitfield starting bit within byte */
6877 int litval; /* source literal value (if AOP_LIT) */
6878 unsigned char mask; /* bitmask within current byte */
6879 int extraPair; /* a tempory register */
6880 bool needPopExtra=0; /* need to restore original value of temp reg */
6882 emitDebug ("; genPackBits","");
6884 blen = SPEC_BLEN (etype);
6885 bstr = SPEC_BSTR (etype);
6887 /* If the bitfield length is less than a byte */
6890 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6891 (unsigned char) (0xFF >> (8 - bstr)));
6893 if (AOP_TYPE (right) == AOP_LIT)
6895 /* Case with a bitfield length <8 and literal source
6897 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6899 litval &= (~mask) & 0xff;
6900 emit2 ("ld a,!*pair", _pairs[pair].name);
6901 if ((mask|litval)!=0xff)
6902 emit2 ("and a,!immedbyte", mask);
6904 emit2 ("or a,!immedbyte", litval);
6905 emit2 ("ld !*pair,a", _pairs[pair].name);
6910 /* Case with a bitfield length <8 and arbitrary source
6912 _moveA (aopGet (AOP (right), 0, FALSE));
6913 /* shift and mask source value */
6915 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6917 extraPair = getFreePairId(ic);
6918 if (extraPair == PAIR_INVALID)
6920 extraPair = PAIR_BC;
6921 if (getPairId (AOP (right)) != PAIR_BC
6922 || !isLastUse (ic, right))
6928 emit2 ("ld %s,a", _pairs[extraPair].l);
6929 emit2 ("ld a,!*pair", _pairs[pair].name);
6931 emit2 ("and a,!immedbyte", mask);
6932 emit2 ("or a,%s", _pairs[extraPair].l);
6933 emit2 ("ld !*pair,a", _pairs[pair].name);
6940 /* Bit length is greater than 7 bits. In this case, copy */
6941 /* all except the partial byte at the end */
6942 for (rlen=blen;rlen>=8;rlen-=8)
6944 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6945 emit2 ("ld !*pair,a", _pairs[pair].name);
6948 emit2 ("inc %s", _pairs[pair].name);
6949 _G.pairs[pair].offset++;
6953 /* If there was a partial byte at the end */
6956 mask = (((unsigned char) -1 << rlen) & 0xff);
6958 if (AOP_TYPE (right) == AOP_LIT)
6960 /* Case with partial byte and literal source
6962 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6963 litval >>= (blen-rlen);
6964 litval &= (~mask) & 0xff;
6965 emit2 ("ld a,!*pair", _pairs[pair].name);
6966 if ((mask|litval)!=0xff)
6967 emit2 ("and a,!immedbyte", mask);
6969 emit2 ("or a,!immedbyte", litval);
6973 /* Case with partial byte and arbitrary source
6975 _moveA (aopGet (AOP (right), offset++, FALSE));
6976 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6978 extraPair = getFreePairId(ic);
6979 if (extraPair == PAIR_INVALID)
6981 extraPair = getPairId (AOP (right));
6982 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6983 extraPair = PAIR_BC;
6985 if (getPairId (AOP (right)) != PAIR_BC
6986 || !isLastUse (ic, right))
6992 emit2 ("ld %s,a", _pairs[extraPair].l);
6993 emit2 ("ld a,!*pair", _pairs[pair].name);
6995 emit2 ("and a,!immedbyte", mask);
6996 emit2 ("or a,%s", _pairs[extraPair].l);
7001 emit2 ("ld !*pair,a", _pairs[pair].name);
7006 /*-----------------------------------------------------------------*/
7007 /* genGenPointerSet - stores the value into a pointer location */
7008 /*-----------------------------------------------------------------*/
7010 genGenPointerSet (operand * right,
7011 operand * result, iCode * ic)
7014 sym_link *retype = getSpec (operandType (right));
7015 sym_link *letype = getSpec (operandType (result));
7016 PAIR_ID pairId = PAIR_HL;
7019 aopOp (result, ic, FALSE, FALSE);
7020 aopOp (right, ic, FALSE, FALSE);
7025 size = AOP_SIZE (right);
7027 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
7028 emitDebug("; isBitvar = %d", isBitvar);
7030 /* Handle the exceptions first */
7031 if (isPair (AOP (result)) && size == 1 && !isBitvar)
7034 const char *l = aopGet (AOP (right), 0, FALSE);
7035 const char *pair = getPairName (AOP (result));
7036 if (canAssignToPtr (l) && isPtr (pair))
7038 emit2 ("ld !*pair,%s", pair, l);
7043 emit2 ("ld !*pair,a", pair);
7048 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7051 const char *l = aopGet (AOP (right), 0, FALSE);
7056 if (canAssignToPtr (l))
7058 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7062 _moveA (aopGet (AOP (right), offset, FALSE));
7063 emit2 ("ld !*iyx,a", offset);
7069 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7076 const char *l = aopGet (AOP (right), offset, FALSE);
7077 if (isRegOrLit (AOP (right)) && !IS_GB)
7079 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7084 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7088 emit2 ("inc %s", _pairs[PAIR_HL].name);
7089 _G.pairs[PAIR_HL].offset++;
7094 /* Fixup HL back down */
7095 for (size = AOP_SIZE (right)-1; size; size--)
7097 emit2 ("dec %s", _pairs[PAIR_HL].name);
7102 /* if the operand is already in dptr
7103 then we do nothing else we move the value to dptr */
7104 if (AOP_TYPE (result) != AOP_STR)
7106 fetchPair (pairId, AOP (result));
7108 /* so hl now contains the address */
7109 freeAsmop (result, NULL, ic);
7111 /* if bit then unpack */
7114 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7124 const char *l = aopGet (AOP (right), offset, FALSE);
7125 if (isRegOrLit (AOP (right)) && !IS_GB)
7127 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7132 emit2 ("ld !*pair,a", _pairs[pairId].name);
7136 emit2 ("inc %s", _pairs[pairId].name);
7137 _G.pairs[pairId].offset++;
7143 freeAsmop (right, NULL, ic);
7146 /*-----------------------------------------------------------------*/
7147 /* genPointerSet - stores the value into a pointer location */
7148 /*-----------------------------------------------------------------*/
7150 genPointerSet (iCode * ic)
7152 operand *right, *result;
7153 sym_link *type, *etype;
7155 right = IC_RIGHT (ic);
7156 result = IC_RESULT (ic);
7158 /* depending on the type of pointer we need to
7159 move it to the correct pointer register */
7160 type = operandType (result);
7161 etype = getSpec (type);
7163 genGenPointerSet (right, result, ic);
7166 /*-----------------------------------------------------------------*/
7167 /* genIfx - generate code for Ifx statement */
7168 /*-----------------------------------------------------------------*/
7170 genIfx (iCode * ic, iCode * popIc)
7172 operand *cond = IC_COND (ic);
7175 aopOp (cond, ic, FALSE, TRUE);
7177 /* get the value into acc */
7178 if (AOP_TYPE (cond) != AOP_CRY)
7182 /* the result is now in the accumulator */
7183 freeAsmop (cond, NULL, ic);
7185 /* if there was something to be popped then do it */
7189 /* if the condition is a bit variable */
7190 if (isbit && IS_ITEMP (cond) &&
7192 genIfxJump (ic, SPIL_LOC (cond)->rname);
7193 else if (isbit && !IS_ITEMP (cond))
7194 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7196 genIfxJump (ic, "a");
7201 /*-----------------------------------------------------------------*/
7202 /* genAddrOf - generates code for address of */
7203 /*-----------------------------------------------------------------*/
7205 genAddrOf (iCode * ic)
7207 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7209 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7211 /* if the operand is on the stack then we
7212 need to get the stack offset of this
7218 spillPair (PAIR_HL);
7219 if (sym->stack <= 0)
7221 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7225 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7227 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7231 emit2 ("ld de,!hashedstr", sym->rname);
7232 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7237 spillPair (PAIR_HL);
7240 /* if it has an offset then we need to compute it */
7242 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7244 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7245 emit2 ("add hl,sp");
7249 emit2 ("ld hl,!hashedstr", sym->rname);
7251 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7253 freeAsmop (IC_RESULT (ic), NULL, ic);
7256 /*-----------------------------------------------------------------*/
7257 /* genAssign - generate code for assignment */
7258 /*-----------------------------------------------------------------*/
7260 genAssign (iCode * ic)
7262 operand *result, *right;
7264 unsigned long lit = 0L;
7266 result = IC_RESULT (ic);
7267 right = IC_RIGHT (ic);
7269 /* Dont bother assigning if they are the same */
7270 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7272 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7276 aopOp (right, ic, FALSE, FALSE);
7277 aopOp (result, ic, TRUE, FALSE);
7279 /* if they are the same registers */
7280 if (sameRegs (AOP (right), AOP (result)))
7282 emitDebug ("; (registers are the same)");
7286 /* if the result is a bit */
7287 if (AOP_TYPE (result) == AOP_CRY)
7289 wassertl (0, "Tried to assign to a bit");
7293 size = AOP_SIZE (result);
7296 if (AOP_TYPE (right) == AOP_LIT)
7298 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7301 if (isPair (AOP (result)))
7303 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7305 else if ((size > 1) &&
7306 (AOP_TYPE (result) != AOP_REG) &&
7307 (AOP_TYPE (right) == AOP_LIT) &&
7308 !IS_FLOAT (operandType (right)) &&
7311 bool fXored = FALSE;
7313 /* Work from the top down.
7314 Done this way so that we can use the cached copy of 0
7315 in A for a fast clear */
7318 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7320 if (!fXored && size > 1)
7327 aopPut (AOP (result), "a", offset);
7331 aopPut (AOP (result), "!zero", offset);
7335 aopPut (AOP (result),
7336 aopGet (AOP (right), offset, FALSE),
7341 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7343 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7344 aopPut (AOP (result), "l", LSB);
7345 aopPut (AOP (result), "h", MSB16);
7347 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7349 /* Special case. Load into a and d, then load out. */
7350 _moveA (aopGet (AOP (right), 0, FALSE));
7351 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7352 aopPut (AOP (result), "a", 0);
7353 aopPut (AOP (result), "e", 1);
7355 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7357 /* Special case - simple memcpy */
7358 aopGet (AOP (right), LSB, FALSE);
7361 aopGet (AOP (result), LSB, FALSE);
7365 emit2 ("ld a,(de)");
7366 /* Peephole will optimise this. */
7367 emit2 ("ld (hl),a");
7375 spillPair (PAIR_HL);
7381 /* PENDING: do this check better */
7382 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7384 _moveA (aopGet (AOP (right), offset, FALSE));
7385 aopPut (AOP (result), "a", offset);
7388 aopPut (AOP (result),
7389 aopGet (AOP (right), offset, FALSE),
7396 freeAsmop (right, NULL, ic);
7397 freeAsmop (result, NULL, ic);
7400 /*-----------------------------------------------------------------*/
7401 /* genJumpTab - genrates code for jump table */
7402 /*-----------------------------------------------------------------*/
7404 genJumpTab (iCode * ic)
7409 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7410 /* get the condition into accumulator */
7411 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7414 emit2 ("ld e,%s", l);
7415 emit2 ("ld d,!zero");
7416 jtab = newiTempLabel (NULL);
7417 spillPair (PAIR_HL);
7418 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7419 emit2 ("add hl,de");
7420 emit2 ("add hl,de");
7421 emit2 ("add hl,de");
7422 freeAsmop (IC_JTCOND (ic), NULL, ic);
7426 emitLabel (jtab->key + 100);
7427 /* now generate the jump labels */
7428 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7429 jtab = setNextItem (IC_JTLABELS (ic)))
7430 emit2 ("jp !tlabel", jtab->key + 100);
7433 /*-----------------------------------------------------------------*/
7434 /* genCast - gen code for casting */
7435 /*-----------------------------------------------------------------*/
7437 genCast (iCode * ic)
7439 operand *result = IC_RESULT (ic);
7440 sym_link *rtype = operandType (IC_RIGHT (ic));
7441 operand *right = IC_RIGHT (ic);
7444 /* if they are equivalent then do nothing */
7445 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7448 aopOp (right, ic, FALSE, FALSE);
7449 aopOp (result, ic, FALSE, FALSE);
7451 /* if the result is a bit */
7452 if (AOP_TYPE (result) == AOP_CRY)
7454 wassertl (0, "Tried to cast to a bit");
7457 /* if they are the same size : or less */
7458 if (AOP_SIZE (result) <= AOP_SIZE (right))
7461 /* if they are in the same place */
7462 if (sameRegs (AOP (right), AOP (result)))
7465 /* if they in different places then copy */
7466 size = AOP_SIZE (result);
7470 aopPut (AOP (result),
7471 aopGet (AOP (right), offset, FALSE),
7478 /* So we now know that the size of destination is greater
7479 than the size of the source */
7480 /* we move to result for the size of source */
7481 size = AOP_SIZE (right);
7485 aopPut (AOP (result),
7486 aopGet (AOP (right), offset, FALSE),
7491 /* now depending on the sign of the destination */
7492 size = AOP_SIZE (result) - AOP_SIZE (right);
7493 /* Unsigned or not an integral type - right fill with zeros */
7494 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7497 aopPut (AOP (result), "!zero", offset++);
7501 /* we need to extend the sign :{ */
7502 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE);
7507 aopPut (AOP (result), "a", offset++);
7511 freeAsmop (right, NULL, ic);
7512 freeAsmop (result, NULL, ic);
7515 /*-----------------------------------------------------------------*/
7516 /* genReceive - generate code for a receive iCode */
7517 /*-----------------------------------------------------------------*/
7519 genReceive (iCode * ic)
7521 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7522 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7523 IS_TRUE_SYMOP (IC_RESULT (ic))))
7533 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7534 size = AOP_SIZE(IC_RESULT(ic));
7536 for (i = 0; i < size; i++) {
7537 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7541 freeAsmop (IC_RESULT (ic), NULL, ic);
7544 /*-----------------------------------------------------------------*/
7545 /* genDummyRead - generate code for dummy read of volatiles */
7546 /*-----------------------------------------------------------------*/
7548 genDummyRead (iCode * ic)
7554 if (op && IS_SYMOP (op))
7556 aopOp (op, ic, FALSE, FALSE);
7559 size = AOP_SIZE (op);
7564 _moveA (aopGet (AOP (op), offset, FALSE));
7568 freeAsmop (op, NULL, ic);
7572 if (op && IS_SYMOP (op))
7574 aopOp (op, ic, FALSE, FALSE);
7577 size = AOP_SIZE (op);
7582 _moveA (aopGet (AOP (op), offset, FALSE));
7586 freeAsmop (op, NULL, ic);
7590 /*-----------------------------------------------------------------*/
7591 /* genCritical - generate code for start of a critical sequence */
7592 /*-----------------------------------------------------------------*/
7594 genCritical (iCode *ic)
7596 symbol *tlbl = newiTempLabel (NULL);
7602 else if (IC_RESULT (ic))
7604 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7605 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7606 //get interrupt enable flag IFF2 into P/O
7610 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7611 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7612 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7613 emit2 ("!tlabeldef", (tlbl->key + 100));
7614 _G.lines.current->isLabel = 1;
7615 freeAsmop (IC_RESULT (ic), NULL, ic);
7619 //get interrupt enable flag IFF2 into P/O
7628 /*-----------------------------------------------------------------*/
7629 /* genEndCritical - generate code for end of a critical sequence */
7630 /*-----------------------------------------------------------------*/
7632 genEndCritical (iCode *ic)
7634 symbol *tlbl = newiTempLabel (NULL);
7640 else if (IC_RIGHT (ic))
7642 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7643 _toBoolean (IC_RIGHT (ic));
7644 //don't enable interrupts if they were off before
7645 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7647 emitLabel (tlbl->key + 100);
7648 freeAsmop (IC_RIGHT (ic), NULL, ic);
7654 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7655 //don't enable interrupts as they were off before
7656 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7658 emit2 ("!tlabeldef", (tlbl->key + 100));
7659 _G.lines.current->isLabel = 1;
7665 /** Maximum number of bytes to emit per line. */
7669 /** Context for the byte output chunker. */
7672 unsigned char buffer[DBEMIT_MAX_RUN];
7677 /** Flushes a byte chunker by writing out all in the buffer and
7681 _dbFlush(DBEMITCTX *self)
7688 sprintf(line, ".db 0x%02X", self->buffer[0]);
7690 for (i = 1; i < self->pos; i++)
7692 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7699 /** Write out another byte, buffering until a decent line is
7703 _dbEmit(DBEMITCTX *self, int c)
7705 if (self->pos == DBEMIT_MAX_RUN)
7709 self->buffer[self->pos++] = c;
7712 /** Context for a simple run length encoder. */
7716 unsigned char buffer[128];
7718 /** runLen may be equivalent to pos. */
7724 RLE_CHANGE_COST = 4,
7728 /** Flush the buffer of a run length encoder by writing out the run or
7729 data that it currently contains.
7732 _rleCommit(RLECTX *self)
7738 memset(&db, 0, sizeof(db));
7740 emit2(".db %u", self->pos);
7742 for (i = 0; i < self->pos; i++)
7744 _dbEmit(&db, self->buffer[i]);
7753 Can get either a run or a block of random stuff.
7754 Only want to change state if a good run comes in or a run ends.
7755 Detecting run end is easy.
7758 Say initial state is in run, len zero, last zero. Then if you get a
7759 few zeros then something else then a short run will be output.
7760 Seems OK. While in run mode, keep counting. While in random mode,
7761 keep a count of the run. If run hits margin, output all up to run,
7762 restart, enter run mode.
7765 /** Add another byte into the run length encoder, flushing as
7766 required. The run length encoder uses the Amiga IFF style, where
7767 a block is prefixed by its run length. A positive length means
7768 the next n bytes pass straight through. A negative length means
7769 that the next byte is repeated -n times. A zero terminates the
7773 _rleAppend(RLECTX *self, unsigned c)
7777 if (c != self->last)
7779 /* The run has stopped. See if it is worthwhile writing it out
7780 as a run. Note that the random data comes in as runs of
7783 if (self->runLen > RLE_CHANGE_COST)
7785 /* Yes, worthwhile. */
7786 /* Commit whatever was in the buffer. */
7788 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7792 /* Not worthwhile. Append to the end of the random list. */
7793 for (i = 0; i < self->runLen; i++)
7795 if (self->pos >= RLE_MAX_BLOCK)
7800 self->buffer[self->pos++] = self->last;
7808 if (self->runLen >= RLE_MAX_BLOCK)
7810 /* Commit whatever was in the buffer. */
7813 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7821 _rleFlush(RLECTX *self)
7823 _rleAppend(self, -1);
7830 /** genArrayInit - Special code for initialising an array with constant
7834 genArrayInit (iCode * ic)
7838 int elementSize = 0, eIndex, i;
7839 unsigned val, lastVal;
7843 memset(&rle, 0, sizeof(rle));
7845 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7847 _saveRegsForCall(ic, 0);
7849 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7850 emit2 ("call __initrleblock");
7852 type = operandType(IC_LEFT(ic));
7854 if (type && type->next)
7856 if (IS_SPEC(type->next) || IS_PTR(type->next))
7858 elementSize = getSize(type->next);
7860 else if (IS_ARRAY(type->next) && type->next->next)
7862 elementSize = getSize(type->next->next);
7866 printTypeChainRaw (type, NULL);
7867 wassertl (0, "Can't determine element size in genArrayInit.");
7872 wassertl (0, "Can't determine element size in genArrayInit.");
7875 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7877 iLoop = IC_ARRAYILIST(ic);
7878 lastVal = (unsigned)-1;
7880 /* Feed all the bytes into the run length encoder which will handle
7882 This works well for mixed char data, and for random int and long
7889 for (i = 0; i < ix; i++)
7891 for (eIndex = 0; eIndex < elementSize; eIndex++)
7893 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7894 _rleAppend(&rle, val);
7898 iLoop = iLoop->next;
7902 /* Mark the end of the run. */
7905 _restoreRegsAfterCall();
7909 freeAsmop (IC_LEFT(ic), NULL, ic);
7913 _swap (PAIR_ID one, PAIR_ID two)
7915 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7921 emit2 ("ld a,%s", _pairs[one].l);
7922 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7923 emit2 ("ld %s,a", _pairs[two].l);
7924 emit2 ("ld a,%s", _pairs[one].h);
7925 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7926 emit2 ("ld %s,a", _pairs[two].h);
7930 /* The problem is that we may have all three pairs used and they may
7931 be needed in a different order.
7936 hl = hl => unity, fine
7940 hl = hl hl = hl, swap de <=> bc
7948 hl = bc de = de, swap bc <=> hl
7956 hl = de bc = bc, swap hl <=> de
7961 * Any pair = pair are done last
7962 * Any pair = iTemp are done last
7963 * Any swaps can be done any time
7971 So how do we detect the cases?
7972 How about a 3x3 matrix?
7976 x x x x (Fourth for iTemp/other)
7978 First determin which mode to use by counting the number of unity and
7981 Two - Assign the pair first, then the rest
7982 One - Swap the two, then the rest
7986 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7988 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7990 PAIR_BC, PAIR_HL, PAIR_DE
7992 int i, j, nunity = 0;
7993 memset (ids, PAIR_INVALID, sizeof (ids));
7996 wassert (nparams == 3);
7998 /* First save everything that needs to be saved. */
7999 _saveRegsForCall (ic, 0);
8001 /* Loading HL first means that DE is always fine. */
8002 for (i = 0; i < nparams; i++)
8004 aopOp (pparams[i], ic, FALSE, FALSE);
8005 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
8008 /* Count the number of unity or iTemp assigns. */
8009 for (i = 0; i < 3; i++)
8011 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
8019 /* Any order, fall through. */
8021 else if (nunity == 2)
8023 /* One is assigned. Pull it out and assign. */
8024 for (i = 0; i < 3; i++)
8026 for (j = 0; j < NUM_PAIRS; j++)
8028 if (ids[dest[i]][j] == TRUE)
8030 /* Found it. See if it's the right one. */
8031 if (j == PAIR_INVALID || j == dest[i])
8037 fetchPair(dest[i], AOP (pparams[i]));
8044 else if (nunity == 1)
8046 /* Find the pairs to swap. */
8047 for (i = 0; i < 3; i++)
8049 for (j = 0; j < NUM_PAIRS; j++)
8051 if (ids[dest[i]][j] == TRUE)
8053 if (j == PAIR_INVALID || j == dest[i])
8068 int next = getPairId (AOP (pparams[0]));
8069 emit2 ("push %s", _pairs[next].name);
8071 if (next == dest[1])
8073 fetchPair (dest[1], AOP (pparams[1]));
8074 fetchPair (dest[2], AOP (pparams[2]));
8078 fetchPair (dest[2], AOP (pparams[2]));
8079 fetchPair (dest[1], AOP (pparams[1]));
8081 emit2 ("pop %s", _pairs[dest[0]].name);
8084 /* Finally pull out all of the iTemps */
8085 for (i = 0; i < 3; i++)
8087 if (ids[dest[i]][PAIR_INVALID] == 1)
8089 fetchPair (dest[i], AOP (pparams[i]));
8095 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8101 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8105 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8107 setupForBuiltin3 (ic, nParams, pparams);
8109 label = newiTempLabel(NULL);
8111 emitLabel (label->key);
8112 emit2 ("ld a,(hl)");
8115 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8117 freeAsmop (from, NULL, ic->next);
8118 freeAsmop (to, NULL, ic);
8122 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8124 operand *from, *to, *count;
8127 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8132 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8134 setupForBuiltin3 (ic, nParams, pparams);
8138 freeAsmop (count, NULL, ic->next->next);
8139 freeAsmop (from, NULL, ic);
8141 _restoreRegsAfterCall();
8143 /* if we need assign a result value */
8144 if ((IS_ITEMP (IC_RESULT (ic)) &&
8145 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8146 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8147 IS_TRUE_SYMOP (IC_RESULT (ic)))
8149 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8150 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8151 freeAsmop (IC_RESULT (ic), NULL, ic);
8154 freeAsmop (to, NULL, ic->next);
8157 /*-----------------------------------------------------------------*/
8158 /* genBuiltIn - calls the appropriate function to generating code */
8159 /* for a built in function */
8160 /*-----------------------------------------------------------------*/
8161 static void genBuiltIn (iCode *ic)
8163 operand *bi_parms[MAX_BUILTIN_ARGS];
8168 /* get all the arguments for a built in function */
8169 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8171 /* which function is it */
8172 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8174 if (strcmp(bif->name,"__builtin_strcpy")==0)
8176 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8178 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8180 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8184 wassertl (0, "Unknown builtin function encountered");
8188 /*-----------------------------------------------------------------*/
8189 /* genZ80Code - generate code for Z80 based controllers */
8190 /*-----------------------------------------------------------------*/
8192 genZ80Code (iCode * lic)
8200 _fReturn = _gbz80_return;
8201 _fTmp = _gbz80_return;
8205 _fReturn = _z80_return;
8206 _fTmp = _z80_return;
8209 _G.lines.head = _G.lines.current = NULL;
8211 /* if debug information required */
8212 if (options.debug && currFunc)
8214 debugFile->writeFunction (currFunc, lic);
8217 for (ic = lic; ic; ic = ic->next)
8219 _G.current_iCode = ic;
8221 if (ic->lineno && cln != ic->lineno)
8225 debugFile->writeCLine (ic);
8227 if (!options.noCcodeInAsm)
8229 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8230 printCLine(ic->filename, ic->lineno));
8234 if (options.iCodeInAsm)
8236 const char *iLine = printILine(ic);
8237 emit2 (";ic:%d: %s", ic->key, iLine);
8240 /* if the result is marked as
8241 spilt and rematerializable or code for
8242 this has already been generated then
8244 if (resultRemat (ic) || ic->generated)
8247 /* depending on the operation */
8251 emitDebug ("; genNot");
8256 emitDebug ("; genCpl");
8261 emitDebug ("; genUminus");
8266 emitDebug ("; genIpush");
8271 /* IPOP happens only when trying to restore a
8272 spilt live range, if there is an ifx statement
8273 following this pop then the if statement might
8274 be using some of the registers being popped which
8275 would destroy the contents of the register so
8276 we need to check for this condition and handle it */
8278 ic->next->op == IFX &&
8279 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8281 emitDebug ("; genIfx");
8282 genIfx (ic->next, ic);
8286 emitDebug ("; genIpop");
8292 emitDebug ("; genCall");
8297 emitDebug ("; genPcall");
8302 emitDebug ("; genFunction");
8307 emitDebug ("; genEndFunction");
8308 genEndFunction (ic);
8312 emitDebug ("; genRet");
8317 emitDebug ("; genLabel");
8322 emitDebug ("; genGoto");
8327 emitDebug ("; genPlus");
8332 emitDebug ("; genMinus");
8337 emitDebug ("; genMult");
8342 emitDebug ("; genDiv");
8347 emitDebug ("; genMod");
8352 emitDebug ("; genCmpGt");
8353 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8357 emitDebug ("; genCmpLt");
8358 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8365 /* note these two are xlated by algebraic equivalence
8366 during parsing SDCC.y */
8367 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8368 "got '>=' or '<=' shouldn't have come here");
8372 emitDebug ("; genCmpEq");
8373 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8377 emitDebug ("; genAndOp");
8382 emitDebug ("; genOrOp");
8387 emitDebug ("; genXor");
8388 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8392 emitDebug ("; genOr");
8393 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8397 emitDebug ("; genAnd");
8398 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8402 emitDebug ("; genInline");
8407 emitDebug ("; genRRC");
8412 emitDebug ("; genRLC");
8417 emitDebug ("; genGetHBIT");
8422 emitDebug ("; genLeftShift");
8427 emitDebug ("; genRightShift");
8431 case GET_VALUE_AT_ADDRESS:
8432 emitDebug ("; genPointerGet");
8438 if (POINTER_SET (ic))
8440 emitDebug ("; genAssign (pointer)");
8445 emitDebug ("; genAssign");
8451 emitDebug ("; genIfx");
8456 emitDebug ("; genAddrOf");
8461 emitDebug ("; genJumpTab");
8466 emitDebug ("; genCast");
8471 emitDebug ("; genReceive");
8476 if (ic->builtinSEND)
8478 emitDebug ("; genBuiltIn");
8483 emitDebug ("; addSet");
8484 addSet (&_G.sendSet, ic);
8489 emitDebug ("; genArrayInit");
8493 case DUMMY_READ_VOLATILE:
8494 emitDebug ("; genDummyRead");
8499 emitDebug ("; genCritical");
8504 emitDebug ("; genEndCritical");
8505 genEndCritical (ic);
8514 /* now we are ready to call the
8515 peep hole optimizer */
8516 if (!options.nopeep)
8517 peepHole (&_G.lines.head);
8519 /* This is unfortunate */
8520 /* now do the actual printing */
8522 struct dbuf_s *buf = codeOutBuf;
8523 if (isInHome () && codeOutBuf == &code->oBuf)
8524 codeOutBuf = &home->oBuf;
8525 printLine (_G.lines.head, codeOutBuf);
8526 if (_G.flushStatics)
8529 _G.flushStatics = 0;
8534 freeTrace(&_G.lines.trace);
8535 freeTrace(&_G.trace.aops);
8541 _isPairUsed (iCode * ic, PAIR_ID pairId)
8547 if (bitVectBitValue (ic->rMask, D_IDX))
8549 if (bitVectBitValue (ic->rMask, E_IDX))
8559 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8562 value *val = aop->aopu.aop_lit;
8564 wassert (aop->type == AOP_LIT);
8565 wassert (!IS_FLOAT (val->type));
8567 v = ulFromVal (val);
8575 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8576 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));