1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
91 #include "SDCCglobl.h"
92 #include "SDCCpeeph.h"
97 /* This is the down and dirty file with all kinds of kludgy & hacky
98 stuff. This is what it is all about CODE GENERATION for a specific MCU.
99 Some of the routines may be reusable, will have to see */
101 /* Z80 calling convention description.
102 Parameters are passed right to left. As the stack grows downwards,
103 the parameters are arranged in left to right in memory.
104 Parameters may be passed in the HL and DE registers with one
106 PENDING: What if the parameter is a long?
107 Everything is caller saves. i.e. the caller must save any registers
108 that it wants to preserve over the call.
109 GB: The return value is returned in DEHL. DE is normally used as a
110 working register pair. Caller saves allows it to be used for a
112 va args functions do not use register parameters. All arguments
113 are passed on the stack.
114 IX is used as an index register to the top of the local variable
115 area. ix-0 is the top most local variable.
120 /* Set to enable debugging trace statements in the output assembly code. */
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129 { "c", "b", "e", "d" };
131 static char **_fReturn;
134 extern struct dbuf_s *codeOutBuf;
142 /** Enum covering all the possible register pairs.
161 } _pairs[NUM_PAIRS] = {
162 { "??1", "?2", "?3" },
167 { "iy", "iyl", "iyh" },
168 { "ix", "ixl", "ixh" }
172 #define ACC_NAME _pairs[PAIR_AF].h
182 /** Code generator persistent data.
186 /** Used to optimised setting up of a pair by remebering what it
187 contains and adjusting instead of reloading where possible.
216 const char *lastFunctionName;
217 iCode *current_iCode;
224 /** TRUE if the registers have already been saved. */
243 static const char *aopGet (asmop * aop, int offset, bool bit16);
245 static const char *aopNames[] = {
266 isLastUse (iCode *ic, operand *op)
268 bitVect *uses = bitVectCopy (OP_USES (op));
270 while (!bitVectIsZero (uses))
272 if (bitVectFirstBit (uses) == ic->key)
274 if (bitVectnBitsOn (uses) == 1)
283 bitVectUnSetBit (uses, bitVectFirstBit (uses));
303 _getTempPairName(void)
305 return _pairs[_getTempPairId()].name;
309 isPairInUse (PAIR_ID id, iCode *ic)
313 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
315 else if (id == PAIR_BC)
317 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
321 wassertl (0, "Only implemented for DE and BC");
327 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
331 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
335 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
339 wassertl (0, "Only implemented for DE");
345 getFreePairId (iCode *ic)
347 if (!isPairInUse (PAIR_BC, ic))
351 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
364 /* Clean up the line so that it is 'prettier' */
365 if (strchr (buf, ':'))
367 /* Is a label - cant do anything */
370 /* Change the first (and probably only) ' ' to a tab so
385 _newLineNode (const char *line)
389 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
390 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
396 _vemit2 (const char *szFormat, va_list ap)
401 dbuf_init(&dbuf, INITIAL_INLINEASM);
403 dbuf_tvprintf (&dbuf, szFormat, ap);
405 buffer = (char *)dbuf_c_str(&dbuf);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
413 _G.lines.current->isDebug = _G.lines.isDebug;
414 _G.lines.current->ic = _G.current_iCode;
415 _G.lines.current->isComment = (*buffer == ';');
421 emit2 (const char *szFormat,...)
425 va_start (ap, szFormat);
427 _vemit2 (szFormat, ap);
433 emitDebug (const char *szFormat,...)
435 if (!options.verboseAsm)
441 va_start (ap, szFormat);
443 _vemit2 (szFormat, ap);
449 /*-----------------------------------------------------------------*/
450 /* z80_emitDebuggerSymbol - associate the current code location */
451 /* with a debugger symbol */
452 /*-----------------------------------------------------------------*/
454 z80_emitDebuggerSymbol (char * debugSym)
456 _G.lines.isDebug = 1;
457 emit2 ("%s !equ .", debugSym);
458 emit2 ("!global", debugSym);
459 _G.lines.isDebug = 0;
462 /*-----------------------------------------------------------------*/
463 /* emit2 - writes the code into a file : for now it is simple */
464 /*-----------------------------------------------------------------*/
466 _emit2 (const char *inst, const char *fmt,...)
469 char lb[INITIAL_INLINEASM];
476 sprintf (lb, "%s\t", inst);
477 vsprintf (lb + (strlen (lb)), fmt, ap);
480 vsprintf (lb, fmt, ap);
482 while (isspace (*lbp))
487 _G.lines.current = (_G.lines.current ?
488 connectLine (_G.lines.current, _newLineNode (lb)) :
489 (_G.lines.head = _newLineNode (lb)));
491 _G.lines.current->isInline = _G.lines.isInline;
492 _G.lines.current->ic = _G.current_iCode;
497 _emitMove(const char *to, const char *from)
499 if (STRCASECMP(to, from) != 0)
501 emit2("ld %s,%s", to, from);
506 // Could leave this to the peephole, but sometimes the peephole is inhibited.
511 aopDump(const char *plabel, asmop *aop)
517 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
522 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
525 for (i=aop->size-1;i>=0;i--)
526 *rbp++ = *(aop->aopu.aop_reg[i]->name);
528 emitDebug("; reg = %s", regbuf);
531 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
534 /* No information. */
540 _moveA(const char *moveFrom)
542 // Let the peephole optimiser take care of redundent loads
543 _emitMove(ACC_NAME, moveFrom);
553 getPairName (asmop * aop)
555 if (aop->type == AOP_REG)
557 switch (aop->aopu.aop_reg[0]->rIdx)
570 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
573 for (i = 0; i < NUM_PAIRS; i++)
575 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
577 return _pairs[i].name;
581 wassertl (0, "Tried to get the pair name of something that isn't a pair");
586 getPairId (asmop * aop)
590 if (aop->type == AOP_REG)
592 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
596 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
600 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
605 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
608 for (i = 0; i < NUM_PAIRS; i++)
610 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
620 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
624 return (getPairId (aop) != PAIR_INVALID);
627 /** Returns TRUE if the registers used in aop cannot be split into high
630 isUnsplitable (asmop * aop)
632 switch (getPairId (aop))
644 isPtrPair (asmop * aop)
646 PAIR_ID pairId = getPairId (aop);
659 spillPair (PAIR_ID pairId)
661 _G.pairs[pairId].last_type = AOP_INVALID;
662 _G.pairs[pairId].base = NULL;
665 /* Given a register name, spill the pair (if any) the register is part of */
667 spillPairReg (const char *regname)
669 if (strlen(regname)==1)
689 /** Push a register pair onto the stack */
691 genPairPush (asmop * aop)
693 emit2 ("push %s", getPairName (aop));
697 _push (PAIR_ID pairId)
699 emit2 ("push %s", _pairs[pairId].name);
700 _G.stack.pushed += 2;
704 _pop (PAIR_ID pairId)
706 if (pairId != PAIR_INVALID)
708 emit2 ("pop %s", _pairs[pairId].name);
709 _G.stack.pushed -= 2;
715 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
728 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
735 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
736 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
739 wassertl (0, "Tried to move a nonphysical pair");
741 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
742 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
743 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
747 /*-----------------------------------------------------------------*/
748 /* newAsmop - creates a new asmOp */
749 /*-----------------------------------------------------------------*/
751 newAsmop (short type)
755 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
760 /*-----------------------------------------------------------------*/
761 /* aopForSym - for a true symbol */
762 /*-----------------------------------------------------------------*/
764 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
771 wassert (sym->etype);
773 space = SPEC_OCLS (sym->etype);
775 /* if already has one */
781 /* Assign depending on the storage class */
782 if (sym->onStack || sym->iaccess)
784 /* The pointer that is used depends on how big the offset is.
785 Normally everything is AOP_STK, but for offsets of < -128 or
786 > 127 on the Z80 an extended stack pointer is used.
788 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
790 emitDebug ("; AOP_EXSTK for %s", sym->rname);
791 sym->aop = aop = newAsmop (AOP_EXSTK);
795 emitDebug ("; AOP_STK for %s", sym->rname);
796 sym->aop = aop = newAsmop (AOP_STK);
799 aop->size = getSize (sym->type);
800 aop->aopu.aop_stk = sym->stack;
804 /* special case for a function */
805 if (IS_FUNC (sym->type))
807 sym->aop = aop = newAsmop (AOP_IMMD);
808 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
813 if( IN_REGSP( space ))
814 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
817 /* if it is in direct space */
820 sym->aop = aop = newAsmop (AOP_SFR);
821 aop->aopu.aop_dir = sym->rname;
822 aop->size = getSize (sym->type);
823 emitDebug ("; AOP_SFR for %s", sym->rname);
828 { /*.p.t.20030716 adding SFR support to the Z80 port */
829 aop = newAsmop (AOP_SFR);
831 aop->aopu.aop_dir = sym->rname;
832 aop->size = getSize( sym->type );
833 aop->paged = FUNC_REGBANK(sym->type);
834 aop->bcInUse = isPairInUse( PAIR_BC, ic );
835 aop->deInUse = isPairInUse( PAIR_DE, ic );
836 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
842 /* only remaining is far space */
843 /* in which case DPTR gets the address */
846 emitDebug ("; AOP_HL for %s", sym->rname);
847 sym->aop = aop = newAsmop (AOP_HL);
851 sym->aop = aop = newAsmop (AOP_IY);
853 aop->size = getSize (sym->type);
854 aop->aopu.aop_dir = sym->rname;
856 /* if it is in code space */
857 if (IN_CODESPACE (space))
863 /*-----------------------------------------------------------------*/
864 /* aopForRemat - rematerialzes an object */
865 /*-----------------------------------------------------------------*/
867 aopForRemat (symbol * sym)
870 iCode *ic = sym->rematiCode;
871 asmop *aop = newAsmop (AOP_IMMD);
875 /* if plus or minus print the right hand side */
876 if (ic->op == '+' || ic->op == '-')
878 /* PENDING: for re-target */
879 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
882 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
885 /* we reached the end */
886 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
890 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
894 /*-----------------------------------------------------------------*/
895 /* regsInCommon - two operands have some registers in common */
896 /*-----------------------------------------------------------------*/
898 regsInCommon (operand * op1, operand * op2)
903 /* if they have registers in common */
904 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
907 sym1 = OP_SYMBOL (op1);
908 sym2 = OP_SYMBOL (op2);
910 if (sym1->nRegs == 0 || sym2->nRegs == 0)
913 for (i = 0; i < sym1->nRegs; i++)
919 for (j = 0; j < sym2->nRegs; j++)
924 if (sym2->regs[j] == sym1->regs[i])
932 /*-----------------------------------------------------------------*/
933 /* operandsEqu - equivalent */
934 /*-----------------------------------------------------------------*/
936 operandsEqu (operand * op1, operand * op2)
940 /* if they not symbols */
941 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
944 sym1 = OP_SYMBOL (op1);
945 sym2 = OP_SYMBOL (op2);
947 /* if both are itemps & one is spilt
948 and the other is not then false */
949 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
950 sym1->isspilt != sym2->isspilt)
953 /* if they are the same */
957 if (sym1->rname[0] && sym2->rname[0]
958 && strcmp (sym1->rname, sym2->rname) == 0)
961 /* if left is a tmp & right is not */
962 if (IS_ITEMP (op1) &&
965 (sym1->usl.spillLoc == sym2))
968 if (IS_ITEMP (op2) &&
972 (sym2->usl.spillLoc == sym1))
978 /*-----------------------------------------------------------------*/
979 /* sameRegs - two asmops have the same registers */
980 /*-----------------------------------------------------------------*/
982 sameRegs (asmop * aop1, asmop * aop2)
986 if (aop1->type == AOP_SFR ||
987 aop2->type == AOP_SFR)
993 if (aop1->type != AOP_REG ||
994 aop2->type != AOP_REG)
997 if (aop1->size != aop2->size)
1000 for (i = 0; i < aop1->size; i++)
1001 if (aop1->aopu.aop_reg[i] !=
1002 aop2->aopu.aop_reg[i])
1008 /*-----------------------------------------------------------------*/
1009 /* aopOp - allocates an asmop for an operand : */
1010 /*-----------------------------------------------------------------*/
1012 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1021 /* if this a literal */
1022 if (IS_OP_LITERAL (op))
1024 op->aop = aop = newAsmop (AOP_LIT);
1025 aop->aopu.aop_lit = op->operand.valOperand;
1026 aop->size = getSize (operandType (op));
1030 /* if already has a asmop then continue */
1033 if (op->aop->type == AOP_SFR)
1035 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1036 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1041 /* if the underlying symbol has a aop */
1042 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1044 op->aop = OP_SYMBOL (op)->aop;
1045 if (op->aop->type == AOP_SFR)
1047 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1048 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1053 /* if this is a true symbol */
1054 if (IS_TRUE_SYMOP (op))
1056 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1060 /* this is a temporary : this has
1066 e) can be a return use only */
1068 sym = OP_SYMBOL (op);
1070 /* if the type is a conditional */
1071 if (sym->regType == REG_CND)
1073 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1078 /* if it is spilt then two situations
1080 b) has a spill location */
1081 if (sym->isspilt || sym->nRegs == 0)
1083 /* rematerialize it NOW */
1086 sym->aop = op->aop = aop =
1088 aop->size = getSize (sym->type);
1095 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1096 aop->size = getSize (sym->type);
1097 for (i = 0; i < 4; i++)
1098 aop->aopu.aop_str[i] = _fReturn[i];
1104 if (sym->accuse == ACCUSE_A)
1106 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1107 aop->size = getSize (sym->type);
1108 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1110 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1112 else if (sym->accuse == ACCUSE_SCRATCH)
1114 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1115 aop->size = getSize (sym->type);
1116 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1117 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1118 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1120 else if (sym->accuse == ACCUSE_IY)
1122 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1123 aop->size = getSize (sym->type);
1124 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1125 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1126 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1130 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1135 if (sym->usl.spillLoc)
1137 asmop *oldAsmOp = NULL;
1139 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1141 /* force a new aop if sizes differ */
1142 oldAsmOp = sym->usl.spillLoc->aop;
1143 sym->usl.spillLoc->aop = NULL;
1145 sym->aop = op->aop = aop =
1146 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1147 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1149 /* Don't reuse the new aop, go with the last one */
1150 sym->usl.spillLoc->aop = oldAsmOp;
1152 aop->size = getSize (sym->type);
1156 /* else must be a dummy iTemp */
1157 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1158 aop->size = getSize (sym->type);
1162 /* must be in a register */
1163 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1164 aop->size = sym->nRegs;
1165 for (i = 0; i < sym->nRegs; i++)
1166 aop->aopu.aop_reg[i] = sym->regs[i];
1169 /*-----------------------------------------------------------------*/
1170 /* freeAsmop - free up the asmop given to an operand */
1171 /*----------------------------------------------------------------*/
1173 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1190 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1192 _pop (aop->aopu.aop_pairId);
1195 if (getPairId (aop) == PAIR_HL)
1197 spillPair (PAIR_HL);
1201 /* all other cases just dealloc */
1207 OP_SYMBOL (op)->aop = NULL;
1208 /* if the symbol has a spill */
1210 SPIL_LOC (op)->aop = NULL;
1217 isLitWord (asmop * aop)
1219 /* if (aop->size != 2)
1232 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1234 /* depending on type */
1240 /* PENDING: for re-target */
1243 tsprintf (buffer, sizeof(buffer),
1244 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1246 else if (offset == 0)
1248 tsprintf (buffer, sizeof(buffer),
1249 "%s", aop->aopu.aop_immd);
1253 tsprintf (buffer, sizeof(buffer),
1254 "%s + %d", aop->aopu.aop_immd, offset);
1256 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1260 value *val = aop->aopu.aop_lit;
1261 /* if it is a float then it gets tricky */
1262 /* otherwise it is fairly simple */
1263 if (!IS_FLOAT (val->type))
1265 unsigned long v = ulFromVal (val);
1271 else if (offset == 0)
1277 wassertl(0, "Encountered an invalid offset while fetching a literal");
1281 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1283 tsprintf (buffer, sizeof(buffer), "!constword", v);
1285 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1296 /* it is type float */
1297 fl.f = (float) floatFromVal (val);
1299 #ifdef WORDS_BIGENDIAN
1300 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1302 i = fl.c[offset] | (fl.c[offset+1]<<8);
1305 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1307 tsprintf (buffer, sizeof(buffer), "!constword", i);
1309 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1318 aopGetWord (asmop * aop, int offset)
1320 return aopGetLitWordLong (aop, offset, TRUE);
1324 isPtr (const char *s)
1326 if (!strcmp (s, "hl"))
1328 if (!strcmp (s, "ix"))
1330 if (!strcmp (s, "iy"))
1336 adjustPair (const char *pair, int *pold, int new)
1342 emit2 ("inc %s", pair);
1347 emit2 ("dec %s", pair);
1355 spillPair (PAIR_HL);
1356 spillPair (PAIR_IY);
1360 requiresHL (asmop * aop)
1376 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1378 const char *l, *base;
1379 const char *pair = _pairs[pairId].name;
1380 l = aopGetLitWordLong (left, offset, FALSE);
1381 base = aopGetLitWordLong (left, 0, FALSE);
1382 wassert (l && pair && base);
1386 if (pairId == PAIR_HL || pairId == PAIR_IY)
1388 if (_G.pairs[pairId].last_type == left->type)
1390 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1392 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1394 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1397 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1404 _G.pairs[pairId].last_type = left->type;
1405 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1406 _G.pairs[pairId].offset = offset;
1408 /* Both a lit on the right and a true symbol on the left */
1409 emit2 ("ld %s,!hashedstr", pair, l);
1413 makeFreePairId (iCode *ic, bool *pisUsed)
1419 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1423 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1441 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1443 /* if this is remateriazable */
1444 if (isLitWord (aop)) {
1445 fetchLitPair (pairId, aop, offset);
1449 if (getPairId (aop) == pairId)
1453 /* we need to get it byte by byte */
1454 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1455 aopGet (aop, offset, FALSE);
1456 switch (aop->size - offset) {
1458 emit2 ("ld l,!*hl");
1459 emit2 ("ld h,!immedbyte", 0);
1462 // PENDING: Requires that you are only fetching two bytes.
1465 emit2 ("ld h,!*hl");
1469 wassertl (0, "Attempted to fetch too much data into HL");
1473 else if (IS_Z80 && aop->type == AOP_IY) {
1474 /* Instead of fetching relative to IY, just grab directly
1475 from the address IY refers to */
1476 char *l = aopGetLitWordLong (aop, offset, FALSE);
1478 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1480 if (aop->size < 2) {
1481 emit2("ld %s,!zero", _pairs[pairId].h);
1484 else if (pairId == PAIR_IY)
1488 emit2 ("push %s", _pairs[getPairId(aop)].name);
1494 PAIR_ID id = makeFreePairId (ic, &isUsed);
1497 /* Can't load into parts, so load into HL then exchange. */
1498 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1499 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1500 emit2 ("push %s", _pairs[id].name);
1506 else if (isUnsplitable(aop))
1508 emit2("push %s", _pairs[getPairId(aop)].name);
1509 emit2("pop %s", _pairs[pairId].name);
1513 /* Swapping register contents within register pair */
1514 if(!strcmp(aopGet (aop, offset, FALSE), _pairs[pairId].h))
1516 emit2 ("ld a,%s",aopGet (aop, offset + 1, FALSE));
1517 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1518 emit2 ("ld %s,a", _pairs[pairId].h);
1522 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1523 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1526 /* PENDING: check? */
1527 if (pairId == PAIR_HL)
1528 spillPair (PAIR_HL);
1533 fetchPair (PAIR_ID pairId, asmop * aop)
1535 fetchPairLong (pairId, aop, NULL, 0);
1539 fetchHL (asmop * aop)
1541 fetchPair (PAIR_HL, aop);
1545 setupPairFromSP (PAIR_ID id, int offset)
1547 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1549 if (_G.preserveCarry)
1555 if (offset < INT8MIN || offset > INT8MAX)
1557 emit2 ("ld hl,!immedword", offset);
1558 emit2 ("add hl,sp");
1562 emit2 ("!ldahlsp", offset);
1565 if (_G.preserveCarry)
1573 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1578 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1579 fetchLitPair (pairId, aop, 0);
1583 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1585 fetchLitPair (pairId, aop, offset);
1586 _G.pairs[pairId].offset = offset;
1590 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1591 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1594 int offset = aop->aopu.aop_stk + _G.stack.offset;
1596 if (_G.pairs[pairId].last_type == aop->type &&
1597 _G.pairs[pairId].offset == offset)
1603 /* PENDING: Do this better. */
1604 if (_G.preserveCarry)
1606 sprintf (buffer, "%d", offset + _G.stack.pushed);
1607 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1608 emit2 ("add %s,sp", _pairs[pairId].name);
1609 _G.pairs[pairId].last_type = aop->type;
1610 _G.pairs[pairId].offset = offset;
1611 if (_G.preserveCarry)
1619 /* Doesnt include _G.stack.pushed */
1620 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1622 if (aop->aopu.aop_stk > 0)
1624 abso += _G.stack.param_offset;
1626 assert (pairId == PAIR_HL);
1627 /* In some cases we can still inc or dec hl */
1628 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1630 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1634 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1636 _G.pairs[pairId].offset = abso;
1641 if (pairId != aop->aopu.aop_pairId)
1642 genMovePairPair(aop->aopu.aop_pairId, pairId);
1643 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1649 _G.pairs[pairId].last_type = aop->type;
1655 emit2 ("!tlabeldef", key);
1656 _G.lines.current->isLabel = 1;
1660 /*-----------------------------------------------------------------*/
1661 /* aopGet - for fetching value of the aop */
1662 /*-----------------------------------------------------------------*/
1664 aopGet (asmop * aop, int offset, bool bit16)
1666 // char *s = buffer;
1668 /* offset is greater than size then zero */
1669 /* PENDING: this seems a bit screwed in some pointer cases. */
1670 if (offset > (aop->size - 1) &&
1671 aop->type != AOP_LIT)
1673 tsprintf (buffer, sizeof(buffer), "!zero");
1674 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1677 /* depending on type */
1681 tsprintf (buffer, sizeof(buffer), "!zero");
1682 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1685 /* PENDING: re-target */
1687 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1692 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1695 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1698 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1701 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1704 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1708 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1709 SNPRINTF (buffer, sizeof(buffer), "a");
1711 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1717 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1718 SNPRINTF (buffer, sizeof(buffer), "a");
1720 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1723 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1726 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1727 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1728 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1730 else if( z80_opts.port_mode == 180 )
1731 { /* z180 in0/out0 mode */
1732 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1736 emit2( "in a,(%s)", aop->aopu.aop_dir );
1739 SNPRINTF (buffer, sizeof(buffer), "a");
1741 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1745 return aop->aopu.aop_reg[offset]->name;
1749 setupPair (PAIR_HL, aop, offset);
1750 tsprintf (buffer, sizeof(buffer), "!*hl");
1752 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1756 setupPair (PAIR_IY, aop, offset);
1757 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1759 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1763 setupPair (PAIR_IY, aop, offset);
1764 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1766 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1771 setupPair (PAIR_HL, aop, offset);
1772 tsprintf (buffer, sizeof(buffer), "!*hl");
1776 if (aop->aopu.aop_stk >= 0)
1777 offset += _G.stack.param_offset;
1778 tsprintf (buffer, sizeof(buffer),
1779 "!*ixx", aop->aopu.aop_stk + offset);
1782 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1785 wassertl (0, "Tried to fetch from a bit variable");
1794 tsprintf(buffer, sizeof(buffer), "!zero");
1795 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1799 wassert (offset < 2);
1800 return aop->aopu.aop_str[offset];
1803 return aopLiteral (aop->aopu.aop_lit, offset);
1807 unsigned long v = aop->aopu.aop_simplelit;
1810 tsprintf (buffer, sizeof(buffer),
1811 "!immedbyte", (unsigned int) v & 0xff);
1813 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1817 return aop->aopu.aop_str[offset];
1820 setupPair (aop->aopu.aop_pairId, aop, offset);
1821 if (aop->aopu.aop_pairId==PAIR_IX)
1822 tsprintf (buffer, sizeof(buffer), "!*ixx", offset);
1823 else if (aop->aopu.aop_pairId==PAIR_IY)
1824 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1826 SNPRINTF (buffer, sizeof(buffer),
1827 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1829 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1834 wassertl (0, "aopget got unsupported aop->type");
1839 isRegString (const char *s)
1841 if (!strcmp (s, "b") ||
1853 isConstant (const char *s)
1855 /* This is a bit of a hack... */
1856 return (*s == '#' || *s == '$');
1860 canAssignToPtr (const char *s)
1862 if (isRegString (s))
1869 /*-----------------------------------------------------------------*/
1870 /* aopPut - puts a string for a aop */
1871 /*-----------------------------------------------------------------*/
1873 aopPut (asmop * aop, const char *s, int offset)
1877 if (aop->size && offset > (aop->size - 1))
1879 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1880 "aopPut got offset > aop->size");
1885 tsprintf(buffer2, sizeof(buffer2), s);
1888 /* will assign value to value */
1889 /* depending on where it is ofcourse */
1893 _moveA (s); /* in case s is volatile */
1899 if (strcmp (s, "a"))
1900 emit2 ("ld a,%s", s);
1901 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1908 if (strcmp (s, "a"))
1909 emit2 ("ld a,%s", s);
1910 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1913 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1920 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1921 && s[0] != 'h' && s[0] != 'l'))
1923 emit2( "ld a,%s", s );
1927 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1928 emit2( "out (c),%s", s );
1933 spillPair (PAIR_BC);
1935 else if( z80_opts.port_mode == 180 )
1936 { /* z180 in0/out0 mode */
1937 emit2( "ld a,%s", s );
1938 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1942 emit2( "ld a,%s", s );
1943 emit2( "out (%s),a", aop->aopu.aop_dir );
1949 if (!strcmp (s, "!*hl"))
1950 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1953 aop->aopu.aop_reg[offset]->name, s);
1954 spillPairReg(aop->aopu.aop_reg[offset]->name);
1959 if (!canAssignToPtr (s))
1961 emit2 ("ld a,%s", s);
1962 setupPair (PAIR_IY, aop, offset);
1963 emit2 ("ld !*iyx,a", offset);
1967 setupPair (PAIR_IY, aop, offset);
1968 emit2 ("ld !*iyx,%s", offset, s);
1974 /* PENDING: for re-target */
1975 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1977 emit2 ("ld a,!*hl");
1980 setupPair (PAIR_HL, aop, offset);
1982 emit2 ("ld !*hl,%s", s);
1987 if (!canAssignToPtr (s))
1989 emit2 ("ld a,%s", s);
1990 setupPair (PAIR_IY, aop, offset);
1991 emit2 ("ld !*iyx,a", offset);
1995 setupPair (PAIR_IY, aop, offset);
1996 emit2 ("ld !*iyx,%s", offset, s);
2003 /* PENDING: re-target */
2004 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2006 emit2 ("ld a,!*hl");
2009 setupPair (PAIR_HL, aop, offset);
2010 if (!canAssignToPtr (s))
2012 emit2 ("ld a,%s", s);
2013 emit2 ("ld !*hl,a");
2016 emit2 ("ld !*hl,%s", s);
2020 if (aop->aopu.aop_stk >= 0)
2021 offset += _G.stack.param_offset;
2022 if (!canAssignToPtr (s))
2024 emit2 ("ld a,%s", s);
2025 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2029 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2035 /* if bit variable */
2036 if (!aop->aopu.aop_dir)
2038 emit2 ("ld a,!zero");
2043 /* In bit space but not in C - cant happen */
2044 wassertl (0, "Tried to write into a bit variable");
2050 if (strcmp (aop->aopu.aop_str[offset], s))
2052 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2054 spillPairReg(aop->aopu.aop_str[offset]);
2059 if (!offset && (strcmp (s, "acc") == 0))
2063 wassertl (0, "Tried to access past the end of A");
2067 if (strcmp (aop->aopu.aop_str[offset], s))
2069 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2070 spillPairReg(aop->aopu.aop_str[offset]);
2076 wassert (offset < 2);
2077 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2078 spillPairReg(aop->aopu.aop_str[offset]);
2082 setupPair (aop->aopu.aop_pairId, aop, offset);
2083 if (aop->aopu.aop_pairId==PAIR_IX)
2084 emit2 ("ld !*ixx,%s", 0, s);
2085 else if (aop->aopu.aop_pairId==PAIR_IY)
2086 emit2 ("ld !*iyx,%s", 0, s);
2088 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2092 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2093 "aopPut got unsupported aop->type");
2098 #define AOP(op) op->aop
2099 #define AOP_TYPE(op) AOP(op)->type
2100 #define AOP_SIZE(op) AOP(op)->size
2101 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2102 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2105 commitPair (asmop * aop, PAIR_ID id)
2107 /* PENDING: Verify this. */
2108 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2112 aopPut (aop, "a", 0);
2113 aopPut (aop, "d", 1);
2118 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2120 char *l = aopGetLitWordLong (aop, 0, FALSE);
2123 emit2 ("ld (%s),%s", l, _pairs[id].name);
2127 aopPut (aop, _pairs[id].l, 0);
2128 aopPut (aop, _pairs[id].h, 1);
2133 /*-----------------------------------------------------------------*/
2134 /* getDataSize - get the operand data size */
2135 /*-----------------------------------------------------------------*/
2137 getDataSize (operand * op)
2140 size = AOP_SIZE (op);
2144 wassertl (0, "Somehow got a three byte data pointer");
2149 /*-----------------------------------------------------------------*/
2150 /* movLeft2Result - move byte from left to result */
2151 /*-----------------------------------------------------------------*/
2153 movLeft2Result (operand * left, int offl,
2154 operand * result, int offr, int sign)
2158 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2160 l = aopGet (AOP (left), offl, FALSE);
2164 aopPut (AOP (result), l, offr);
2168 if (getDataSize (left) == offl + 1)
2170 emit2 ("ld a,%s", l);
2171 aopPut (AOP (result), "a", offr);
2178 movLeft2ResultLong (operand * left, int offl,
2179 operand * result, int offr, int sign,
2184 movLeft2Result (left, offl, result, offr, sign);
2188 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2189 wassertl (size == 2, "Only implemented for two bytes or one");
2191 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2193 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2194 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2196 spillPair (PAIR_HL);
2198 else if ( getPairId ( AOP (result)) == PAIR_IY)
2200 PAIR_ID id = getPairId (AOP (left));
2201 if (id != PAIR_INVALID)
2203 emit2("push %s", _pairs[id].name);
2214 movLeft2Result (left, offl, result, offr, sign);
2215 movLeft2Result (left, offl+1, result, offr+1, sign);
2220 /** Put Acc into a register set
2223 outAcc (operand * result)
2226 size = getDataSize (result);
2229 aopPut (AOP (result), "a", 0);
2232 /* unsigned or positive */
2235 aopPut (AOP (result), "!zero", offset++);
2240 /** Take the value in carry and put it into a register
2243 outBitC (operand * result)
2245 /* if the result is bit */
2246 if (AOP_TYPE (result) == AOP_CRY)
2248 if (!IS_OP_RUONLY (result))
2249 aopPut (AOP (result), "c", 0);
2253 emit2 ("ld a,!zero");
2259 /*-----------------------------------------------------------------*/
2260 /* toBoolean - emit code for orl a,operator(sizeop) */
2261 /*-----------------------------------------------------------------*/
2263 _toBoolean (operand * oper)
2265 int size = AOP_SIZE (oper);
2269 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2272 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2276 if (AOP (oper)->type != AOP_ACC)
2279 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2285 /*-----------------------------------------------------------------*/
2286 /* genNot - generate code for ! operation */
2287 /*-----------------------------------------------------------------*/
2292 /* assign asmOps to operand & result */
2293 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2294 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2296 /* if in bit space then a special case */
2297 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2299 wassertl (0, "Tried to negate a bit");
2302 _toBoolean (IC_LEFT (ic));
2307 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2308 emit2 ("sub a,!one");
2309 outBitC (IC_RESULT (ic));
2311 /* release the aops */
2312 freeAsmop (IC_LEFT (ic), NULL, ic);
2313 freeAsmop (IC_RESULT (ic), NULL, ic);
2316 /*-----------------------------------------------------------------*/
2317 /* genCpl - generate code for complement */
2318 /*-----------------------------------------------------------------*/
2326 /* assign asmOps to operand & result */
2327 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2328 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2330 /* if both are in bit space then
2332 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2333 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2335 wassertl (0, "Left and the result are in bit space");
2338 size = AOP_SIZE (IC_RESULT (ic));
2341 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2344 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2347 /* release the aops */
2348 freeAsmop (IC_LEFT (ic), NULL, ic);
2349 freeAsmop (IC_RESULT (ic), NULL, ic);
2353 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2360 store de into result
2365 store de into result
2367 const char *first = isAdd ? "add" : "sub";
2368 const char *later = isAdd ? "adc" : "sbc";
2370 wassertl (IS_GB, "Code is only relevent to the gbz80");
2371 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2373 fetchPair (PAIR_DE, left);
2376 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2379 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2382 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2383 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2385 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2386 aopGet (right, MSB24, FALSE);
2390 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2393 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2395 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2396 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2400 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2402 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2405 /*-----------------------------------------------------------------*/
2406 /* genUminusFloat - unary minus for floating points */
2407 /*-----------------------------------------------------------------*/
2409 genUminusFloat (operand * op, operand * result)
2411 int size, offset = 0;
2413 emitDebug("; genUminusFloat");
2415 /* for this we just need to flip the
2416 first bit then copy the rest in place */
2417 size = AOP_SIZE (op) - 1;
2419 _moveA(aopGet (AOP (op), MSB32, FALSE));
2421 emit2("xor a,!immedbyte", 0x80);
2422 aopPut (AOP (result), "a", MSB32);
2426 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2431 /*-----------------------------------------------------------------*/
2432 /* genUminus - unary minus code generation */
2433 /*-----------------------------------------------------------------*/
2435 genUminus (iCode * ic)
2438 sym_link *optype, *rtype;
2441 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2442 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2444 /* if both in bit space then special
2446 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2447 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2449 wassertl (0, "Left and right are in bit space");
2453 optype = operandType (IC_LEFT (ic));
2454 rtype = operandType (IC_RESULT (ic));
2456 /* if float then do float stuff */
2457 if (IS_FLOAT (optype))
2459 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2463 /* otherwise subtract from zero */
2464 size = AOP_SIZE (IC_LEFT (ic));
2466 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2468 /* Create a new asmop with value zero */
2469 asmop *azero = newAsmop (AOP_SIMPLELIT);
2470 azero->aopu.aop_simplelit = 0;
2472 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2480 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2481 emit2 ("ld a,!zero");
2482 emit2 ("sbc a,%s", l);
2483 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2486 /* if any remaining bytes in the result */
2487 /* we just need to propagate the sign */
2488 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2493 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2497 /* release the aops */
2498 freeAsmop (IC_LEFT (ic), NULL, ic);
2499 freeAsmop (IC_RESULT (ic), NULL, ic);
2502 /*-----------------------------------------------------------------*/
2503 /* assignResultValue - */
2504 /*-----------------------------------------------------------------*/
2506 assignResultValue (operand * oper)
2508 int size = AOP_SIZE (oper);
2511 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2512 topInA = requiresHL (AOP (oper));
2514 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2516 /* We do it the hard way here. */
2518 aopPut (AOP (oper), _fReturn[0], 0);
2519 aopPut (AOP (oper), _fReturn[1], 1);
2521 aopPut (AOP (oper), _fReturn[0], 2);
2522 aopPut (AOP (oper), _fReturn[1], 3);
2526 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2527 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2530 _emitMove ("a", _fReturn[size-1]);
2531 _emitMove (_fReturn[size-1], _fReturn[size]);
2532 _emitMove (_fReturn[size], "a");
2533 aopPut (AOP (oper), _fReturn[size], size-1);
2538 aopPut (AOP (oper), _fReturn[size], size);
2543 /** Simple restore that doesn't take into account what is used in the
2547 _restoreRegsAfterCall(void)
2549 if (_G.stack.pushedDE)
2552 _G.stack.pushedDE = FALSE;
2554 if (_G.stack.pushedBC)
2557 _G.stack.pushedBC = FALSE;
2559 _G.saves.saved = FALSE;
2563 _saveRegsForCall(iCode *ic, int sendSetSize)
2566 o Stack parameters are pushed before this function enters
2567 o DE and BC may be used in this function.
2568 o HL and DE may be used to return the result.
2569 o HL and DE may be used to send variables.
2570 o DE and BC may be used to store the result value.
2571 o HL may be used in computing the sent value of DE
2572 o The iPushes for other parameters occur before any addSets
2574 Logic: (to be run inside the first iPush or if none, before sending)
2575 o Compute if DE and/or BC are in use over the call
2576 o Compute if DE is used in the send set
2577 o Compute if DE and/or BC are used to hold the result value
2578 o If (DE is used, or in the send set) and is not used in the result, push.
2579 o If BC is used and is not in the result, push
2581 o If DE is used in the send set, fetch
2582 o If HL is used in the send set, fetch
2586 if (_G.saves.saved == FALSE) {
2587 bool deInUse, bcInUse;
2589 bool bcInRet = FALSE, deInRet = FALSE;
2592 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2593 z80_rUmaskForOp (IC_RESULT(ic)));
2595 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2596 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2598 deSending = (sendSetSize > 1);
2600 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2602 if (bcInUse && bcInRet == FALSE) {
2604 _G.stack.pushedBC = TRUE;
2606 if (deInUse && deInRet == FALSE) {
2608 _G.stack.pushedDE = TRUE;
2611 _G.saves.saved = TRUE;
2614 /* Already saved. */
2618 /*-----------------------------------------------------------------*/
2619 /* genIpush - genrate code for pushing this gets a little complex */
2620 /*-----------------------------------------------------------------*/
2622 genIpush (iCode * ic)
2624 int size, offset = 0;
2627 /* if this is not a parm push : ie. it is spill push
2628 and spill push is always done on the local stack */
2631 wassertl(0, "Encountered an unsupported spill push.");
2635 if (_G.saves.saved == FALSE) {
2636 /* Caller saves, and this is the first iPush. */
2637 /* Scan ahead until we find the function that we are pushing parameters to.
2638 Count the number of addSets on the way to figure out what registers
2639 are used in the send set.
2642 iCode *walk = ic->next;
2645 if (walk->op == SEND) {
2648 else if (walk->op == CALL || walk->op == PCALL) {
2657 _saveRegsForCall(walk, nAddSets);
2660 /* Already saved by another iPush. */
2663 /* then do the push */
2664 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2666 size = AOP_SIZE (IC_LEFT (ic));
2668 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2670 _G.stack.pushed += 2;
2671 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2677 fetchHL (AOP (IC_LEFT (ic)));
2679 spillPair (PAIR_HL);
2680 _G.stack.pushed += 2;
2685 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2687 spillPair (PAIR_HL);
2688 _G.stack.pushed += 2;
2689 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2691 spillPair (PAIR_HL);
2692 _G.stack.pushed += 2;
2698 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2700 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2702 emit2 ("ld a,(%s)", l);
2707 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2708 if (!strcmp(l, "b"))
2710 else if (!strcmp(l, "d"))
2712 else if (!strcmp(l, "h"))
2716 emit2 ("ld a,%s", l);
2725 freeAsmop (IC_LEFT (ic), NULL, ic);
2728 /*-----------------------------------------------------------------*/
2729 /* genIpop - recover the registers: can happen only for spilling */
2730 /*-----------------------------------------------------------------*/
2732 genIpop (iCode * ic)
2737 /* if the temp was not pushed then */
2738 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2741 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2742 size = AOP_SIZE (IC_LEFT (ic));
2743 offset = (size - 1);
2744 if (isPair (AOP (IC_LEFT (ic))))
2746 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2754 spillPair (PAIR_HL);
2755 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2759 freeAsmop (IC_LEFT (ic), NULL, ic);
2762 /* This is quite unfortunate */
2764 setArea (int inHome)
2767 static int lastArea = 0;
2769 if (_G.in_home != inHome) {
2771 const char *sz = port->mem.code_name;
2772 port->mem.code_name = "HOME";
2773 emit2("!area", CODE_NAME);
2774 port->mem.code_name = sz;
2777 emit2("!area", CODE_NAME); */
2778 _G.in_home = inHome;
2789 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2793 symbol *sym = OP_SYMBOL (op);
2795 if (sym->isspilt || sym->nRegs == 0)
2798 aopOp (op, ic, FALSE, FALSE);
2801 if (aop->type == AOP_REG)
2804 for (i = 0; i < aop->size; i++)
2806 if (pairId == PAIR_DE)
2808 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2809 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2811 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2814 else if (pairId == PAIR_BC)
2816 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2817 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2819 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2829 freeAsmop (IC_LEFT (ic), NULL, ic);
2833 /** Emit the code for a call statement
2836 emitCall (iCode * ic, bool ispcall)
2838 bool bInRet, cInRet, dInRet, eInRet;
2839 sym_link *dtype = operandType (IC_LEFT (ic));
2841 /* if caller saves & we have not saved then */
2847 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2849 /* if send set is not empty then assign */
2854 int nSend = elementsInSet(_G.sendSet);
2855 bool swapped = FALSE;
2857 int _z80_sendOrder[] = {
2862 /* Check if the parameters are swapped. If so route through hl instead. */
2863 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2865 sic = setFirstItem(_G.sendSet);
2866 sic = setNextItem(_G.sendSet);
2868 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2869 /* The second send value is loaded from one the one that holds the first
2870 send, i.e. it is overwritten. */
2871 /* Cache the first in HL, and load the second from HL instead. */
2872 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2873 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2879 for (sic = setFirstItem (_G.sendSet); sic;
2880 sic = setNextItem (_G.sendSet))
2883 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2885 size = AOP_SIZE (IC_LEFT (sic));
2886 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2887 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2889 // PENDING: Mild hack
2890 if (swapped == TRUE && send == 1) {
2892 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2895 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2897 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2900 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2904 freeAsmop (IC_LEFT (sic), NULL, sic);
2911 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2913 werror (W_INDIR_BANKED);
2915 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2917 if (isLitWord (AOP (IC_LEFT (ic))))
2919 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2923 symbol *rlbl = newiTempLabel (NULL);
2924 spillPair (PAIR_HL);
2925 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2927 _G.stack.pushed += 2;
2929 fetchHL (AOP (IC_LEFT (ic)));
2931 emit2 ("!tlabeldef", (rlbl->key + 100));
2932 _G.lines.current->isLabel = 1;
2933 _G.stack.pushed -= 2;
2935 freeAsmop (IC_LEFT (ic), NULL, ic);
2939 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2940 OP_SYMBOL (IC_LEFT (ic))->rname :
2941 OP_SYMBOL (IC_LEFT (ic))->name;
2942 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2944 emit2 ("call banked_call");
2945 emit2 ("!dws", name);
2946 emit2 ("!dw !bankimmeds", name);
2951 emit2 ("call %s", name);
2956 /* Mark the registers as restored. */
2957 _G.saves.saved = FALSE;
2959 /* adjust the stack for parameters if required */
2962 int i = ic->parmBytes;
2964 _G.stack.pushed -= i;
2967 emit2 ("!ldaspsp", i);
2974 emit2 ("ld iy,!immedword", i);
2975 emit2 ("add iy,sp");
2993 /* if we need assign a result value */
2994 if ((IS_ITEMP (IC_RESULT (ic)) &&
2995 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2996 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2997 IS_TRUE_SYMOP (IC_RESULT (ic)))
2999 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3001 assignResultValue (IC_RESULT (ic));
3003 freeAsmop (IC_RESULT (ic), NULL, ic);
3009 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3010 bInRet = bitVectBitValue(result, B_IDX);
3011 cInRet = bitVectBitValue(result, C_IDX);
3012 dInRet = bitVectBitValue(result, D_IDX);
3013 eInRet = bitVectBitValue(result, E_IDX);
3023 if (_G.stack.pushedDE)
3025 if (dInRet && eInRet)
3027 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3031 /* Only restore E */
3038 /* Only restore D */
3046 _G.stack.pushedDE = FALSE;
3049 if (_G.stack.pushedBC)
3051 if (bInRet && cInRet)
3053 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3057 /* Only restore C */
3064 /* Only restore B */
3072 _G.stack.pushedBC = FALSE;
3076 /*-----------------------------------------------------------------*/
3077 /* genCall - generates a call statement */
3078 /*-----------------------------------------------------------------*/
3080 genCall (iCode * ic)
3082 emitCall (ic, FALSE);
3085 /*-----------------------------------------------------------------*/
3086 /* genPcall - generates a call by pointer statement */
3087 /*-----------------------------------------------------------------*/
3089 genPcall (iCode * ic)
3091 emitCall (ic, TRUE);
3094 /*-----------------------------------------------------------------*/
3095 /* resultRemat - result is rematerializable */
3096 /*-----------------------------------------------------------------*/
3098 resultRemat (iCode * ic)
3100 if (SKIP_IC (ic) || ic->op == IFX)
3103 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3105 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3106 if (sym->remat && !POINTER_SET (ic))
3113 extern set *publics;
3115 /*-----------------------------------------------------------------*/
3116 /* genFunction - generated code for function entry */
3117 /*-----------------------------------------------------------------*/
3119 genFunction (iCode * ic)
3123 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3126 bool bcInUse = FALSE;
3127 bool deInUse = FALSE;
3129 setArea (IFFUNC_NONBANKED (sym->type));
3131 /* PENDING: Reset the receive offset as it
3132 doesn't seem to get reset anywhere else.
3134 _G.receiveOffset = 0;
3136 /* Record the last function name for debugging. */
3137 _G.lastFunctionName = sym->rname;
3139 /* Create the function header */
3140 emit2 ("!functionheader", sym->name);
3141 if (!IS_STATIC(sym->etype))
3143 sprintf (buffer, "%s_start", sym->rname);
3144 emit2 ("!labeldef", buffer);
3145 _G.lines.current->isLabel = 1;
3147 emit2 ("!functionlabeldef", sym->rname);
3148 _G.lines.current->isLabel = 1;
3150 ftype = operandType (IC_LEFT (ic));
3152 if (IFFUNC_ISNAKED(ftype))
3154 emitDebug("; naked function: no prologue.");
3158 /* if this is an interrupt service routine
3159 then save all potentially used registers. */
3160 if (IFFUNC_ISISR (sym->type))
3162 /* If critical function then turn interrupts off */
3163 /* except when no interrupt number is given then it implies the NMI handler */
3164 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3173 /* This is a non-ISR function.
3174 If critical function then turn interrupts off */
3175 if (IFFUNC_ISCRITICAL (sym->type))
3183 //get interrupt enable flag IFF2 into P/O
3192 if (options.profile)
3194 emit2 ("!profileenter");
3197 /* PENDING: callee-save etc */
3199 _G.stack.param_offset = 0;
3201 if (z80_opts.calleeSavesBC)
3206 /* Detect which registers are used. */
3207 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3210 for (i = 0; i < sym->regsUsed->size; i++)
3212 if (bitVectBitValue (sym->regsUsed, i))
3226 /* Other systems use DE as a temporary. */
3237 _G.stack.param_offset += 2;
3240 _G.calleeSaves.pushedBC = bcInUse;
3245 _G.stack.param_offset += 2;
3248 _G.calleeSaves.pushedDE = deInUse;
3250 /* adjust the stack for the function */
3251 _G.stack.last = sym->stack;
3254 for (sym = setFirstItem (istack->syms); sym;
3255 sym = setNextItem (istack->syms))
3257 if (sym->_isparm && !IS_REGPARM (sym->etype))
3263 sym = OP_SYMBOL (IC_LEFT (ic));
3265 _G.omitFramePtr = options.ommitFramePtr;
3266 if (IS_Z80 && !stackParm && !sym->stack)
3268 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3269 /* the above !sym->stack condition can be removed. -- EEP */
3271 emit2 ("!ldaspsp", -sym->stack);
3272 _G.omitFramePtr = TRUE;
3274 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3275 emit2 ("!enterxl", sym->stack);
3276 else if (sym->stack)
3278 if ((optimize.codeSize && sym->stack <= 8) || sym->stack <= 4)
3280 int stack = sym->stack;
3291 emit2 ("!enterx", sym->stack);
3296 _G.stack.offset = sym->stack;
3299 /*-----------------------------------------------------------------*/
3300 /* genEndFunction - generates epilogue for functions */
3301 /*-----------------------------------------------------------------*/
3303 genEndFunction (iCode * ic)
3305 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3307 if (IFFUNC_ISNAKED(sym->type))
3309 emitDebug("; naked function: no epilogue.");
3313 /* PENDING: calleeSave */
3314 if (IS_Z80 && _G.omitFramePtr)
3316 if (_G.stack.offset)
3317 emit2 ("!ldaspsp", _G.stack.offset);
3319 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3321 emit2 ("!leavexl", _G.stack.offset);
3323 else if (_G.stack.offset)
3325 emit2 ("!leavex", _G.stack.offset);
3332 if (_G.calleeSaves.pushedDE)
3335 _G.calleeSaves.pushedDE = FALSE;
3338 if (_G.calleeSaves.pushedBC)
3341 _G.calleeSaves.pushedBC = FALSE;
3344 if (options.profile)
3346 emit2 ("!profileexit");
3349 /* if this is an interrupt service routine
3350 then save all potentially used registers. */
3351 if (IFFUNC_ISISR (sym->type))
3355 /* If critical function then turn interrupts back on */
3356 /* except when no interrupt number is given then it implies the NMI handler */
3357 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3364 /* This is a non-ISR function.
3365 If critical function then turn interrupts back on */
3366 if (IFFUNC_ISCRITICAL (sym->type))
3374 symbol *tlbl = newiTempLabel (NULL);
3377 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3378 //don't enable interrupts as they were off before
3379 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3381 emit2 ("!tlabeldef", (tlbl->key + 100));
3382 _G.lines.current->isLabel = 1;
3387 if (options.debug && currFunc)
3389 debugFile->writeEndFunction (currFunc, ic, 1);
3392 if (IFFUNC_ISISR (sym->type))
3394 /* "critical interrupt" is used to imply NMI handler */
3395 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3402 /* Both banked and non-banked just ret */
3406 if (!IS_STATIC(sym->etype))
3408 sprintf (buffer, "%s_end", sym->rname);
3409 emit2 ("!labeldef", buffer);
3410 _G.lines.current->isLabel = 1;
3413 _G.flushStatics = 1;
3414 _G.stack.pushed = 0;
3415 _G.stack.offset = 0;
3418 /*-----------------------------------------------------------------*/
3419 /* genRet - generate code for return statement */
3420 /*-----------------------------------------------------------------*/
3425 /* Errk. This is a hack until I can figure out how
3426 to cause dehl to spill on a call */
3427 int size, offset = 0;
3429 /* if we have no return value then
3430 just generate the "ret" */
3434 /* we have something to return then
3435 move the return value into place */
3436 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3437 size = AOP_SIZE (IC_LEFT (ic));
3439 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3442 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3446 emit2 ("ld de,%s", l);
3450 emit2 ("ld hl,%s", l);
3456 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3460 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3462 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3463 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3469 l = aopGet (AOP (IC_LEFT (ic)), offset,
3471 if (strcmp (_fReturn[offset], l))
3472 emit2 ("ld %s,%s", _fReturn[offset], l);
3477 freeAsmop (IC_LEFT (ic), NULL, ic);
3480 /* generate a jump to the return label
3481 if the next is not the return statement */
3482 if (!(ic->next && ic->next->op == LABEL &&
3483 IC_LABEL (ic->next) == returnLabel))
3485 emit2 ("jp !tlabel", returnLabel->key + 100);
3488 /*-----------------------------------------------------------------*/
3489 /* genLabel - generates a label */
3490 /*-----------------------------------------------------------------*/
3492 genLabel (iCode * ic)
3494 /* special case never generate */
3495 if (IC_LABEL (ic) == entryLabel)
3498 emitLabel (IC_LABEL (ic)->key + 100);
3501 /*-----------------------------------------------------------------*/
3502 /* genGoto - generates a ljmp */
3503 /*-----------------------------------------------------------------*/
3505 genGoto (iCode * ic)
3507 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3510 /*-----------------------------------------------------------------*/
3511 /* genPlusIncr :- does addition with increment if possible */
3512 /*-----------------------------------------------------------------*/
3514 genPlusIncr (iCode * ic)
3516 unsigned int icount;
3517 unsigned int size = getDataSize (IC_RESULT (ic));
3518 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3520 /* will try to generate an increment */
3521 /* if the right side is not a literal
3523 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3526 emitDebug ("; genPlusIncr");
3528 icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3530 /* If result is a pair */
3531 if (resultId != PAIR_INVALID)
3533 if (isLitWord (AOP (IC_LEFT (ic))))
3535 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3538 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3540 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3542 PAIR_ID freep = getFreePairId (ic);
3543 if (freep != PAIR_INVALID)
3545 fetchPair (freep, AOP (IC_RIGHT (ic)));
3546 emit2 ("add hl,%s", _pairs[freep].name);
3552 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3553 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3560 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3564 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3568 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3573 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3575 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3576 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3580 /* if the literal value of the right hand side
3581 is greater than 4 then it is not worth it */
3585 /* if increment 16 bits in register */
3586 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3592 symbol *tlbl = NULL;
3593 tlbl = newiTempLabel (NULL);
3596 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3599 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3602 emitLabel (tlbl->key + 100);
3606 /* if the sizes are greater than 1 then we cannot */
3607 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3608 AOP_SIZE (IC_LEFT (ic)) > 1)
3611 /* If the result is in a register then we can load then increment.
3613 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3615 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3618 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3623 /* we can if the aops of the left & result match or
3624 if they are in registers and the registers are the
3626 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3630 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3638 /*-----------------------------------------------------------------*/
3639 /* outBitAcc - output a bit in acc */
3640 /*-----------------------------------------------------------------*/
3642 outBitAcc (operand * result)
3644 symbol *tlbl = newiTempLabel (NULL);
3645 /* if the result is a bit */
3646 if (AOP_TYPE (result) == AOP_CRY)
3648 wassertl (0, "Tried to write A into a bit");
3652 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3653 emit2 ("ld a,!one");
3654 emitLabel (tlbl->key + 100);
3660 couldDestroyCarry (asmop *aop)
3664 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3673 shiftIntoPair (int idx, asmop *aop)
3675 PAIR_ID id = PAIR_INVALID;
3677 wassertl (IS_Z80, "Only implemented for the Z80");
3678 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3680 emitDebug ("; Shift into pair idx %u", idx);
3686 setupPair (PAIR_HL, aop, 0);
3691 setupPair (PAIR_IY, aop, 0);
3693 emit2 ("pop %s", _pairs[id].name);
3697 setupPair (PAIR_IY, aop, 0);
3700 wassertl (0, "Internal error - hit default case");
3703 aop->type = AOP_PAIRPTR;
3704 aop->aopu.aop_pairId = id;
3705 _G.pairs[id].offset = 0;
3706 _G.pairs[id].last_type = aop->type;
3710 setupToPreserveCarry (iCode * ic)
3712 asmop *left = AOP (IC_LEFT (ic));
3713 asmop *right = AOP (IC_RIGHT (ic));
3714 asmop *result = AOP (IC_RESULT (ic));
3716 wassert (left && right);
3720 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3722 shiftIntoPair (0, right);
3723 /* check result again, in case right == result */
3724 if (couldDestroyCarry (result))
3726 if (!isPairInUse (PAIR_DE, ic))
3727 shiftIntoPair (1, result);
3729 shiftIntoPair (2, result);
3732 else if (couldDestroyCarry (right))
3734 if (getPairId (result) == PAIR_HL)
3735 _G.preserveCarry = TRUE;
3737 shiftIntoPair (0, right);
3739 else if (couldDestroyCarry (result))
3741 shiftIntoPair (0, result);
3750 /*-----------------------------------------------------------------*/
3751 /* genPlus - generates code for addition */
3752 /*-----------------------------------------------------------------*/
3754 genPlus (iCode * ic)
3756 int size, offset = 0;
3758 /* special cases :- */
3760 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3761 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3762 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3764 /* Swap the left and right operands if:
3766 if literal, literal on the right or
3767 if left requires ACC or right is already
3770 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3771 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3772 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3774 operand *t = IC_RIGHT (ic);
3775 IC_RIGHT (ic) = IC_LEFT (ic);
3779 /* if both left & right are in bit
3781 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3782 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3785 wassertl (0, "Tried to add two bits");
3788 /* if left in bit space & right literal */
3789 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3790 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3792 /* Can happen I guess */
3793 wassertl (0, "Tried to add a bit to a literal");
3796 /* if I can do an increment instead
3797 of add then GOOD for ME */
3798 if (genPlusIncr (ic) == TRUE)
3801 size = getDataSize (IC_RESULT (ic));
3803 /* Special case when left and right are constant */
3804 if (isPair (AOP (IC_RESULT (ic))))
3807 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3808 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3810 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3816 sprintf (buffer, "#(%s + %s)", left, right);
3817 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3822 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3824 /* Fetch into HL then do the add */
3825 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3826 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3828 spillPair (PAIR_HL);
3830 if (left == PAIR_HL && right != PAIR_INVALID)
3832 emit2 ("add hl,%s", _pairs[right].name);
3835 else if (right == PAIR_HL && left != PAIR_INVALID)
3837 emit2 ("add hl,%s", _pairs[left].name);
3840 else if (right != PAIR_INVALID && right != PAIR_HL)
3842 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3843 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3846 else if (left != PAIR_INVALID && left != PAIR_HL)
3848 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3849 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3858 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3860 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3861 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3862 spillPair (PAIR_HL);
3863 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3867 if (isPair (AOP (IC_LEFT (ic))) && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && getPairId (AOP (IC_LEFT (ic))) != PAIR_HL)
3869 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3870 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3871 spillPair (PAIR_HL);
3872 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3877 ld hl,sp+n trashes C so we can't afford to do it during an
3878 add with stack based variables. Worst case is:
3891 So you can't afford to load up hl if either left, right, or result
3892 is on the stack (*sigh*) The alt is:
3900 Combinations in here are:
3901 * If left or right are in bc then the loss is small - trap later
3902 * If the result is in bc then the loss is also small
3906 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3907 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3908 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3910 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3911 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3912 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3913 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3915 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3917 /* Swap left and right */
3918 operand *t = IC_RIGHT (ic);
3919 IC_RIGHT (ic) = IC_LEFT (ic);
3922 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3924 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3925 emit2 ("add hl,bc");
3929 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3930 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3931 emit2 ("add hl,de");
3933 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3939 /* Be paranoid on the GB with 4 byte variables due to how C
3940 can be trashed by lda hl,n(sp).
3942 _gbz80_emitAddSubLong (ic, TRUE);
3947 setupToPreserveCarry (ic);
3949 /* This is ugly, but it fixes the worst code generation bug on Z80. */
3950 /* Probably something similar has to be done for addition of larger numbers, too. */
3953 _moveA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3954 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), 0, FALSE));
3955 if(strcmp (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), aopGet (AOP (IC_LEFT (ic)), 1, FALSE)))
3957 aopPut (AOP (IC_RESULT (ic)), "a", 0);
3958 _moveA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3962 emitDebug ("; Addition result is in same register as operand of next addition.");
3963 if(strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'c') ||
3964 strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'b') )
3968 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3971 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3979 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
3982 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3988 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), 1, FALSE));
3989 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3995 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3997 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3999 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4000 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4004 _G.preserveCarry = FALSE;
4005 freeAsmop (IC_LEFT (ic), NULL, ic);
4006 freeAsmop (IC_RIGHT (ic), NULL, ic);
4007 freeAsmop (IC_RESULT (ic), NULL, ic);
4010 /*-----------------------------------------------------------------*/
4011 /* genMinusDec :- does subtraction with deccrement if possible */
4012 /*-----------------------------------------------------------------*/
4014 genMinusDec (iCode * ic)
4016 unsigned int icount;
4017 unsigned int size = getDataSize (IC_RESULT (ic));
4019 /* will try to generate an increment */
4020 /* if the right side is not a literal we cannot */
4021 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4024 /* if the literal value of the right hand side
4025 is greater than 4 then it is not worth it */
4026 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
4029 size = getDataSize (IC_RESULT (ic));
4031 /* if decrement 16 bits in register */
4032 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4033 (size > 1) && isPair (AOP (IC_RESULT (ic))))
4036 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4040 /* If result is a pair */
4041 if (isPair (AOP (IC_RESULT (ic))))
4043 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
4045 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4049 /* if increment 16 bits in register */
4050 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4054 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4057 emit2 ("dec %s", _getTempPairName());
4060 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4066 /* if the sizes are greater than 1 then we cannot */
4067 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4068 AOP_SIZE (IC_LEFT (ic)) > 1)
4071 /* we can if the aops of the left & result match or if they are in
4072 registers and the registers are the same */
4073 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4076 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4083 /*-----------------------------------------------------------------*/
4084 /* genMinus - generates code for subtraction */
4085 /*-----------------------------------------------------------------*/
4087 genMinus (iCode * ic)
4089 int size, offset = 0;
4090 unsigned long lit = 0L;
4092 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4093 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4094 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4096 /* special cases :- */
4097 /* if both left & right are in bit space */
4098 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4099 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4101 wassertl (0, "Tried to subtract two bits");
4105 /* if I can do an decrement instead of subtract then GOOD for ME */
4106 if (genMinusDec (ic) == TRUE)
4109 size = getDataSize (IC_RESULT (ic));
4111 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4116 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4120 /* Same logic as genPlus */
4123 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4124 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4125 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4127 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4128 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4129 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4130 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4132 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4133 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4135 if (left == PAIR_INVALID && right == PAIR_INVALID)
4140 else if (right == PAIR_INVALID)
4142 else if (left == PAIR_INVALID)
4145 fetchPair (left, AOP (IC_LEFT (ic)));
4146 /* Order is important. Right may be HL */
4147 fetchPair (right, AOP (IC_RIGHT (ic)));
4149 emit2 ("ld a,%s", _pairs[left].l);
4150 emit2 ("sub a,%s", _pairs[right].l);
4152 emit2 ("ld a,%s", _pairs[left].h);
4153 emit2 ("sbc a,%s", _pairs[right].h);
4155 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4157 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4159 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4165 /* Be paranoid on the GB with 4 byte variables due to how C
4166 can be trashed by lda hl,n(sp).
4168 _gbz80_emitAddSubLong (ic, FALSE);
4173 setupToPreserveCarry (ic);
4175 /* if literal, add a,#-lit, else normal subb */
4178 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4179 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4183 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4186 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4190 /* first add without previous c */
4193 if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
4196 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4199 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4201 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4204 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4205 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4206 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4208 wassertl (0, "Tried to subtract on a long pointer");
4212 _G.preserveCarry = FALSE;
4213 freeAsmop (IC_LEFT (ic), NULL, ic);
4214 freeAsmop (IC_RIGHT (ic), NULL, ic);
4215 freeAsmop (IC_RESULT (ic), NULL, ic);
4218 /*-----------------------------------------------------------------*/
4219 /* genMultChar - generates code for unsigned 8x8 multiplication */
4220 /*-----------------------------------------------------------------*/
4222 genMultOneChar (iCode * ic)
4224 symbol *tlbl1, *tlbl2;
4225 bool savedB = FALSE;
4229 wassertl (0, "Multiplication is handled through support function calls on gbz80");
4233 /* Save b into a if b is in use. */
4234 if (bitVectBitValue (ic->rMask, B_IDX) &&
4235 !(getPairId (AOP (IC_RESULT (ic))) == PAIR_BC))
4240 if (isPairInUse (PAIR_DE, ic) &&
4241 !(getPairId (AOP (IC_RESULT (ic))) == PAIR_DE))
4244 _G.stack.pushedDE = TRUE;
4247 tlbl1 = newiTempLabel (NULL);
4248 tlbl2 = newiTempLabel (NULL);
4250 emit2 ("ld e,%s", aopGet (AOP (IC_RIGHT (ic)), LSB, FALSE));
4251 emit2 ("ld h,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4252 emit2 ("ld l,#0x00");
4254 emit2 ("ld b,#0x08");
4255 emitLabel (tlbl1->key + 100);
4256 emit2 ("add hl,hl");
4257 emit2 ("jp NC,!tlabel", tlbl2->key + 100);
4258 emit2 ("add hl,de");
4259 emitLabel (tlbl2->key + 100);
4260 emit2 ("djnz !tlabel", tlbl1->key + 100);
4264 if (IS_Z80 && _G.stack.pushedDE)
4267 _G.stack.pushedDE = FALSE;
4274 if (AOP_SIZE (IC_RESULT (ic)) == 1)
4275 aopPut (AOP (IC_RESULT (ic)), "l", 0);
4277 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4279 freeAsmop (IC_LEFT (ic), NULL, ic);
4280 freeAsmop (IC_RIGHT (ic), NULL, ic);
4281 freeAsmop (IC_RESULT (ic), NULL, ic);
4284 /*-----------------------------------------------------------------*/
4285 /* genMult - generates code for multiplication */
4286 /*-----------------------------------------------------------------*/
4288 genMult (iCode * ic)
4292 /* If true then the final operation should be a subtract */
4293 bool active = FALSE;
4296 /* Shouldn't occur - all done through function calls */
4297 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4298 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4299 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4301 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4303 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4304 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4305 AOP_SIZE (IC_RESULT (ic)) > 2)
4307 wassertl (0, "Multiplication is handled through support function calls");
4310 /* Swap left and right such that right is a literal */
4311 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4313 operand *t = IC_RIGHT (ic);
4314 IC_RIGHT (ic) = IC_LEFT (ic);
4318 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4320 genMultOneChar (ic);
4324 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4326 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4327 // wassertl (val > 0, "Multiply must be positive");
4328 wassertl (val != 1, "Can't multiply by 1");
4330 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4332 _G.stack.pushedDE = TRUE;
4336 emit2 ("ld a,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4337 else if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4339 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4350 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4355 for (count = 0; count < 16; count++)
4357 if (count != 0 && active)
4362 emit2 ("add hl,hl");
4366 if (active == FALSE)
4381 emit2 ("add hl,de");
4390 if (IS_Z80 && _G.stack.pushedDE)
4393 _G.stack.pushedDE = FALSE;
4397 aopPut (AOP (IC_RESULT (ic)), "a", 0);
4399 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4401 freeAsmop (IC_LEFT (ic), NULL, ic);
4402 freeAsmop (IC_RIGHT (ic), NULL, ic);
4403 freeAsmop (IC_RESULT (ic), NULL, ic);
4406 /*-----------------------------------------------------------------*/
4407 /* genDiv - generates code for division */
4408 /*-----------------------------------------------------------------*/
4412 /* Shouldn't occur - all done through function calls */
4413 wassertl (0, "Division is handled through support function calls");
4416 /*-----------------------------------------------------------------*/
4417 /* genMod - generates code for division */
4418 /*-----------------------------------------------------------------*/
4422 /* Shouldn't occur - all done through function calls */
4426 /*-----------------------------------------------------------------*/
4427 /* genIfxJump :- will create a jump depending on the ifx */
4428 /*-----------------------------------------------------------------*/
4430 genIfxJump (iCode * ic, char *jval)
4435 /* if true label then we jump if condition
4439 jlbl = IC_TRUE (ic);
4440 if (!strcmp (jval, "a"))
4444 else if (!strcmp (jval, "c"))
4448 else if (!strcmp (jval, "nc"))
4452 else if (!strcmp (jval, "m"))
4456 else if (!strcmp (jval, "p"))
4462 /* The buffer contains the bit on A that we should test */
4468 /* false label is present */
4469 jlbl = IC_FALSE (ic);
4470 if (!strcmp (jval, "a"))
4474 else if (!strcmp (jval, "c"))
4478 else if (!strcmp (jval, "nc"))
4482 else if (!strcmp (jval, "m"))
4486 else if (!strcmp (jval, "p"))
4492 /* The buffer contains the bit on A that we should test */
4496 /* Z80 can do a conditional long jump */
4497 if (!strcmp (jval, "a"))
4501 else if (!strcmp (jval, "c"))
4504 else if (!strcmp (jval, "nc"))
4507 else if (!strcmp (jval, "m"))
4510 else if (!strcmp (jval, "p"))
4515 emit2 ("bit %s,a", jval);
4517 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4519 /* mark the icode as generated */
4525 _getPairIdName (PAIR_ID id)
4527 return _pairs[id].name;
4532 /* if unsigned char cmp with lit, just compare */
4534 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4536 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4539 emit2 ("xor a,!immedbyte", 0x80);
4540 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4543 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4545 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4547 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4548 // Pull left into DE and right into HL
4549 aopGet (AOP(left), LSB, FALSE);
4552 aopGet (AOP(right), LSB, FALSE);
4556 if (size == 0 && sign)
4558 // Highest byte when signed needs the bits flipped
4561 emit2 ("ld a,(de)");
4562 emit2 ("xor !immedbyte", 0x80);
4564 emit2 ("ld a,(hl)");
4565 emit2 ("xor !immedbyte", 0x80);
4569 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4573 emit2 ("ld a,(de)");
4574 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4584 spillPair (PAIR_HL);
4586 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4588 setupPair (PAIR_HL, AOP (left), 0);
4589 aopGet (AOP(right), LSB, FALSE);
4593 if (size == 0 && sign)
4595 // Highest byte when signed needs the bits flipped
4598 emit2 ("ld a,(hl)");
4599 emit2 ("xor !immedbyte", 0x80);
4601 emit2 ("ld a,%d(iy)", offset);
4602 emit2 ("xor !immedbyte", 0x80);
4606 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4610 emit2 ("ld a,(hl)");
4611 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4620 spillPair (PAIR_HL);
4621 spillPair (PAIR_IY);
4625 if (AOP_TYPE (right) == AOP_LIT)
4627 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4628 /* optimize if(x < 0) or if(x >= 0) */
4633 /* No sign so it's always false */
4638 /* Just load in the top most bit */
4639 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4640 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4642 genIfxJump (ifx, "7");
4654 /* First setup h and l contaning the top most bytes XORed */
4655 bool fDidXor = FALSE;
4656 if (AOP_TYPE (left) == AOP_LIT)
4658 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4659 emit2 ("ld %s,!immedbyte", _fTmp[0],
4660 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4664 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4665 emit2 ("xor a,!immedbyte", 0x80);
4666 emit2 ("ld %s,a", _fTmp[0]);
4669 if (AOP_TYPE (right) == AOP_LIT)
4671 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4672 emit2 ("ld %s,!immedbyte", _fTmp[1],
4673 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4677 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4678 emit2 ("xor a,!immedbyte", 0x80);
4679 emit2 ("ld %s,a", _fTmp[1]);
4685 /* Do a long subtract */
4688 _moveA (aopGet (AOP (left), offset, FALSE));
4690 if (sign && size == 0)
4692 emit2 ("ld a,%s", _fTmp[0]);
4693 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4697 /* Subtract through, propagating the carry */
4698 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4706 /** Generic compare for > or <
4709 genCmp (operand * left, operand * right,
4710 operand * result, iCode * ifx, int sign)
4712 int size, offset = 0;
4713 unsigned long lit = 0L;
4715 /* if left & right are bit variables */
4716 if (AOP_TYPE (left) == AOP_CRY &&
4717 AOP_TYPE (right) == AOP_CRY)
4719 /* Cant happen on the Z80 */
4720 wassertl (0, "Tried to compare two bits");
4724 /* Do a long subtract of right from left. */
4725 size = max (AOP_SIZE (left), AOP_SIZE (right));
4727 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4729 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4730 // Pull left into DE and right into HL
4731 aopGet (AOP(left), LSB, FALSE);
4734 aopGet (AOP(right), LSB, FALSE);
4738 emit2 ("ld a,(de)");
4739 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4748 spillPair (PAIR_HL);
4752 if (AOP_TYPE (right) == AOP_LIT)
4754 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4755 /* optimize if(x < 0) or if(x >= 0) */
4760 /* No sign so it's always false */
4765 /* Just load in the top most bit */
4766 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4767 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4769 genIfxJump (ifx, "7");
4780 genIfxJump (ifx, "nc");
4791 _moveA (aopGet (AOP (left), offset, FALSE));
4792 /* Subtract through, propagating the carry */
4793 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4799 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4803 /* Shift the sign bit up into carry */
4810 /* if the result is used in the next
4811 ifx conditional branch then generate
4812 code a little differently */
4820 genIfxJump (ifx, "c");
4824 genIfxJump (ifx, "m");
4829 genIfxJump (ifx, "c");
4836 /* Shift the sign bit up into carry */
4841 /* leave the result in acc */
4845 /*-----------------------------------------------------------------*/
4846 /* genCmpGt :- greater than comparison */
4847 /*-----------------------------------------------------------------*/
4849 genCmpGt (iCode * ic, iCode * ifx)
4851 operand *left, *right, *result;
4852 sym_link *letype, *retype;
4855 left = IC_LEFT (ic);
4856 right = IC_RIGHT (ic);
4857 result = IC_RESULT (ic);
4859 letype = getSpec (operandType (left));
4860 retype = getSpec (operandType (right));
4861 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4862 /* assign the asmops */
4863 aopOp (left, ic, FALSE, FALSE);
4864 aopOp (right, ic, FALSE, FALSE);
4865 aopOp (result, ic, TRUE, FALSE);
4867 setupToPreserveCarry (ic);
4869 genCmp (right, left, result, ifx, sign);
4871 _G.preserveCarry = FALSE;
4872 freeAsmop (left, NULL, ic);
4873 freeAsmop (right, NULL, ic);
4874 freeAsmop (result, NULL, ic);
4877 /*-----------------------------------------------------------------*/
4878 /* genCmpLt - less than comparisons */
4879 /*-----------------------------------------------------------------*/
4881 genCmpLt (iCode * ic, iCode * ifx)
4883 operand *left, *right, *result;
4884 sym_link *letype, *retype;
4887 left = IC_LEFT (ic);
4888 right = IC_RIGHT (ic);
4889 result = IC_RESULT (ic);
4891 letype = getSpec (operandType (left));
4892 retype = getSpec (operandType (right));
4893 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4895 /* assign the asmops */
4896 aopOp (left, ic, FALSE, FALSE);
4897 aopOp (right, ic, FALSE, FALSE);
4898 aopOp (result, ic, TRUE, FALSE);
4900 setupToPreserveCarry (ic);
4902 genCmp (left, right, result, ifx, sign);
4904 _G.preserveCarry = FALSE;
4905 freeAsmop (left, NULL, ic);
4906 freeAsmop (right, NULL, ic);
4907 freeAsmop (result, NULL, ic);
4910 /*-----------------------------------------------------------------*/
4911 /* gencjneshort - compare and jump if not equal */
4912 /* returns pair that still needs to be popped */
4913 /*-----------------------------------------------------------------*/
4915 gencjneshort (operand * left, operand * right, symbol * lbl)
4917 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4919 unsigned long lit = 0L;
4921 /* Swap the left and right if it makes the computation easier */
4922 if (AOP_TYPE (left) == AOP_LIT)
4929 /* if the right side is a literal then anything goes */
4930 if (AOP_TYPE (right) == AOP_LIT)
4932 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4935 _moveA (aopGet (AOP (left), offset, FALSE));
4940 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4947 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4953 _moveA (aopGet (AOP (left), offset, FALSE));
4954 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4957 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4958 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4963 /* if the right side is in a register or
4964 pointed to by HL, IX or IY */
4965 else if (AOP_TYPE (right) == AOP_REG ||
4966 AOP_TYPE (right) == AOP_HL ||
4967 AOP_TYPE (right) == AOP_IY ||
4968 AOP_TYPE (right) == AOP_STK ||
4969 AOP_IS_PAIRPTR (right, PAIR_HL) ||
4970 AOP_IS_PAIRPTR (right, PAIR_IX) ||
4971 AOP_IS_PAIRPTR (right, PAIR_IY))
4975 _moveA (aopGet (AOP (left), offset, FALSE));
4976 if (AOP_TYPE (right) == AOP_LIT &&
4977 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4980 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4984 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4985 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4990 /* right is in direct space or a pointer reg, need both a & b */
4994 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
4996 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
4997 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
5005 emit2 ("; direct compare");
5006 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
5007 _moveA (aopGet (AOP (right), offset, FALSE));
5008 emit2 ("sub %s", _pairs[pair].l);
5009 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
5014 return PAIR_INVALID;
5017 /*-----------------------------------------------------------------*/
5018 /* gencjne - compare and jump if not equal */
5019 /*-----------------------------------------------------------------*/
5021 gencjne (operand * left, operand * right, symbol * lbl)
5023 symbol *tlbl = newiTempLabel (NULL);
5025 PAIR_ID pop = gencjneshort (left, right, lbl);
5028 emit2 ("ld a,!one");
5029 emit2 ("!shortjp !tlabel", tlbl->key + 100);
5030 emitLabel (lbl->key + 100);
5032 emitLabel (tlbl->key + 100);
5036 /*-----------------------------------------------------------------*/
5037 /* genCmpEq - generates code for equal to */
5038 /*-----------------------------------------------------------------*/
5040 genCmpEq (iCode * ic, iCode * ifx)
5042 operand *left, *right, *result;
5044 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5045 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5046 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5048 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
5050 /* Swap operands if it makes the operation easier. ie if:
5051 1. Left is a literal.
5053 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
5055 operand *t = IC_RIGHT (ic);
5056 IC_RIGHT (ic) = IC_LEFT (ic);
5060 if (ifx && !AOP_SIZE (result))
5063 /* if they are both bit variables */
5064 if (AOP_TYPE (left) == AOP_CRY &&
5065 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5067 wassertl (0, "Tried to compare two bits");
5072 tlbl = newiTempLabel (NULL);
5073 pop = gencjneshort (left, right, tlbl);
5077 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
5078 emitLabel (tlbl->key + 100);
5083 /* PENDING: do this better */
5084 symbol *lbl = newiTempLabel (NULL);
5086 emit2 ("!shortjp !tlabel", lbl->key + 100);
5087 emitLabel (tlbl->key + 100);
5089 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
5090 emitLabel (lbl->key + 100);
5093 /* mark the icode as generated */
5098 /* if they are both bit variables */
5099 if (AOP_TYPE (left) == AOP_CRY &&
5100 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5102 wassertl (0, "Tried to compare a bit to either a literal or another bit");
5108 gencjne (left, right, newiTempLabel (NULL));
5109 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5116 genIfxJump (ifx, "a");
5119 /* if the result is used in an arithmetic operation
5120 then put the result in place */
5121 if (AOP_TYPE (result) != AOP_CRY)
5126 /* leave the result in acc */
5130 freeAsmop (left, NULL, ic);
5131 freeAsmop (right, NULL, ic);
5132 freeAsmop (result, NULL, ic);
5135 /*-----------------------------------------------------------------*/
5136 /* ifxForOp - returns the icode containing the ifx for operand */
5137 /*-----------------------------------------------------------------*/
5139 ifxForOp (operand * op, iCode * ic)
5141 /* if true symbol then needs to be assigned */
5142 if (IS_TRUE_SYMOP (op))
5145 /* if this has register type condition and
5146 the next instruction is ifx with the same operand
5147 and live to of the operand is upto the ifx only then */
5149 ic->next->op == IFX &&
5150 IC_COND (ic->next)->key == op->key &&
5151 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5157 /*-----------------------------------------------------------------*/
5158 /* genAndOp - for && operation */
5159 /*-----------------------------------------------------------------*/
5161 genAndOp (iCode * ic)
5163 operand *left, *right, *result;
5166 /* note here that && operations that are in an if statement are
5167 taken away by backPatchLabels only those used in arthmetic
5168 operations remain */
5169 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5170 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5171 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5173 /* if both are bit variables */
5174 if (AOP_TYPE (left) == AOP_CRY &&
5175 AOP_TYPE (right) == AOP_CRY)
5177 wassertl (0, "Tried to and two bits");
5181 tlbl = newiTempLabel (NULL);
5183 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5185 emitLabel (tlbl->key + 100);
5189 freeAsmop (left, NULL, ic);
5190 freeAsmop (right, NULL, ic);
5191 freeAsmop (result, NULL, ic);
5194 /*-----------------------------------------------------------------*/
5195 /* genOrOp - for || operation */
5196 /*-----------------------------------------------------------------*/
5198 genOrOp (iCode * ic)
5200 operand *left, *right, *result;
5203 /* note here that || operations that are in an
5204 if statement are taken away by backPatchLabels
5205 only those used in arthmetic operations remain */
5206 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5207 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5208 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5210 /* if both are bit variables */
5211 if (AOP_TYPE (left) == AOP_CRY &&
5212 AOP_TYPE (right) == AOP_CRY)
5214 wassertl (0, "Tried to OR two bits");
5218 tlbl = newiTempLabel (NULL);
5220 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5222 emitLabel (tlbl->key + 100);
5226 freeAsmop (left, NULL, ic);
5227 freeAsmop (right, NULL, ic);
5228 freeAsmop (result, NULL, ic);
5231 /*-----------------------------------------------------------------*/
5232 /* isLiteralBit - test if lit == 2^n */
5233 /*-----------------------------------------------------------------*/
5235 isLiteralBit (unsigned long lit)
5237 unsigned long pw[32] =
5238 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5239 0x100L, 0x200L, 0x400L, 0x800L,
5240 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5241 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5242 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5243 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5244 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5247 for (idx = 0; idx < 32; idx++)
5253 /*-----------------------------------------------------------------*/
5254 /* jmpTrueOrFalse - */
5255 /*-----------------------------------------------------------------*/
5257 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5259 // ugly but optimized by peephole
5262 symbol *nlbl = newiTempLabel (NULL);
5263 emit2 ("jp !tlabel", nlbl->key + 100);
5264 emitLabel (tlbl->key + 100);
5265 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5266 emitLabel (nlbl->key + 100);
5270 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5271 emitLabel (tlbl->key + 100);
5276 /*-----------------------------------------------------------------*/
5277 /* genAnd - code for and */
5278 /*-----------------------------------------------------------------*/
5280 genAnd (iCode * ic, iCode * ifx)
5282 operand *left, *right, *result;
5283 int size, offset = 0;
5284 unsigned long lit = 0L;
5287 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5288 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5289 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5291 /* if left is a literal & right is not then exchange them */
5292 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5293 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5295 operand *tmp = right;
5300 /* if result = right then exchange them */
5301 if (sameRegs (AOP (result), AOP (right)))
5303 operand *tmp = right;
5308 /* if right is bit then exchange them */
5309 if (AOP_TYPE (right) == AOP_CRY &&
5310 AOP_TYPE (left) != AOP_CRY)
5312 operand *tmp = right;
5316 if (AOP_TYPE (right) == AOP_LIT)
5317 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5319 size = AOP_SIZE (result);
5321 if (AOP_TYPE (left) == AOP_CRY)
5323 wassertl (0, "Tried to perform an AND with a bit as an operand");
5327 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5328 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5329 if ((AOP_TYPE (right) == AOP_LIT) &&
5330 (AOP_TYPE (result) == AOP_CRY) &&
5331 (AOP_TYPE (left) != AOP_CRY))
5333 symbol *tlbl = newiTempLabel (NULL);
5334 int sizel = AOP_SIZE (left);
5337 /* PENDING: Test case for this. */
5342 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5344 _moveA (aopGet (AOP (left), offset, FALSE));
5345 if (bytelit != 0x0FFL)
5347 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5354 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5358 // bit = left & literal
5362 emit2 ("!tlabeldef", tlbl->key + 100);
5363 _G.lines.current->isLabel = 1;
5365 // if(left & literal)
5370 jmpTrueOrFalse (ifx, tlbl);
5378 /* if left is same as result */
5379 if (sameRegs (AOP (result), AOP (left)))
5381 for (; size--; offset++)
5383 if (AOP_TYPE (right) == AOP_LIT)
5385 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5390 aopPut (AOP (result), "!zero", offset);
5393 _moveA (aopGet (AOP (left), offset, FALSE));
5395 aopGet (AOP (right), offset, FALSE));
5396 aopPut (AOP (left), "a", offset);
5403 if (AOP_TYPE (left) == AOP_ACC)
5405 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5409 _moveA (aopGet (AOP (left), offset, FALSE));
5411 aopGet (AOP (right), offset, FALSE));
5412 aopPut (AOP (left), "a", offset);
5419 // left & result in different registers
5420 if (AOP_TYPE (result) == AOP_CRY)
5422 wassertl (0, "Tried to AND where the result is in carry");
5426 for (; (size--); offset++)
5429 // result = left & right
5430 if (AOP_TYPE (right) == AOP_LIT)
5432 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5434 aopPut (AOP (result),
5435 aopGet (AOP (left), offset, FALSE),
5439 else if (bytelit == 0)
5441 aopPut (AOP (result), "!zero", offset);
5445 // faster than result <- left, anl result,right
5446 // and better if result is SFR
5447 if (AOP_TYPE (left) == AOP_ACC)
5448 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5451 _moveA (aopGet (AOP (left), offset, FALSE));
5453 aopGet (AOP (right), offset, FALSE));
5455 aopPut (AOP (result), "a", offset);
5462 freeAsmop (left, NULL, ic);
5463 freeAsmop (right, NULL, ic);
5464 freeAsmop (result, NULL, ic);
5467 /*-----------------------------------------------------------------*/
5468 /* genOr - code for or */
5469 /*-----------------------------------------------------------------*/
5471 genOr (iCode * ic, iCode * ifx)
5473 operand *left, *right, *result;
5474 int size, offset = 0;
5475 unsigned long lit = 0L;
5478 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5479 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5480 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5482 /* if left is a literal & right is not then exchange them */
5483 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5484 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5486 operand *tmp = right;
5491 /* if result = right then exchange them */
5492 if (sameRegs (AOP (result), AOP (right)))
5494 operand *tmp = right;
5499 /* if right is bit then exchange them */
5500 if (AOP_TYPE (right) == AOP_CRY &&
5501 AOP_TYPE (left) != AOP_CRY)
5503 operand *tmp = right;
5507 if (AOP_TYPE (right) == AOP_LIT)
5508 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5510 size = AOP_SIZE (result);
5512 if (AOP_TYPE (left) == AOP_CRY)
5514 wassertl (0, "Tried to OR where left is a bit");
5518 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5519 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5520 if ((AOP_TYPE (right) == AOP_LIT) &&
5521 (AOP_TYPE (result) == AOP_CRY) &&
5522 (AOP_TYPE (left) != AOP_CRY))
5524 symbol *tlbl = newiTempLabel (NULL);
5525 int sizel = AOP_SIZE (left);
5529 wassertl (0, "Result is assigned to a bit");
5531 /* PENDING: Modeled after the AND code which is inefficient. */
5534 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5536 _moveA (aopGet (AOP (left), offset, FALSE));
5537 /* OR with any literal is the same as OR with itself. */
5539 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5545 jmpTrueOrFalse (ifx, tlbl);
5550 /* if left is same as result */
5551 if (sameRegs (AOP (result), AOP (left)))
5553 for (; size--; offset++)
5555 if (AOP_TYPE (right) == AOP_LIT)
5557 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5561 _moveA (aopGet (AOP (left), offset, FALSE));
5563 aopGet (AOP (right), offset, FALSE));
5564 aopPut (AOP (result), "a", offset);
5569 if (AOP_TYPE (left) == AOP_ACC)
5570 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5573 _moveA (aopGet (AOP (left), offset, FALSE));
5575 aopGet (AOP (right), offset, FALSE));
5576 aopPut (AOP (result), "a", offset);
5583 // left & result in different registers
5584 if (AOP_TYPE (result) == AOP_CRY)
5586 wassertl (0, "Result of OR is in a bit");
5589 for (; (size--); offset++)
5592 // result = left & right
5593 if (AOP_TYPE (right) == AOP_LIT)
5595 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5597 aopPut (AOP (result),
5598 aopGet (AOP (left), offset, FALSE),
5603 // faster than result <- left, anl result,right
5604 // and better if result is SFR
5605 if (AOP_TYPE (left) == AOP_ACC)
5606 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5609 _moveA (aopGet (AOP (left), offset, FALSE));
5611 aopGet (AOP (right), offset, FALSE));
5613 aopPut (AOP (result), "a", offset);
5614 /* PENDING: something weird is going on here. Add exception. */
5615 if (AOP_TYPE (result) == AOP_ACC)
5621 freeAsmop (left, NULL, ic);
5622 freeAsmop (right, NULL, ic);
5623 freeAsmop (result, NULL, ic);
5626 /*-----------------------------------------------------------------*/
5627 /* genXor - code for xclusive or */
5628 /*-----------------------------------------------------------------*/
5630 genXor (iCode * ic, iCode * ifx)
5632 operand *left, *right, *result;
5633 int size, offset = 0;
5634 unsigned long lit = 0L;
5636 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5637 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5638 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5640 /* if left is a literal & right is not then exchange them */
5641 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5642 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5644 operand *tmp = right;
5649 /* if result = right then exchange them */
5650 if (sameRegs (AOP (result), AOP (right)))
5652 operand *tmp = right;
5657 /* if right is bit then exchange them */
5658 if (AOP_TYPE (right) == AOP_CRY &&
5659 AOP_TYPE (left) != AOP_CRY)
5661 operand *tmp = right;
5665 if (AOP_TYPE (right) == AOP_LIT)
5666 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5668 size = AOP_SIZE (result);
5670 if (AOP_TYPE (left) == AOP_CRY)
5672 wassertl (0, "Tried to XOR a bit");
5676 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5677 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5678 if ((AOP_TYPE (right) == AOP_LIT) &&
5679 (AOP_TYPE (result) == AOP_CRY) &&
5680 (AOP_TYPE (left) != AOP_CRY))
5682 symbol *tlbl = newiTempLabel (NULL);
5683 int sizel = AOP_SIZE (left);
5687 /* PENDING: Test case for this. */
5688 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5692 _moveA (aopGet (AOP (left), offset, FALSE));
5693 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5694 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5699 jmpTrueOrFalse (ifx, tlbl);
5703 wassertl (0, "Result of XOR was destined for a bit");
5708 /* if left is same as result */
5709 if (sameRegs (AOP (result), AOP (left)))
5711 for (; size--; offset++)
5713 if (AOP_TYPE (right) == AOP_LIT)
5715 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5719 _moveA (aopGet (AOP (left), offset, FALSE));
5721 aopGet (AOP (right), offset, FALSE));
5722 aopPut (AOP (result), "a", offset);
5727 if (AOP_TYPE (left) == AOP_ACC)
5729 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5733 _moveA (aopGet (AOP (left), offset, FALSE));
5735 aopGet (AOP (right), offset, FALSE));
5736 aopPut (AOP (result), "a", offset);
5743 // left & result in different registers
5744 if (AOP_TYPE (result) == AOP_CRY)
5746 wassertl (0, "Result of XOR is in a bit");
5749 for (; (size--); offset++)
5752 // result = left & right
5753 if (AOP_TYPE (right) == AOP_LIT)
5755 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5757 aopPut (AOP (result),
5758 aopGet (AOP (left), offset, FALSE),
5763 // faster than result <- left, anl result,right
5764 // and better if result is SFR
5765 if (AOP_TYPE (left) == AOP_ACC)
5767 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5771 _moveA (aopGet (AOP (left), offset, FALSE));
5773 aopGet (AOP (right), offset, FALSE));
5775 aopPut (AOP (result), "a", offset);
5780 freeAsmop (left, NULL, ic);
5781 freeAsmop (right, NULL, ic);
5782 freeAsmop (result, NULL, ic);
5785 /*-----------------------------------------------------------------*/
5786 /* genInline - write the inline code out */
5787 /*-----------------------------------------------------------------*/
5789 genInline (iCode * ic)
5791 char *buffer, *bp, *bp1;
5792 bool inComment = FALSE;
5794 _G.lines.isInline += (!options.asmpeep);
5796 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5798 /* emit each line as a code */
5816 /* Add \n for labels, not dirs such as c:\mydir */
5817 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5835 _G.lines.isInline -= (!options.asmpeep);
5839 /*-----------------------------------------------------------------*/
5840 /* genRRC - rotate right with carry */
5841 /*-----------------------------------------------------------------*/
5848 /*-----------------------------------------------------------------*/
5849 /* genRLC - generate code for rotate left with carry */
5850 /*-----------------------------------------------------------------*/
5857 /*-----------------------------------------------------------------*/
5858 /* genGetHbit - generates code get highest order bit */
5859 /*-----------------------------------------------------------------*/
5861 genGetHbit (iCode * ic)
5863 operand *left, *result;
5864 left = IC_LEFT (ic);
5865 result = IC_RESULT (ic);
5867 aopOp (left, ic, FALSE, FALSE);
5868 aopOp (result, ic, FALSE, FALSE);
5870 /* get the highest order byte into a */
5871 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5873 if (AOP_TYPE (result) == AOP_CRY)
5881 emit2 ("and a,!one");
5886 freeAsmop (left, NULL, ic);
5887 freeAsmop (result, NULL, ic);
5891 emitRsh2 (asmop *aop, int size, int is_signed)
5897 const char *l = aopGet (aop, size, FALSE);
5900 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5910 /*-----------------------------------------------------------------*/
5911 /* shiftR2Left2Result - shift right two bytes from left to result */
5912 /*-----------------------------------------------------------------*/
5914 shiftR2Left2Result (operand * left, int offl,
5915 operand * result, int offr,
5916 int shCount, int is_signed)
5921 movLeft2Result (left, offl, result, offr, 0);
5922 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5927 /* if (AOP(result)->type == AOP_REG) { */
5929 tlbl = newiTempLabel (NULL);
5931 /* Left is already in result - so now do the shift */
5932 /* Optimizing for speed by default. */
5933 if (!optimize.codeSize || shCount <= 2)
5937 emitRsh2 (AOP (result), size, is_signed);
5942 emit2 ("ld a,!immedbyte", shCount);
5944 emitLabel (tlbl->key + 100);
5946 emitRsh2 (AOP (result), size, is_signed);
5949 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5953 /*-----------------------------------------------------------------*/
5954 /* shiftL2Left2Result - shift left two bytes from left to result */
5955 /*-----------------------------------------------------------------*/
5957 shiftL2Left2Result (operand * left, int offl,
5958 operand * result, int offr, int shCount)
5960 if (sameRegs (AOP (result), AOP (left)) &&
5961 ((offl + MSB16) == offr))
5967 /* Copy left into result */
5968 movLeft2Result (left, offl, result, offr, 0);
5969 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5975 if (getPairId (AOP (result)) == PAIR_HL)
5979 emit2 ("add hl,hl");
5986 symbol *tlbl, *tlbl1;
5989 tlbl = newiTempLabel (NULL);
5990 tlbl1 = newiTempLabel (NULL);
5992 if (AOP (result)->type == AOP_REG)
5996 for (offset = 0; offset < size; offset++)
5998 l = aopGet (AOP (result), offset, FALSE);
6002 emit2 ("sla %s", l);
6013 /* Left is already in result - so now do the shift */
6016 emit2 ("ld a,!immedbyte+1", shCount);
6017 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6018 emitLabel (tlbl->key + 100);
6023 l = aopGet (AOP (result), offset, FALSE);
6027 emit2 ("sla %s", l);
6038 emitLabel (tlbl1->key + 100);
6040 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6046 /*-----------------------------------------------------------------*/
6047 /* AccRol - rotate left accumulator by known count */
6048 /*-----------------------------------------------------------------*/
6050 AccRol (int shCount)
6052 shCount &= 0x0007; // shCount : 0..7
6129 /*-----------------------------------------------------------------*/
6130 /* AccLsh - left shift accumulator by known count */
6131 /*-----------------------------------------------------------------*/
6133 AccLsh (int shCount)
6135 static const unsigned char SLMask[] =
6137 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6146 else if (shCount == 2)
6153 /* rotate left accumulator */
6155 /* and kill the lower order bits */
6156 emit2 ("and a,!immedbyte", SLMask[shCount]);
6161 /*-----------------------------------------------------------------*/
6162 /* shiftL1Left2Result - shift left one byte from left to result */
6163 /*-----------------------------------------------------------------*/
6165 shiftL1Left2Result (operand * left, int offl,
6166 operand * result, int offr, int shCount)
6170 /* If operand and result are the same we can shift in place.
6171 However shifting in acc using add is cheaper than shifting
6172 in place using sla; when shifting by more than 2 shifting in
6173 acc is worth the additional effort for loading from/to acc. */
6174 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6177 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6181 l = aopGet (AOP (left), offl, FALSE);
6183 /* shift left accumulator */
6185 aopPut (AOP (result), "a", offr);
6189 /*-----------------------------------------------------------------*/
6190 /* genlshTwo - left shift two bytes by known amount */
6191 /*-----------------------------------------------------------------*/
6193 genlshTwo (operand * result, operand * left, int shCount)
6195 int size = AOP_SIZE (result);
6197 wassert (size == 2);
6199 /* if shCount >= 8 */
6207 movLeft2Result (left, LSB, result, MSB16, 0);
6208 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6209 aopPut (AOP (result), "!zero", LSB);
6213 movLeft2Result (left, LSB, result, MSB16, 0);
6214 aopPut (AOP (result), "!zero", 0);
6219 aopPut (AOP (result), "!zero", LSB);
6222 /* 0 <= shCount <= 7 */
6231 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6236 /*-----------------------------------------------------------------*/
6237 /* genlshOne - left shift a one byte quantity by known count */
6238 /*-----------------------------------------------------------------*/
6240 genlshOne (operand * result, operand * left, int shCount)
6242 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6245 /*-----------------------------------------------------------------*/
6246 /* genLeftShiftLiteral - left shifting by known count */
6247 /*-----------------------------------------------------------------*/
6249 genLeftShiftLiteral (operand * left,
6254 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6257 freeAsmop (right, NULL, ic);
6259 aopOp (left, ic, FALSE, FALSE);
6260 aopOp (result, ic, FALSE, FALSE);
6262 size = getSize (operandType (result));
6264 /* I suppose that the left size >= result size */
6266 if (shCount >= (size * 8))
6270 aopPut (AOP (result), "!zero", size);
6278 genlshOne (result, left, shCount);
6281 genlshTwo (result, left, shCount);
6284 wassertl (0, "Shifting of longs is currently unsupported");
6290 freeAsmop (left, NULL, ic);
6291 freeAsmop (result, NULL, ic);
6294 /*-----------------------------------------------------------------*/
6295 /* genLeftShift - generates code for left shifting */
6296 /*-----------------------------------------------------------------*/
6298 genLeftShift (iCode * ic)
6302 symbol *tlbl, *tlbl1;
6303 operand *left, *right, *result;
6305 right = IC_RIGHT (ic);
6306 left = IC_LEFT (ic);
6307 result = IC_RESULT (ic);
6309 aopOp (right, ic, FALSE, FALSE);
6311 /* if the shift count is known then do it
6312 as efficiently as possible */
6313 if (AOP_TYPE (right) == AOP_LIT)
6315 genLeftShiftLiteral (left, right, result, ic);
6319 /* shift count is unknown then we have to form a loop get the loop
6320 count in B : Note: we take only the lower order byte since
6321 shifting more that 32 bits make no sense anyway, ( the largest
6322 size of an object can be only 32 bits ) */
6323 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6325 freeAsmop (right, NULL, ic);
6326 aopOp (left, ic, FALSE, FALSE);
6327 aopOp (result, ic, FALSE, FALSE);
6329 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6332 /* now move the left to the result if they are not the
6335 if (!sameRegs (AOP (left), AOP (result)))
6338 size = AOP_SIZE (result);
6342 l = aopGet (AOP (left), offset, FALSE);
6343 aopPut (AOP (result), l, offset);
6348 tlbl = newiTempLabel (NULL);
6349 size = AOP_SIZE (result);
6351 tlbl1 = newiTempLabel (NULL);
6353 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6356 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6357 emitLabel (tlbl->key + 100);
6358 l = aopGet (AOP (result), offset, FALSE);
6362 l = aopGet (AOP (result), offset, FALSE);
6366 emit2 ("sla %s", l);
6374 emitLabel (tlbl1->key + 100);
6376 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6378 freeAsmop (left, NULL, ic);
6379 freeAsmop (result, NULL, ic);
6382 /*-----------------------------------------------------------------*/
6383 /* genrshOne - left shift two bytes by known amount != 0 */
6384 /*-----------------------------------------------------------------*/
6386 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6389 int size = AOP_SIZE (result);
6392 wassert (size == 1);
6393 wassert (shCount < 8);
6395 l = aopGet (AOP (left), 0, FALSE);
6397 if (AOP (result)->type == AOP_REG)
6399 aopPut (AOP (result), l, 0);
6400 l = aopGet (AOP (result), 0, FALSE);
6403 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6411 emit2 ("%s a", is_signed ? "sra" : "srl");
6413 aopPut (AOP (result), "a", 0);
6417 /*-----------------------------------------------------------------*/
6418 /* AccRsh - right shift accumulator by known count */
6419 /*-----------------------------------------------------------------*/
6421 AccRsh (int shCount)
6423 static const unsigned char SRMask[] =
6425 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6430 /* rotate right accumulator */
6431 AccRol (8 - shCount);
6432 /* and kill the higher order bits */
6433 emit2 ("and a,!immedbyte", SRMask[shCount]);
6437 /*-----------------------------------------------------------------*/
6438 /* shiftR1Left2Result - shift right one byte from left to result */
6439 /*-----------------------------------------------------------------*/
6441 shiftR1Left2Result (operand * left, int offl,
6442 operand * result, int offr,
6443 int shCount, int sign)
6445 _moveA (aopGet (AOP (left), offl, FALSE));
6450 emit2 ("%s a", sign ? "sra" : "srl");
6457 aopPut (AOP (result), "a", offr);
6460 /*-----------------------------------------------------------------*/
6461 /* genrshTwo - right shift two bytes by known amount */
6462 /*-----------------------------------------------------------------*/
6464 genrshTwo (operand * result, operand * left,
6465 int shCount, int sign)
6467 /* if shCount >= 8 */
6473 shiftR1Left2Result (left, MSB16, result, LSB,
6478 movLeft2Result (left, MSB16, result, LSB, sign);
6482 /* Sign extend the result */
6483 _moveA(aopGet (AOP (result), 0, FALSE));
6487 aopPut (AOP (result), ACC_NAME, MSB16);
6491 aopPut (AOP (result), "!zero", 1);
6494 /* 0 <= shCount <= 7 */
6497 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6501 /*-----------------------------------------------------------------*/
6502 /* genRightShiftLiteral - left shifting by known count */
6503 /*-----------------------------------------------------------------*/
6505 genRightShiftLiteral (operand * left,
6511 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6514 freeAsmop (right, NULL, ic);
6516 aopOp (left, ic, FALSE, FALSE);
6517 aopOp (result, ic, FALSE, FALSE);
6519 size = getSize (operandType (result));
6521 /* I suppose that the left size >= result size */
6523 if (shCount >= (size * 8)) {
6525 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6526 _moveA(aopGet (AOP (left), 0, FALSE));
6534 aopPut (AOP (result), s, size);
6541 genrshOne (result, left, shCount, sign);
6544 genrshTwo (result, left, shCount, sign);
6547 wassertl (0, "Asked to shift right a long which should be a function call");
6550 wassertl (0, "Entered default case in right shift delegate");
6553 freeAsmop (left, NULL, ic);
6554 freeAsmop (result, NULL, ic);
6557 /*-----------------------------------------------------------------*/
6558 /* genRightShift - generate code for right shifting */
6559 /*-----------------------------------------------------------------*/
6561 genRightShift (iCode * ic)
6563 operand *right, *left, *result;
6565 int size, offset, first = 1;
6569 symbol *tlbl, *tlbl1;
6571 /* if signed then we do it the hard way preserve the
6572 sign bit moving it inwards */
6573 retype = getSpec (operandType (IC_RESULT (ic)));
6575 is_signed = !SPEC_USIGN (retype);
6577 /* signed & unsigned types are treated the same : i.e. the
6578 signed is NOT propagated inwards : quoting from the
6579 ANSI - standard : "for E1 >> E2, is equivalent to division
6580 by 2**E2 if unsigned or if it has a non-negative value,
6581 otherwise the result is implementation defined ", MY definition
6582 is that the sign does not get propagated */
6584 right = IC_RIGHT (ic);
6585 left = IC_LEFT (ic);
6586 result = IC_RESULT (ic);
6588 aopOp (right, ic, FALSE, FALSE);
6590 /* if the shift count is known then do it
6591 as efficiently as possible */
6592 if (AOP_TYPE (right) == AOP_LIT)
6594 genRightShiftLiteral (left, right, result, ic, is_signed);
6598 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6600 freeAsmop (right, NULL, ic);
6602 aopOp (left, ic, FALSE, FALSE);
6603 aopOp (result, ic, FALSE, FALSE);
6605 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6608 /* now move the left to the result if they are not the
6610 if (!sameRegs (AOP (left), AOP (result)))
6613 size = AOP_SIZE (result);
6617 l = aopGet (AOP (left), offset, FALSE);
6618 aopPut (AOP (result), l, offset);
6623 tlbl = newiTempLabel (NULL);
6624 tlbl1 = newiTempLabel (NULL);
6625 size = AOP_SIZE (result);
6628 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6631 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6632 emitLabel (tlbl->key + 100);
6635 l = aopGet (AOP (result), offset--, FALSE);
6638 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6646 emitLabel (tlbl1->key + 100);
6648 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6650 freeAsmop (left, NULL, ic);
6651 freeAsmop (result, NULL, ic);
6655 /*-----------------------------------------------------------------*/
6656 /* genUnpackBits - generates code for unpacking bits */
6657 /*-----------------------------------------------------------------*/
6659 genUnpackBits (operand * result, int pair)
6661 int offset = 0; /* result byte offset */
6662 int rsize; /* result size */
6663 int rlen = 0; /* remaining bitfield length */
6664 sym_link *etype; /* bitfield type information */
6665 int blen; /* bitfield length */
6666 int bstr; /* bitfield starting bit within byte */
6668 emitDebug ("; genUnpackBits");
6670 etype = getSpec (operandType (result));
6671 rsize = getSize (operandType (result));
6672 blen = SPEC_BLEN (etype);
6673 bstr = SPEC_BSTR (etype);
6675 /* If the bitfield length is less than a byte */
6678 emit2 ("ld a,!*pair", _pairs[pair].name);
6680 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6681 if (!SPEC_USIGN (etype))
6683 /* signed bitfield */
6684 symbol *tlbl = newiTempLabel (NULL);
6686 emit2 ("bit %d,a", blen - 1);
6687 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6688 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6689 emitLabel (tlbl->key + 100);
6691 aopPut (AOP (result), "a", offset++);
6695 /* TODO: what if pair == PAIR_DE ? */
6696 if (getPairId (AOP (result)) == PAIR_HL)
6698 wassertl (rsize == 2, "HL must be of size 2");
6699 emit2 ("ld a,!*hl");
6701 emit2 ("ld h,!*hl");
6704 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6705 if (!SPEC_USIGN (etype))
6707 /* signed bitfield */
6708 symbol *tlbl = newiTempLabel (NULL);
6710 emit2 ("bit %d,a", blen - 1);
6711 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6712 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6713 emitLabel (tlbl->key + 100);
6716 spillPair (PAIR_HL);
6720 /* Bit field did not fit in a byte. Copy all
6721 but the partial byte at the end. */
6722 for (rlen=blen;rlen>=8;rlen-=8)
6724 emit2 ("ld a,!*pair", _pairs[pair].name);
6725 aopPut (AOP (result), "a", offset++);
6728 emit2 ("inc %s", _pairs[pair].name);
6729 _G.pairs[pair].offset++;
6733 /* Handle the partial byte at the end */
6736 emit2 ("ld a,!*pair", _pairs[pair].name);
6737 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6738 if (!SPEC_USIGN (etype))
6740 /* signed bitfield */
6741 symbol *tlbl = newiTempLabel (NULL);
6743 emit2 ("bit %d,a", rlen - 1);
6744 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6745 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6746 emitLabel (tlbl->key + 100);
6748 aopPut (AOP (result), "a", offset++);
6756 if (SPEC_USIGN (etype))
6760 /* signed bitfield: sign extension with 0x00 or 0xff */
6768 aopPut (AOP (result), source, offset++);
6772 /*-----------------------------------------------------------------*/
6773 /* genGenPointerGet - get value from generic pointer space */
6774 /*-----------------------------------------------------------------*/
6776 genGenPointerGet (operand * left,
6777 operand * result, iCode * ic)
6780 sym_link *retype = getSpec (operandType (result));
6786 aopOp (left, ic, FALSE, FALSE);
6787 aopOp (result, ic, FALSE, FALSE);
6789 size = AOP_SIZE (result);
6791 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6794 if (isPtrPair (AOP (left)))
6796 tsprintf (buffer, sizeof(buffer),
6797 "!*pair", getPairName (AOP (left)));
6798 aopPut (AOP (result), buffer, 0);
6802 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6803 aopPut (AOP (result), "a", 0);
6805 freeAsmop (left, NULL, ic);
6809 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6816 tsprintf (at, sizeof(at), "!*iyx", offset);
6817 aopPut (AOP (result), at, offset);
6821 freeAsmop (left, NULL, ic);
6825 /* For now we always load into IY */
6826 /* if this is remateriazable */
6827 fetchPair (pair, AOP (left));
6829 /* if bit then unpack */
6830 if (IS_BITVAR (retype))
6832 genUnpackBits (result, pair);
6833 freeAsmop (left, NULL, ic);
6837 else if (getPairId (AOP (result)) == PAIR_HL)
6839 wassertl (size == 2, "HL must be of size 2");
6840 emit2 ("ld a,!*hl");
6842 emit2 ("ld h,!*hl");
6844 spillPair (PAIR_HL);
6846 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6848 size = AOP_SIZE (result);
6853 /* PENDING: make this better */
6854 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6856 aopPut (AOP (result), "!*hl", offset++);
6860 emit2 ("ld a,!*pair", _pairs[pair].name);
6861 aopPut (AOP (result), "a", offset++);
6865 emit2 ("inc %s", _pairs[pair].name);
6866 _G.pairs[pair].offset++;
6869 /* Fixup HL back down */
6870 for (size = AOP_SIZE (result)-1; size; size--)
6872 emit2 ("dec %s", _pairs[pair].name);
6877 size = AOP_SIZE (result);
6882 /* PENDING: make this better */
6884 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6886 aopPut (AOP (result), "!*hl", offset++);
6890 emit2 ("ld a,!*pair", _pairs[pair].name);
6891 aopPut (AOP (result), "a", offset++);
6895 emit2 ("inc %s", _pairs[pair].name);
6896 _G.pairs[pair].offset++;
6901 freeAsmop (left, NULL, ic);
6904 freeAsmop (result, NULL, ic);
6907 /*-----------------------------------------------------------------*/
6908 /* genPointerGet - generate code for pointer get */
6909 /*-----------------------------------------------------------------*/
6911 genPointerGet (iCode * ic)
6913 operand *left, *result;
6914 sym_link *type, *etype;
6916 left = IC_LEFT (ic);
6917 result = IC_RESULT (ic);
6919 /* depending on the type of pointer we need to
6920 move it to the correct pointer register */
6921 type = operandType (left);
6922 etype = getSpec (type);
6924 genGenPointerGet (left, result, ic);
6928 isRegOrLit (asmop * aop)
6930 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6936 /*-----------------------------------------------------------------*/
6937 /* genPackBits - generates code for packed bit storage */
6938 /*-----------------------------------------------------------------*/
6940 genPackBits (sym_link * etype,
6945 int offset = 0; /* source byte offset */
6946 int rlen = 0; /* remaining bitfield length */
6947 int blen; /* bitfield length */
6948 int bstr; /* bitfield starting bit within byte */
6949 int litval; /* source literal value (if AOP_LIT) */
6950 unsigned char mask; /* bitmask within current byte */
6951 int extraPair; /* a tempory register */
6952 bool needPopExtra=0; /* need to restore original value of temp reg */
6954 emitDebug ("; genPackBits","");
6956 blen = SPEC_BLEN (etype);
6957 bstr = SPEC_BSTR (etype);
6959 /* If the bitfield length is less than a byte */
6962 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6963 (unsigned char) (0xFF >> (8 - bstr)));
6965 if (AOP_TYPE (right) == AOP_LIT)
6967 /* Case with a bitfield length <8 and literal source
6969 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6971 litval &= (~mask) & 0xff;
6972 emit2 ("ld a,!*pair", _pairs[pair].name);
6973 if ((mask|litval)!=0xff)
6974 emit2 ("and a,!immedbyte", mask);
6976 emit2 ("or a,!immedbyte", litval);
6977 emit2 ("ld !*pair,a", _pairs[pair].name);
6982 /* Case with a bitfield length <8 and arbitrary source
6984 _moveA (aopGet (AOP (right), 0, FALSE));
6985 /* shift and mask source value */
6987 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6989 extraPair = getFreePairId(ic);
6990 if (extraPair == PAIR_INVALID)
6992 extraPair = PAIR_BC;
6993 if (getPairId (AOP (right)) != PAIR_BC
6994 || !isLastUse (ic, right))
7000 emit2 ("ld %s,a", _pairs[extraPair].l);
7001 emit2 ("ld a,!*pair", _pairs[pair].name);
7003 emit2 ("and a,!immedbyte", mask);
7004 emit2 ("or a,%s", _pairs[extraPair].l);
7005 emit2 ("ld !*pair,a", _pairs[pair].name);
7012 /* Bit length is greater than 7 bits. In this case, copy */
7013 /* all except the partial byte at the end */
7014 for (rlen=blen;rlen>=8;rlen-=8)
7016 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
7017 emit2 ("ld !*pair,a", _pairs[pair].name);
7020 emit2 ("inc %s", _pairs[pair].name);
7021 _G.pairs[pair].offset++;
7025 /* If there was a partial byte at the end */
7028 mask = (((unsigned char) -1 << rlen) & 0xff);
7030 if (AOP_TYPE (right) == AOP_LIT)
7032 /* Case with partial byte and literal source
7034 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7035 litval >>= (blen-rlen);
7036 litval &= (~mask) & 0xff;
7037 emit2 ("ld a,!*pair", _pairs[pair].name);
7038 if ((mask|litval)!=0xff)
7039 emit2 ("and a,!immedbyte", mask);
7041 emit2 ("or a,!immedbyte", litval);
7045 /* Case with partial byte and arbitrary source
7047 _moveA (aopGet (AOP (right), offset++, FALSE));
7048 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7050 extraPair = getFreePairId(ic);
7051 if (extraPair == PAIR_INVALID)
7053 extraPair = getPairId (AOP (right));
7054 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
7055 extraPair = PAIR_BC;
7057 if (getPairId (AOP (right)) != PAIR_BC
7058 || !isLastUse (ic, right))
7064 emit2 ("ld %s,a", _pairs[extraPair].l);
7065 emit2 ("ld a,!*pair", _pairs[pair].name);
7067 emit2 ("and a,!immedbyte", mask);
7068 emit2 ("or a,%s", _pairs[extraPair].l);
7073 emit2 ("ld !*pair,a", _pairs[pair].name);
7078 /*-----------------------------------------------------------------*/
7079 /* genGenPointerSet - stores the value into a pointer location */
7080 /*-----------------------------------------------------------------*/
7082 genGenPointerSet (operand * right,
7083 operand * result, iCode * ic)
7086 sym_link *retype = getSpec (operandType (right));
7087 sym_link *letype = getSpec (operandType (result));
7088 PAIR_ID pairId = PAIR_HL;
7091 aopOp (result, ic, FALSE, FALSE);
7092 aopOp (right, ic, FALSE, FALSE);
7097 size = AOP_SIZE (right);
7099 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
7100 emitDebug("; isBitvar = %d", isBitvar);
7102 /* Handle the exceptions first */
7103 if (isPair (AOP (result)) && size == 1 && !isBitvar)
7106 const char *l = aopGet (AOP (right), 0, FALSE);
7107 const char *pair = getPairName (AOP (result));
7108 if (canAssignToPtr (l) && isPtr (pair))
7110 emit2 ("ld !*pair,%s", pair, l);
7115 emit2 ("ld !*pair,a", pair);
7120 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7123 const char *l = aopGet (AOP (right), 0, FALSE);
7128 if (canAssignToPtr (l))
7130 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7134 _moveA (aopGet (AOP (right), offset, FALSE));
7135 emit2 ("ld !*iyx,a", offset);
7141 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7148 const char *l = aopGet (AOP (right), offset, FALSE);
7149 if (isRegOrLit (AOP (right)) && !IS_GB)
7151 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7156 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7160 emit2 ("inc %s", _pairs[PAIR_HL].name);
7161 _G.pairs[PAIR_HL].offset++;
7166 /* Fixup HL back down */
7167 for (size = AOP_SIZE (right)-1; size; size--)
7169 emit2 ("dec %s", _pairs[PAIR_HL].name);
7174 /* if the operand is already in dptr
7175 then we do nothing else we move the value to dptr */
7176 if (AOP_TYPE (result) != AOP_STR)
7178 fetchPair (pairId, AOP (result));
7180 /* so hl now contains the address */
7181 freeAsmop (result, NULL, ic);
7183 /* if bit then unpack */
7186 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7196 const char *l = aopGet (AOP (right), offset, FALSE);
7197 if (isRegOrLit (AOP (right)) && !IS_GB)
7199 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7204 emit2 ("ld !*pair,a", _pairs[pairId].name);
7208 emit2 ("inc %s", _pairs[pairId].name);
7209 _G.pairs[pairId].offset++;
7215 freeAsmop (right, NULL, ic);
7218 /*-----------------------------------------------------------------*/
7219 /* genPointerSet - stores the value into a pointer location */
7220 /*-----------------------------------------------------------------*/
7222 genPointerSet (iCode * ic)
7224 operand *right, *result;
7225 sym_link *type, *etype;
7227 right = IC_RIGHT (ic);
7228 result = IC_RESULT (ic);
7230 /* depending on the type of pointer we need to
7231 move it to the correct pointer register */
7232 type = operandType (result);
7233 etype = getSpec (type);
7235 genGenPointerSet (right, result, ic);
7238 /*-----------------------------------------------------------------*/
7239 /* genIfx - generate code for Ifx statement */
7240 /*-----------------------------------------------------------------*/
7242 genIfx (iCode * ic, iCode * popIc)
7244 operand *cond = IC_COND (ic);
7247 aopOp (cond, ic, FALSE, TRUE);
7249 /* get the value into acc */
7250 if (AOP_TYPE (cond) != AOP_CRY)
7254 /* the result is now in the accumulator */
7255 freeAsmop (cond, NULL, ic);
7257 /* if there was something to be popped then do it */
7261 /* if the condition is a bit variable */
7262 if (isbit && IS_ITEMP (cond) &&
7264 genIfxJump (ic, SPIL_LOC (cond)->rname);
7265 else if (isbit && !IS_ITEMP (cond))
7266 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7268 genIfxJump (ic, "a");
7273 /*-----------------------------------------------------------------*/
7274 /* genAddrOf - generates code for address of */
7275 /*-----------------------------------------------------------------*/
7277 genAddrOf (iCode * ic)
7279 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7281 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7283 /* if the operand is on the stack then we
7284 need to get the stack offset of this
7290 spillPair (PAIR_HL);
7291 if (sym->stack <= 0)
7293 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7297 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7299 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7303 emit2 ("ld de,!hashedstr", sym->rname);
7304 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7309 spillPair (PAIR_HL);
7312 /* if it has an offset then we need to compute it */
7314 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7316 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7317 emit2 ("add hl,sp");
7321 emit2 ("ld hl,!hashedstr", sym->rname);
7323 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7325 freeAsmop (IC_RESULT (ic), NULL, ic);
7328 /*-----------------------------------------------------------------*/
7329 /* genAssign - generate code for assignment */
7330 /*-----------------------------------------------------------------*/
7332 genAssign (iCode * ic)
7334 operand *result, *right;
7336 unsigned long lit = 0L;
7338 result = IC_RESULT (ic);
7339 right = IC_RIGHT (ic);
7341 /* Dont bother assigning if they are the same */
7342 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7344 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7348 aopOp (right, ic, FALSE, FALSE);
7349 aopOp (result, ic, TRUE, FALSE);
7351 /* if they are the same registers */
7352 if (sameRegs (AOP (right), AOP (result)))
7354 emitDebug ("; (registers are the same)");
7358 /* if the result is a bit */
7359 if (AOP_TYPE (result) == AOP_CRY)
7361 wassertl (0, "Tried to assign to a bit");
7365 size = AOP_SIZE (result);
7368 if (AOP_TYPE (right) == AOP_LIT)
7370 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7373 if (isPair (AOP (result)))
7375 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7377 else if ((size > 1) &&
7378 (AOP_TYPE (result) != AOP_REG) &&
7379 (AOP_TYPE (right) == AOP_LIT) &&
7380 !IS_FLOAT (operandType (right)) &&
7383 bool fXored = FALSE;
7385 /* Work from the top down.
7386 Done this way so that we can use the cached copy of 0
7387 in A for a fast clear */
7390 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7392 if (!fXored && size > 1)
7399 aopPut (AOP (result), "a", offset);
7403 aopPut (AOP (result), "!zero", offset);
7407 aopPut (AOP (result),
7408 aopGet (AOP (right), offset, FALSE),
7413 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7415 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7416 aopPut (AOP (result), "l", LSB);
7417 aopPut (AOP (result), "h", MSB16);
7419 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7421 /* Special case. Load into a and d, then load out. */
7422 _moveA (aopGet (AOP (right), 0, FALSE));
7423 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7424 aopPut (AOP (result), "a", 0);
7425 aopPut (AOP (result), "e", 1);
7427 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7429 /* Special case - simple memcpy */
7430 aopGet (AOP (right), LSB, FALSE);
7433 aopGet (AOP (result), LSB, FALSE);
7437 emit2 ("ld a,(de)");
7438 /* Peephole will optimise this. */
7439 emit2 ("ld (hl),a");
7447 spillPair (PAIR_HL);
7453 /* PENDING: do this check better */
7454 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7456 _moveA (aopGet (AOP (right), offset, FALSE));
7457 aopPut (AOP (result), "a", offset);
7460 aopPut (AOP (result),
7461 aopGet (AOP (right), offset, FALSE),
7468 freeAsmop (right, NULL, ic);
7469 freeAsmop (result, NULL, ic);
7472 /*-----------------------------------------------------------------*/
7473 /* genJumpTab - genrates code for jump table */
7474 /*-----------------------------------------------------------------*/
7476 genJumpTab (iCode * ic)
7481 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7482 /* get the condition into accumulator */
7483 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7486 emit2 ("ld e,%s", l);
7487 emit2 ("ld d,!zero");
7488 jtab = newiTempLabel (NULL);
7489 spillPair (PAIR_HL);
7490 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7491 emit2 ("add hl,de");
7492 emit2 ("add hl,de");
7493 emit2 ("add hl,de");
7494 freeAsmop (IC_JTCOND (ic), NULL, ic);
7498 emitLabel (jtab->key + 100);
7499 /* now generate the jump labels */
7500 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7501 jtab = setNextItem (IC_JTLABELS (ic)))
7502 emit2 ("jp !tlabel", jtab->key + 100);
7505 /*-----------------------------------------------------------------*/
7506 /* genCast - gen code for casting */
7507 /*-----------------------------------------------------------------*/
7509 genCast (iCode * ic)
7511 operand *result = IC_RESULT (ic);
7512 sym_link *rtype = operandType (IC_RIGHT (ic));
7513 operand *right = IC_RIGHT (ic);
7516 /* if they are equivalent then do nothing */
7517 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7520 aopOp (right, ic, FALSE, FALSE);
7521 aopOp (result, ic, FALSE, FALSE);
7523 /* if the result is a bit */
7524 if (AOP_TYPE (result) == AOP_CRY)
7526 wassertl (0, "Tried to cast to a bit");
7529 /* if they are the same size : or less */
7530 if (AOP_SIZE (result) <= AOP_SIZE (right))
7533 /* if they are in the same place */
7534 if (sameRegs (AOP (right), AOP (result)))
7537 /* if they in different places then copy */
7538 size = AOP_SIZE (result);
7542 aopPut (AOP (result),
7543 aopGet (AOP (right), offset, FALSE),
7550 /* So we now know that the size of destination is greater
7551 than the size of the source */
7552 /* we move to result for the size of source */
7553 size = AOP_SIZE (right);
7557 aopPut (AOP (result),
7558 aopGet (AOP (right), offset, FALSE),
7563 /* now depending on the sign of the destination */
7564 size = AOP_SIZE (result) - AOP_SIZE (right);
7565 /* Unsigned or not an integral type - right fill with zeros */
7566 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7569 aopPut (AOP (result), "!zero", offset++);
7573 /* we need to extend the sign :{ */
7574 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE);
7579 aopPut (AOP (result), "a", offset++);
7583 freeAsmop (right, NULL, ic);
7584 freeAsmop (result, NULL, ic);
7587 /*-----------------------------------------------------------------*/
7588 /* genReceive - generate code for a receive iCode */
7589 /*-----------------------------------------------------------------*/
7591 genReceive (iCode * ic)
7593 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7594 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7595 IS_TRUE_SYMOP (IC_RESULT (ic))))
7605 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7606 size = AOP_SIZE(IC_RESULT(ic));
7608 for (i = 0; i < size; i++) {
7609 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7613 freeAsmop (IC_RESULT (ic), NULL, ic);
7616 /*-----------------------------------------------------------------*/
7617 /* genDummyRead - generate code for dummy read of volatiles */
7618 /*-----------------------------------------------------------------*/
7620 genDummyRead (iCode * ic)
7626 if (op && IS_SYMOP (op))
7628 aopOp (op, ic, FALSE, FALSE);
7631 size = AOP_SIZE (op);
7636 _moveA (aopGet (AOP (op), offset, FALSE));
7640 freeAsmop (op, NULL, ic);
7644 if (op && IS_SYMOP (op))
7646 aopOp (op, ic, FALSE, FALSE);
7649 size = AOP_SIZE (op);
7654 _moveA (aopGet (AOP (op), offset, FALSE));
7658 freeAsmop (op, NULL, ic);
7662 /*-----------------------------------------------------------------*/
7663 /* genCritical - generate code for start of a critical sequence */
7664 /*-----------------------------------------------------------------*/
7666 genCritical (iCode *ic)
7668 symbol *tlbl = newiTempLabel (NULL);
7674 else if (IC_RESULT (ic))
7676 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7677 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7678 //get interrupt enable flag IFF2 into P/O
7682 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7683 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7684 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7685 emit2 ("!tlabeldef", (tlbl->key + 100));
7686 _G.lines.current->isLabel = 1;
7687 freeAsmop (IC_RESULT (ic), NULL, ic);
7691 //get interrupt enable flag IFF2 into P/O
7700 /*-----------------------------------------------------------------*/
7701 /* genEndCritical - generate code for end of a critical sequence */
7702 /*-----------------------------------------------------------------*/
7704 genEndCritical (iCode *ic)
7706 symbol *tlbl = newiTempLabel (NULL);
7712 else if (IC_RIGHT (ic))
7714 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7715 _toBoolean (IC_RIGHT (ic));
7716 //don't enable interrupts if they were off before
7717 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7719 emitLabel (tlbl->key + 100);
7720 freeAsmop (IC_RIGHT (ic), NULL, ic);
7726 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7727 //don't enable interrupts as they were off before
7728 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7730 emit2 ("!tlabeldef", (tlbl->key + 100));
7731 _G.lines.current->isLabel = 1;
7737 /** Maximum number of bytes to emit per line. */
7741 /** Context for the byte output chunker. */
7744 unsigned char buffer[DBEMIT_MAX_RUN];
7749 /** Flushes a byte chunker by writing out all in the buffer and
7753 _dbFlush(DBEMITCTX *self)
7760 sprintf(line, ".db 0x%02X", self->buffer[0]);
7762 for (i = 1; i < self->pos; i++)
7764 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7771 /** Write out another byte, buffering until a decent line is
7775 _dbEmit(DBEMITCTX *self, int c)
7777 if (self->pos == DBEMIT_MAX_RUN)
7781 self->buffer[self->pos++] = c;
7784 /** Context for a simple run length encoder. */
7788 unsigned char buffer[128];
7790 /** runLen may be equivalent to pos. */
7796 RLE_CHANGE_COST = 4,
7800 /** Flush the buffer of a run length encoder by writing out the run or
7801 data that it currently contains.
7804 _rleCommit(RLECTX *self)
7810 memset(&db, 0, sizeof(db));
7812 emit2(".db %u", self->pos);
7814 for (i = 0; i < self->pos; i++)
7816 _dbEmit(&db, self->buffer[i]);
7825 Can get either a run or a block of random stuff.
7826 Only want to change state if a good run comes in or a run ends.
7827 Detecting run end is easy.
7830 Say initial state is in run, len zero, last zero. Then if you get a
7831 few zeros then something else then a short run will be output.
7832 Seems OK. While in run mode, keep counting. While in random mode,
7833 keep a count of the run. If run hits margin, output all up to run,
7834 restart, enter run mode.
7837 /** Add another byte into the run length encoder, flushing as
7838 required. The run length encoder uses the Amiga IFF style, where
7839 a block is prefixed by its run length. A positive length means
7840 the next n bytes pass straight through. A negative length means
7841 that the next byte is repeated -n times. A zero terminates the
7845 _rleAppend(RLECTX *self, unsigned c)
7849 if (c != self->last)
7851 /* The run has stopped. See if it is worthwhile writing it out
7852 as a run. Note that the random data comes in as runs of
7855 if (self->runLen > RLE_CHANGE_COST)
7857 /* Yes, worthwhile. */
7858 /* Commit whatever was in the buffer. */
7860 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7864 /* Not worthwhile. Append to the end of the random list. */
7865 for (i = 0; i < self->runLen; i++)
7867 if (self->pos >= RLE_MAX_BLOCK)
7872 self->buffer[self->pos++] = self->last;
7880 if (self->runLen >= RLE_MAX_BLOCK)
7882 /* Commit whatever was in the buffer. */
7885 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7893 _rleFlush(RLECTX *self)
7895 _rleAppend(self, -1);
7902 /** genArrayInit - Special code for initialising an array with constant
7906 genArrayInit (iCode * ic)
7910 int elementSize = 0, eIndex, i;
7911 unsigned val, lastVal;
7915 memset(&rle, 0, sizeof(rle));
7917 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7919 _saveRegsForCall(ic, 0);
7921 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7922 emit2 ("call __initrleblock");
7924 type = operandType(IC_LEFT(ic));
7926 if (type && type->next)
7928 if (IS_SPEC(type->next) || IS_PTR(type->next))
7930 elementSize = getSize(type->next);
7932 else if (IS_ARRAY(type->next) && type->next->next)
7934 elementSize = getSize(type->next->next);
7938 printTypeChainRaw (type, NULL);
7939 wassertl (0, "Can't determine element size in genArrayInit.");
7944 wassertl (0, "Can't determine element size in genArrayInit.");
7947 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7949 iLoop = IC_ARRAYILIST(ic);
7950 lastVal = (unsigned)-1;
7952 /* Feed all the bytes into the run length encoder which will handle
7954 This works well for mixed char data, and for random int and long
7961 for (i = 0; i < ix; i++)
7963 for (eIndex = 0; eIndex < elementSize; eIndex++)
7965 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7966 _rleAppend(&rle, val);
7970 iLoop = iLoop->next;
7974 /* Mark the end of the run. */
7977 _restoreRegsAfterCall();
7981 freeAsmop (IC_LEFT(ic), NULL, ic);
7985 _swap (PAIR_ID one, PAIR_ID two)
7987 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7993 emit2 ("ld a,%s", _pairs[one].l);
7994 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7995 emit2 ("ld %s,a", _pairs[two].l);
7996 emit2 ("ld a,%s", _pairs[one].h);
7997 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7998 emit2 ("ld %s,a", _pairs[two].h);
8002 /* The problem is that we may have all three pairs used and they may
8003 be needed in a different order.
8008 hl = hl => unity, fine
8012 hl = hl hl = hl, swap de <=> bc
8020 hl = bc de = de, swap bc <=> hl
8028 hl = de bc = bc, swap hl <=> de
8033 * Any pair = pair are done last
8034 * Any pair = iTemp are done last
8035 * Any swaps can be done any time
8043 So how do we detect the cases?
8044 How about a 3x3 matrix?
8048 x x x x (Fourth for iTemp/other)
8050 First determin which mode to use by counting the number of unity and
8053 Two - Assign the pair first, then the rest
8054 One - Swap the two, then the rest
8058 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
8060 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
8062 PAIR_BC, PAIR_HL, PAIR_DE
8064 int i, j, nunity = 0;
8065 memset (ids, PAIR_INVALID, sizeof (ids));
8068 wassert (nparams == 3);
8070 /* First save everything that needs to be saved. */
8071 _saveRegsForCall (ic, 0);
8073 /* Loading HL first means that DE is always fine. */
8074 for (i = 0; i < nparams; i++)
8076 aopOp (pparams[i], ic, FALSE, FALSE);
8077 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
8080 /* Count the number of unity or iTemp assigns. */
8081 for (i = 0; i < 3; i++)
8083 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
8091 /* Any order, fall through. */
8093 else if (nunity == 2)
8095 /* One is assigned. Pull it out and assign. */
8096 for (i = 0; i < 3; i++)
8098 for (j = 0; j < NUM_PAIRS; j++)
8100 if (ids[dest[i]][j] == TRUE)
8102 /* Found it. See if it's the right one. */
8103 if (j == PAIR_INVALID || j == dest[i])
8109 fetchPair(dest[i], AOP (pparams[i]));
8116 else if (nunity == 1)
8118 /* Find the pairs to swap. */
8119 for (i = 0; i < 3; i++)
8121 for (j = 0; j < NUM_PAIRS; j++)
8123 if (ids[dest[i]][j] == TRUE)
8125 if (j == PAIR_INVALID || j == dest[i])
8140 int next = getPairId (AOP (pparams[0]));
8141 emit2 ("push %s", _pairs[next].name);
8143 if (next == dest[1])
8145 fetchPair (dest[1], AOP (pparams[1]));
8146 fetchPair (dest[2], AOP (pparams[2]));
8150 fetchPair (dest[2], AOP (pparams[2]));
8151 fetchPair (dest[1], AOP (pparams[1]));
8153 emit2 ("pop %s", _pairs[dest[0]].name);
8156 /* Finally pull out all of the iTemps */
8157 for (i = 0; i < 3; i++)
8159 if (ids[dest[i]][PAIR_INVALID] == 1)
8161 fetchPair (dest[i], AOP (pparams[i]));
8167 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
8173 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
8177 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8179 setupForBuiltin3 (ic, nParams, pparams);
8181 label = newiTempLabel(NULL);
8183 emitLabel (label->key);
8184 emit2 ("ld a,(hl)");
8187 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
8189 freeAsmop (from, NULL, ic->next);
8190 freeAsmop (to, NULL, ic);
8194 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8196 operand *from, *to, *count;
8199 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8204 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8206 setupForBuiltin3 (ic, nParams, pparams);
8210 freeAsmop (count, NULL, ic->next->next);
8211 freeAsmop (from, NULL, ic);
8213 _restoreRegsAfterCall();
8215 /* if we need assign a result value */
8216 if ((IS_ITEMP (IC_RESULT (ic)) &&
8217 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8218 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8219 IS_TRUE_SYMOP (IC_RESULT (ic)))
8221 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8222 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8223 freeAsmop (IC_RESULT (ic), NULL, ic);
8226 freeAsmop (to, NULL, ic->next);
8229 /*-----------------------------------------------------------------*/
8230 /* genBuiltIn - calls the appropriate function to generating code */
8231 /* for a built in function */
8232 /*-----------------------------------------------------------------*/
8233 static void genBuiltIn (iCode *ic)
8235 operand *bi_parms[MAX_BUILTIN_ARGS];
8240 /* get all the arguments for a built in function */
8241 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8243 /* which function is it */
8244 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8246 if (strcmp(bif->name,"__builtin_strcpy")==0)
8248 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8250 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8252 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8256 wassertl (0, "Unknown builtin function encountered");
8260 /*-----------------------------------------------------------------*/
8261 /* genZ80Code - generate code for Z80 based controllers */
8262 /*-----------------------------------------------------------------*/
8264 genZ80Code (iCode * lic)
8272 _fReturn = _gbz80_return;
8273 _fTmp = _gbz80_return;
8277 _fReturn = _z80_return;
8278 _fTmp = _z80_return;
8281 _G.lines.head = _G.lines.current = NULL;
8283 /* if debug information required */
8284 if (options.debug && currFunc)
8286 debugFile->writeFunction (currFunc, lic);
8289 for (ic = lic; ic; ic = ic->next)
8291 _G.current_iCode = ic;
8293 if (ic->lineno && cln != ic->lineno)
8297 debugFile->writeCLine (ic);
8299 if (!options.noCcodeInAsm)
8301 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8302 printCLine(ic->filename, ic->lineno));
8306 if (options.iCodeInAsm)
8308 const char *iLine = printILine(ic);
8309 emit2 (";ic:%d: %s", ic->key, iLine);
8312 /* if the result is marked as
8313 spilt and rematerializable or code for
8314 this has already been generated then
8316 if (resultRemat (ic) || ic->generated)
8319 /* depending on the operation */
8323 emitDebug ("; genNot");
8328 emitDebug ("; genCpl");
8333 emitDebug ("; genUminus");
8338 emitDebug ("; genIpush");
8343 /* IPOP happens only when trying to restore a
8344 spilt live range, if there is an ifx statement
8345 following this pop then the if statement might
8346 be using some of the registers being popped which
8347 would destroy the contents of the register so
8348 we need to check for this condition and handle it */
8350 ic->next->op == IFX &&
8351 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8353 emitDebug ("; genIfx");
8354 genIfx (ic->next, ic);
8358 emitDebug ("; genIpop");
8364 emitDebug ("; genCall");
8369 emitDebug ("; genPcall");
8374 emitDebug ("; genFunction");
8379 emitDebug ("; genEndFunction");
8380 genEndFunction (ic);
8384 emitDebug ("; genRet");
8389 emitDebug ("; genLabel");
8394 emitDebug ("; genGoto");
8399 emitDebug ("; genPlus");
8404 emitDebug ("; genMinus");
8409 emitDebug ("; genMult");
8414 emitDebug ("; genDiv");
8419 emitDebug ("; genMod");
8424 emitDebug ("; genCmpGt");
8425 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8429 emitDebug ("; genCmpLt");
8430 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8437 /* note these two are xlated by algebraic equivalence
8438 during parsing SDCC.y */
8439 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8440 "got '>=' or '<=' shouldn't have come here");
8444 emitDebug ("; genCmpEq");
8445 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8449 emitDebug ("; genAndOp");
8454 emitDebug ("; genOrOp");
8459 emitDebug ("; genXor");
8460 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8464 emitDebug ("; genOr");
8465 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8469 emitDebug ("; genAnd");
8470 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8474 emitDebug ("; genInline");
8479 emitDebug ("; genRRC");
8484 emitDebug ("; genRLC");
8489 emitDebug ("; genGetHBIT");
8494 emitDebug ("; genLeftShift");
8499 emitDebug ("; genRightShift");
8503 case GET_VALUE_AT_ADDRESS:
8504 emitDebug ("; genPointerGet");
8510 if (POINTER_SET (ic))
8512 emitDebug ("; genAssign (pointer)");
8517 emitDebug ("; genAssign");
8523 emitDebug ("; genIfx");
8528 emitDebug ("; genAddrOf");
8533 emitDebug ("; genJumpTab");
8538 emitDebug ("; genCast");
8543 emitDebug ("; genReceive");
8548 if (ic->builtinSEND)
8550 emitDebug ("; genBuiltIn");
8555 emitDebug ("; addSet");
8556 addSet (&_G.sendSet, ic);
8561 emitDebug ("; genArrayInit");
8565 case DUMMY_READ_VOLATILE:
8566 emitDebug ("; genDummyRead");
8571 emitDebug ("; genCritical");
8576 emitDebug ("; genEndCritical");
8577 genEndCritical (ic);
8586 /* now we are ready to call the
8587 peep hole optimizer */
8588 if (!options.nopeep)
8589 peepHole (&_G.lines.head);
8591 /* This is unfortunate */
8592 /* now do the actual printing */
8594 struct dbuf_s *buf = codeOutBuf;
8595 if (isInHome () && codeOutBuf == &code->oBuf)
8596 codeOutBuf = &home->oBuf;
8597 printLine (_G.lines.head, codeOutBuf);
8598 if (_G.flushStatics)
8601 _G.flushStatics = 0;
8606 freeTrace(&_G.lines.trace);
8607 freeTrace(&_G.trace.aops);
8613 _isPairUsed (iCode * ic, PAIR_ID pairId)
8619 if (bitVectBitValue (ic->rMask, D_IDX))
8621 if (bitVectBitValue (ic->rMask, E_IDX))
8631 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8634 value *val = aop->aopu.aop_lit;
8636 wassert (aop->type == AOP_LIT);
8637 wassert (!IS_FLOAT (val->type));
8639 v = ulFromVal (val);
8647 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8648 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));