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));
3998 if(size == 0 && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) == 1)
4001 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4004 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4005 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4009 _G.preserveCarry = FALSE;
4010 freeAsmop (IC_LEFT (ic), NULL, ic);
4011 freeAsmop (IC_RIGHT (ic), NULL, ic);
4012 freeAsmop (IC_RESULT (ic), NULL, ic);
4015 /*-----------------------------------------------------------------*/
4016 /* genMinusDec :- does subtraction with deccrement if possible */
4017 /*-----------------------------------------------------------------*/
4019 genMinusDec (iCode * ic)
4021 unsigned int icount;
4022 unsigned int size = getDataSize (IC_RESULT (ic));
4024 /* will try to generate an increment */
4025 /* if the right side is not a literal we cannot */
4026 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4029 /* if the literal value of the right hand side
4030 is greater than 4 then it is not worth it */
4031 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
4034 size = getDataSize (IC_RESULT (ic));
4036 /* if decrement 16 bits in register */
4037 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4038 (size > 1) && isPair (AOP (IC_RESULT (ic))))
4041 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4045 /* If result is a pair */
4046 if (isPair (AOP (IC_RESULT (ic))))
4048 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
4050 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4054 /* if increment 16 bits in register */
4055 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4059 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4062 emit2 ("dec %s", _getTempPairName());
4065 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4071 /* if the sizes are greater than 1 then we cannot */
4072 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4073 AOP_SIZE (IC_LEFT (ic)) > 1)
4076 /* we can if the aops of the left & result match or if they are in
4077 registers and the registers are the same */
4078 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4081 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4088 /*-----------------------------------------------------------------*/
4089 /* genMinus - generates code for subtraction */
4090 /*-----------------------------------------------------------------*/
4092 genMinus (iCode * ic)
4094 int size, offset = 0;
4095 unsigned long lit = 0L;
4097 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4098 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4099 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4101 /* special cases :- */
4102 /* if both left & right are in bit space */
4103 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4104 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4106 wassertl (0, "Tried to subtract two bits");
4110 /* if I can do an decrement instead of subtract then GOOD for ME */
4111 if (genMinusDec (ic) == TRUE)
4114 size = getDataSize (IC_RESULT (ic));
4116 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4121 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4125 /* Same logic as genPlus */
4128 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4129 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4130 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4132 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4133 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4134 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4135 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4137 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4138 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4140 if (left == PAIR_INVALID && right == PAIR_INVALID)
4145 else if (right == PAIR_INVALID)
4147 else if (left == PAIR_INVALID)
4150 fetchPair (left, AOP (IC_LEFT (ic)));
4151 /* Order is important. Right may be HL */
4152 fetchPair (right, AOP (IC_RIGHT (ic)));
4154 emit2 ("ld a,%s", _pairs[left].l);
4155 emit2 ("sub a,%s", _pairs[right].l);
4157 emit2 ("ld a,%s", _pairs[left].h);
4158 emit2 ("sbc a,%s", _pairs[right].h);
4160 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4162 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4164 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4170 /* Be paranoid on the GB with 4 byte variables due to how C
4171 can be trashed by lda hl,n(sp).
4173 _gbz80_emitAddSubLong (ic, FALSE);
4178 setupToPreserveCarry (ic);
4180 /* if literal, add a,#-lit, else normal subb */
4183 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4184 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4188 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4191 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4195 /* first add without previous c */
4198 if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
4201 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4204 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4206 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4209 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4210 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4211 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4213 wassertl (0, "Tried to subtract on a long pointer");
4217 _G.preserveCarry = FALSE;
4218 freeAsmop (IC_LEFT (ic), NULL, ic);
4219 freeAsmop (IC_RIGHT (ic), NULL, ic);
4220 freeAsmop (IC_RESULT (ic), NULL, ic);
4223 /*-----------------------------------------------------------------*/
4224 /* genMultChar - generates code for unsigned 8x8 multiplication */
4225 /*-----------------------------------------------------------------*/
4227 genMultOneChar (iCode * ic)
4229 symbol *tlbl1, *tlbl2;
4230 bool savedB = FALSE;
4234 wassertl (0, "Multiplication is handled through support function calls on gbz80");
4238 /* Save b into a if b is in use. */
4239 if (bitVectBitValue (ic->rMask, B_IDX) &&
4240 !(getPairId (AOP (IC_RESULT (ic))) == PAIR_BC))
4245 if (isPairInUse (PAIR_DE, ic) &&
4246 !(getPairId (AOP (IC_RESULT (ic))) == PAIR_DE))
4249 _G.stack.pushedDE = TRUE;
4252 tlbl1 = newiTempLabel (NULL);
4253 tlbl2 = newiTempLabel (NULL);
4255 emit2 ("ld e,%s", aopGet (AOP (IC_RIGHT (ic)), LSB, FALSE));
4256 emit2 ("ld h,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4257 emit2 ("ld l,#0x00");
4259 emit2 ("ld b,#0x08");
4260 emitLabel (tlbl1->key + 100);
4261 emit2 ("add hl,hl");
4262 emit2 ("jp NC,!tlabel", tlbl2->key + 100);
4263 emit2 ("add hl,de");
4264 emitLabel (tlbl2->key + 100);
4265 emit2 ("djnz !tlabel", tlbl1->key + 100);
4269 if (IS_Z80 && _G.stack.pushedDE)
4272 _G.stack.pushedDE = FALSE;
4279 if (AOP_SIZE (IC_RESULT (ic)) == 1)
4280 aopPut (AOP (IC_RESULT (ic)), "l", 0);
4282 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4284 freeAsmop (IC_LEFT (ic), NULL, ic);
4285 freeAsmop (IC_RIGHT (ic), NULL, ic);
4286 freeAsmop (IC_RESULT (ic), NULL, ic);
4289 /*-----------------------------------------------------------------*/
4290 /* genMult - generates code for multiplication */
4291 /*-----------------------------------------------------------------*/
4293 genMult (iCode * ic)
4297 /* If true then the final operation should be a subtract */
4298 bool active = FALSE;
4301 /* Shouldn't occur - all done through function calls */
4302 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4303 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4304 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4306 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4308 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4309 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4310 AOP_SIZE (IC_RESULT (ic)) > 2)
4312 wassertl (0, "Multiplication is handled through support function calls");
4315 /* Swap left and right such that right is a literal */
4316 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4318 operand *t = IC_RIGHT (ic);
4319 IC_RIGHT (ic) = IC_LEFT (ic);
4323 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4325 genMultOneChar (ic);
4329 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4331 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4332 // wassertl (val > 0, "Multiply must be positive");
4333 wassertl (val != 1, "Can't multiply by 1");
4335 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4337 _G.stack.pushedDE = TRUE;
4341 emit2 ("ld a,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4342 else if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4344 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4355 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4360 for (count = 0; count < 16; count++)
4362 if (count != 0 && active)
4367 emit2 ("add hl,hl");
4371 if (active == FALSE)
4386 emit2 ("add hl,de");
4395 if (IS_Z80 && _G.stack.pushedDE)
4398 _G.stack.pushedDE = FALSE;
4402 aopPut (AOP (IC_RESULT (ic)), "a", 0);
4404 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4406 freeAsmop (IC_LEFT (ic), NULL, ic);
4407 freeAsmop (IC_RIGHT (ic), NULL, ic);
4408 freeAsmop (IC_RESULT (ic), NULL, ic);
4411 /*-----------------------------------------------------------------*/
4412 /* genDiv - generates code for division */
4413 /*-----------------------------------------------------------------*/
4417 /* Shouldn't occur - all done through function calls */
4418 wassertl (0, "Division is handled through support function calls");
4421 /*-----------------------------------------------------------------*/
4422 /* genMod - generates code for division */
4423 /*-----------------------------------------------------------------*/
4427 /* Shouldn't occur - all done through function calls */
4431 /*-----------------------------------------------------------------*/
4432 /* genIfxJump :- will create a jump depending on the ifx */
4433 /*-----------------------------------------------------------------*/
4435 genIfxJump (iCode * ic, char *jval)
4440 /* if true label then we jump if condition
4444 jlbl = IC_TRUE (ic);
4445 if (!strcmp (jval, "a"))
4449 else if (!strcmp (jval, "c"))
4453 else if (!strcmp (jval, "nc"))
4457 else if (!strcmp (jval, "m"))
4461 else if (!strcmp (jval, "p"))
4467 /* The buffer contains the bit on A that we should test */
4473 /* false label is present */
4474 jlbl = IC_FALSE (ic);
4475 if (!strcmp (jval, "a"))
4479 else if (!strcmp (jval, "c"))
4483 else if (!strcmp (jval, "nc"))
4487 else if (!strcmp (jval, "m"))
4491 else if (!strcmp (jval, "p"))
4497 /* The buffer contains the bit on A that we should test */
4501 /* Z80 can do a conditional long jump */
4502 if (!strcmp (jval, "a"))
4506 else if (!strcmp (jval, "c"))
4509 else if (!strcmp (jval, "nc"))
4512 else if (!strcmp (jval, "m"))
4515 else if (!strcmp (jval, "p"))
4520 emit2 ("bit %s,a", jval);
4522 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4524 /* mark the icode as generated */
4530 _getPairIdName (PAIR_ID id)
4532 return _pairs[id].name;
4537 /* if unsigned char cmp with lit, just compare */
4539 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4541 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4544 emit2 ("xor a,!immedbyte", 0x80);
4545 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4548 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4550 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4552 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4553 // Pull left into DE and right into HL
4554 aopGet (AOP(left), LSB, FALSE);
4557 aopGet (AOP(right), LSB, FALSE);
4561 if (size == 0 && sign)
4563 // Highest byte when signed needs the bits flipped
4566 emit2 ("ld a,(de)");
4567 emit2 ("xor !immedbyte", 0x80);
4569 emit2 ("ld a,(hl)");
4570 emit2 ("xor !immedbyte", 0x80);
4574 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4578 emit2 ("ld a,(de)");
4579 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4589 spillPair (PAIR_HL);
4591 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4593 setupPair (PAIR_HL, AOP (left), 0);
4594 aopGet (AOP(right), LSB, FALSE);
4598 if (size == 0 && sign)
4600 // Highest byte when signed needs the bits flipped
4603 emit2 ("ld a,(hl)");
4604 emit2 ("xor !immedbyte", 0x80);
4606 emit2 ("ld a,%d(iy)", offset);
4607 emit2 ("xor !immedbyte", 0x80);
4611 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4615 emit2 ("ld a,(hl)");
4616 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4625 spillPair (PAIR_HL);
4626 spillPair (PAIR_IY);
4630 if (AOP_TYPE (right) == AOP_LIT)
4632 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4633 /* optimize if(x < 0) or if(x >= 0) */
4638 /* No sign so it's always false */
4643 /* Just load in the top most bit */
4644 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4645 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4647 genIfxJump (ifx, "7");
4659 /* First setup h and l contaning the top most bytes XORed */
4660 bool fDidXor = FALSE;
4661 if (AOP_TYPE (left) == AOP_LIT)
4663 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4664 emit2 ("ld %s,!immedbyte", _fTmp[0],
4665 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4669 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4670 emit2 ("xor a,!immedbyte", 0x80);
4671 emit2 ("ld %s,a", _fTmp[0]);
4674 if (AOP_TYPE (right) == AOP_LIT)
4676 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4677 emit2 ("ld %s,!immedbyte", _fTmp[1],
4678 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4682 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4683 emit2 ("xor a,!immedbyte", 0x80);
4684 emit2 ("ld %s,a", _fTmp[1]);
4690 /* Do a long subtract */
4693 _moveA (aopGet (AOP (left), offset, FALSE));
4695 if (sign && size == 0)
4697 emit2 ("ld a,%s", _fTmp[0]);
4698 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4702 /* Subtract through, propagating the carry */
4703 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4711 /** Generic compare for > or <
4714 genCmp (operand * left, operand * right,
4715 operand * result, iCode * ifx, int sign)
4717 int size, offset = 0;
4718 unsigned long lit = 0L;
4720 /* if left & right are bit variables */
4721 if (AOP_TYPE (left) == AOP_CRY &&
4722 AOP_TYPE (right) == AOP_CRY)
4724 /* Cant happen on the Z80 */
4725 wassertl (0, "Tried to compare two bits");
4729 /* Do a long subtract of right from left. */
4730 size = max (AOP_SIZE (left), AOP_SIZE (right));
4732 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4734 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4735 // Pull left into DE and right into HL
4736 aopGet (AOP(left), LSB, FALSE);
4739 aopGet (AOP(right), LSB, FALSE);
4743 emit2 ("ld a,(de)");
4744 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4753 spillPair (PAIR_HL);
4757 if (AOP_TYPE (right) == AOP_LIT)
4759 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4760 /* optimize if(x < 0) or if(x >= 0) */
4765 /* No sign so it's always false */
4770 /* Just load in the top most bit */
4771 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4772 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4774 genIfxJump (ifx, "7");
4785 genIfxJump (ifx, "nc");
4796 _moveA (aopGet (AOP (left), offset, FALSE));
4797 /* Subtract through, propagating the carry */
4798 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4804 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4808 /* Shift the sign bit up into carry */
4815 /* if the result is used in the next
4816 ifx conditional branch then generate
4817 code a little differently */
4825 genIfxJump (ifx, "c");
4829 genIfxJump (ifx, "m");
4834 genIfxJump (ifx, "c");
4841 /* Shift the sign bit up into carry */
4846 /* leave the result in acc */
4850 /*-----------------------------------------------------------------*/
4851 /* genCmpGt :- greater than comparison */
4852 /*-----------------------------------------------------------------*/
4854 genCmpGt (iCode * ic, iCode * ifx)
4856 operand *left, *right, *result;
4857 sym_link *letype, *retype;
4860 left = IC_LEFT (ic);
4861 right = IC_RIGHT (ic);
4862 result = IC_RESULT (ic);
4864 letype = getSpec (operandType (left));
4865 retype = getSpec (operandType (right));
4866 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4867 /* assign the asmops */
4868 aopOp (left, ic, FALSE, FALSE);
4869 aopOp (right, ic, FALSE, FALSE);
4870 aopOp (result, ic, TRUE, FALSE);
4872 setupToPreserveCarry (ic);
4874 genCmp (right, left, result, ifx, sign);
4876 _G.preserveCarry = FALSE;
4877 freeAsmop (left, NULL, ic);
4878 freeAsmop (right, NULL, ic);
4879 freeAsmop (result, NULL, ic);
4882 /*-----------------------------------------------------------------*/
4883 /* genCmpLt - less than comparisons */
4884 /*-----------------------------------------------------------------*/
4886 genCmpLt (iCode * ic, iCode * ifx)
4888 operand *left, *right, *result;
4889 sym_link *letype, *retype;
4892 left = IC_LEFT (ic);
4893 right = IC_RIGHT (ic);
4894 result = IC_RESULT (ic);
4896 letype = getSpec (operandType (left));
4897 retype = getSpec (operandType (right));
4898 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4900 /* assign the asmops */
4901 aopOp (left, ic, FALSE, FALSE);
4902 aopOp (right, ic, FALSE, FALSE);
4903 aopOp (result, ic, TRUE, FALSE);
4905 setupToPreserveCarry (ic);
4907 genCmp (left, right, result, ifx, sign);
4909 _G.preserveCarry = FALSE;
4910 freeAsmop (left, NULL, ic);
4911 freeAsmop (right, NULL, ic);
4912 freeAsmop (result, NULL, ic);
4915 /*-----------------------------------------------------------------*/
4916 /* gencjneshort - compare and jump if not equal */
4917 /* returns pair that still needs to be popped */
4918 /*-----------------------------------------------------------------*/
4920 gencjneshort (operand * left, operand * right, symbol * lbl)
4922 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4924 unsigned long lit = 0L;
4926 /* Swap the left and right if it makes the computation easier */
4927 if (AOP_TYPE (left) == AOP_LIT)
4934 /* if the right side is a literal then anything goes */
4935 if (AOP_TYPE (right) == AOP_LIT)
4937 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4940 _moveA (aopGet (AOP (left), offset, FALSE));
4945 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4952 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4958 _moveA (aopGet (AOP (left), offset, FALSE));
4959 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4962 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4963 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4968 /* if the right side is in a register or
4969 pointed to by HL, IX or IY */
4970 else if (AOP_TYPE (right) == AOP_REG ||
4971 AOP_TYPE (right) == AOP_HL ||
4972 AOP_TYPE (right) == AOP_IY ||
4973 AOP_TYPE (right) == AOP_STK ||
4974 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4975 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4976 AOP_IS_PAIRPTR (right, PAIR_IY))
4980 _moveA (aopGet (AOP (left), offset, FALSE));
4981 if (AOP_TYPE (right) == AOP_LIT &&
4982 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4985 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4989 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4990 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4995 /* right is in direct space or a pointer reg, need both a & b */
4999 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
5001 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
5002 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
5010 emit2 ("; direct compare");
5011 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
5012 _moveA (aopGet (AOP (right), offset, FALSE));
5013 emit2 ("sub %s", _pairs[pair].l);
5014 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
5019 return PAIR_INVALID;
5022 /*-----------------------------------------------------------------*/
5023 /* gencjne - compare and jump if not equal */
5024 /*-----------------------------------------------------------------*/
5026 gencjne (operand * left, operand * right, symbol * lbl)
5028 symbol *tlbl = newiTempLabel (NULL);
5030 PAIR_ID pop = gencjneshort (left, right, lbl);
5033 emit2 ("ld a,!one");
5034 emit2 ("!shortjp !tlabel", tlbl->key + 100);
5035 emitLabel (lbl->key + 100);
5037 emitLabel (tlbl->key + 100);
5041 /*-----------------------------------------------------------------*/
5042 /* genCmpEq - generates code for equal to */
5043 /*-----------------------------------------------------------------*/
5045 genCmpEq (iCode * ic, iCode * ifx)
5047 operand *left, *right, *result;
5049 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5050 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5051 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5053 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
5055 /* Swap operands if it makes the operation easier. ie if:
5056 1. Left is a literal.
5058 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
5060 operand *t = IC_RIGHT (ic);
5061 IC_RIGHT (ic) = IC_LEFT (ic);
5065 if (ifx && !AOP_SIZE (result))
5068 /* if they are both bit variables */
5069 if (AOP_TYPE (left) == AOP_CRY &&
5070 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5072 wassertl (0, "Tried to compare two bits");
5077 tlbl = newiTempLabel (NULL);
5078 pop = gencjneshort (left, right, tlbl);
5082 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
5083 emitLabel (tlbl->key + 100);
5088 /* PENDING: do this better */
5089 symbol *lbl = newiTempLabel (NULL);
5091 emit2 ("!shortjp !tlabel", lbl->key + 100);
5092 emitLabel (tlbl->key + 100);
5094 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
5095 emitLabel (lbl->key + 100);
5098 /* mark the icode as generated */
5103 /* if they are both bit variables */
5104 if (AOP_TYPE (left) == AOP_CRY &&
5105 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5107 wassertl (0, "Tried to compare a bit to either a literal or another bit");
5113 gencjne (left, right, newiTempLabel (NULL));
5114 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5121 genIfxJump (ifx, "a");
5124 /* if the result is used in an arithmetic operation
5125 then put the result in place */
5126 if (AOP_TYPE (result) != AOP_CRY)
5131 /* leave the result in acc */
5135 freeAsmop (left, NULL, ic);
5136 freeAsmop (right, NULL, ic);
5137 freeAsmop (result, NULL, ic);
5140 /*-----------------------------------------------------------------*/
5141 /* ifxForOp - returns the icode containing the ifx for operand */
5142 /*-----------------------------------------------------------------*/
5144 ifxForOp (operand * op, iCode * ic)
5146 /* if true symbol then needs to be assigned */
5147 if (IS_TRUE_SYMOP (op))
5150 /* if this has register type condition and
5151 the next instruction is ifx with the same operand
5152 and live to of the operand is upto the ifx only then */
5154 ic->next->op == IFX &&
5155 IC_COND (ic->next)->key == op->key &&
5156 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5162 /*-----------------------------------------------------------------*/
5163 /* genAndOp - for && operation */
5164 /*-----------------------------------------------------------------*/
5166 genAndOp (iCode * ic)
5168 operand *left, *right, *result;
5171 /* note here that && operations that are in an if statement are
5172 taken away by backPatchLabels only those used in arthmetic
5173 operations remain */
5174 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5175 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5176 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5178 /* if both are bit variables */
5179 if (AOP_TYPE (left) == AOP_CRY &&
5180 AOP_TYPE (right) == AOP_CRY)
5182 wassertl (0, "Tried to and two bits");
5186 tlbl = newiTempLabel (NULL);
5188 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5190 emitLabel (tlbl->key + 100);
5194 freeAsmop (left, NULL, ic);
5195 freeAsmop (right, NULL, ic);
5196 freeAsmop (result, NULL, ic);
5199 /*-----------------------------------------------------------------*/
5200 /* genOrOp - for || operation */
5201 /*-----------------------------------------------------------------*/
5203 genOrOp (iCode * ic)
5205 operand *left, *right, *result;
5208 /* note here that || operations that are in an
5209 if statement are taken away by backPatchLabels
5210 only those used in arthmetic operations remain */
5211 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5212 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5213 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5215 /* if both are bit variables */
5216 if (AOP_TYPE (left) == AOP_CRY &&
5217 AOP_TYPE (right) == AOP_CRY)
5219 wassertl (0, "Tried to OR two bits");
5223 tlbl = newiTempLabel (NULL);
5225 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5227 emitLabel (tlbl->key + 100);
5231 freeAsmop (left, NULL, ic);
5232 freeAsmop (right, NULL, ic);
5233 freeAsmop (result, NULL, ic);
5236 /*-----------------------------------------------------------------*/
5237 /* isLiteralBit - test if lit == 2^n */
5238 /*-----------------------------------------------------------------*/
5240 isLiteralBit (unsigned long lit)
5242 unsigned long pw[32] =
5243 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5244 0x100L, 0x200L, 0x400L, 0x800L,
5245 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5246 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5247 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5248 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5249 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5252 for (idx = 0; idx < 32; idx++)
5258 /*-----------------------------------------------------------------*/
5259 /* jmpTrueOrFalse - */
5260 /*-----------------------------------------------------------------*/
5262 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5264 // ugly but optimized by peephole
5267 symbol *nlbl = newiTempLabel (NULL);
5268 emit2 ("jp !tlabel", nlbl->key + 100);
5269 emitLabel (tlbl->key + 100);
5270 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5271 emitLabel (nlbl->key + 100);
5275 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5276 emitLabel (tlbl->key + 100);
5281 /*-----------------------------------------------------------------*/
5282 /* genAnd - code for and */
5283 /*-----------------------------------------------------------------*/
5285 genAnd (iCode * ic, iCode * ifx)
5287 operand *left, *right, *result;
5288 int size, offset = 0;
5289 unsigned long lit = 0L;
5292 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5293 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5294 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5296 /* if left is a literal & right is not then exchange them */
5297 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5298 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5300 operand *tmp = right;
5305 /* if result = right then exchange them */
5306 if (sameRegs (AOP (result), AOP (right)))
5308 operand *tmp = right;
5313 /* if right is bit then exchange them */
5314 if (AOP_TYPE (right) == AOP_CRY &&
5315 AOP_TYPE (left) != AOP_CRY)
5317 operand *tmp = right;
5321 if (AOP_TYPE (right) == AOP_LIT)
5322 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5324 size = AOP_SIZE (result);
5326 if (AOP_TYPE (left) == AOP_CRY)
5328 wassertl (0, "Tried to perform an AND with a bit as an operand");
5332 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5333 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5334 if ((AOP_TYPE (right) == AOP_LIT) &&
5335 (AOP_TYPE (result) == AOP_CRY) &&
5336 (AOP_TYPE (left) != AOP_CRY))
5338 symbol *tlbl = newiTempLabel (NULL);
5339 int sizel = AOP_SIZE (left);
5342 /* PENDING: Test case for this. */
5347 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5349 _moveA (aopGet (AOP (left), offset, FALSE));
5350 if (bytelit != 0x0FFL)
5352 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5359 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5363 // bit = left & literal
5367 emit2 ("!tlabeldef", tlbl->key + 100);
5368 _G.lines.current->isLabel = 1;
5370 // if(left & literal)
5375 jmpTrueOrFalse (ifx, tlbl);
5383 /* if left is same as result */
5384 if (sameRegs (AOP (result), AOP (left)))
5386 for (; size--; offset++)
5388 if (AOP_TYPE (right) == AOP_LIT)
5390 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5395 aopPut (AOP (result), "!zero", offset);
5398 _moveA (aopGet (AOP (left), offset, FALSE));
5400 aopGet (AOP (right), offset, FALSE));
5401 aopPut (AOP (left), "a", offset);
5408 if (AOP_TYPE (left) == AOP_ACC)
5410 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5414 _moveA (aopGet (AOP (left), offset, FALSE));
5416 aopGet (AOP (right), offset, FALSE));
5417 aopPut (AOP (left), "a", offset);
5424 // left & result in different registers
5425 if (AOP_TYPE (result) == AOP_CRY)
5427 wassertl (0, "Tried to AND where the result is in carry");
5431 for (; (size--); offset++)
5434 // result = left & right
5435 if (AOP_TYPE (right) == AOP_LIT)
5437 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5439 aopPut (AOP (result),
5440 aopGet (AOP (left), offset, FALSE),
5444 else if (bytelit == 0)
5446 aopPut (AOP (result), "!zero", offset);
5450 // faster than result <- left, anl result,right
5451 // and better if result is SFR
5452 if (AOP_TYPE (left) == AOP_ACC)
5453 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5456 _moveA (aopGet (AOP (left), offset, FALSE));
5458 aopGet (AOP (right), offset, FALSE));
5460 aopPut (AOP (result), "a", offset);
5467 freeAsmop (left, NULL, ic);
5468 freeAsmop (right, NULL, ic);
5469 freeAsmop (result, NULL, ic);
5472 /*-----------------------------------------------------------------*/
5473 /* genOr - code for or */
5474 /*-----------------------------------------------------------------*/
5476 genOr (iCode * ic, iCode * ifx)
5478 operand *left, *right, *result;
5479 int size, offset = 0;
5480 unsigned long lit = 0L;
5483 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5484 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5485 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5487 /* if left is a literal & right is not then exchange them */
5488 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5489 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5491 operand *tmp = right;
5496 /* if result = right then exchange them */
5497 if (sameRegs (AOP (result), AOP (right)))
5499 operand *tmp = right;
5504 /* if right is bit then exchange them */
5505 if (AOP_TYPE (right) == AOP_CRY &&
5506 AOP_TYPE (left) != AOP_CRY)
5508 operand *tmp = right;
5512 if (AOP_TYPE (right) == AOP_LIT)
5513 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5515 size = AOP_SIZE (result);
5517 if (AOP_TYPE (left) == AOP_CRY)
5519 wassertl (0, "Tried to OR where left is a bit");
5523 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5524 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5525 if ((AOP_TYPE (right) == AOP_LIT) &&
5526 (AOP_TYPE (result) == AOP_CRY) &&
5527 (AOP_TYPE (left) != AOP_CRY))
5529 symbol *tlbl = newiTempLabel (NULL);
5530 int sizel = AOP_SIZE (left);
5534 wassertl (0, "Result is assigned to a bit");
5536 /* PENDING: Modeled after the AND code which is inefficient. */
5539 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5541 _moveA (aopGet (AOP (left), offset, FALSE));
5542 /* OR with any literal is the same as OR with itself. */
5544 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5550 jmpTrueOrFalse (ifx, tlbl);
5555 /* if left is same as result */
5556 if (sameRegs (AOP (result), AOP (left)))
5558 for (; size--; offset++)
5560 if (AOP_TYPE (right) == AOP_LIT)
5562 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5566 _moveA (aopGet (AOP (left), offset, FALSE));
5568 aopGet (AOP (right), offset, FALSE));
5569 aopPut (AOP (result), "a", offset);
5574 if (AOP_TYPE (left) == AOP_ACC)
5575 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5578 _moveA (aopGet (AOP (left), offset, FALSE));
5580 aopGet (AOP (right), offset, FALSE));
5581 aopPut (AOP (result), "a", offset);
5588 // left & result in different registers
5589 if (AOP_TYPE (result) == AOP_CRY)
5591 wassertl (0, "Result of OR is in a bit");
5594 for (; (size--); offset++)
5597 // result = left & right
5598 if (AOP_TYPE (right) == AOP_LIT)
5600 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5602 aopPut (AOP (result),
5603 aopGet (AOP (left), offset, FALSE),
5608 // faster than result <- left, anl result,right
5609 // and better if result is SFR
5610 if (AOP_TYPE (left) == AOP_ACC)
5611 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5614 _moveA (aopGet (AOP (left), offset, FALSE));
5616 aopGet (AOP (right), offset, FALSE));
5618 aopPut (AOP (result), "a", offset);
5619 /* PENDING: something weird is going on here. Add exception. */
5620 if (AOP_TYPE (result) == AOP_ACC)
5626 freeAsmop (left, NULL, ic);
5627 freeAsmop (right, NULL, ic);
5628 freeAsmop (result, NULL, ic);
5631 /*-----------------------------------------------------------------*/
5632 /* genXor - code for xclusive or */
5633 /*-----------------------------------------------------------------*/
5635 genXor (iCode * ic, iCode * ifx)
5637 operand *left, *right, *result;
5638 int size, offset = 0;
5639 unsigned long lit = 0L;
5641 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5642 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5643 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5645 /* if left is a literal & right is not then exchange them */
5646 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5647 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5649 operand *tmp = right;
5654 /* if result = right then exchange them */
5655 if (sameRegs (AOP (result), AOP (right)))
5657 operand *tmp = right;
5662 /* if right is bit then exchange them */
5663 if (AOP_TYPE (right) == AOP_CRY &&
5664 AOP_TYPE (left) != AOP_CRY)
5666 operand *tmp = right;
5670 if (AOP_TYPE (right) == AOP_LIT)
5671 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5673 size = AOP_SIZE (result);
5675 if (AOP_TYPE (left) == AOP_CRY)
5677 wassertl (0, "Tried to XOR a bit");
5681 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5682 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5683 if ((AOP_TYPE (right) == AOP_LIT) &&
5684 (AOP_TYPE (result) == AOP_CRY) &&
5685 (AOP_TYPE (left) != AOP_CRY))
5687 symbol *tlbl = newiTempLabel (NULL);
5688 int sizel = AOP_SIZE (left);
5692 /* PENDING: Test case for this. */
5693 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5697 _moveA (aopGet (AOP (left), offset, FALSE));
5698 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5699 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5704 jmpTrueOrFalse (ifx, tlbl);
5708 wassertl (0, "Result of XOR was destined for a bit");
5713 /* if left is same as result */
5714 if (sameRegs (AOP (result), AOP (left)))
5716 for (; size--; offset++)
5718 if (AOP_TYPE (right) == AOP_LIT)
5720 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5724 _moveA (aopGet (AOP (left), offset, FALSE));
5726 aopGet (AOP (right), offset, FALSE));
5727 aopPut (AOP (result), "a", offset);
5732 if (AOP_TYPE (left) == AOP_ACC)
5734 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5738 _moveA (aopGet (AOP (left), offset, FALSE));
5740 aopGet (AOP (right), offset, FALSE));
5741 aopPut (AOP (result), "a", offset);
5748 // left & result in different registers
5749 if (AOP_TYPE (result) == AOP_CRY)
5751 wassertl (0, "Result of XOR is in a bit");
5754 for (; (size--); offset++)
5757 // result = left & right
5758 if (AOP_TYPE (right) == AOP_LIT)
5760 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5762 aopPut (AOP (result),
5763 aopGet (AOP (left), offset, FALSE),
5768 // faster than result <- left, anl result,right
5769 // and better if result is SFR
5770 if (AOP_TYPE (left) == AOP_ACC)
5772 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5776 _moveA (aopGet (AOP (left), offset, FALSE));
5778 aopGet (AOP (right), offset, FALSE));
5780 aopPut (AOP (result), "a", offset);
5785 freeAsmop (left, NULL, ic);
5786 freeAsmop (right, NULL, ic);
5787 freeAsmop (result, NULL, ic);
5790 /*-----------------------------------------------------------------*/
5791 /* genInline - write the inline code out */
5792 /*-----------------------------------------------------------------*/
5794 genInline (iCode * ic)
5796 char *buffer, *bp, *bp1;
5797 bool inComment = FALSE;
5799 _G.lines.isInline += (!options.asmpeep);
5801 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5803 /* emit each line as a code */
5821 /* Add \n for labels, not dirs such as c:\mydir */
5822 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5840 _G.lines.isInline -= (!options.asmpeep);
5844 /*-----------------------------------------------------------------*/
5845 /* genRRC - rotate right with carry */
5846 /*-----------------------------------------------------------------*/
5853 /*-----------------------------------------------------------------*/
5854 /* genRLC - generate code for rotate left with carry */
5855 /*-----------------------------------------------------------------*/
5862 /*-----------------------------------------------------------------*/
5863 /* genGetHbit - generates code get highest order bit */
5864 /*-----------------------------------------------------------------*/
5866 genGetHbit (iCode * ic)
5868 operand *left, *result;
5869 left = IC_LEFT (ic);
5870 result = IC_RESULT (ic);
5872 aopOp (left, ic, FALSE, FALSE);
5873 aopOp (result, ic, FALSE, FALSE);
5875 /* get the highest order byte into a */
5876 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5878 if (AOP_TYPE (result) == AOP_CRY)
5886 emit2 ("and a,!one");
5891 freeAsmop (left, NULL, ic);
5892 freeAsmop (result, NULL, ic);
5896 emitRsh2 (asmop *aop, int size, int is_signed)
5902 const char *l = aopGet (aop, size, FALSE);
5905 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5915 /*-----------------------------------------------------------------*/
5916 /* shiftR2Left2Result - shift right two bytes from left to result */
5917 /*-----------------------------------------------------------------*/
5919 shiftR2Left2Result (operand * left, int offl,
5920 operand * result, int offr,
5921 int shCount, int is_signed)
5926 movLeft2Result (left, offl, result, offr, 0);
5927 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5932 /* if (AOP(result)->type == AOP_REG) { */
5934 tlbl = newiTempLabel (NULL);
5936 /* Left is already in result - so now do the shift */
5937 /* Optimizing for speed by default. */
5938 if (!optimize.codeSize || shCount <= 2)
5942 emitRsh2 (AOP (result), size, is_signed);
5947 emit2 ("ld a,!immedbyte", shCount);
5949 emitLabel (tlbl->key + 100);
5951 emitRsh2 (AOP (result), size, is_signed);
5954 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5958 /*-----------------------------------------------------------------*/
5959 /* shiftL2Left2Result - shift left two bytes from left to result */
5960 /*-----------------------------------------------------------------*/
5962 shiftL2Left2Result (operand * left, int offl,
5963 operand * result, int offr, int shCount)
5965 if (sameRegs (AOP (result), AOP (left)) &&
5966 ((offl + MSB16) == offr))
5972 /* Copy left into result */
5973 movLeft2Result (left, offl, result, offr, 0);
5974 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5980 if (getPairId (AOP (result)) == PAIR_HL)
5984 emit2 ("add hl,hl");
5991 symbol *tlbl, *tlbl1;
5994 tlbl = newiTempLabel (NULL);
5995 tlbl1 = newiTempLabel (NULL);
5997 if (AOP (result)->type == AOP_REG)
6001 for (offset = 0; offset < size; offset++)
6003 l = aopGet (AOP (result), offset, FALSE);
6007 emit2 ("sla %s", l);
6018 /* Left is already in result - so now do the shift */
6021 emit2 ("ld a,!immedbyte+1", shCount);
6022 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6023 emitLabel (tlbl->key + 100);
6028 l = aopGet (AOP (result), offset, FALSE);
6032 emit2 ("sla %s", l);
6043 emitLabel (tlbl1->key + 100);
6045 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6051 /*-----------------------------------------------------------------*/
6052 /* AccRol - rotate left accumulator by known count */
6053 /*-----------------------------------------------------------------*/
6055 AccRol (int shCount)
6057 shCount &= 0x0007; // shCount : 0..7
6134 /*-----------------------------------------------------------------*/
6135 /* AccLsh - left shift accumulator by known count */
6136 /*-----------------------------------------------------------------*/
6138 AccLsh (int shCount)
6140 static const unsigned char SLMask[] =
6142 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6151 else if (shCount == 2)
6158 /* rotate left accumulator */
6160 /* and kill the lower order bits */
6161 emit2 ("and a,!immedbyte", SLMask[shCount]);
6166 /*-----------------------------------------------------------------*/
6167 /* shiftL1Left2Result - shift left one byte from left to result */
6168 /*-----------------------------------------------------------------*/
6170 shiftL1Left2Result (operand * left, int offl,
6171 operand * result, int offr, int shCount)
6175 /* If operand and result are the same we can shift in place.
6176 However shifting in acc using add is cheaper than shifting
6177 in place using sla; when shifting by more than 2 shifting in
6178 acc is worth the additional effort for loading from/to acc. */
6179 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6182 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6186 l = aopGet (AOP (left), offl, FALSE);
6188 /* shift left accumulator */
6190 aopPut (AOP (result), "a", offr);
6194 /*-----------------------------------------------------------------*/
6195 /* genlshTwo - left shift two bytes by known amount */
6196 /*-----------------------------------------------------------------*/
6198 genlshTwo (operand * result, operand * left, int shCount)
6200 int size = AOP_SIZE (result);
6202 wassert (size == 2);
6204 /* if shCount >= 8 */
6212 movLeft2Result (left, LSB, result, MSB16, 0);
6213 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6214 aopPut (AOP (result), "!zero", LSB);
6218 movLeft2Result (left, LSB, result, MSB16, 0);
6219 aopPut (AOP (result), "!zero", 0);
6224 aopPut (AOP (result), "!zero", LSB);
6227 /* 0 <= shCount <= 7 */
6236 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6241 /*-----------------------------------------------------------------*/
6242 /* genlshOne - left shift a one byte quantity by known count */
6243 /*-----------------------------------------------------------------*/
6245 genlshOne (operand * result, operand * left, int shCount)
6247 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6250 /*-----------------------------------------------------------------*/
6251 /* genLeftShiftLiteral - left shifting by known count */
6252 /*-----------------------------------------------------------------*/
6254 genLeftShiftLiteral (operand * left,
6259 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6262 freeAsmop (right, NULL, ic);
6264 aopOp (left, ic, FALSE, FALSE);
6265 aopOp (result, ic, FALSE, FALSE);
6267 size = getSize (operandType (result));
6269 /* I suppose that the left size >= result size */
6271 if (shCount >= (size * 8))
6275 aopPut (AOP (result), "!zero", size);
6283 genlshOne (result, left, shCount);
6286 genlshTwo (result, left, shCount);
6289 wassertl (0, "Shifting of longs is currently unsupported");
6295 freeAsmop (left, NULL, ic);
6296 freeAsmop (result, NULL, ic);
6299 /*-----------------------------------------------------------------*/
6300 /* genLeftShift - generates code for left shifting */
6301 /*-----------------------------------------------------------------*/
6303 genLeftShift (iCode * ic)
6307 symbol *tlbl, *tlbl1;
6308 operand *left, *right, *result;
6310 right = IC_RIGHT (ic);
6311 left = IC_LEFT (ic);
6312 result = IC_RESULT (ic);
6314 aopOp (right, ic, FALSE, FALSE);
6316 /* if the shift count is known then do it
6317 as efficiently as possible */
6318 if (AOP_TYPE (right) == AOP_LIT)
6320 genLeftShiftLiteral (left, right, result, ic);
6324 /* shift count is unknown then we have to form a loop get the loop
6325 count in B : Note: we take only the lower order byte since
6326 shifting more that 32 bits make no sense anyway, ( the largest
6327 size of an object can be only 32 bits ) */
6328 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6330 freeAsmop (right, NULL, ic);
6331 aopOp (left, ic, FALSE, FALSE);
6332 aopOp (result, ic, FALSE, FALSE);
6334 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6337 /* now move the left to the result if they are not the
6340 if (!sameRegs (AOP (left), AOP (result)))
6343 size = AOP_SIZE (result);
6347 l = aopGet (AOP (left), offset, FALSE);
6348 aopPut (AOP (result), l, offset);
6353 tlbl = newiTempLabel (NULL);
6354 size = AOP_SIZE (result);
6356 tlbl1 = newiTempLabel (NULL);
6358 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6361 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6362 emitLabel (tlbl->key + 100);
6363 l = aopGet (AOP (result), offset, FALSE);
6367 l = aopGet (AOP (result), offset, FALSE);
6371 emit2 ("sla %s", l);
6379 emitLabel (tlbl1->key + 100);
6381 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6383 freeAsmop (left, NULL, ic);
6384 freeAsmop (result, NULL, ic);
6387 /*-----------------------------------------------------------------*/
6388 /* genrshOne - left shift two bytes by known amount != 0 */
6389 /*-----------------------------------------------------------------*/
6391 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6394 int size = AOP_SIZE (result);
6397 wassert (size == 1);
6398 wassert (shCount < 8);
6400 l = aopGet (AOP (left), 0, FALSE);
6402 if (AOP (result)->type == AOP_REG)
6404 aopPut (AOP (result), l, 0);
6405 l = aopGet (AOP (result), 0, FALSE);
6408 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6416 emit2 ("%s a", is_signed ? "sra" : "srl");
6418 aopPut (AOP (result), "a", 0);
6422 /*-----------------------------------------------------------------*/
6423 /* AccRsh - right shift accumulator by known count */
6424 /*-----------------------------------------------------------------*/
6426 AccRsh (int shCount)
6428 static const unsigned char SRMask[] =
6430 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6435 /* rotate right accumulator */
6436 AccRol (8 - shCount);
6437 /* and kill the higher order bits */
6438 emit2 ("and a,!immedbyte", SRMask[shCount]);
6442 /*-----------------------------------------------------------------*/
6443 /* shiftR1Left2Result - shift right one byte from left to result */
6444 /*-----------------------------------------------------------------*/
6446 shiftR1Left2Result (operand * left, int offl,
6447 operand * result, int offr,
6448 int shCount, int sign)
6450 _moveA (aopGet (AOP (left), offl, FALSE));
6455 emit2 ("%s a", sign ? "sra" : "srl");
6462 aopPut (AOP (result), "a", offr);
6465 /*-----------------------------------------------------------------*/
6466 /* genrshTwo - right shift two bytes by known amount */
6467 /*-----------------------------------------------------------------*/
6469 genrshTwo (operand * result, operand * left,
6470 int shCount, int sign)
6472 /* if shCount >= 8 */
6478 shiftR1Left2Result (left, MSB16, result, LSB,
6483 movLeft2Result (left, MSB16, result, LSB, sign);
6487 /* Sign extend the result */
6488 _moveA(aopGet (AOP (result), 0, FALSE));
6492 aopPut (AOP (result), ACC_NAME, MSB16);
6496 aopPut (AOP (result), "!zero", 1);
6499 /* 0 <= shCount <= 7 */
6502 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6506 /*-----------------------------------------------------------------*/
6507 /* genRightShiftLiteral - left shifting by known count */
6508 /*-----------------------------------------------------------------*/
6510 genRightShiftLiteral (operand * left,
6516 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6519 freeAsmop (right, NULL, ic);
6521 aopOp (left, ic, FALSE, FALSE);
6522 aopOp (result, ic, FALSE, FALSE);
6524 size = getSize (operandType (result));
6526 /* I suppose that the left size >= result size */
6528 if (shCount >= (size * 8)) {
6530 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6531 _moveA(aopGet (AOP (left), 0, FALSE));
6539 aopPut (AOP (result), s, size);
6546 genrshOne (result, left, shCount, sign);
6549 genrshTwo (result, left, shCount, sign);
6552 wassertl (0, "Asked to shift right a long which should be a function call");
6555 wassertl (0, "Entered default case in right shift delegate");
6558 freeAsmop (left, NULL, ic);
6559 freeAsmop (result, NULL, ic);
6562 /*-----------------------------------------------------------------*/
6563 /* genRightShift - generate code for right shifting */
6564 /*-----------------------------------------------------------------*/
6566 genRightShift (iCode * ic)
6568 operand *right, *left, *result;
6570 int size, offset, first = 1;
6574 symbol *tlbl, *tlbl1;
6576 /* if signed then we do it the hard way preserve the
6577 sign bit moving it inwards */
6578 retype = getSpec (operandType (IC_RESULT (ic)));
6580 is_signed = !SPEC_USIGN (retype);
6582 /* signed & unsigned types are treated the same : i.e. the
6583 signed is NOT propagated inwards : quoting from the
6584 ANSI - standard : "for E1 >> E2, is equivalent to division
6585 by 2**E2 if unsigned or if it has a non-negative value,
6586 otherwise the result is implementation defined ", MY definition
6587 is that the sign does not get propagated */
6589 right = IC_RIGHT (ic);
6590 left = IC_LEFT (ic);
6591 result = IC_RESULT (ic);
6593 aopOp (right, ic, FALSE, FALSE);
6595 /* if the shift count is known then do it
6596 as efficiently as possible */
6597 if (AOP_TYPE (right) == AOP_LIT)
6599 genRightShiftLiteral (left, right, result, ic, is_signed);
6603 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6605 freeAsmop (right, NULL, ic);
6607 aopOp (left, ic, FALSE, FALSE);
6608 aopOp (result, ic, FALSE, FALSE);
6610 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6613 /* now move the left to the result if they are not the
6615 if (!sameRegs (AOP (left), AOP (result)))
6618 size = AOP_SIZE (result);
6622 l = aopGet (AOP (left), offset, FALSE);
6623 aopPut (AOP (result), l, offset);
6628 tlbl = newiTempLabel (NULL);
6629 tlbl1 = newiTempLabel (NULL);
6630 size = AOP_SIZE (result);
6633 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6636 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6637 emitLabel (tlbl->key + 100);
6640 l = aopGet (AOP (result), offset--, FALSE);
6643 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6651 emitLabel (tlbl1->key + 100);
6653 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6655 freeAsmop (left, NULL, ic);
6656 freeAsmop (result, NULL, ic);
6660 /*-----------------------------------------------------------------*/
6661 /* genUnpackBits - generates code for unpacking bits */
6662 /*-----------------------------------------------------------------*/
6664 genUnpackBits (operand * result, int pair)
6666 int offset = 0; /* result byte offset */
6667 int rsize; /* result size */
6668 int rlen = 0; /* remaining bitfield length */
6669 sym_link *etype; /* bitfield type information */
6670 int blen; /* bitfield length */
6671 int bstr; /* bitfield starting bit within byte */
6673 emitDebug ("; genUnpackBits");
6675 etype = getSpec (operandType (result));
6676 rsize = getSize (operandType (result));
6677 blen = SPEC_BLEN (etype);
6678 bstr = SPEC_BSTR (etype);
6680 /* If the bitfield length is less than a byte */
6683 emit2 ("ld a,!*pair", _pairs[pair].name);
6685 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6686 if (!SPEC_USIGN (etype))
6688 /* signed bitfield */
6689 symbol *tlbl = newiTempLabel (NULL);
6691 emit2 ("bit %d,a", blen - 1);
6692 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6693 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6694 emitLabel (tlbl->key + 100);
6696 aopPut (AOP (result), "a", offset++);
6700 /* TODO: what if pair == PAIR_DE ? */
6701 if (getPairId (AOP (result)) == PAIR_HL)
6703 wassertl (rsize == 2, "HL must be of size 2");
6704 emit2 ("ld a,!*hl");
6706 emit2 ("ld h,!*hl");
6709 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6710 if (!SPEC_USIGN (etype))
6712 /* signed bitfield */
6713 symbol *tlbl = newiTempLabel (NULL);
6715 emit2 ("bit %d,a", blen - 1);
6716 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6717 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6718 emitLabel (tlbl->key + 100);
6721 spillPair (PAIR_HL);
6725 /* Bit field did not fit in a byte. Copy all
6726 but the partial byte at the end. */
6727 for (rlen=blen;rlen>=8;rlen-=8)
6729 emit2 ("ld a,!*pair", _pairs[pair].name);
6730 aopPut (AOP (result), "a", offset++);
6733 emit2 ("inc %s", _pairs[pair].name);
6734 _G.pairs[pair].offset++;
6738 /* Handle the partial byte at the end */
6741 emit2 ("ld a,!*pair", _pairs[pair].name);
6742 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6743 if (!SPEC_USIGN (etype))
6745 /* signed bitfield */
6746 symbol *tlbl = newiTempLabel (NULL);
6748 emit2 ("bit %d,a", rlen - 1);
6749 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6750 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6751 emitLabel (tlbl->key + 100);
6753 aopPut (AOP (result), "a", offset++);
6761 if (SPEC_USIGN (etype))
6765 /* signed bitfield: sign extension with 0x00 or 0xff */
6773 aopPut (AOP (result), source, offset++);
6777 /*-----------------------------------------------------------------*/
6778 /* genGenPointerGet - get value from generic pointer space */
6779 /*-----------------------------------------------------------------*/
6781 genGenPointerGet (operand * left,
6782 operand * result, iCode * ic)
6785 sym_link *retype = getSpec (operandType (result));
6791 aopOp (left, ic, FALSE, FALSE);
6792 aopOp (result, ic, FALSE, FALSE);
6794 size = AOP_SIZE (result);
6796 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6799 if (isPtrPair (AOP (left)))
6801 tsprintf (buffer, sizeof(buffer),
6802 "!*pair", getPairName (AOP (left)));
6803 aopPut (AOP (result), buffer, 0);
6807 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6808 aopPut (AOP (result), "a", 0);
6810 freeAsmop (left, NULL, ic);
6814 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6821 tsprintf (at, sizeof(at), "!*iyx", offset);
6822 aopPut (AOP (result), at, offset);
6826 freeAsmop (left, NULL, ic);
6830 /* For now we always load into IY */
6831 /* if this is remateriazable */
6832 fetchPair (pair, AOP (left));
6834 /* if bit then unpack */
6835 if (IS_BITVAR (retype))
6837 genUnpackBits (result, pair);
6838 freeAsmop (left, NULL, ic);
6842 else if (getPairId (AOP (result)) == PAIR_HL)
6844 wassertl (size == 2, "HL must be of size 2");
6845 emit2 ("ld a,!*hl");
6847 emit2 ("ld h,!*hl");
6849 spillPair (PAIR_HL);
6851 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6853 size = AOP_SIZE (result);
6858 /* PENDING: make this better */
6859 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6861 aopPut (AOP (result), "!*hl", offset++);
6865 emit2 ("ld a,!*pair", _pairs[pair].name);
6866 aopPut (AOP (result), "a", offset++);
6870 emit2 ("inc %s", _pairs[pair].name);
6871 _G.pairs[pair].offset++;
6874 /* Fixup HL back down */
6875 for (size = AOP_SIZE (result)-1; size; size--)
6877 emit2 ("dec %s", _pairs[pair].name);
6882 size = AOP_SIZE (result);
6887 /* PENDING: make this better */
6889 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6891 aopPut (AOP (result), "!*hl", offset++);
6895 emit2 ("ld a,!*pair", _pairs[pair].name);
6896 aopPut (AOP (result), "a", offset++);
6900 emit2 ("inc %s", _pairs[pair].name);
6901 _G.pairs[pair].offset++;
6906 freeAsmop (left, NULL, ic);
6909 freeAsmop (result, NULL, ic);
6912 /*-----------------------------------------------------------------*/
6913 /* genPointerGet - generate code for pointer get */
6914 /*-----------------------------------------------------------------*/
6916 genPointerGet (iCode * ic)
6918 operand *left, *result;
6919 sym_link *type, *etype;
6921 left = IC_LEFT (ic);
6922 result = IC_RESULT (ic);
6924 /* depending on the type of pointer we need to
6925 move it to the correct pointer register */
6926 type = operandType (left);
6927 etype = getSpec (type);
6929 genGenPointerGet (left, result, ic);
6933 isRegOrLit (asmop * aop)
6935 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6941 /*-----------------------------------------------------------------*/
6942 /* genPackBits - generates code for packed bit storage */
6943 /*-----------------------------------------------------------------*/
6945 genPackBits (sym_link * etype,
6950 int offset = 0; /* source byte offset */
6951 int rlen = 0; /* remaining bitfield length */
6952 int blen; /* bitfield length */
6953 int bstr; /* bitfield starting bit within byte */
6954 int litval; /* source literal value (if AOP_LIT) */
6955 unsigned char mask; /* bitmask within current byte */
6956 int extraPair; /* a tempory register */
6957 bool needPopExtra=0; /* need to restore original value of temp reg */
6959 emitDebug ("; genPackBits","");
6961 blen = SPEC_BLEN (etype);
6962 bstr = SPEC_BSTR (etype);
6964 /* If the bitfield length is less than a byte */
6967 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6968 (unsigned char) (0xFF >> (8 - bstr)));
6970 if (AOP_TYPE (right) == AOP_LIT)
6972 /* Case with a bitfield length <8 and literal source
6974 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6976 litval &= (~mask) & 0xff;
6977 emit2 ("ld a,!*pair", _pairs[pair].name);
6978 if ((mask|litval)!=0xff)
6979 emit2 ("and a,!immedbyte", mask);
6981 emit2 ("or a,!immedbyte", litval);
6982 emit2 ("ld !*pair,a", _pairs[pair].name);
6987 /* Case with a bitfield length <8 and arbitrary source
6989 _moveA (aopGet (AOP (right), 0, FALSE));
6990 /* shift and mask source value */
6992 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6994 extraPair = getFreePairId(ic);
6995 if (extraPair == PAIR_INVALID)
6997 extraPair = PAIR_BC;
6998 if (getPairId (AOP (right)) != PAIR_BC
6999 || !isLastUse (ic, right))
7005 emit2 ("ld %s,a", _pairs[extraPair].l);
7006 emit2 ("ld a,!*pair", _pairs[pair].name);
7008 emit2 ("and a,!immedbyte", mask);
7009 emit2 ("or a,%s", _pairs[extraPair].l);
7010 emit2 ("ld !*pair,a", _pairs[pair].name);
7017 /* Bit length is greater than 7 bits. In this case, copy */
7018 /* all except the partial byte at the end */
7019 for (rlen=blen;rlen>=8;rlen-=8)
7021 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
7022 emit2 ("ld !*pair,a", _pairs[pair].name);
7025 emit2 ("inc %s", _pairs[pair].name);
7026 _G.pairs[pair].offset++;
7030 /* If there was a partial byte at the end */
7033 mask = (((unsigned char) -1 << rlen) & 0xff);
7035 if (AOP_TYPE (right) == AOP_LIT)
7037 /* Case with partial byte and literal source
7039 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7040 litval >>= (blen-rlen);
7041 litval &= (~mask) & 0xff;
7042 emit2 ("ld a,!*pair", _pairs[pair].name);
7043 if ((mask|litval)!=0xff)
7044 emit2 ("and a,!immedbyte", mask);
7046 emit2 ("or a,!immedbyte", litval);
7050 /* Case with partial byte and arbitrary source
7052 _moveA (aopGet (AOP (right), offset++, FALSE));
7053 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7055 extraPair = getFreePairId(ic);
7056 if (extraPair == PAIR_INVALID)
7058 extraPair = getPairId (AOP (right));
7059 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
7060 extraPair = PAIR_BC;
7062 if (getPairId (AOP (right)) != PAIR_BC
7063 || !isLastUse (ic, right))
7069 emit2 ("ld %s,a", _pairs[extraPair].l);
7070 emit2 ("ld a,!*pair", _pairs[pair].name);
7072 emit2 ("and a,!immedbyte", mask);
7073 emit2 ("or a,%s", _pairs[extraPair].l);
7078 emit2 ("ld !*pair,a", _pairs[pair].name);
7083 /*-----------------------------------------------------------------*/
7084 /* genGenPointerSet - stores the value into a pointer location */
7085 /*-----------------------------------------------------------------*/
7087 genGenPointerSet (operand * right,
7088 operand * result, iCode * ic)
7091 sym_link *retype = getSpec (operandType (right));
7092 sym_link *letype = getSpec (operandType (result));
7093 PAIR_ID pairId = PAIR_HL;
7096 aopOp (result, ic, FALSE, FALSE);
7097 aopOp (right, ic, FALSE, FALSE);
7102 size = AOP_SIZE (right);
7104 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
7105 emitDebug("; isBitvar = %d", isBitvar);
7107 /* Handle the exceptions first */
7108 if (isPair (AOP (result)) && size == 1 && !isBitvar)
7111 const char *l = aopGet (AOP (right), 0, FALSE);
7112 const char *pair = getPairName (AOP (result));
7113 if (canAssignToPtr (l) && isPtr (pair))
7115 emit2 ("ld !*pair,%s", pair, l);
7120 emit2 ("ld !*pair,a", pair);
7125 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7128 const char *l = aopGet (AOP (right), 0, FALSE);
7133 if (canAssignToPtr (l))
7135 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7139 _moveA (aopGet (AOP (right), offset, FALSE));
7140 emit2 ("ld !*iyx,a", offset);
7146 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7153 const char *l = aopGet (AOP (right), offset, FALSE);
7154 if (isRegOrLit (AOP (right)) && !IS_GB)
7156 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7161 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7165 emit2 ("inc %s", _pairs[PAIR_HL].name);
7166 _G.pairs[PAIR_HL].offset++;
7171 /* Fixup HL back down */
7172 for (size = AOP_SIZE (right)-1; size; size--)
7174 emit2 ("dec %s", _pairs[PAIR_HL].name);
7179 /* if the operand is already in dptr
7180 then we do nothing else we move the value to dptr */
7181 if (AOP_TYPE (result) != AOP_STR)
7183 fetchPair (pairId, AOP (result));
7185 /* so hl now contains the address */
7186 freeAsmop (result, NULL, ic);
7188 /* if bit then unpack */
7191 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7201 const char *l = aopGet (AOP (right), offset, FALSE);
7202 if (isRegOrLit (AOP (right)) && !IS_GB)
7204 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7209 emit2 ("ld !*pair,a", _pairs[pairId].name);
7213 emit2 ("inc %s", _pairs[pairId].name);
7214 _G.pairs[pairId].offset++;
7220 freeAsmop (right, NULL, ic);
7223 /*-----------------------------------------------------------------*/
7224 /* genPointerSet - stores the value into a pointer location */
7225 /*-----------------------------------------------------------------*/
7227 genPointerSet (iCode * ic)
7229 operand *right, *result;
7230 sym_link *type, *etype;
7232 right = IC_RIGHT (ic);
7233 result = IC_RESULT (ic);
7235 /* depending on the type of pointer we need to
7236 move it to the correct pointer register */
7237 type = operandType (result);
7238 etype = getSpec (type);
7240 genGenPointerSet (right, result, ic);
7243 /*-----------------------------------------------------------------*/
7244 /* genIfx - generate code for Ifx statement */
7245 /*-----------------------------------------------------------------*/
7247 genIfx (iCode * ic, iCode * popIc)
7249 operand *cond = IC_COND (ic);
7252 aopOp (cond, ic, FALSE, TRUE);
7254 /* get the value into acc */
7255 if (AOP_TYPE (cond) != AOP_CRY)
7259 /* the result is now in the accumulator */
7260 freeAsmop (cond, NULL, ic);
7262 /* if there was something to be popped then do it */
7266 /* if the condition is a bit variable */
7267 if (isbit && IS_ITEMP (cond) &&
7269 genIfxJump (ic, SPIL_LOC (cond)->rname);
7270 else if (isbit && !IS_ITEMP (cond))
7271 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7273 genIfxJump (ic, "a");
7278 /*-----------------------------------------------------------------*/
7279 /* genAddrOf - generates code for address of */
7280 /*-----------------------------------------------------------------*/
7282 genAddrOf (iCode * ic)
7284 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7286 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7288 /* if the operand is on the stack then we
7289 need to get the stack offset of this
7295 spillPair (PAIR_HL);
7296 if (sym->stack <= 0)
7298 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7302 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7304 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7308 emit2 ("ld de,!hashedstr", sym->rname);
7309 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7314 spillPair (PAIR_HL);
7317 /* if it has an offset then we need to compute it */
7319 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7321 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7322 emit2 ("add hl,sp");
7326 emit2 ("ld hl,!hashedstr", sym->rname);
7328 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7330 freeAsmop (IC_RESULT (ic), NULL, ic);
7333 /*-----------------------------------------------------------------*/
7334 /* genAssign - generate code for assignment */
7335 /*-----------------------------------------------------------------*/
7337 genAssign (iCode * ic)
7339 operand *result, *right;
7341 unsigned long lit = 0L;
7343 result = IC_RESULT (ic);
7344 right = IC_RIGHT (ic);
7346 /* Dont bother assigning if they are the same */
7347 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7349 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7353 aopOp (right, ic, FALSE, FALSE);
7354 aopOp (result, ic, TRUE, FALSE);
7356 /* if they are the same registers */
7357 if (sameRegs (AOP (right), AOP (result)))
7359 emitDebug ("; (registers are the same)");
7363 /* if the result is a bit */
7364 if (AOP_TYPE (result) == AOP_CRY)
7366 wassertl (0, "Tried to assign to a bit");
7370 size = AOP_SIZE (result);
7373 if (AOP_TYPE (right) == AOP_LIT)
7375 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7378 if (isPair (AOP (result)))
7380 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7382 else if ((size > 1) &&
7383 (AOP_TYPE (result) != AOP_REG) &&
7384 (AOP_TYPE (right) == AOP_LIT) &&
7385 !IS_FLOAT (operandType (right)) &&
7388 bool fXored = FALSE;
7390 /* Work from the top down.
7391 Done this way so that we can use the cached copy of 0
7392 in A for a fast clear */
7395 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7397 if (!fXored && size > 1)
7404 aopPut (AOP (result), "a", offset);
7408 aopPut (AOP (result), "!zero", offset);
7412 aopPut (AOP (result),
7413 aopGet (AOP (right), offset, FALSE),
7418 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7420 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7421 aopPut (AOP (result), "l", LSB);
7422 aopPut (AOP (result), "h", MSB16);
7424 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7426 /* Special case. Load into a and d, then load out. */
7427 _moveA (aopGet (AOP (right), 0, FALSE));
7428 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7429 aopPut (AOP (result), "a", 0);
7430 aopPut (AOP (result), "e", 1);
7432 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7434 /* Special case - simple memcpy */
7435 aopGet (AOP (right), LSB, FALSE);
7438 aopGet (AOP (result), LSB, FALSE);
7442 emit2 ("ld a,(de)");
7443 /* Peephole will optimise this. */
7444 emit2 ("ld (hl),a");
7452 spillPair (PAIR_HL);
7458 /* PENDING: do this check better */
7459 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7461 _moveA (aopGet (AOP (right), offset, FALSE));
7462 aopPut (AOP (result), "a", offset);
7465 aopPut (AOP (result),
7466 aopGet (AOP (right), offset, FALSE),
7473 freeAsmop (right, NULL, ic);
7474 freeAsmop (result, NULL, ic);
7477 /*-----------------------------------------------------------------*/
7478 /* genJumpTab - genrates code for jump table */
7479 /*-----------------------------------------------------------------*/
7481 genJumpTab (iCode * ic)
7486 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7487 /* get the condition into accumulator */
7488 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7491 emit2 ("ld e,%s", l);
7492 emit2 ("ld d,!zero");
7493 jtab = newiTempLabel (NULL);
7494 spillPair (PAIR_HL);
7495 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7496 emit2 ("add hl,de");
7497 emit2 ("add hl,de");
7498 emit2 ("add hl,de");
7499 freeAsmop (IC_JTCOND (ic), NULL, ic);
7503 emitLabel (jtab->key + 100);
7504 /* now generate the jump labels */
7505 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7506 jtab = setNextItem (IC_JTLABELS (ic)))
7507 emit2 ("jp !tlabel", jtab->key + 100);
7510 /*-----------------------------------------------------------------*/
7511 /* genCast - gen code for casting */
7512 /*-----------------------------------------------------------------*/
7514 genCast (iCode * ic)
7516 operand *result = IC_RESULT (ic);
7517 sym_link *rtype = operandType (IC_RIGHT (ic));
7518 operand *right = IC_RIGHT (ic);
7521 /* if they are equivalent then do nothing */
7522 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7525 aopOp (right, ic, FALSE, FALSE);
7526 aopOp (result, ic, FALSE, FALSE);
7528 /* if the result is a bit */
7529 if (AOP_TYPE (result) == AOP_CRY)
7531 wassertl (0, "Tried to cast to a bit");
7534 /* if they are the same size : or less */
7535 if (AOP_SIZE (result) <= AOP_SIZE (right))
7538 /* if they are in the same place */
7539 if (sameRegs (AOP (right), AOP (result)))
7542 /* if they in different places then copy */
7543 size = AOP_SIZE (result);
7547 aopPut (AOP (result),
7548 aopGet (AOP (right), offset, FALSE),
7555 /* So we now know that the size of destination is greater
7556 than the size of the source */
7557 /* we move to result for the size of source */
7558 size = AOP_SIZE (right);
7562 aopPut (AOP (result),
7563 aopGet (AOP (right), offset, FALSE),
7568 /* now depending on the sign of the destination */
7569 size = AOP_SIZE (result) - AOP_SIZE (right);
7570 /* Unsigned or not an integral type - right fill with zeros */
7571 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7574 aopPut (AOP (result), "!zero", offset++);
7578 /* we need to extend the sign :{ */
7579 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE);
7584 aopPut (AOP (result), "a", offset++);
7588 freeAsmop (right, NULL, ic);
7589 freeAsmop (result, NULL, ic);
7592 /*-----------------------------------------------------------------*/
7593 /* genReceive - generate code for a receive iCode */
7594 /*-----------------------------------------------------------------*/
7596 genReceive (iCode * ic)
7598 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7599 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7600 IS_TRUE_SYMOP (IC_RESULT (ic))))
7610 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7611 size = AOP_SIZE(IC_RESULT(ic));
7613 for (i = 0; i < size; i++) {
7614 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7618 freeAsmop (IC_RESULT (ic), NULL, ic);
7621 /*-----------------------------------------------------------------*/
7622 /* genDummyRead - generate code for dummy read of volatiles */
7623 /*-----------------------------------------------------------------*/
7625 genDummyRead (iCode * ic)
7631 if (op && IS_SYMOP (op))
7633 aopOp (op, ic, FALSE, FALSE);
7636 size = AOP_SIZE (op);
7641 _moveA (aopGet (AOP (op), offset, FALSE));
7645 freeAsmop (op, NULL, ic);
7649 if (op && IS_SYMOP (op))
7651 aopOp (op, ic, FALSE, FALSE);
7654 size = AOP_SIZE (op);
7659 _moveA (aopGet (AOP (op), offset, FALSE));
7663 freeAsmop (op, NULL, ic);
7667 /*-----------------------------------------------------------------*/
7668 /* genCritical - generate code for start of a critical sequence */
7669 /*-----------------------------------------------------------------*/
7671 genCritical (iCode *ic)
7673 symbol *tlbl = newiTempLabel (NULL);
7679 else if (IC_RESULT (ic))
7681 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7682 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7683 //get interrupt enable flag IFF2 into P/O
7687 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7688 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7689 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7690 emit2 ("!tlabeldef", (tlbl->key + 100));
7691 _G.lines.current->isLabel = 1;
7692 freeAsmop (IC_RESULT (ic), NULL, ic);
7696 //get interrupt enable flag IFF2 into P/O
7705 /*-----------------------------------------------------------------*/
7706 /* genEndCritical - generate code for end of a critical sequence */
7707 /*-----------------------------------------------------------------*/
7709 genEndCritical (iCode *ic)
7711 symbol *tlbl = newiTempLabel (NULL);
7717 else if (IC_RIGHT (ic))
7719 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7720 _toBoolean (IC_RIGHT (ic));
7721 //don't enable interrupts if they were off before
7722 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7724 emitLabel (tlbl->key + 100);
7725 freeAsmop (IC_RIGHT (ic), NULL, ic);
7731 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7732 //don't enable interrupts as they were off before
7733 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7735 emit2 ("!tlabeldef", (tlbl->key + 100));
7736 _G.lines.current->isLabel = 1;
7742 /** Maximum number of bytes to emit per line. */
7746 /** Context for the byte output chunker. */
7749 unsigned char buffer[DBEMIT_MAX_RUN];
7754 /** Flushes a byte chunker by writing out all in the buffer and
7758 _dbFlush(DBEMITCTX *self)
7765 sprintf(line, ".db 0x%02X", self->buffer[0]);
7767 for (i = 1; i < self->pos; i++)
7769 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7776 /** Write out another byte, buffering until a decent line is
7780 _dbEmit(DBEMITCTX *self, int c)
7782 if (self->pos == DBEMIT_MAX_RUN)
7786 self->buffer[self->pos++] = c;
7789 /** Context for a simple run length encoder. */
7793 unsigned char buffer[128];
7795 /** runLen may be equivalent to pos. */
7801 RLE_CHANGE_COST = 4,
7805 /** Flush the buffer of a run length encoder by writing out the run or
7806 data that it currently contains.
7809 _rleCommit(RLECTX *self)
7815 memset(&db, 0, sizeof(db));
7817 emit2(".db %u", self->pos);
7819 for (i = 0; i < self->pos; i++)
7821 _dbEmit(&db, self->buffer[i]);
7830 Can get either a run or a block of random stuff.
7831 Only want to change state if a good run comes in or a run ends.
7832 Detecting run end is easy.
7835 Say initial state is in run, len zero, last zero. Then if you get a
7836 few zeros then something else then a short run will be output.
7837 Seems OK. While in run mode, keep counting. While in random mode,
7838 keep a count of the run. If run hits margin, output all up to run,
7839 restart, enter run mode.
7842 /** Add another byte into the run length encoder, flushing as
7843 required. The run length encoder uses the Amiga IFF style, where
7844 a block is prefixed by its run length. A positive length means
7845 the next n bytes pass straight through. A negative length means
7846 that the next byte is repeated -n times. A zero terminates the
7850 _rleAppend(RLECTX *self, unsigned c)
7854 if (c != self->last)
7856 /* The run has stopped. See if it is worthwhile writing it out
7857 as a run. Note that the random data comes in as runs of
7860 if (self->runLen > RLE_CHANGE_COST)
7862 /* Yes, worthwhile. */
7863 /* Commit whatever was in the buffer. */
7865 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7869 /* Not worthwhile. Append to the end of the random list. */
7870 for (i = 0; i < self->runLen; i++)
7872 if (self->pos >= RLE_MAX_BLOCK)
7877 self->buffer[self->pos++] = self->last;
7885 if (self->runLen >= RLE_MAX_BLOCK)
7887 /* Commit whatever was in the buffer. */
7890 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7898 _rleFlush(RLECTX *self)
7900 _rleAppend(self, -1);
7907 /** genArrayInit - Special code for initialising an array with constant
7911 genArrayInit (iCode * ic)
7915 int elementSize = 0, eIndex, i;
7916 unsigned val, lastVal;
7920 memset(&rle, 0, sizeof(rle));
7922 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7924 _saveRegsForCall(ic, 0);
7926 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7927 emit2 ("call __initrleblock");
7929 type = operandType(IC_LEFT(ic));
7931 if (type && type->next)
7933 if (IS_SPEC(type->next) || IS_PTR(type->next))
7935 elementSize = getSize(type->next);
7937 else if (IS_ARRAY(type->next) && type->next->next)
7939 elementSize = getSize(type->next->next);
7943 printTypeChainRaw (type, NULL);
7944 wassertl (0, "Can't determine element size in genArrayInit.");
7949 wassertl (0, "Can't determine element size in genArrayInit.");
7952 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7954 iLoop = IC_ARRAYILIST(ic);
7955 lastVal = (unsigned)-1;
7957 /* Feed all the bytes into the run length encoder which will handle
7959 This works well for mixed char data, and for random int and long
7966 for (i = 0; i < ix; i++)
7968 for (eIndex = 0; eIndex < elementSize; eIndex++)
7970 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7971 _rleAppend(&rle, val);
7975 iLoop = iLoop->next;
7979 /* Mark the end of the run. */
7982 _restoreRegsAfterCall();
7986 freeAsmop (IC_LEFT(ic), NULL, ic);
7990 _swap (PAIR_ID one, PAIR_ID two)
7992 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7998 emit2 ("ld a,%s", _pairs[one].l);
7999 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
8000 emit2 ("ld %s,a", _pairs[two].l);
8001 emit2 ("ld a,%s", _pairs[one].h);
8002 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
8003 emit2 ("ld %s,a", _pairs[two].h);
8008 setupForMemcpy (iCode *ic, int nparams, operand **pparams)
8010 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
8012 PAIR_DE, PAIR_HL, PAIR_BC
8014 int i, j, nunity = 0;
8015 memset (ids, PAIR_INVALID, sizeof (ids));
8018 wassert (nparams == 3);
8020 for (i = 0; i < nparams; i++)
8022 aopOp (pparams[i], ic, FALSE, FALSE);
8023 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
8026 /* Count the number of unity or iTemp assigns. */
8027 for (i = 0; i < 3; i++)
8029 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
8037 /* Any order, fall through. */
8039 else if (nunity == 2)
8041 /* Two are OK. Assign the other one. */
8042 for (i = 0; i < 3; i++)
8044 for (j = 0; j < NUM_PAIRS; j++)
8046 if (ids[dest[i]][j] == TRUE)
8048 /* Found it. See if it's the right one. */
8049 if (j == PAIR_INVALID || j == dest[i])
8055 fetchPair(dest[i], AOP (pparams[i]));
8062 else if (nunity == 1)
8064 /* One is OK. Find the other two. */
8065 for (i = 0; i < 3; i++)
8067 for (j = 0; j < NUM_PAIRS; j++)
8069 if (ids[dest[i]][j] == TRUE)
8071 if (j == PAIR_INVALID || j == dest[i])
8073 /* This one is OK. */
8078 if(ids[j][dest[i]] == TRUE)
8086 fetchPair (dest[i], AOP (pparams[i]));
8096 int next = getPairId (AOP (pparams[0]));
8097 emit2 ("push %s", _pairs[next].name);
8099 if (next == dest[1])
8101 fetchPair (dest[1], AOP (pparams[1]));
8102 fetchPair (dest[2], AOP (pparams[2]));
8106 fetchPair (dest[2], AOP (pparams[2]));
8107 fetchPair (dest[1], AOP (pparams[1]));
8109 emit2 ("pop %s", _pairs[dest[0]].name);
8112 /* Finally pull out all of the iTemps */
8113 for (i = 0; i < 3; i++)
8115 if (ids[dest[i]][PAIR_INVALID] == 1)
8117 fetchPair (dest[i], AOP (pparams[i]));
8123 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8125 operand *from, *to, *count;
8127 wassertl (nParams == 3, "Built-in memcpy() must have three parameters");
8132 _saveRegsForCall (ic, 0);
8134 setupForMemcpy (ic, nParams, pparams);
8138 freeAsmop (count, NULL, ic->next->next);
8139 freeAsmop (from, NULL, ic);
8141 spillPair (PAIR_HL);
8143 _restoreRegsAfterCall();
8145 /* if we need assign a result value */
8146 if ((IS_ITEMP (IC_RESULT (ic)) &&
8147 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8148 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8149 IS_TRUE_SYMOP (IC_RESULT (ic)))
8151 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8152 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8153 freeAsmop (IC_RESULT (ic), NULL, ic);
8156 freeAsmop (to, NULL, ic->next);
8159 /*-----------------------------------------------------------------*/
8160 /* genBuiltIn - calls the appropriate function to generating code */
8161 /* for a built in function */
8162 /*-----------------------------------------------------------------*/
8163 static void genBuiltIn (iCode *ic)
8165 operand *bi_parms[MAX_BUILTIN_ARGS];
8170 /* get all the arguments for a built in function */
8171 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8173 /* which function is it */
8174 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8176 if (strcmp(bif->name,"__builtin_memcpy")==0)
8178 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8182 wassertl (0, "Unknown builtin function encountered");
8186 /*-----------------------------------------------------------------*/
8187 /* genZ80Code - generate code for Z80 based controllers */
8188 /*-----------------------------------------------------------------*/
8190 genZ80Code (iCode * lic)
8198 _fReturn = _gbz80_return;
8199 _fTmp = _gbz80_return;
8203 _fReturn = _z80_return;
8204 _fTmp = _z80_return;
8207 _G.lines.head = _G.lines.current = NULL;
8209 /* if debug information required */
8210 if (options.debug && currFunc)
8212 debugFile->writeFunction (currFunc, lic);
8215 for (ic = lic; ic; ic = ic->next)
8217 _G.current_iCode = ic;
8219 if (ic->lineno && cln != ic->lineno)
8223 debugFile->writeCLine (ic);
8225 if (!options.noCcodeInAsm)
8227 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8228 printCLine(ic->filename, ic->lineno));
8232 if (options.iCodeInAsm)
8234 const char *iLine = printILine(ic);
8235 emit2 (";ic:%d: %s", ic->key, iLine);
8238 /* if the result is marked as
8239 spilt and rematerializable or code for
8240 this has already been generated then
8242 if (resultRemat (ic) || ic->generated)
8245 /* depending on the operation */
8249 emitDebug ("; genNot");
8254 emitDebug ("; genCpl");
8259 emitDebug ("; genUminus");
8264 emitDebug ("; genIpush");
8269 /* IPOP happens only when trying to restore a
8270 spilt live range, if there is an ifx statement
8271 following this pop then the if statement might
8272 be using some of the registers being popped which
8273 would destroy the contents of the register so
8274 we need to check for this condition and handle it */
8276 ic->next->op == IFX &&
8277 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8279 emitDebug ("; genIfx");
8280 genIfx (ic->next, ic);
8284 emitDebug ("; genIpop");
8290 emitDebug ("; genCall");
8295 emitDebug ("; genPcall");
8300 emitDebug ("; genFunction");
8305 emitDebug ("; genEndFunction");
8306 genEndFunction (ic);
8310 emitDebug ("; genRet");
8315 emitDebug ("; genLabel");
8320 emitDebug ("; genGoto");
8325 emitDebug ("; genPlus");
8330 emitDebug ("; genMinus");
8335 emitDebug ("; genMult");
8340 emitDebug ("; genDiv");
8345 emitDebug ("; genMod");
8350 emitDebug ("; genCmpGt");
8351 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8355 emitDebug ("; genCmpLt");
8356 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8363 /* note these two are xlated by algebraic equivalence
8364 during parsing SDCC.y */
8365 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8366 "got '>=' or '<=' shouldn't have come here");
8370 emitDebug ("; genCmpEq");
8371 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8375 emitDebug ("; genAndOp");
8380 emitDebug ("; genOrOp");
8385 emitDebug ("; genXor");
8386 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8390 emitDebug ("; genOr");
8391 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8395 emitDebug ("; genAnd");
8396 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8400 emitDebug ("; genInline");
8405 emitDebug ("; genRRC");
8410 emitDebug ("; genRLC");
8415 emitDebug ("; genGetHBIT");
8420 emitDebug ("; genLeftShift");
8425 emitDebug ("; genRightShift");
8429 case GET_VALUE_AT_ADDRESS:
8430 emitDebug ("; genPointerGet");
8436 if (POINTER_SET (ic))
8438 emitDebug ("; genAssign (pointer)");
8443 emitDebug ("; genAssign");
8449 emitDebug ("; genIfx");
8454 emitDebug ("; genAddrOf");
8459 emitDebug ("; genJumpTab");
8464 emitDebug ("; genCast");
8469 emitDebug ("; genReceive");
8474 if (ic->builtinSEND)
8476 emitDebug ("; genBuiltIn");
8481 emitDebug ("; addSet");
8482 addSet (&_G.sendSet, ic);
8487 emitDebug ("; genArrayInit");
8491 case DUMMY_READ_VOLATILE:
8492 emitDebug ("; genDummyRead");
8497 emitDebug ("; genCritical");
8502 emitDebug ("; genEndCritical");
8503 genEndCritical (ic);
8512 /* now we are ready to call the
8513 peep hole optimizer */
8514 if (!options.nopeep)
8515 peepHole (&_G.lines.head);
8517 /* This is unfortunate */
8518 /* now do the actual printing */
8520 struct dbuf_s *buf = codeOutBuf;
8521 if (isInHome () && codeOutBuf == &code->oBuf)
8522 codeOutBuf = &home->oBuf;
8523 printLine (_G.lines.head, codeOutBuf);
8524 if (_G.flushStatics)
8527 _G.flushStatics = 0;
8532 freeTrace(&_G.lines.trace);
8533 freeTrace(&_G.trace.aops);
8539 _isPairUsed (iCode * ic, PAIR_ID pairId)
8545 if (bitVectBitValue (ic->rMask, D_IDX))
8547 if (bitVectBitValue (ic->rMask, E_IDX))
8557 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8560 value *val = aop->aopu.aop_lit;
8562 wassert (aop->type == AOP_LIT);
8563 wassert (!IS_FLOAT (val->type));
8565 v = ulFromVal (val);
8573 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8574 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));