1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
91 #include "SDCCglobl.h"
92 #include "SDCCpeeph.h"
97 /* This is the down and dirty file with all kinds of kludgy & hacky
98 stuff. This is what it is all about CODE GENERATION for a specific MCU.
99 Some of the routines may be reusable, will have to see */
101 /* Z80 calling convention description.
102 Parameters are passed right to left. As the stack grows downwards,
103 the parameters are arranged in left to right in memory.
104 Parameters may be passed in the HL and DE registers with one
106 PENDING: What if the parameter is a long?
107 Everything is caller saves. i.e. the caller must save any registers
108 that it wants to preserve over the call.
109 GB: The return value is returned in DEHL. DE is normally used as a
110 working register pair. Caller saves allows it to be used for a
112 va args functions do not use register parameters. All arguments
113 are passed on the stack.
114 IX is used as an index register to the top of the local variable
115 area. ix-0 is the top most local variable.
120 /* Set to enable debugging trace statements in the output assembly code. */
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129 { "c", "b", "e", "d" };
131 static char **_fReturn;
134 extern struct dbuf_s *codeOutBuf;
142 /** Enum covering all the possible register pairs.
161 } _pairs[NUM_PAIRS] = {
162 { "??1", "?2", "?3" },
167 { "iy", "iyl", "iyh" },
168 { "ix", "ixl", "ixh" }
172 #define ACC_NAME _pairs[PAIR_AF].h
182 /** Code generator persistent data.
186 /** Used to optimised setting up of a pair by remebering what it
187 contains and adjusting instead of reloading where possible.
216 const char *lastFunctionName;
217 iCode *current_iCode;
224 /** TRUE if the registers have already been saved. */
243 static const char *aopGet (asmop * aop, int offset, bool bit16);
245 static const char *aopNames[] = {
266 isLastUse (iCode *ic, operand *op)
268 bitVect *uses = bitVectCopy (OP_USES (op));
270 while (!bitVectIsZero (uses))
272 if (bitVectFirstBit (uses) == ic->key)
274 if (bitVectnBitsOn (uses) == 1)
283 bitVectUnSetBit (uses, bitVectFirstBit (uses));
303 _getTempPairName(void)
305 return _pairs[_getTempPairId()].name;
309 isPairInUse (PAIR_ID id, iCode *ic)
313 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
315 else if (id == PAIR_BC)
317 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
321 wassertl (0, "Only implemented for DE and BC");
327 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
331 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
335 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
339 wassertl (0, "Only implemented for DE");
345 getFreePairId (iCode *ic)
347 if (!isPairInUse (PAIR_BC, ic))
351 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
364 /* Clean up the line so that it is 'prettier' */
365 if (strchr (buf, ':'))
367 /* Is a label - cant do anything */
370 /* Change the first (and probably only) ' ' to a tab so
385 _newLineNode (const char *line)
389 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
390 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
396 _vemit2 (const char *szFormat, va_list ap)
401 dbuf_init(&dbuf, INITIAL_INLINEASM);
403 dbuf_tvprintf (&dbuf, szFormat, ap);
405 buffer = (char *)dbuf_c_str(&dbuf);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
413 _G.lines.current->isDebug = _G.lines.isDebug;
414 _G.lines.current->ic = _G.current_iCode;
415 _G.lines.current->isComment = (*buffer == ';');
421 emit2 (const char *szFormat,...)
425 va_start (ap, szFormat);
427 _vemit2 (szFormat, ap);
433 emitDebug (const char *szFormat,...)
435 if (!options.verboseAsm)
441 va_start (ap, szFormat);
443 _vemit2 (szFormat, ap);
449 /*-----------------------------------------------------------------*/
450 /* z80_emitDebuggerSymbol - associate the current code location */
451 /* with a debugger symbol */
452 /*-----------------------------------------------------------------*/
454 z80_emitDebuggerSymbol (char * debugSym)
456 _G.lines.isDebug = 1;
457 emit2 ("%s !equ .", debugSym);
458 emit2 ("!global", debugSym);
459 _G.lines.isDebug = 0;
462 /*-----------------------------------------------------------------*/
463 /* emit2 - writes the code into a file : for now it is simple */
464 /*-----------------------------------------------------------------*/
466 _emit2 (const char *inst, const char *fmt,...)
469 char lb[INITIAL_INLINEASM];
476 sprintf (lb, "%s\t", inst);
477 vsprintf (lb + (strlen (lb)), fmt, ap);
480 vsprintf (lb, fmt, ap);
482 while (isspace (*lbp))
487 _G.lines.current = (_G.lines.current ?
488 connectLine (_G.lines.current, _newLineNode (lb)) :
489 (_G.lines.head = _newLineNode (lb)));
491 _G.lines.current->isInline = _G.lines.isInline;
492 _G.lines.current->ic = _G.current_iCode;
497 _emitMove(const char *to, const char *from)
499 if (STRCASECMP(to, from) != 0)
501 emit2("ld %s,%s", to, from);
506 // Could leave this to the peephole, but sometimes the peephole is inhibited.
511 aopDump(const char *plabel, asmop *aop)
517 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
522 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
525 for (i=aop->size-1;i>=0;i--)
526 *rbp++ = *(aop->aopu.aop_reg[i]->name);
528 emitDebug("; reg = %s", regbuf);
531 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
534 /* No information. */
540 _moveA(const char *moveFrom)
542 // Let the peephole optimiser take care of redundent loads
543 _emitMove(ACC_NAME, moveFrom);
553 getPairName (asmop * aop)
555 if (aop->type == AOP_REG)
557 switch (aop->aopu.aop_reg[0]->rIdx)
570 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
573 for (i = 0; i < NUM_PAIRS; i++)
575 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
577 return _pairs[i].name;
581 wassertl (0, "Tried to get the pair name of something that isn't a pair");
586 getPairId (asmop * aop)
590 if (aop->type == AOP_REG)
592 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
596 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
600 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
605 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
608 for (i = 0; i < NUM_PAIRS; i++)
610 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
620 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
624 return (getPairId (aop) != PAIR_INVALID);
627 /** Returns TRUE if the registers used in aop cannot be split into high
630 isUnsplitable (asmop * aop)
632 switch (getPairId (aop))
644 isPtrPair (asmop * aop)
646 PAIR_ID pairId = getPairId (aop);
659 spillPair (PAIR_ID pairId)
661 _G.pairs[pairId].last_type = AOP_INVALID;
662 _G.pairs[pairId].base = NULL;
665 /* Given a register name, spill the pair (if any) the register is part of */
667 spillPairReg (const char *regname)
669 if (strlen(regname)==1)
689 /** Push a register pair onto the stack */
691 genPairPush (asmop * aop)
693 emit2 ("push %s", getPairName (aop));
697 _push (PAIR_ID pairId)
699 emit2 ("push %s", _pairs[pairId].name);
700 _G.stack.pushed += 2;
704 _pop (PAIR_ID pairId)
706 if (pairId != PAIR_INVALID)
708 emit2 ("pop %s", _pairs[pairId].name);
709 _G.stack.pushed -= 2;
715 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
728 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
735 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
736 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
739 wassertl (0, "Tried to move a nonphysical pair");
741 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
742 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
743 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
747 /*-----------------------------------------------------------------*/
748 /* newAsmop - creates a new asmOp */
749 /*-----------------------------------------------------------------*/
751 newAsmop (short type)
755 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
760 /*-----------------------------------------------------------------*/
761 /* aopForSym - for a true symbol */
762 /*-----------------------------------------------------------------*/
764 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
771 wassert (sym->etype);
773 space = SPEC_OCLS (sym->etype);
775 /* if already has one */
781 /* Assign depending on the storage class */
782 if (sym->onStack || sym->iaccess)
784 /* The pointer that is used depends on how big the offset is.
785 Normally everything is AOP_STK, but for offsets of < -128 or
786 > 127 on the Z80 an extended stack pointer is used.
788 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
790 emitDebug ("; AOP_EXSTK for %s", sym->rname);
791 sym->aop = aop = newAsmop (AOP_EXSTK);
795 emitDebug ("; AOP_STK for %s", sym->rname);
796 sym->aop = aop = newAsmop (AOP_STK);
799 aop->size = getSize (sym->type);
800 aop->aopu.aop_stk = sym->stack;
804 /* special case for a function */
805 if (IS_FUNC (sym->type))
807 sym->aop = aop = newAsmop (AOP_IMMD);
808 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
813 if( IN_REGSP( space ))
814 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
817 /* if it is in direct space */
820 sym->aop = aop = newAsmop (AOP_SFR);
821 aop->aopu.aop_dir = sym->rname;
822 aop->size = getSize (sym->type);
823 emitDebug ("; AOP_SFR for %s", sym->rname);
828 { /*.p.t.20030716 adding SFR support to the Z80 port */
829 aop = newAsmop (AOP_SFR);
831 aop->aopu.aop_dir = sym->rname;
832 aop->size = getSize( sym->type );
833 aop->paged = FUNC_REGBANK(sym->type);
834 aop->bcInUse = isPairInUse( PAIR_BC, ic );
835 aop->deInUse = isPairInUse( PAIR_DE, ic );
836 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
842 /* only remaining is far space */
843 /* in which case DPTR gets the address */
846 emitDebug ("; AOP_HL for %s", sym->rname);
847 sym->aop = aop = newAsmop (AOP_HL);
851 sym->aop = aop = newAsmop (AOP_IY);
853 aop->size = getSize (sym->type);
854 aop->aopu.aop_dir = sym->rname;
856 /* if it is in code space */
857 if (IN_CODESPACE (space))
863 /*-----------------------------------------------------------------*/
864 /* aopForRemat - rematerialzes an object */
865 /*-----------------------------------------------------------------*/
867 aopForRemat (symbol * sym)
870 iCode *ic = sym->rematiCode;
871 asmop *aop = newAsmop (AOP_IMMD);
875 /* if plus or minus print the right hand side */
876 if (ic->op == '+' || ic->op == '-')
878 /* PENDING: for re-target */
879 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
882 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
885 /* we reached the end */
886 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
890 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
894 /*-----------------------------------------------------------------*/
895 /* regsInCommon - two operands have some registers in common */
896 /*-----------------------------------------------------------------*/
898 regsInCommon (operand * op1, operand * op2)
903 /* if they have registers in common */
904 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
907 sym1 = OP_SYMBOL (op1);
908 sym2 = OP_SYMBOL (op2);
910 if (sym1->nRegs == 0 || sym2->nRegs == 0)
913 for (i = 0; i < sym1->nRegs; i++)
919 for (j = 0; j < sym2->nRegs; j++)
924 if (sym2->regs[j] == sym1->regs[i])
932 /*-----------------------------------------------------------------*/
933 /* operandsEqu - equivalent */
934 /*-----------------------------------------------------------------*/
936 operandsEqu (operand * op1, operand * op2)
940 /* if they not symbols */
941 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
944 sym1 = OP_SYMBOL (op1);
945 sym2 = OP_SYMBOL (op2);
947 /* if both are itemps & one is spilt
948 and the other is not then false */
949 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
950 sym1->isspilt != sym2->isspilt)
953 /* if they are the same */
957 if (sym1->rname[0] && sym2->rname[0]
958 && strcmp (sym1->rname, sym2->rname) == 0)
961 /* if left is a tmp & right is not */
962 if (IS_ITEMP (op1) &&
965 (sym1->usl.spillLoc == sym2))
968 if (IS_ITEMP (op2) &&
972 (sym2->usl.spillLoc == sym1))
978 /*-----------------------------------------------------------------*/
979 /* sameRegs - two asmops have the same registers */
980 /*-----------------------------------------------------------------*/
982 sameRegs (asmop * aop1, asmop * aop2)
986 if (aop1->type == AOP_SFR ||
987 aop2->type == AOP_SFR)
993 if (aop1->type != AOP_REG ||
994 aop2->type != AOP_REG)
997 if (aop1->size != aop2->size)
1000 for (i = 0; i < aop1->size; i++)
1001 if (aop1->aopu.aop_reg[i] !=
1002 aop2->aopu.aop_reg[i])
1008 /*-----------------------------------------------------------------*/
1009 /* aopOp - allocates an asmop for an operand : */
1010 /*-----------------------------------------------------------------*/
1012 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1021 /* if this a literal */
1022 if (IS_OP_LITERAL (op))
1024 op->aop = aop = newAsmop (AOP_LIT);
1025 aop->aopu.aop_lit = op->operand.valOperand;
1026 aop->size = getSize (operandType (op));
1030 /* if already has a asmop then continue */
1033 if (op->aop->type == AOP_SFR)
1035 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1036 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1041 /* if the underlying symbol has a aop */
1042 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1044 op->aop = OP_SYMBOL (op)->aop;
1045 if (op->aop->type == AOP_SFR)
1047 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1048 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1053 /* if this is a true symbol */
1054 if (IS_TRUE_SYMOP (op))
1056 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1060 /* this is a temporary : this has
1066 e) can be a return use only */
1068 sym = OP_SYMBOL (op);
1070 /* if the type is a conditional */
1071 if (sym->regType == REG_CND)
1073 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1078 /* if it is spilt then two situations
1080 b) has a spill location */
1081 if (sym->isspilt || sym->nRegs == 0)
1083 /* rematerialize it NOW */
1086 sym->aop = op->aop = aop =
1088 aop->size = getSize (sym->type);
1095 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1096 aop->size = getSize (sym->type);
1097 for (i = 0; i < 4; i++)
1098 aop->aopu.aop_str[i] = _fReturn[i];
1104 if (sym->accuse == ACCUSE_A)
1106 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1107 aop->size = getSize (sym->type);
1108 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1110 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1112 else if (sym->accuse == ACCUSE_SCRATCH)
1114 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1115 aop->size = getSize (sym->type);
1116 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1117 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1118 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1120 else if (sym->accuse == ACCUSE_IY)
1122 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1123 aop->size = getSize (sym->type);
1124 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1125 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1126 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1130 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1135 if (sym->usl.spillLoc)
1137 asmop *oldAsmOp = NULL;
1139 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1141 /* force a new aop if sizes differ */
1142 oldAsmOp = sym->usl.spillLoc->aop;
1143 sym->usl.spillLoc->aop = NULL;
1145 sym->aop = op->aop = aop =
1146 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1147 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1149 /* Don't reuse the new aop, go with the last one */
1150 sym->usl.spillLoc->aop = oldAsmOp;
1152 aop->size = getSize (sym->type);
1156 /* else must be a dummy iTemp */
1157 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1158 aop->size = getSize (sym->type);
1162 /* must be in a register */
1163 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1164 aop->size = sym->nRegs;
1165 for (i = 0; i < sym->nRegs; i++)
1166 aop->aopu.aop_reg[i] = sym->regs[i];
1169 /*-----------------------------------------------------------------*/
1170 /* freeAsmop - free up the asmop given to an operand */
1171 /*----------------------------------------------------------------*/
1173 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1190 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1192 _pop (aop->aopu.aop_pairId);
1195 if (getPairId (aop) == PAIR_HL)
1197 spillPair (PAIR_HL);
1201 /* all other cases just dealloc */
1207 OP_SYMBOL (op)->aop = NULL;
1208 /* if the symbol has a spill */
1210 SPIL_LOC (op)->aop = NULL;
1217 isLitWord (asmop * aop)
1219 /* if (aop->size != 2)
1232 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1234 /* depending on type */
1240 /* PENDING: for re-target */
1243 tsprintf (buffer, sizeof(buffer),
1244 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1246 else if (offset == 0)
1248 tsprintf (buffer, sizeof(buffer),
1249 "%s", aop->aopu.aop_immd);
1253 tsprintf (buffer, sizeof(buffer),
1254 "%s + %d", aop->aopu.aop_immd, offset);
1256 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1260 value *val = aop->aopu.aop_lit;
1261 /* if it is a float then it gets tricky */
1262 /* otherwise it is fairly simple */
1263 if (!IS_FLOAT (val->type))
1265 unsigned long v = ulFromVal (val);
1271 else if (offset == 0)
1277 wassertl(0, "Encountered an invalid offset while fetching a literal");
1281 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1283 tsprintf (buffer, sizeof(buffer), "!constword", v);
1285 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1296 /* it is type float */
1297 fl.f = (float) floatFromVal (val);
1299 #ifdef WORDS_BIGENDIAN
1300 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1302 i = fl.c[offset] | (fl.c[offset+1]<<8);
1305 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1307 tsprintf (buffer, sizeof(buffer), "!constword", i);
1309 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1318 aopGetWord (asmop * aop, int offset)
1320 return aopGetLitWordLong (aop, offset, TRUE);
1324 isPtr (const char *s)
1326 if (!strcmp (s, "hl"))
1328 if (!strcmp (s, "ix"))
1330 if (!strcmp (s, "iy"))
1336 adjustPair (const char *pair, int *pold, int new)
1342 emit2 ("inc %s", pair);
1347 emit2 ("dec %s", pair);
1355 spillPair (PAIR_HL);
1356 spillPair (PAIR_IY);
1360 requiresHL (asmop * aop)
1376 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1378 const char *l, *base;
1379 const char *pair = _pairs[pairId].name;
1380 l = aopGetLitWordLong (left, offset, FALSE);
1381 base = aopGetLitWordLong (left, 0, FALSE);
1382 wassert (l && pair && base);
1386 if (pairId == PAIR_HL || pairId == PAIR_IY)
1388 if ((_G.pairs[pairId].last_type == AOP_IMMD && left->type == AOP_IMMD) ||
1389 (_G.pairs[pairId].last_type == AOP_IY && left->type == AOP_IY))
1391 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1393 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1395 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1398 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1406 if (pairId == PAIR_HL && left->type == AOP_LIT && _G.pairs[pairId].last_type == AOP_LIT &&
1407 !IS_FLOAT (left->aopu.aop_lit->type) && offset == 0 && _G.pairs[pairId].offset == 0)
1409 unsigned new_low, new_high, old_low, old_high;
1410 unsigned long v_new = ulFromVal (left->aopu.aop_lit);
1411 unsigned long v_old = strtoul (_G.pairs[pairId].base, NULL, 0);
1412 new_low = (v_new >> 0) & 0xff;
1413 new_high = (v_new >> 8) & 0xff;
1414 old_low = (v_old >> 0) & 0xff;
1415 old_high = (v_old >> 8) & 0xff;
1417 /* Change lower byte only. */
1418 if(new_high == old_high)
1420 emit2("ld l, %s", aopGet (left, 0, FALSE));
1423 /* Change upper byte only. */
1424 else if(new_low == old_low)
1426 emit2("ld h, %s", aopGet (left, 1, FALSE));
1432 _G.pairs[pairId].last_type = left->type;
1433 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1434 _G.pairs[pairId].offset = offset;
1436 /* Both a lit on the right and a true symbol on the left */
1437 emit2 ("ld %s,!hashedstr", pair, l);
1441 _G.pairs[pairId].last_type = left->type;
1442 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1443 _G.pairs[pairId].offset = offset;
1447 makeFreePairId (iCode *ic, bool *pisUsed)
1453 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1457 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1475 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1477 /* if this is remateriazable */
1478 if (isLitWord (aop)) {
1479 fetchLitPair (pairId, aop, offset);
1483 if (getPairId (aop) == pairId)
1487 /* we need to get it byte by byte */
1488 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1489 aopGet (aop, offset, FALSE);
1490 switch (aop->size - offset) {
1492 emit2 ("ld l,!*hl");
1493 emit2 ("ld h,!immedbyte", 0);
1496 // PENDING: Requires that you are only fetching two bytes.
1499 emit2 ("ld h,!*hl");
1503 wassertl (0, "Attempted to fetch too much data into HL");
1507 else if (IS_Z80 && aop->type == AOP_IY) {
1508 /* Instead of fetching relative to IY, just grab directly
1509 from the address IY refers to */
1510 char *l = aopGetLitWordLong (aop, offset, FALSE);
1512 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1514 if (aop->size < 2) {
1515 emit2("ld %s,!zero", _pairs[pairId].h);
1518 else if (pairId == PAIR_IY)
1522 emit2 ("push %s", _pairs[getPairId(aop)].name);
1528 PAIR_ID id = makeFreePairId (ic, &isUsed);
1531 /* Can't load into parts, so load into HL then exchange. */
1532 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1533 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1534 emit2 ("push %s", _pairs[id].name);
1540 else if (isUnsplitable(aop))
1542 emit2("push %s", _pairs[getPairId(aop)].name);
1543 emit2("pop %s", _pairs[pairId].name);
1547 /* Operand resides (partially) in the pair */
1548 if(!strcmp(aopGet (aop, offset + 1, FALSE), _pairs[pairId].l))
1550 emit2 ("ld a,%s", aopGet (aop, offset + 1, FALSE));
1551 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1552 emit2 ("ld %s,a", _pairs[pairId].h);
1556 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1557 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1560 /* PENDING: check? */
1561 if (pairId == PAIR_HL)
1562 spillPair (PAIR_HL);
1567 fetchPair (PAIR_ID pairId, asmop * aop)
1569 fetchPairLong (pairId, aop, NULL, 0);
1573 fetchHL (asmop * aop)
1575 fetchPair (PAIR_HL, aop);
1579 setupPairFromSP (PAIR_ID id, int offset)
1581 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1583 if (_G.preserveCarry)
1589 if (offset < INT8MIN || offset > INT8MAX)
1591 emit2 ("ld hl,!immedword", offset);
1592 emit2 ("add hl,sp");
1596 emit2 ("!ldahlsp", offset);
1599 if (_G.preserveCarry)
1607 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1612 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1613 fetchLitPair (pairId, aop, 0);
1617 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1619 fetchLitPair (pairId, aop, offset);
1620 _G.pairs[pairId].offset = offset;
1624 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1625 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1628 int offset = aop->aopu.aop_stk + _G.stack.offset;
1630 if (_G.pairs[pairId].last_type == aop->type &&
1631 _G.pairs[pairId].offset == offset)
1637 /* PENDING: Do this better. */
1638 if (_G.preserveCarry)
1640 sprintf (buffer, "%d", offset + _G.stack.pushed);
1641 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1642 emit2 ("add %s,sp", _pairs[pairId].name);
1643 _G.pairs[pairId].last_type = aop->type;
1644 _G.pairs[pairId].offset = offset;
1645 if (_G.preserveCarry)
1653 /* Doesnt include _G.stack.pushed */
1654 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1656 if (aop->aopu.aop_stk > 0)
1658 abso += _G.stack.param_offset;
1660 assert (pairId == PAIR_HL);
1661 /* In some cases we can still inc or dec hl */
1662 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1664 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1668 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1670 _G.pairs[pairId].offset = abso;
1675 if (pairId != aop->aopu.aop_pairId)
1676 genMovePairPair(aop->aopu.aop_pairId, pairId);
1677 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1683 _G.pairs[pairId].last_type = aop->type;
1686 /* Can be used for local labels where Code generation takes care of spilling */
1688 emitLabelNoSpill (int key)
1690 emit2 ("!tlabeldef", key);
1691 _G.lines.current->isLabel = 1;
1697 emit2 ("!tlabeldef", key);
1698 _G.lines.current->isLabel = 1;
1702 /*-----------------------------------------------------------------*/
1703 /* aopGet - for fetching value of the aop */
1704 /*-----------------------------------------------------------------*/
1706 aopGet (asmop * aop, int offset, bool bit16)
1708 // char *s = buffer;
1710 /* offset is greater than size then zero */
1711 /* PENDING: this seems a bit screwed in some pointer cases. */
1712 if (offset > (aop->size - 1) &&
1713 aop->type != AOP_LIT)
1715 tsprintf (buffer, sizeof(buffer), "!zero");
1716 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1719 /* depending on type */
1723 tsprintf (buffer, sizeof(buffer), "!zero");
1724 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1727 /* PENDING: re-target */
1729 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1734 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1737 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1740 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1743 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1746 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1750 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1751 SNPRINTF (buffer, sizeof(buffer), "a");
1753 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1759 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1760 SNPRINTF (buffer, sizeof(buffer), "a");
1762 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1765 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1768 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1769 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1770 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1772 else if( z80_opts.port_mode == 180 )
1773 { /* z180 in0/out0 mode */
1774 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1778 emit2( "in a,(%s)", aop->aopu.aop_dir );
1781 SNPRINTF (buffer, sizeof(buffer), "a");
1783 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1787 return aop->aopu.aop_reg[offset]->name;
1791 setupPair (PAIR_HL, aop, offset);
1792 tsprintf (buffer, sizeof(buffer), "!*hl");
1794 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1798 setupPair (PAIR_IY, aop, offset);
1799 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1801 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1805 setupPair (PAIR_IY, aop, offset);
1806 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1808 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1813 setupPair (PAIR_HL, aop, offset);
1814 tsprintf (buffer, sizeof(buffer), "!*hl");
1818 if (aop->aopu.aop_stk >= 0)
1819 offset += _G.stack.param_offset;
1820 tsprintf (buffer, sizeof(buffer),
1821 "!*ixx", aop->aopu.aop_stk + offset);
1824 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1827 wassertl (0, "Tried to fetch from a bit variable");
1836 tsprintf(buffer, sizeof(buffer), "!zero");
1837 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1841 wassert (offset < 2);
1842 return aop->aopu.aop_str[offset];
1845 return aopLiteral (aop->aopu.aop_lit, offset);
1849 unsigned long v = aop->aopu.aop_simplelit;
1852 tsprintf (buffer, sizeof(buffer),
1853 "!immedbyte", (unsigned int) v & 0xff);
1855 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1859 return aop->aopu.aop_str[offset];
1862 setupPair (aop->aopu.aop_pairId, aop, offset);
1863 if (aop->aopu.aop_pairId==PAIR_IX)
1864 tsprintf (buffer, sizeof(buffer), "!*ixx", offset);
1865 else if (aop->aopu.aop_pairId==PAIR_IY)
1866 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1868 SNPRINTF (buffer, sizeof(buffer),
1869 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1871 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1876 wassertl (0, "aopget got unsupported aop->type");
1881 isRegString (const char *s)
1883 if (!strcmp (s, "b") ||
1895 isConstant (const char *s)
1897 /* This is a bit of a hack... */
1898 return (*s == '#' || *s == '$');
1902 canAssignToPtr (const char *s)
1904 if (isRegString (s))
1911 /*-----------------------------------------------------------------*/
1912 /* aopPut - puts a string for a aop */
1913 /*-----------------------------------------------------------------*/
1915 aopPut (asmop * aop, const char *s, int offset)
1919 if (aop->size && offset > (aop->size - 1))
1921 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1922 "aopPut got offset > aop->size");
1927 tsprintf(buffer2, sizeof(buffer2), s);
1930 /* will assign value to value */
1931 /* depending on where it is ofcourse */
1935 _moveA (s); /* in case s is volatile */
1941 if (strcmp (s, "a"))
1942 emit2 ("ld a,%s", s);
1943 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1950 if (strcmp (s, "a"))
1951 emit2 ("ld a,%s", s);
1952 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1955 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1962 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1963 && s[0] != 'h' && s[0] != 'l'))
1965 emit2( "ld a,%s", s );
1969 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1970 emit2( "out (c),%s", s );
1975 spillPair (PAIR_BC);
1977 else if( z80_opts.port_mode == 180 )
1978 { /* z180 in0/out0 mode */
1979 emit2( "ld a,%s", s );
1980 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1984 emit2( "ld a,%s", s );
1985 emit2( "out (%s),a", aop->aopu.aop_dir );
1991 if (!strcmp (s, "!*hl"))
1992 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1995 aop->aopu.aop_reg[offset]->name, s);
1996 spillPairReg(aop->aopu.aop_reg[offset]->name);
2001 if (!canAssignToPtr (s))
2003 emit2 ("ld a,%s", s);
2004 setupPair (PAIR_IY, aop, offset);
2005 emit2 ("ld !*iyx,a", offset);
2009 setupPair (PAIR_IY, aop, offset);
2010 emit2 ("ld !*iyx,%s", offset, s);
2016 /* PENDING: for re-target */
2017 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2019 emit2 ("ld a,!*hl");
2022 setupPair (PAIR_HL, aop, offset);
2024 emit2 ("ld !*hl,%s", s);
2029 if (!canAssignToPtr (s))
2031 emit2 ("ld a,%s", s);
2032 setupPair (PAIR_IY, aop, offset);
2033 emit2 ("ld !*iyx,a", offset);
2037 setupPair (PAIR_IY, aop, offset);
2038 emit2 ("ld !*iyx,%s", offset, s);
2045 /* PENDING: re-target */
2046 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2048 emit2 ("ld a,!*hl");
2051 setupPair (PAIR_HL, aop, offset);
2052 if (!canAssignToPtr (s))
2054 emit2 ("ld a,%s", s);
2055 emit2 ("ld !*hl,a");
2058 emit2 ("ld !*hl,%s", s);
2062 if (aop->aopu.aop_stk >= 0)
2063 offset += _G.stack.param_offset;
2064 if (!canAssignToPtr (s))
2066 emit2 ("ld a,%s", s);
2067 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2071 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2077 /* if bit variable */
2078 if (!aop->aopu.aop_dir)
2080 emit2 ("ld a,!zero");
2085 /* In bit space but not in C - cant happen */
2086 wassertl (0, "Tried to write into a bit variable");
2092 if (strcmp (aop->aopu.aop_str[offset], s))
2094 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2096 spillPairReg(aop->aopu.aop_str[offset]);
2101 if (!offset && (strcmp (s, "acc") == 0))
2105 wassertl (0, "Tried to access past the end of A");
2109 if (strcmp (aop->aopu.aop_str[offset], s))
2111 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2112 spillPairReg(aop->aopu.aop_str[offset]);
2118 wassert (offset < 2);
2119 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2120 spillPairReg(aop->aopu.aop_str[offset]);
2124 setupPair (aop->aopu.aop_pairId, aop, offset);
2125 if (aop->aopu.aop_pairId==PAIR_IX)
2126 emit2 ("ld !*ixx,%s", 0, s);
2127 else if (aop->aopu.aop_pairId==PAIR_IY)
2128 emit2 ("ld !*iyx,%s", 0, s);
2130 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2134 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2135 "aopPut got unsupported aop->type");
2140 #define AOP(op) op->aop
2141 #define AOP_TYPE(op) AOP(op)->type
2142 #define AOP_SIZE(op) AOP(op)->size
2143 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2144 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2147 commitPair (asmop * aop, PAIR_ID id)
2149 /* PENDING: Verify this. */
2150 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2154 aopPut (aop, "a", 0);
2155 aopPut (aop, "d", 1);
2160 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2162 char *l = aopGetLitWordLong (aop, 0, FALSE);
2165 emit2 ("ld (%s),%s", l, _pairs[id].name);
2169 aopPut (aop, _pairs[id].l, 0);
2170 aopPut (aop, _pairs[id].h, 1);
2175 /*-----------------------------------------------------------------*/
2176 /* getDataSize - get the operand data size */
2177 /*-----------------------------------------------------------------*/
2179 getDataSize (operand * op)
2182 size = AOP_SIZE (op);
2186 wassertl (0, "Somehow got a three byte data pointer");
2191 /*-----------------------------------------------------------------*/
2192 /* movLeft2Result - move byte from left to result */
2193 /*-----------------------------------------------------------------*/
2195 movLeft2Result (operand * left, int offl,
2196 operand * result, int offr, int sign)
2200 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2202 l = aopGet (AOP (left), offl, FALSE);
2206 aopPut (AOP (result), l, offr);
2210 if (getDataSize (left) == offl + 1)
2212 emit2 ("ld a,%s", l);
2213 aopPut (AOP (result), "a", offr);
2220 movLeft2ResultLong (operand * left, int offl,
2221 operand * result, int offr, int sign,
2226 movLeft2Result (left, offl, result, offr, sign);
2230 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2231 wassertl (size == 2, "Only implemented for two bytes or one");
2233 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2235 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2236 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2238 spillPair (PAIR_HL);
2240 else if ( getPairId ( AOP (result)) == PAIR_IY)
2242 PAIR_ID id = getPairId (AOP (left));
2243 if (id != PAIR_INVALID)
2245 emit2("push %s", _pairs[id].name);
2256 movLeft2Result (left, offl, result, offr, sign);
2257 movLeft2Result (left, offl+1, result, offr+1, sign);
2262 /** Put Acc into a register set
2265 outAcc (operand * result)
2268 size = getDataSize (result);
2271 aopPut (AOP (result), "a", 0);
2274 /* unsigned or positive */
2277 aopPut (AOP (result), "!zero", offset++);
2282 /** Take the value in carry and put it into a register
2285 outBitC (operand * result)
2287 /* if the result is bit */
2288 if (AOP_TYPE (result) == AOP_CRY)
2290 if (!IS_OP_RUONLY (result))
2291 aopPut (AOP (result), "c", 0);
2295 emit2 ("ld a,!zero");
2301 /*-----------------------------------------------------------------*/
2302 /* toBoolean - emit code for orl a,operator(sizeop) */
2303 /*-----------------------------------------------------------------*/
2305 _toBoolean (operand * oper)
2307 int size = AOP_SIZE (oper);
2311 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2314 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2318 if (AOP (oper)->type != AOP_ACC)
2321 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2327 /*-----------------------------------------------------------------*/
2328 /* genNot - generate code for ! operation */
2329 /*-----------------------------------------------------------------*/
2334 /* assign asmOps to operand & result */
2335 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2336 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2338 /* if in bit space then a special case */
2339 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2341 wassertl (0, "Tried to negate a bit");
2344 _toBoolean (IC_LEFT (ic));
2349 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2350 emit2 ("sub a,!one");
2351 outBitC (IC_RESULT (ic));
2353 /* release the aops */
2354 freeAsmop (IC_LEFT (ic), NULL, ic);
2355 freeAsmop (IC_RESULT (ic), NULL, ic);
2358 /*-----------------------------------------------------------------*/
2359 /* genCpl - generate code for complement */
2360 /*-----------------------------------------------------------------*/
2368 /* assign asmOps to operand & result */
2369 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2370 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2372 /* if both are in bit space then
2374 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2375 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2377 wassertl (0, "Left and the result are in bit space");
2380 size = AOP_SIZE (IC_RESULT (ic));
2383 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2386 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2389 /* release the aops */
2390 freeAsmop (IC_LEFT (ic), NULL, ic);
2391 freeAsmop (IC_RESULT (ic), NULL, ic);
2395 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2402 store de into result
2407 store de into result
2409 const char *first = isAdd ? "add" : "sub";
2410 const char *later = isAdd ? "adc" : "sbc";
2412 wassertl (IS_GB, "Code is only relevent to the gbz80");
2413 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2415 fetchPair (PAIR_DE, left);
2418 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2421 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2424 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2425 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2427 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2428 aopGet (right, MSB24, FALSE);
2432 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2435 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2437 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2438 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2442 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2444 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2447 /*-----------------------------------------------------------------*/
2448 /* genUminusFloat - unary minus for floating points */
2449 /*-----------------------------------------------------------------*/
2451 genUminusFloat (operand * op, operand * result)
2453 int size, offset = 0;
2455 emitDebug("; genUminusFloat");
2457 /* for this we just need to flip the
2458 first bit then copy the rest in place */
2459 size = AOP_SIZE (op) - 1;
2461 _moveA(aopGet (AOP (op), MSB32, FALSE));
2463 emit2("xor a,!immedbyte", 0x80);
2464 aopPut (AOP (result), "a", MSB32);
2468 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2473 /*-----------------------------------------------------------------*/
2474 /* genUminus - unary minus code generation */
2475 /*-----------------------------------------------------------------*/
2477 genUminus (iCode * ic)
2480 sym_link *optype, *rtype;
2483 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2484 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2486 /* if both in bit space then special
2488 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2489 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2491 wassertl (0, "Left and right are in bit space");
2495 optype = operandType (IC_LEFT (ic));
2496 rtype = operandType (IC_RESULT (ic));
2498 /* if float then do float stuff */
2499 if (IS_FLOAT (optype))
2501 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2505 /* otherwise subtract from zero */
2506 size = AOP_SIZE (IC_LEFT (ic));
2508 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2510 /* Create a new asmop with value zero */
2511 asmop *azero = newAsmop (AOP_SIMPLELIT);
2512 azero->aopu.aop_simplelit = 0;
2514 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2522 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2523 emit2 ("ld a,!zero");
2524 emit2 ("sbc a,%s", l);
2525 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2528 /* if any remaining bytes in the result */
2529 /* we just need to propagate the sign */
2530 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2535 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2539 /* release the aops */
2540 freeAsmop (IC_LEFT (ic), NULL, ic);
2541 freeAsmop (IC_RESULT (ic), NULL, ic);
2544 /*-----------------------------------------------------------------*/
2545 /* assignResultValue - */
2546 /*-----------------------------------------------------------------*/
2548 assignResultValue (operand * oper)
2550 int size = AOP_SIZE (oper);
2553 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2554 topInA = requiresHL (AOP (oper));
2556 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2558 /* We do it the hard way here. */
2560 aopPut (AOP (oper), _fReturn[0], 0);
2561 aopPut (AOP (oper), _fReturn[1], 1);
2563 aopPut (AOP (oper), _fReturn[0], 2);
2564 aopPut (AOP (oper), _fReturn[1], 3);
2568 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2569 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2572 _emitMove ("a", _fReturn[size-1]);
2573 _emitMove (_fReturn[size-1], _fReturn[size]);
2574 _emitMove (_fReturn[size], "a");
2575 aopPut (AOP (oper), _fReturn[size], size-1);
2580 aopPut (AOP (oper), _fReturn[size], size);
2585 /** Simple restore that doesn't take into account what is used in the
2589 _restoreRegsAfterCall(void)
2591 if (_G.stack.pushedDE)
2594 _G.stack.pushedDE = FALSE;
2596 if (_G.stack.pushedBC)
2599 _G.stack.pushedBC = FALSE;
2601 _G.saves.saved = FALSE;
2605 _saveRegsForCall(iCode *ic, int sendSetSize)
2608 o Stack parameters are pushed before this function enters
2609 o DE and BC may be used in this function.
2610 o HL and DE may be used to return the result.
2611 o HL and DE may be used to send variables.
2612 o DE and BC may be used to store the result value.
2613 o HL may be used in computing the sent value of DE
2614 o The iPushes for other parameters occur before any addSets
2616 Logic: (to be run inside the first iPush or if none, before sending)
2617 o Compute if DE and/or BC are in use over the call
2618 o Compute if DE is used in the send set
2619 o Compute if DE and/or BC are used to hold the result value
2620 o If (DE is used, or in the send set) and is not used in the result, push.
2621 o If BC is used and is not in the result, push
2623 o If DE is used in the send set, fetch
2624 o If HL is used in the send set, fetch
2628 if (_G.saves.saved == FALSE) {
2629 bool deInUse, bcInUse;
2631 bool bcInRet = FALSE, deInRet = FALSE;
2634 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2635 z80_rUmaskForOp (IC_RESULT(ic)));
2637 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2638 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2640 deSending = (sendSetSize > 1);
2642 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2644 if (bcInUse && bcInRet == FALSE) {
2646 _G.stack.pushedBC = TRUE;
2648 if (deInUse && deInRet == FALSE) {
2650 _G.stack.pushedDE = TRUE;
2653 _G.saves.saved = TRUE;
2656 /* Already saved. */
2660 /*-----------------------------------------------------------------*/
2661 /* genIpush - genrate code for pushing this gets a little complex */
2662 /*-----------------------------------------------------------------*/
2664 genIpush (iCode * ic)
2666 int size, offset = 0;
2669 /* if this is not a parm push : ie. it is spill push
2670 and spill push is always done on the local stack */
2673 wassertl(0, "Encountered an unsupported spill push.");
2677 if (_G.saves.saved == FALSE) {
2678 /* Caller saves, and this is the first iPush. */
2679 /* Scan ahead until we find the function that we are pushing parameters to.
2680 Count the number of addSets on the way to figure out what registers
2681 are used in the send set.
2684 iCode *walk = ic->next;
2687 if (walk->op == SEND) {
2690 else if (walk->op == CALL || walk->op == PCALL) {
2699 _saveRegsForCall(walk, nAddSets);
2702 /* Already saved by another iPush. */
2705 /* then do the push */
2706 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2708 size = AOP_SIZE (IC_LEFT (ic));
2710 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2712 _G.stack.pushed += 2;
2713 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2719 fetchHL (AOP (IC_LEFT (ic)));
2721 _G.stack.pushed += 2;
2726 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2728 _G.stack.pushed += 2;
2729 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2731 _G.stack.pushed += 2;
2737 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2739 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2741 emit2 ("ld a,(%s)", l);
2746 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2747 if (!strcmp(l, "b"))
2749 else if (!strcmp(l, "d"))
2751 else if (!strcmp(l, "h"))
2755 emit2 ("ld a,%s", l);
2764 freeAsmop (IC_LEFT (ic), NULL, ic);
2767 /*-----------------------------------------------------------------*/
2768 /* genIpop - recover the registers: can happen only for spilling */
2769 /*-----------------------------------------------------------------*/
2771 genIpop (iCode * ic)
2776 /* if the temp was not pushed then */
2777 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2780 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2781 size = AOP_SIZE (IC_LEFT (ic));
2782 offset = (size - 1);
2783 if (isPair (AOP (IC_LEFT (ic))))
2785 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2793 spillPair (PAIR_HL);
2794 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2798 freeAsmop (IC_LEFT (ic), NULL, ic);
2801 /* This is quite unfortunate */
2803 setArea (int inHome)
2806 static int lastArea = 0;
2808 if (_G.in_home != inHome) {
2810 const char *sz = port->mem.code_name;
2811 port->mem.code_name = "HOME";
2812 emit2("!area", CODE_NAME);
2813 port->mem.code_name = sz;
2816 emit2("!area", CODE_NAME); */
2817 _G.in_home = inHome;
2828 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2832 symbol *sym = OP_SYMBOL (op);
2834 if (sym->isspilt || sym->nRegs == 0)
2837 aopOp (op, ic, FALSE, FALSE);
2840 if (aop->type == AOP_REG)
2843 for (i = 0; i < aop->size; i++)
2845 if (pairId == PAIR_DE)
2847 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2848 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2850 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2853 else if (pairId == PAIR_BC)
2855 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2856 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2858 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2868 freeAsmop (IC_LEFT (ic), NULL, ic);
2872 /** Emit the code for a call statement
2875 emitCall (iCode * ic, bool ispcall)
2877 bool bInRet, cInRet, dInRet, eInRet;
2878 sym_link *dtype = operandType (IC_LEFT (ic));
2880 /* if caller saves & we have not saved then */
2886 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2888 /* if send set is not empty then assign */
2893 int nSend = elementsInSet(_G.sendSet);
2894 bool swapped = FALSE;
2896 int _z80_sendOrder[] = {
2901 /* Check if the parameters are swapped. If so route through hl instead. */
2902 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2904 sic = setFirstItem(_G.sendSet);
2905 sic = setNextItem(_G.sendSet);
2907 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2908 /* The second send value is loaded from one the one that holds the first
2909 send, i.e. it is overwritten. */
2910 /* Cache the first in HL, and load the second from HL instead. */
2911 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2912 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2918 for (sic = setFirstItem (_G.sendSet); sic;
2919 sic = setNextItem (_G.sendSet))
2922 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2924 size = AOP_SIZE (IC_LEFT (sic));
2925 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2926 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2928 // PENDING: Mild hack
2929 if (swapped == TRUE && send == 1) {
2931 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2934 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2936 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2939 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2943 freeAsmop (IC_LEFT (sic), NULL, sic);
2950 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2952 werror (W_INDIR_BANKED);
2954 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2956 if (isLitWord (AOP (IC_LEFT (ic))))
2958 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2962 symbol *rlbl = newiTempLabel (NULL);
2963 spillPair (PAIR_HL);
2964 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2966 _G.stack.pushed += 2;
2968 fetchHL (AOP (IC_LEFT (ic)));
2970 emit2 ("!tlabeldef", (rlbl->key + 100));
2971 _G.lines.current->isLabel = 1;
2972 _G.stack.pushed -= 2;
2974 freeAsmop (IC_LEFT (ic), NULL, ic);
2978 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2979 OP_SYMBOL (IC_LEFT (ic))->rname :
2980 OP_SYMBOL (IC_LEFT (ic))->name;
2981 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2983 emit2 ("call banked_call");
2984 emit2 ("!dws", name);
2985 emit2 ("!dw !bankimmeds", name);
2990 emit2 ("call %s", name);
2995 /* Mark the registers as restored. */
2996 _G.saves.saved = FALSE;
2998 /* adjust the stack for parameters if required */
3001 int i = ic->parmBytes;
3003 _G.stack.pushed -= i;
3006 emit2 ("!ldaspsp", i);
3013 emit2 ("ld iy,!immedword", i);
3014 emit2 ("add iy,sp");
3032 /* if we need assign a result value */
3033 if ((IS_ITEMP (IC_RESULT (ic)) &&
3034 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3035 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3036 IS_TRUE_SYMOP (IC_RESULT (ic)))
3038 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3040 assignResultValue (IC_RESULT (ic));
3042 freeAsmop (IC_RESULT (ic), NULL, ic);
3048 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
3049 bInRet = bitVectBitValue(result, B_IDX);
3050 cInRet = bitVectBitValue(result, C_IDX);
3051 dInRet = bitVectBitValue(result, D_IDX);
3052 eInRet = bitVectBitValue(result, E_IDX);
3062 if (_G.stack.pushedDE)
3064 if (dInRet && eInRet)
3066 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3070 /* Only restore E */
3077 /* Only restore D */
3085 _G.stack.pushedDE = FALSE;
3088 if (_G.stack.pushedBC)
3090 if (bInRet && cInRet)
3092 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3096 /* Only restore C */
3103 /* Only restore B */
3111 _G.stack.pushedBC = FALSE;
3115 /*-----------------------------------------------------------------*/
3116 /* genCall - generates a call statement */
3117 /*-----------------------------------------------------------------*/
3119 genCall (iCode * ic)
3121 emitCall (ic, FALSE);
3124 /*-----------------------------------------------------------------*/
3125 /* genPcall - generates a call by pointer statement */
3126 /*-----------------------------------------------------------------*/
3128 genPcall (iCode * ic)
3130 emitCall (ic, TRUE);
3133 /*-----------------------------------------------------------------*/
3134 /* resultRemat - result is rematerializable */
3135 /*-----------------------------------------------------------------*/
3137 resultRemat (iCode * ic)
3139 if (SKIP_IC (ic) || ic->op == IFX)
3142 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3144 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3145 if (sym->remat && !POINTER_SET (ic))
3152 extern set *publics;
3154 /*-----------------------------------------------------------------*/
3155 /* genFunction - generated code for function entry */
3156 /*-----------------------------------------------------------------*/
3158 genFunction (iCode * ic)
3162 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3165 bool bcInUse = FALSE;
3166 bool deInUse = FALSE;
3168 setArea (IFFUNC_NONBANKED (sym->type));
3170 /* PENDING: Reset the receive offset as it
3171 doesn't seem to get reset anywhere else.
3173 _G.receiveOffset = 0;
3175 /* Record the last function name for debugging. */
3176 _G.lastFunctionName = sym->rname;
3178 /* Create the function header */
3179 emit2 ("!functionheader", sym->name);
3180 if (!IS_STATIC(sym->etype))
3182 sprintf (buffer, "%s_start", sym->rname);
3183 emit2 ("!labeldef", buffer);
3184 _G.lines.current->isLabel = 1;
3186 emit2 ("!functionlabeldef", sym->rname);
3187 _G.lines.current->isLabel = 1;
3189 ftype = operandType (IC_LEFT (ic));
3191 if (IFFUNC_ISNAKED(ftype))
3193 emitDebug("; naked function: no prologue.");
3197 /* if this is an interrupt service routine
3198 then save all potentially used registers. */
3199 if (IFFUNC_ISISR (sym->type))
3201 /* If critical function then turn interrupts off */
3202 /* except when no interrupt number is given then it implies the NMI handler */
3203 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3212 /* This is a non-ISR function.
3213 If critical function then turn interrupts off */
3214 if (IFFUNC_ISCRITICAL (sym->type))
3222 //get interrupt enable flag IFF2 into P/O
3231 if (options.profile)
3233 emit2 ("!profileenter");
3236 /* PENDING: callee-save etc */
3238 _G.stack.param_offset = 0;
3240 if (z80_opts.calleeSavesBC)
3245 /* Detect which registers are used. */
3246 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3249 for (i = 0; i < sym->regsUsed->size; i++)
3251 if (bitVectBitValue (sym->regsUsed, i))
3265 /* Other systems use DE as a temporary. */
3276 _G.stack.param_offset += 2;
3279 _G.calleeSaves.pushedBC = bcInUse;
3284 _G.stack.param_offset += 2;
3287 _G.calleeSaves.pushedDE = deInUse;
3289 /* adjust the stack for the function */
3290 _G.stack.last = sym->stack;
3293 for (sym = setFirstItem (istack->syms); sym;
3294 sym = setNextItem (istack->syms))
3296 if (sym->_isparm && !IS_REGPARM (sym->etype))
3302 sym = OP_SYMBOL (IC_LEFT (ic));
3304 _G.omitFramePtr = options.ommitFramePtr;
3305 if (IS_Z80 && !stackParm && !sym->stack)
3307 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3308 /* the above !sym->stack condition can be removed. -- EEP */
3310 emit2 ("!ldaspsp", -sym->stack);
3311 _G.omitFramePtr = TRUE;
3313 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3314 emit2 ("!enterxl", sym->stack);
3315 else if (sym->stack)
3317 if ((optimize.codeSize && sym->stack <= 8) || sym->stack <= 4)
3319 int stack = sym->stack;
3330 emit2 ("!enterx", sym->stack);
3335 _G.stack.offset = sym->stack;
3338 /*-----------------------------------------------------------------*/
3339 /* genEndFunction - generates epilogue for functions */
3340 /*-----------------------------------------------------------------*/
3342 genEndFunction (iCode * ic)
3344 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3346 if (IFFUNC_ISNAKED(sym->type))
3348 emitDebug("; naked function: no epilogue.");
3352 /* PENDING: calleeSave */
3353 if (IS_Z80 && _G.omitFramePtr)
3355 if (_G.stack.offset)
3356 emit2 ("!ldaspsp", _G.stack.offset);
3358 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3360 emit2 ("!leavexl", _G.stack.offset);
3362 else if (_G.stack.offset)
3364 emit2 ("!leavex", _G.stack.offset);
3371 if (_G.calleeSaves.pushedDE)
3374 _G.calleeSaves.pushedDE = FALSE;
3377 if (_G.calleeSaves.pushedBC)
3380 _G.calleeSaves.pushedBC = FALSE;
3383 if (options.profile)
3385 emit2 ("!profileexit");
3388 /* if this is an interrupt service routine
3389 then save all potentially used registers. */
3390 if (IFFUNC_ISISR (sym->type))
3394 /* If critical function then turn interrupts back on */
3395 /* except when no interrupt number is given then it implies the NMI handler */
3396 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3403 /* This is a non-ISR function.
3404 If critical function then turn interrupts back on */
3405 if (IFFUNC_ISCRITICAL (sym->type))
3413 symbol *tlbl = newiTempLabel (NULL);
3416 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3417 //don't enable interrupts as they were off before
3418 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3420 emit2 ("!tlabeldef", (tlbl->key + 100));
3421 _G.lines.current->isLabel = 1;
3426 if (options.debug && currFunc)
3428 debugFile->writeEndFunction (currFunc, ic, 1);
3431 if (IFFUNC_ISISR (sym->type))
3433 /* "critical interrupt" is used to imply NMI handler */
3434 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3441 /* Both banked and non-banked just ret */
3445 if (!IS_STATIC(sym->etype))
3447 sprintf (buffer, "%s_end", sym->rname);
3448 emit2 ("!labeldef", buffer);
3449 _G.lines.current->isLabel = 1;
3452 _G.flushStatics = 1;
3453 _G.stack.pushed = 0;
3454 _G.stack.offset = 0;
3457 /*-----------------------------------------------------------------*/
3458 /* genRet - generate code for return statement */
3459 /*-----------------------------------------------------------------*/
3464 /* Errk. This is a hack until I can figure out how
3465 to cause dehl to spill on a call */
3466 int size, offset = 0;
3468 /* if we have no return value then
3469 just generate the "ret" */
3473 /* we have something to return then
3474 move the return value into place */
3475 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3476 size = AOP_SIZE (IC_LEFT (ic));
3478 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3481 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3485 emit2 ("ld de,%s", l);
3489 emit2 ("ld hl,%s", l);
3495 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3499 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3501 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3502 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3508 l = aopGet (AOP (IC_LEFT (ic)), offset,
3510 if (strcmp (_fReturn[offset], l))
3511 emit2 ("ld %s,%s", _fReturn[offset], l);
3516 freeAsmop (IC_LEFT (ic), NULL, ic);
3519 /* generate a jump to the return label
3520 if the next is not the return statement */
3521 if (!(ic->next && ic->next->op == LABEL &&
3522 IC_LABEL (ic->next) == returnLabel))
3524 emit2 ("jp !tlabel", returnLabel->key + 100);
3527 /*-----------------------------------------------------------------*/
3528 /* genLabel - generates a label */
3529 /*-----------------------------------------------------------------*/
3531 genLabel (iCode * ic)
3533 /* special case never generate */
3534 if (IC_LABEL (ic) == entryLabel)
3537 emitLabel (IC_LABEL (ic)->key + 100);
3540 /*-----------------------------------------------------------------*/
3541 /* genGoto - generates a ljmp */
3542 /*-----------------------------------------------------------------*/
3544 genGoto (iCode * ic)
3546 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3549 /*-----------------------------------------------------------------*/
3550 /* genPlusIncr :- does addition with increment if possible */
3551 /*-----------------------------------------------------------------*/
3553 genPlusIncr (iCode * ic)
3555 unsigned int icount;
3556 unsigned int size = getDataSize (IC_RESULT (ic));
3557 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3559 /* will try to generate an increment */
3560 /* if the right side is not a literal
3562 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3565 emitDebug ("; genPlusIncr");
3567 icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3569 /* If result is a pair */
3570 if (resultId != PAIR_INVALID)
3572 if (isLitWord (AOP (IC_LEFT (ic))))
3574 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3577 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3579 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3581 PAIR_ID freep = getFreePairId (ic);
3582 if (freep != PAIR_INVALID)
3584 fetchPair (freep, AOP (IC_RIGHT (ic)));
3585 emit2 ("add hl,%s", _pairs[freep].name);
3591 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3592 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3599 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3603 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3607 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3612 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3614 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3615 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3619 /* if the literal value of the right hand side
3620 is greater than 4 then it is not worth it */
3624 /* if increment 16 bits in register */
3625 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3631 symbol *tlbl = NULL;
3632 tlbl = newiTempLabel (NULL);
3635 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3638 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3641 emitLabelNoSpill (tlbl->key + 100);
3645 /* if the sizes are greater than 1 then we cannot */
3646 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3647 AOP_SIZE (IC_LEFT (ic)) > 1)
3650 /* If the result is in a register then we can load then increment.
3652 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3654 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3657 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3662 /* we can if the aops of the left & result match or
3663 if they are in registers and the registers are the
3665 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3669 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3677 /*-----------------------------------------------------------------*/
3678 /* outBitAcc - output a bit in acc */
3679 /*-----------------------------------------------------------------*/
3681 outBitAcc (operand * result)
3683 symbol *tlbl = newiTempLabel (NULL);
3684 /* if the result is a bit */
3685 if (AOP_TYPE (result) == AOP_CRY)
3687 wassertl (0, "Tried to write A into a bit");
3691 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3692 emit2 ("ld a,!one");
3693 emitLabelNoSpill (tlbl->key + 100);
3699 couldDestroyCarry (asmop *aop)
3703 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3712 shiftIntoPair (int idx, asmop *aop)
3714 PAIR_ID id = PAIR_INVALID;
3716 wassertl (IS_Z80, "Only implemented for the Z80");
3717 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3719 emitDebug ("; Shift into pair idx %u", idx);
3725 setupPair (PAIR_HL, aop, 0);
3730 setupPair (PAIR_IY, aop, 0);
3732 emit2 ("pop %s", _pairs[id].name);
3736 setupPair (PAIR_IY, aop, 0);
3739 wassertl (0, "Internal error - hit default case");
3742 aop->type = AOP_PAIRPTR;
3743 aop->aopu.aop_pairId = id;
3744 _G.pairs[id].offset = 0;
3745 _G.pairs[id].last_type = aop->type;
3749 setupToPreserveCarry (iCode * ic)
3751 asmop *left = AOP (IC_LEFT (ic));
3752 asmop *right = AOP (IC_RIGHT (ic));
3753 asmop *result = AOP (IC_RESULT (ic));
3755 wassert (left && right);
3759 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3761 shiftIntoPair (0, right);
3762 /* check result again, in case right == result */
3763 if (couldDestroyCarry (result))
3765 if (!isPairInUse (PAIR_DE, ic))
3766 shiftIntoPair (1, result);
3768 shiftIntoPair (2, result);
3771 else if (couldDestroyCarry (right))
3773 if (getPairId (result) == PAIR_HL)
3774 _G.preserveCarry = TRUE;
3776 shiftIntoPair (0, right);
3778 else if (couldDestroyCarry (result))
3780 shiftIntoPair (0, result);
3789 /*-----------------------------------------------------------------*/
3790 /* genPlus - generates code for addition */
3791 /*-----------------------------------------------------------------*/
3793 genPlus (iCode * ic)
3795 int size, offset = 0;
3797 /* special cases :- */
3799 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3800 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3801 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3803 /* Swap the left and right operands if:
3805 if literal, literal on the right or
3806 if left requires ACC or right is already
3809 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3810 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3811 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3813 operand *t = IC_RIGHT (ic);
3814 IC_RIGHT (ic) = IC_LEFT (ic);
3818 /* if both left & right are in bit
3820 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3821 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3824 wassertl (0, "Tried to add two bits");
3827 /* if left in bit space & right literal */
3828 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3829 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3831 /* Can happen I guess */
3832 wassertl (0, "Tried to add a bit to a literal");
3835 /* if I can do an increment instead
3836 of add then GOOD for ME */
3837 if (genPlusIncr (ic) == TRUE)
3840 size = getDataSize (IC_RESULT (ic));
3842 /* Special case when left and right are constant */
3843 if (isPair (AOP (IC_RESULT (ic))))
3846 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3847 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3849 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3855 sprintf (buffer, "#(%s + %s)", left, right);
3856 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3861 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3863 /* Fetch into HL then do the add */
3864 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3865 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3867 spillPair (PAIR_HL);
3869 if (left == PAIR_HL && right != PAIR_INVALID)
3871 emit2 ("add hl,%s", _pairs[right].name);
3874 else if (right == PAIR_HL && left != PAIR_INVALID)
3876 emit2 ("add hl,%s", _pairs[left].name);
3879 else if (right != PAIR_INVALID && right != PAIR_HL)
3881 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3882 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3885 else if (left != PAIR_INVALID && left != PAIR_HL)
3887 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3888 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3897 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3899 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3900 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3901 spillPair (PAIR_HL);
3902 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3906 if (isPair (AOP (IC_LEFT (ic))) && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && getPairId (AOP (IC_LEFT (ic))) != PAIR_HL)
3908 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3909 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3910 spillPair (PAIR_HL);
3911 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3916 ld hl,sp+n trashes C so we can't afford to do it during an
3917 add with stack based variables. Worst case is:
3930 So you can't afford to load up hl if either left, right, or result
3931 is on the stack (*sigh*) The alt is:
3939 Combinations in here are:
3940 * If left or right are in bc then the loss is small - trap later
3941 * If the result is in bc then the loss is also small
3945 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3946 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3947 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3949 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3950 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3951 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3952 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3954 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3956 /* Swap left and right */
3957 operand *t = IC_RIGHT (ic);
3958 IC_RIGHT (ic) = IC_LEFT (ic);
3961 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3963 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3964 emit2 ("add hl,bc");
3968 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3969 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3970 emit2 ("add hl,de");
3972 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3978 /* Be paranoid on the GB with 4 byte variables due to how C
3979 can be trashed by lda hl,n(sp).
3981 _gbz80_emitAddSubLong (ic, TRUE);
3986 setupToPreserveCarry (ic);
3988 /* This is ugly, but it fixes the worst code generation bug on Z80. */
3989 /* Probably something similar has to be done for addition of larger numbers, too. */
3992 _moveA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3993 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), 0, FALSE));
3994 if(strcmp (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), aopGet (AOP (IC_LEFT (ic)), 1, FALSE)))
3996 aopPut (AOP (IC_RESULT (ic)), "a", 0);
3997 _moveA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
4001 emitDebug ("; Addition result is in same register as operand of next addition.");
4002 if(strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'c') ||
4003 strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'b') )
4007 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
4010 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4018 emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
4021 emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4027 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), 1, FALSE));
4028 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4034 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4037 if(size == 0 && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) == 1)
4040 emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4043 emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4044 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4048 _G.preserveCarry = FALSE;
4049 freeAsmop (IC_LEFT (ic), NULL, ic);
4050 freeAsmop (IC_RIGHT (ic), NULL, ic);
4051 freeAsmop (IC_RESULT (ic), NULL, ic);
4054 /*-----------------------------------------------------------------*/
4055 /* genMinusDec :- does subtraction with deccrement if possible */
4056 /*-----------------------------------------------------------------*/
4058 genMinusDec (iCode * ic)
4060 unsigned int icount;
4061 unsigned int size = getDataSize (IC_RESULT (ic));
4063 /* will try to generate an increment */
4064 /* if the right side is not a literal we cannot */
4065 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4068 /* if the literal value of the right hand side
4069 is greater than 4 then it is not worth it */
4070 if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
4073 size = getDataSize (IC_RESULT (ic));
4075 /* if decrement 16 bits in register */
4076 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4077 (size > 1) && isPair (AOP (IC_RESULT (ic))))
4080 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4084 /* If result is a pair */
4085 if (isPair (AOP (IC_RESULT (ic))))
4087 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
4089 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
4093 /* if increment 16 bits in register */
4094 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4098 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
4101 emit2 ("dec %s", _getTempPairName());
4104 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
4110 /* if the sizes are greater than 1 then we cannot */
4111 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4112 AOP_SIZE (IC_LEFT (ic)) > 1)
4115 /* we can if the aops of the left & result match or if they are in
4116 registers and the registers are the same */
4117 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4120 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4127 /*-----------------------------------------------------------------*/
4128 /* genMinus - generates code for subtraction */
4129 /*-----------------------------------------------------------------*/
4131 genMinus (iCode * ic)
4133 int size, offset = 0;
4134 unsigned long lit = 0L;
4136 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4137 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4138 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4140 /* special cases :- */
4141 /* if both left & right are in bit space */
4142 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4143 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4145 wassertl (0, "Tried to subtract two bits");
4149 /* if I can do an decrement instead of subtract then GOOD for ME */
4150 if (genMinusDec (ic) == TRUE)
4153 size = getDataSize (IC_RESULT (ic));
4155 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4160 lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4164 /* Same logic as genPlus */
4167 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4168 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4169 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4171 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4172 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4173 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4174 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4176 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4177 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4179 if (left == PAIR_INVALID && right == PAIR_INVALID)
4184 else if (right == PAIR_INVALID)
4186 else if (left == PAIR_INVALID)
4189 fetchPair (left, AOP (IC_LEFT (ic)));
4190 /* Order is important. Right may be HL */
4191 fetchPair (right, AOP (IC_RIGHT (ic)));
4193 emit2 ("ld a,%s", _pairs[left].l);
4194 emit2 ("sub a,%s", _pairs[right].l);
4196 emit2 ("ld a,%s", _pairs[left].h);
4197 emit2 ("sbc a,%s", _pairs[right].h);
4199 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4201 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4203 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4209 /* Be paranoid on the GB with 4 byte variables due to how C
4210 can be trashed by lda hl,n(sp).
4212 _gbz80_emitAddSubLong (ic, FALSE);
4217 setupToPreserveCarry (ic);
4219 /* if literal, add a,#-lit, else normal subb */
4222 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4223 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4227 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4230 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4234 /* first add without previous c */
4237 if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
4240 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4243 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4245 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4248 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4249 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4250 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4252 wassertl (0, "Tried to subtract on a long pointer");
4256 _G.preserveCarry = FALSE;
4257 freeAsmop (IC_LEFT (ic), NULL, ic);
4258 freeAsmop (IC_RIGHT (ic), NULL, ic);
4259 freeAsmop (IC_RESULT (ic), NULL, ic);
4262 /*-----------------------------------------------------------------*/
4263 /* genMultChar - generates code for unsigned 8x8 multiplication */
4264 /*-----------------------------------------------------------------*/
4266 genMultOneChar (iCode * ic)
4268 symbol *tlbl1, *tlbl2;
4269 bool savedB = FALSE;
4273 wassertl (0, "Multiplication is handled through support function calls on gbz80");
4277 /* Save b into a if b is in use. */
4278 if (bitVectBitValue (ic->rMask, B_IDX) &&
4279 !(getPairId (AOP (IC_RESULT (ic))) == PAIR_BC))
4284 if (isPairInUse (PAIR_DE, ic) &&
4285 !(getPairId (AOP (IC_RESULT (ic))) == PAIR_DE))
4288 _G.stack.pushedDE = TRUE;
4291 tlbl1 = newiTempLabel (NULL);
4292 tlbl2 = newiTempLabel (NULL);
4294 emit2 ("ld e,%s", aopGet (AOP (IC_RIGHT (ic)), LSB, FALSE));
4295 emit2 ("ld h,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4296 emit2 ("ld l,#0x00");
4298 emit2 ("ld b,#0x08");
4299 emitLabelNoSpill (tlbl1->key + 100);
4300 emit2 ("add hl,hl");
4301 emit2 ("jp NC,!tlabel", tlbl2->key + 100);
4302 emit2 ("add hl,de");
4303 emitLabelNoSpill (tlbl2->key + 100);
4304 emit2 ("djnz !tlabel", tlbl1->key + 100);
4308 if (IS_Z80 && _G.stack.pushedDE)
4311 _G.stack.pushedDE = FALSE;
4318 if (AOP_SIZE (IC_RESULT (ic)) == 1)
4319 aopPut (AOP (IC_RESULT (ic)), "l", 0);
4321 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4323 freeAsmop (IC_LEFT (ic), NULL, ic);
4324 freeAsmop (IC_RIGHT (ic), NULL, ic);
4325 freeAsmop (IC_RESULT (ic), NULL, ic);
4328 /*-----------------------------------------------------------------*/
4329 /* genMult - generates code for multiplication */
4330 /*-----------------------------------------------------------------*/
4332 genMult (iCode * ic)
4336 /* If true then the final operation should be a subtract */
4337 bool active = FALSE;
4340 /* Shouldn't occur - all done through function calls */
4341 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4342 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4343 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4345 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4347 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4348 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4349 AOP_SIZE (IC_RESULT (ic)) > 2)
4351 wassertl (0, "Multiplication is handled through support function calls");
4354 /* Swap left and right such that right is a literal */
4355 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4357 operand *t = IC_RIGHT (ic);
4358 IC_RIGHT (ic) = IC_LEFT (ic);
4362 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4364 genMultOneChar (ic);
4368 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4370 val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4371 // wassertl (val > 0, "Multiply must be positive");
4372 wassertl (val != 1, "Can't multiply by 1");
4374 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4376 _G.stack.pushedDE = TRUE;
4380 emit2 ("ld a,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4381 else if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4383 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4394 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4399 for (count = 0; count < 16; count++)
4401 if (count != 0 && active)
4406 emit2 ("add hl,hl");
4410 if (active == FALSE)
4425 emit2 ("add hl,de");
4434 if (IS_Z80 && _G.stack.pushedDE)
4437 _G.stack.pushedDE = FALSE;
4441 aopPut (AOP (IC_RESULT (ic)), "a", 0);
4443 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4445 freeAsmop (IC_LEFT (ic), NULL, ic);
4446 freeAsmop (IC_RIGHT (ic), NULL, ic);
4447 freeAsmop (IC_RESULT (ic), NULL, ic);
4450 /*-----------------------------------------------------------------*/
4451 /* genDiv - generates code for division */
4452 /*-----------------------------------------------------------------*/
4456 /* Shouldn't occur - all done through function calls */
4457 wassertl (0, "Division is handled through support function calls");
4460 /*-----------------------------------------------------------------*/
4461 /* genMod - generates code for division */
4462 /*-----------------------------------------------------------------*/
4466 /* Shouldn't occur - all done through function calls */
4470 /*-----------------------------------------------------------------*/
4471 /* genIfxJump :- will create a jump depending on the ifx */
4472 /*-----------------------------------------------------------------*/
4474 genIfxJump (iCode * ic, char *jval)
4479 /* if true label then we jump if condition
4483 jlbl = IC_TRUE (ic);
4484 if (!strcmp (jval, "a"))
4488 else if (!strcmp (jval, "c"))
4492 else if (!strcmp (jval, "nc"))
4496 else if (!strcmp (jval, "m"))
4500 else if (!strcmp (jval, "p"))
4506 /* The buffer contains the bit on A that we should test */
4512 /* false label is present */
4513 jlbl = IC_FALSE (ic);
4514 if (!strcmp (jval, "a"))
4518 else if (!strcmp (jval, "c"))
4522 else if (!strcmp (jval, "nc"))
4526 else if (!strcmp (jval, "m"))
4530 else if (!strcmp (jval, "p"))
4536 /* The buffer contains the bit on A that we should test */
4540 /* Z80 can do a conditional long jump */
4541 if (!strcmp (jval, "a"))
4545 else if (!strcmp (jval, "c"))
4548 else if (!strcmp (jval, "nc"))
4551 else if (!strcmp (jval, "m"))
4554 else if (!strcmp (jval, "p"))
4559 emit2 ("bit %s,a", jval);
4561 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4563 /* mark the icode as generated */
4569 _getPairIdName (PAIR_ID id)
4571 return _pairs[id].name;
4576 /* if unsigned char cmp with lit, just compare */
4578 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4580 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4583 emit2 ("xor a,!immedbyte", 0x80);
4584 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4587 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4589 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4591 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4592 // Pull left into DE and right into HL
4593 aopGet (AOP(left), LSB, FALSE);
4596 aopGet (AOP(right), LSB, FALSE);
4600 if (size == 0 && sign)
4602 // Highest byte when signed needs the bits flipped
4605 emit2 ("ld a,(de)");
4606 emit2 ("xor !immedbyte", 0x80);
4608 emit2 ("ld a,(hl)");
4609 emit2 ("xor !immedbyte", 0x80);
4613 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4617 emit2 ("ld a,(de)");
4618 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4628 spillPair (PAIR_HL);
4630 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4632 setupPair (PAIR_HL, AOP (left), 0);
4633 aopGet (AOP(right), LSB, FALSE);
4637 if (size == 0 && sign)
4639 // Highest byte when signed needs the bits flipped
4642 emit2 ("ld a,(hl)");
4643 emit2 ("xor !immedbyte", 0x80);
4645 emit2 ("ld a,%d(iy)", offset);
4646 emit2 ("xor !immedbyte", 0x80);
4650 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4654 emit2 ("ld a,(hl)");
4655 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4664 spillPair (PAIR_HL);
4665 spillPair (PAIR_IY);
4669 if (AOP_TYPE (right) == AOP_LIT)
4671 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4672 /* optimize if(x < 0) or if(x >= 0) */
4677 /* No sign so it's always false */
4682 /* Just load in the top most bit */
4683 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4684 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4686 genIfxJump (ifx, "7");
4698 /* First setup h and l contaning the top most bytes XORed */
4699 bool fDidXor = FALSE;
4700 if (AOP_TYPE (left) == AOP_LIT)
4702 unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
4703 emit2 ("ld %s,!immedbyte", _fTmp[0],
4704 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4708 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4709 emit2 ("xor a,!immedbyte", 0x80);
4710 emit2 ("ld %s,a", _fTmp[0]);
4713 if (AOP_TYPE (right) == AOP_LIT)
4715 unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
4716 emit2 ("ld %s,!immedbyte", _fTmp[1],
4717 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4721 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4722 emit2 ("xor a,!immedbyte", 0x80);
4723 emit2 ("ld %s,a", _fTmp[1]);
4729 /* Do a long subtract */
4732 _moveA (aopGet (AOP (left), offset, FALSE));
4734 if (sign && size == 0)
4736 emit2 ("ld a,%s", _fTmp[0]);
4737 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4741 /* Subtract through, propagating the carry */
4742 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4750 /** Generic compare for > or <
4753 genCmp (operand * left, operand * right,
4754 operand * result, iCode * ifx, int sign)
4756 int size, offset = 0;
4757 unsigned long lit = 0L;
4759 /* if left & right are bit variables */
4760 if (AOP_TYPE (left) == AOP_CRY &&
4761 AOP_TYPE (right) == AOP_CRY)
4763 /* Cant happen on the Z80 */
4764 wassertl (0, "Tried to compare two bits");
4768 /* Do a long subtract of right from left. */
4769 size = max (AOP_SIZE (left), AOP_SIZE (right));
4771 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4773 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4774 // Pull left into DE and right into HL
4775 aopGet (AOP(left), LSB, FALSE);
4778 aopGet (AOP(right), LSB, FALSE);
4782 emit2 ("ld a,(de)");
4783 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4792 spillPair (PAIR_HL);
4796 if (AOP_TYPE (right) == AOP_LIT)
4798 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4799 /* optimize if(x < 0) or if(x >= 0) */
4804 /* No sign so it's always false */
4809 /* Just load in the top most bit */
4810 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4811 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4813 genIfxJump (ifx, "7");
4824 genIfxJump (ifx, "nc");
4835 _moveA (aopGet (AOP (left), offset, FALSE));
4836 /* Subtract through, propagating the carry */
4837 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4843 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4847 /* Shift the sign bit up into carry */
4854 /* if the result is used in the next
4855 ifx conditional branch then generate
4856 code a little differently */
4864 genIfxJump (ifx, "c");
4868 genIfxJump (ifx, "m");
4873 genIfxJump (ifx, "c");
4880 /* Shift the sign bit up into carry */
4885 /* leave the result in acc */
4889 /*-----------------------------------------------------------------*/
4890 /* genCmpGt :- greater than comparison */
4891 /*-----------------------------------------------------------------*/
4893 genCmpGt (iCode * ic, iCode * ifx)
4895 operand *left, *right, *result;
4896 sym_link *letype, *retype;
4899 left = IC_LEFT (ic);
4900 right = IC_RIGHT (ic);
4901 result = IC_RESULT (ic);
4903 letype = getSpec (operandType (left));
4904 retype = getSpec (operandType (right));
4905 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4906 /* assign the asmops */
4907 aopOp (left, ic, FALSE, FALSE);
4908 aopOp (right, ic, FALSE, FALSE);
4909 aopOp (result, ic, TRUE, FALSE);
4911 setupToPreserveCarry (ic);
4913 genCmp (right, left, result, ifx, sign);
4915 _G.preserveCarry = FALSE;
4916 freeAsmop (left, NULL, ic);
4917 freeAsmop (right, NULL, ic);
4918 freeAsmop (result, NULL, ic);
4921 /*-----------------------------------------------------------------*/
4922 /* genCmpLt - less than comparisons */
4923 /*-----------------------------------------------------------------*/
4925 genCmpLt (iCode * ic, iCode * ifx)
4927 operand *left, *right, *result;
4928 sym_link *letype, *retype;
4931 left = IC_LEFT (ic);
4932 right = IC_RIGHT (ic);
4933 result = IC_RESULT (ic);
4935 letype = getSpec (operandType (left));
4936 retype = getSpec (operandType (right));
4937 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4939 /* assign the asmops */
4940 aopOp (left, ic, FALSE, FALSE);
4941 aopOp (right, ic, FALSE, FALSE);
4942 aopOp (result, ic, TRUE, FALSE);
4944 setupToPreserveCarry (ic);
4946 genCmp (left, right, result, ifx, sign);
4948 _G.preserveCarry = FALSE;
4949 freeAsmop (left, NULL, ic);
4950 freeAsmop (right, NULL, ic);
4951 freeAsmop (result, NULL, ic);
4954 /*-----------------------------------------------------------------*/
4955 /* gencjneshort - compare and jump if not equal */
4956 /* returns pair that still needs to be popped */
4957 /*-----------------------------------------------------------------*/
4959 gencjneshort (operand * left, operand * right, symbol * lbl)
4961 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4963 unsigned long lit = 0L;
4965 /* Swap the left and right if it makes the computation easier */
4966 if (AOP_TYPE (left) == AOP_LIT)
4973 /* if the right side is a literal then anything goes */
4974 if (AOP_TYPE (right) == AOP_LIT)
4976 lit = ulFromVal (AOP (right)->aopu.aop_lit);
4979 _moveA (aopGet (AOP (left), offset, FALSE));
4984 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4991 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4997 _moveA (aopGet (AOP (left), offset, FALSE));
4998 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5001 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
5002 emit2 ("jp NZ,!tlabel", lbl->key + 100);
5007 /* if the right side is in a register or
5008 pointed to by HL, IX or IY */
5009 else if (AOP_TYPE (right) == AOP_REG ||
5010 AOP_TYPE (right) == AOP_HL ||
5011 AOP_TYPE (right) == AOP_IY ||
5012 AOP_TYPE (right) == AOP_STK ||
5013 AOP_IS_PAIRPTR (right, PAIR_HL) ||
5014 AOP_IS_PAIRPTR (right, PAIR_IX) ||
5015 AOP_IS_PAIRPTR (right, PAIR_IY))
5019 _moveA (aopGet (AOP (left), offset, FALSE));
5020 if (AOP_TYPE (right) == AOP_LIT &&
5021 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5024 emit2 ("jp NZ,!tlabel", lbl->key + 100);
5028 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
5029 emit2 ("jp NZ,!tlabel", lbl->key + 100);
5034 /* right is in direct space or a pointer reg, need both a & b */
5038 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
5040 if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
5041 ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
5049 emit2 ("; direct compare");
5050 _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
5051 _moveA (aopGet (AOP (right), offset, FALSE));
5052 emit2 ("sub a,%s", _pairs[pair].l);
5053 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
5058 return PAIR_INVALID;
5061 /*-----------------------------------------------------------------*/
5062 /* gencjne - compare and jump if not equal */
5063 /*-----------------------------------------------------------------*/
5065 gencjne (operand * left, operand * right, symbol * lbl)
5067 symbol *tlbl = newiTempLabel (NULL);
5069 PAIR_ID pop = gencjneshort (left, right, lbl);
5072 emit2 ("ld a,!one");
5073 emit2 ("!shortjp !tlabel", tlbl->key + 100);
5074 emitLabel (lbl->key + 100);
5076 emitLabelNoSpill (tlbl->key + 100);
5080 /*-----------------------------------------------------------------*/
5081 /* genCmpEq - generates code for equal to */
5082 /*-----------------------------------------------------------------*/
5084 genCmpEq (iCode * ic, iCode * ifx)
5086 operand *left, *right, *result;
5088 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5089 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5090 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5092 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
5094 /* Swap operands if it makes the operation easier. ie if:
5095 1. Left is a literal.
5097 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
5099 operand *t = IC_RIGHT (ic);
5100 IC_RIGHT (ic) = IC_LEFT (ic);
5104 if (ifx && !AOP_SIZE (result))
5107 /* if they are both bit variables */
5108 if (AOP_TYPE (left) == AOP_CRY &&
5109 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5111 wassertl (0, "Tried to compare two bits");
5116 tlbl = newiTempLabel (NULL);
5117 pop = gencjneshort (left, right, tlbl);
5121 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
5122 emitLabelNoSpill (tlbl->key + 100);
5127 /* PENDING: do this better */
5128 symbol *lbl = newiTempLabel (NULL);
5130 emit2 ("!shortjp !tlabel", lbl->key + 100);
5131 emitLabelNoSpill (tlbl->key + 100);
5133 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
5134 emitLabelNoSpill (lbl->key + 100);
5137 /* mark the icode as generated */
5142 /* if they are both bit variables */
5143 if (AOP_TYPE (left) == AOP_CRY &&
5144 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5146 wassertl (0, "Tried to compare a bit to either a literal or another bit");
5152 gencjne (left, right, newiTempLabel (NULL));
5153 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5160 genIfxJump (ifx, "a");
5163 /* if the result is used in an arithmetic operation
5164 then put the result in place */
5165 if (AOP_TYPE (result) != AOP_CRY)
5170 /* leave the result in acc */
5174 freeAsmop (left, NULL, ic);
5175 freeAsmop (right, NULL, ic);
5176 freeAsmop (result, NULL, ic);
5179 /*-----------------------------------------------------------------*/
5180 /* ifxForOp - returns the icode containing the ifx for operand */
5181 /*-----------------------------------------------------------------*/
5183 ifxForOp (operand * op, iCode * ic)
5185 /* if true symbol then needs to be assigned */
5186 if (IS_TRUE_SYMOP (op))
5189 /* if this has register type condition and
5190 the next instruction is ifx with the same operand
5191 and live to of the operand is upto the ifx only then */
5193 ic->next->op == IFX &&
5194 IC_COND (ic->next)->key == op->key &&
5195 OP_SYMBOL (op)->liveTo <= ic->next->seq)
5201 /*-----------------------------------------------------------------*/
5202 /* genAndOp - for && operation */
5203 /*-----------------------------------------------------------------*/
5205 genAndOp (iCode * ic)
5207 operand *left, *right, *result;
5210 /* note here that && operations that are in an if statement are
5211 taken away by backPatchLabels only those used in arthmetic
5212 operations remain */
5213 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5214 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5215 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5217 /* if both are bit variables */
5218 if (AOP_TYPE (left) == AOP_CRY &&
5219 AOP_TYPE (right) == AOP_CRY)
5221 wassertl (0, "Tried to and two bits");
5225 tlbl = newiTempLabel (NULL);
5227 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5229 emitLabelNoSpill (tlbl->key + 100);
5233 freeAsmop (left, NULL, ic);
5234 freeAsmop (right, NULL, ic);
5235 freeAsmop (result, NULL, ic);
5238 /*-----------------------------------------------------------------*/
5239 /* genOrOp - for || operation */
5240 /*-----------------------------------------------------------------*/
5242 genOrOp (iCode * ic)
5244 operand *left, *right, *result;
5247 /* note here that || operations that are in an
5248 if statement are taken away by backPatchLabels
5249 only those used in arthmetic operations remain */
5250 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5251 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5252 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5254 /* if both are bit variables */
5255 if (AOP_TYPE (left) == AOP_CRY &&
5256 AOP_TYPE (right) == AOP_CRY)
5258 wassertl (0, "Tried to OR two bits");
5262 tlbl = newiTempLabel (NULL);
5264 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5266 emitLabelNoSpill (tlbl->key + 100);
5270 freeAsmop (left, NULL, ic);
5271 freeAsmop (right, NULL, ic);
5272 freeAsmop (result, NULL, ic);
5275 /*-----------------------------------------------------------------*/
5276 /* isLiteralBit - test if lit == 2^n */
5277 /*-----------------------------------------------------------------*/
5279 isLiteralBit (unsigned long lit)
5281 unsigned long pw[32] =
5282 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5283 0x100L, 0x200L, 0x400L, 0x800L,
5284 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5285 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5286 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5287 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5288 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5291 for (idx = 0; idx < 32; idx++)
5297 /*-----------------------------------------------------------------*/
5298 /* jmpTrueOrFalse - */
5299 /*-----------------------------------------------------------------*/
5301 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5303 // ugly but optimized by peephole
5306 symbol *nlbl = newiTempLabel (NULL);
5307 emit2 ("jp !tlabel", nlbl->key + 100);
5308 emitLabelNoSpill (tlbl->key + 100);
5309 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5310 emitLabelNoSpill (nlbl->key + 100);
5314 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5315 emitLabelNoSpill (tlbl->key + 100);
5320 /*-----------------------------------------------------------------*/
5321 /* genAnd - code for and */
5322 /*-----------------------------------------------------------------*/
5324 genAnd (iCode * ic, iCode * ifx)
5326 operand *left, *right, *result;
5327 int size, offset = 0;
5328 unsigned long lit = 0L;
5331 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5332 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5333 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5335 /* if left is a literal & right is not then exchange them */
5336 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5337 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5339 operand *tmp = right;
5344 /* if result = right then exchange them */
5345 if (sameRegs (AOP (result), AOP (right)))
5347 operand *tmp = right;
5352 /* if right is bit then exchange them */
5353 if (AOP_TYPE (right) == AOP_CRY &&
5354 AOP_TYPE (left) != AOP_CRY)
5356 operand *tmp = right;
5360 if (AOP_TYPE (right) == AOP_LIT)
5361 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5363 size = AOP_SIZE (result);
5365 if (AOP_TYPE (left) == AOP_CRY)
5367 wassertl (0, "Tried to perform an AND with a bit as an operand");
5371 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5372 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5373 if ((AOP_TYPE (right) == AOP_LIT) &&
5374 (AOP_TYPE (result) == AOP_CRY) &&
5375 (AOP_TYPE (left) != AOP_CRY))
5377 symbol *tlbl = newiTempLabel (NULL);
5378 int sizel = AOP_SIZE (left);
5381 /* PENDING: Test case for this. */
5386 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5388 _moveA (aopGet (AOP (left), offset, FALSE));
5389 if (bytelit != 0x0FFL)
5391 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5398 if (size || ifx) /* emit jmp only, if it is actually used */
5399 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5403 // bit = left & literal
5407 emit2 ("!tlabeldef", tlbl->key + 100);
5408 _G.lines.current->isLabel = 1;
5410 // if(left & literal)
5415 jmpTrueOrFalse (ifx, tlbl);
5423 /* if left is same as result */
5424 if (sameRegs (AOP (result), AOP (left)))
5426 for (; size--; offset++)
5428 if (AOP_TYPE (right) == AOP_LIT)
5430 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5435 aopPut (AOP (result), "!zero", offset);
5438 _moveA (aopGet (AOP (left), offset, FALSE));
5440 aopGet (AOP (right), offset, FALSE));
5441 aopPut (AOP (left), "a", offset);
5448 if (AOP_TYPE (left) == AOP_ACC)
5450 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5454 _moveA (aopGet (AOP (left), offset, FALSE));
5456 aopGet (AOP (right), offset, FALSE));
5457 aopPut (AOP (left), "a", offset);
5464 // left & result in different registers
5465 if (AOP_TYPE (result) == AOP_CRY)
5467 wassertl (0, "Tried to AND where the result is in carry");
5471 for (; (size--); offset++)
5474 // result = left & right
5475 if (AOP_TYPE (right) == AOP_LIT)
5477 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5479 aopPut (AOP (result),
5480 aopGet (AOP (left), offset, FALSE),
5484 else if (bytelit == 0)
5486 aopPut (AOP (result), "!zero", offset);
5490 // faster than result <- left, anl result,right
5491 // and better if result is SFR
5492 if (AOP_TYPE (left) == AOP_ACC)
5493 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5496 _moveA (aopGet (AOP (left), offset, FALSE));
5498 aopGet (AOP (right), offset, FALSE));
5500 aopPut (AOP (result), "a", offset);
5507 freeAsmop (left, NULL, ic);
5508 freeAsmop (right, NULL, ic);
5509 freeAsmop (result, NULL, ic);
5512 /*-----------------------------------------------------------------*/
5513 /* genOr - code for or */
5514 /*-----------------------------------------------------------------*/
5516 genOr (iCode * ic, iCode * ifx)
5518 operand *left, *right, *result;
5519 int size, offset = 0;
5520 unsigned long lit = 0L;
5523 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5524 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5525 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5527 /* if left is a literal & right is not then exchange them */
5528 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5529 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5531 operand *tmp = right;
5536 /* if result = right then exchange them */
5537 if (sameRegs (AOP (result), AOP (right)))
5539 operand *tmp = right;
5544 /* if right is bit then exchange them */
5545 if (AOP_TYPE (right) == AOP_CRY &&
5546 AOP_TYPE (left) != AOP_CRY)
5548 operand *tmp = right;
5552 if (AOP_TYPE (right) == AOP_LIT)
5553 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5555 size = AOP_SIZE (result);
5557 if (AOP_TYPE (left) == AOP_CRY)
5559 wassertl (0, "Tried to OR where left is a bit");
5563 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5564 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5565 if ((AOP_TYPE (right) == AOP_LIT) &&
5566 (AOP_TYPE (result) == AOP_CRY) &&
5567 (AOP_TYPE (left) != AOP_CRY))
5569 symbol *tlbl = newiTempLabel (NULL);
5570 int sizel = AOP_SIZE (left);
5574 wassertl (0, "Result is assigned to a bit");
5576 /* PENDING: Modeled after the AND code which is inefficient. */
5579 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5581 _moveA (aopGet (AOP (left), offset, FALSE));
5584 { /* FIXME, allways true, shortcut possible */
5585 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5593 if (ifx) /* emit jmp only, if it is actually used */
5594 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5600 jmpTrueOrFalse (ifx, tlbl);
5605 /* if left is same as result */
5606 if (sameRegs (AOP (result), AOP (left)))
5608 for (; size--; offset++)
5610 if (AOP_TYPE (right) == AOP_LIT)
5612 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5616 _moveA (aopGet (AOP (left), offset, FALSE));
5618 aopGet (AOP (right), offset, FALSE));
5619 aopPut (AOP (result), "a", offset);
5624 if (AOP_TYPE (left) == AOP_ACC)
5625 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5628 _moveA (aopGet (AOP (left), offset, FALSE));
5630 aopGet (AOP (right), offset, FALSE));
5631 aopPut (AOP (result), "a", offset);
5638 // left & result in different registers
5639 if (AOP_TYPE (result) == AOP_CRY)
5641 wassertl (0, "Result of OR is in a bit");
5644 for (; (size--); offset++)
5647 // result = left & right
5648 if (AOP_TYPE (right) == AOP_LIT)
5650 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5652 aopPut (AOP (result),
5653 aopGet (AOP (left), offset, FALSE),
5658 // faster than result <- left, anl result,right
5659 // and better if result is SFR
5660 if (AOP_TYPE (left) == AOP_ACC)
5661 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5664 _moveA (aopGet (AOP (left), offset, FALSE));
5666 aopGet (AOP (right), offset, FALSE));
5668 aopPut (AOP (result), "a", offset);
5669 /* PENDING: something weird is going on here. Add exception. */
5670 if (AOP_TYPE (result) == AOP_ACC)
5676 freeAsmop (left, NULL, ic);
5677 freeAsmop (right, NULL, ic);
5678 freeAsmop (result, NULL, ic);
5681 /*-----------------------------------------------------------------*/
5682 /* genXor - code for xclusive or */
5683 /*-----------------------------------------------------------------*/
5685 genXor (iCode * ic, iCode * ifx)
5687 operand *left, *right, *result;
5688 int size, offset = 0;
5689 unsigned long lit = 0L;
5691 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5692 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5693 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5695 /* if left is a literal & right is not then exchange them */
5696 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5697 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5699 operand *tmp = right;
5704 /* if result = right then exchange them */
5705 if (sameRegs (AOP (result), AOP (right)))
5707 operand *tmp = right;
5712 /* if right is bit then exchange them */
5713 if (AOP_TYPE (right) == AOP_CRY &&
5714 AOP_TYPE (left) != AOP_CRY)
5716 operand *tmp = right;
5720 if (AOP_TYPE (right) == AOP_LIT)
5721 lit = ulFromVal (AOP (right)->aopu.aop_lit);
5723 size = AOP_SIZE (result);
5725 if (AOP_TYPE (left) == AOP_CRY)
5727 wassertl (0, "Tried to XOR a bit");
5731 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5732 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5733 if ((AOP_TYPE (right) == AOP_LIT) &&
5734 (AOP_TYPE (result) == AOP_CRY) &&
5735 (AOP_TYPE (left) != AOP_CRY))
5737 symbol *tlbl = newiTempLabel (NULL);
5738 int sizel = AOP_SIZE (left);
5742 /* PENDING: Test case for this. */
5743 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5747 _moveA (aopGet (AOP (left), offset, FALSE));
5748 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5749 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5754 jmpTrueOrFalse (ifx, tlbl);
5758 wassertl (0, "Result of XOR was destined for a bit");
5763 /* if left is same as result */
5764 if (sameRegs (AOP (result), AOP (left)))
5766 for (; size--; offset++)
5768 if (AOP_TYPE (right) == AOP_LIT)
5770 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5774 _moveA (aopGet (AOP (left), offset, FALSE));
5776 aopGet (AOP (right), offset, FALSE));
5777 aopPut (AOP (result), "a", offset);
5782 if (AOP_TYPE (left) == AOP_ACC)
5784 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5788 _moveA (aopGet (AOP (left), offset, FALSE));
5790 aopGet (AOP (right), offset, FALSE));
5791 aopPut (AOP (result), "a", offset);
5798 // left & result in different registers
5799 if (AOP_TYPE (result) == AOP_CRY)
5801 wassertl (0, "Result of XOR is in a bit");
5804 for (; (size--); offset++)
5807 // result = left & right
5808 if (AOP_TYPE (right) == AOP_LIT)
5810 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5812 aopPut (AOP (result),
5813 aopGet (AOP (left), offset, FALSE),
5818 // faster than result <- left, anl result,right
5819 // and better if result is SFR
5820 if (AOP_TYPE (left) == AOP_ACC)
5822 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5826 _moveA (aopGet (AOP (left), offset, FALSE));
5828 aopGet (AOP (right), offset, FALSE));
5830 aopPut (AOP (result), "a", offset);
5835 freeAsmop (left, NULL, ic);
5836 freeAsmop (right, NULL, ic);
5837 freeAsmop (result, NULL, ic);
5840 /*-----------------------------------------------------------------*/
5841 /* genInline - write the inline code out */
5842 /*-----------------------------------------------------------------*/
5844 genInline (iCode * ic)
5846 char *buffer, *bp, *bp1;
5847 bool inComment = FALSE;
5849 _G.lines.isInline += (!options.asmpeep);
5851 buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
5853 /* emit each line as a code */
5871 /* Add \n for labels, not dirs such as c:\mydir */
5872 if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
5890 _G.lines.isInline -= (!options.asmpeep);
5894 /*-----------------------------------------------------------------*/
5895 /* genRRC - rotate right with carry */
5896 /*-----------------------------------------------------------------*/
5903 /*-----------------------------------------------------------------*/
5904 /* genRLC - generate code for rotate left with carry */
5905 /*-----------------------------------------------------------------*/
5912 /*-----------------------------------------------------------------*/
5913 /* genGetHbit - generates code get highest order bit */
5914 /*-----------------------------------------------------------------*/
5916 genGetHbit (iCode * ic)
5918 operand *left, *result;
5919 left = IC_LEFT (ic);
5920 result = IC_RESULT (ic);
5922 aopOp (left, ic, FALSE, FALSE);
5923 aopOp (result, ic, FALSE, FALSE);
5925 /* get the highest order byte into a */
5926 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5928 if (AOP_TYPE (result) == AOP_CRY)
5936 emit2 ("and a,!one");
5941 freeAsmop (left, NULL, ic);
5942 freeAsmop (result, NULL, ic);
5946 emitRsh2 (asmop *aop, int size, int is_signed)
5952 const char *l = aopGet (aop, size, FALSE);
5955 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5965 /*-----------------------------------------------------------------*/
5966 /* shiftR2Left2Result - shift right two bytes from left to result */
5967 /*-----------------------------------------------------------------*/
5969 shiftR2Left2Result (operand * left, int offl,
5970 operand * result, int offr,
5971 int shCount, int is_signed)
5976 movLeft2Result (left, offl, result, offr, 0);
5977 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5982 /* if (AOP(result)->type == AOP_REG) { */
5984 tlbl = newiTempLabel (NULL);
5986 /* Left is already in result - so now do the shift */
5987 /* Optimizing for speed by default. */
5988 if (!optimize.codeSize || shCount <= 2)
5992 emitRsh2 (AOP (result), size, is_signed);
5997 emit2 ("ld a,!immedbyte", shCount);
5999 emitLabelNoSpill (tlbl->key + 100);
6001 emitRsh2 (AOP (result), size, is_signed);
6004 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6008 /*-----------------------------------------------------------------*/
6009 /* shiftL2Left2Result - shift left two bytes from left to result */
6010 /*-----------------------------------------------------------------*/
6012 shiftL2Left2Result (operand * left, int offl,
6013 operand * result, int offr, int shCount)
6015 if (sameRegs (AOP (result), AOP (left)) &&
6016 ((offl + MSB16) == offr))
6022 /* Copy left into result */
6023 movLeft2Result (left, offl, result, offr, 0);
6024 movLeft2Result (left, offl + 1, result, offr + 1, 0);
6030 if (getPairId (AOP (result)) == PAIR_HL)
6034 emit2 ("add hl,hl");
6041 symbol *tlbl, *tlbl1;
6044 tlbl = newiTempLabel (NULL);
6045 tlbl1 = newiTempLabel (NULL);
6047 if (AOP (result)->type == AOP_REG)
6051 for (offset = 0; offset < size; offset++)
6053 l = aopGet (AOP (result), offset, FALSE);
6057 emit2 ("sla %s", l);
6068 /* Left is already in result - so now do the shift */
6071 emit2 ("ld a,!immedbyte+1", shCount);
6072 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6073 emitLabelNoSpill (tlbl->key + 100);
6078 l = aopGet (AOP (result), offset, FALSE);
6082 emit2 ("sla %s", l);
6093 emitLabelNoSpill (tlbl1->key + 100);
6095 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6101 /*-----------------------------------------------------------------*/
6102 /* AccRol - rotate left accumulator by known count */
6103 /*-----------------------------------------------------------------*/
6105 AccRol (int shCount)
6107 shCount &= 0x0007; // shCount : 0..7
6184 /*-----------------------------------------------------------------*/
6185 /* AccLsh - left shift accumulator by known count */
6186 /*-----------------------------------------------------------------*/
6188 AccLsh (int shCount)
6190 static const unsigned char SLMask[] =
6192 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
6201 else if (shCount == 2)
6208 /* rotate left accumulator */
6210 /* and kill the lower order bits */
6211 emit2 ("and a,!immedbyte", SLMask[shCount]);
6216 /*-----------------------------------------------------------------*/
6217 /* shiftL1Left2Result - shift left one byte from left to result */
6218 /*-----------------------------------------------------------------*/
6220 shiftL1Left2Result (operand * left, int offl,
6221 operand * result, int offr, int shCount)
6225 /* If operand and result are the same we can shift in place.
6226 However shifting in acc using add is cheaper than shifting
6227 in place using sla; when shifting by more than 2 shifting in
6228 acc is worth the additional effort for loading from/to acc. */
6229 if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
6232 emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
6236 l = aopGet (AOP (left), offl, FALSE);
6238 /* shift left accumulator */
6240 aopPut (AOP (result), "a", offr);
6244 /*-----------------------------------------------------------------*/
6245 /* genlshTwo - left shift two bytes by known amount */
6246 /*-----------------------------------------------------------------*/
6248 genlshTwo (operand * result, operand * left, int shCount)
6250 int size = AOP_SIZE (result);
6252 wassert (size == 2);
6254 /* if shCount >= 8 */
6262 movLeft2Result (left, LSB, result, MSB16, 0);
6263 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6264 aopPut (AOP (result), "!zero", LSB);
6268 movLeft2Result (left, LSB, result, MSB16, 0);
6269 aopPut (AOP (result), "!zero", 0);
6274 aopPut (AOP (result), "!zero", LSB);
6277 /* 0 <= shCount <= 7 */
6286 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6291 /*-----------------------------------------------------------------*/
6292 /* genlshOne - left shift a one byte quantity by known count */
6293 /*-----------------------------------------------------------------*/
6295 genlshOne (operand * result, operand * left, int shCount)
6297 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6300 /*-----------------------------------------------------------------*/
6301 /* genLeftShiftLiteral - left shifting by known count */
6302 /*-----------------------------------------------------------------*/
6304 genLeftShiftLiteral (operand * left,
6309 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6312 freeAsmop (right, NULL, ic);
6314 aopOp (left, ic, FALSE, FALSE);
6315 aopOp (result, ic, FALSE, FALSE);
6317 size = getSize (operandType (result));
6319 /* I suppose that the left size >= result size */
6321 if (shCount >= (size * 8))
6325 aopPut (AOP (result), "!zero", size);
6333 genlshOne (result, left, shCount);
6336 genlshTwo (result, left, shCount);
6339 wassertl (0, "Shifting of longs is currently unsupported");
6345 freeAsmop (left, NULL, ic);
6346 freeAsmop (result, NULL, ic);
6349 /*-----------------------------------------------------------------*/
6350 /* genLeftShift - generates code for left shifting */
6351 /*-----------------------------------------------------------------*/
6353 genLeftShift (iCode * ic)
6357 symbol *tlbl, *tlbl1;
6358 operand *left, *right, *result;
6360 right = IC_RIGHT (ic);
6361 left = IC_LEFT (ic);
6362 result = IC_RESULT (ic);
6364 aopOp (right, ic, FALSE, FALSE);
6366 /* if the shift count is known then do it
6367 as efficiently as possible */
6368 if (AOP_TYPE (right) == AOP_LIT)
6370 genLeftShiftLiteral (left, right, result, ic);
6374 /* shift count is unknown then we have to form a loop get the loop
6375 count in B : Note: we take only the lower order byte since
6376 shifting more that 32 bits make no sense anyway, ( the largest
6377 size of an object can be only 32 bits ) */
6378 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6380 freeAsmop (right, NULL, ic);
6381 aopOp (left, ic, FALSE, FALSE);
6382 aopOp (result, ic, FALSE, FALSE);
6384 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6387 /* now move the left to the result if they are not the
6390 if (!sameRegs (AOP (left), AOP (result)))
6393 size = AOP_SIZE (result);
6397 l = aopGet (AOP (left), offset, FALSE);
6398 aopPut (AOP (result), l, offset);
6403 tlbl = newiTempLabel (NULL);
6404 size = AOP_SIZE (result);
6406 tlbl1 = newiTempLabel (NULL);
6408 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6411 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6412 emitLabelNoSpill (tlbl->key + 100);
6413 l = aopGet (AOP (result), offset, FALSE);
6417 l = aopGet (AOP (result), offset, FALSE);
6421 emit2 ("sla %s", l);
6429 emitLabelNoSpill (tlbl1->key + 100);
6431 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6433 freeAsmop (left, NULL, ic);
6434 freeAsmop (result, NULL, ic);
6437 /*-----------------------------------------------------------------*/
6438 /* genrshOne - left shift two bytes by known amount != 0 */
6439 /*-----------------------------------------------------------------*/
6441 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6444 int size = AOP_SIZE (result);
6447 wassert (size == 1);
6448 wassert (shCount < 8);
6450 l = aopGet (AOP (left), 0, FALSE);
6452 if (AOP (result)->type == AOP_REG)
6454 aopPut (AOP (result), l, 0);
6455 l = aopGet (AOP (result), 0, FALSE);
6458 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6466 emit2 ("%s a", is_signed ? "sra" : "srl");
6468 aopPut (AOP (result), "a", 0);
6472 /*-----------------------------------------------------------------*/
6473 /* AccRsh - right shift accumulator by known count */
6474 /*-----------------------------------------------------------------*/
6476 AccRsh (int shCount)
6478 static const unsigned char SRMask[] =
6480 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6485 /* rotate right accumulator */
6486 AccRol (8 - shCount);
6487 /* and kill the higher order bits */
6488 emit2 ("and a,!immedbyte", SRMask[shCount]);
6492 /*-----------------------------------------------------------------*/
6493 /* shiftR1Left2Result - shift right one byte from left to result */
6494 /*-----------------------------------------------------------------*/
6496 shiftR1Left2Result (operand * left, int offl,
6497 operand * result, int offr,
6498 int shCount, int sign)
6500 _moveA (aopGet (AOP (left), offl, FALSE));
6505 emit2 ("%s a", sign ? "sra" : "srl");
6512 aopPut (AOP (result), "a", offr);
6515 /*-----------------------------------------------------------------*/
6516 /* genrshTwo - right shift two bytes by known amount */
6517 /*-----------------------------------------------------------------*/
6519 genrshTwo (operand * result, operand * left,
6520 int shCount, int sign)
6522 /* if shCount >= 8 */
6528 shiftR1Left2Result (left, MSB16, result, LSB,
6533 movLeft2Result (left, MSB16, result, LSB, sign);
6537 /* Sign extend the result */
6538 _moveA(aopGet (AOP (result), 0, FALSE));
6542 aopPut (AOP (result), ACC_NAME, MSB16);
6546 aopPut (AOP (result), "!zero", 1);
6549 /* 0 <= shCount <= 7 */
6552 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6556 /*-----------------------------------------------------------------*/
6557 /* genRightShiftLiteral - left shifting by known count */
6558 /*-----------------------------------------------------------------*/
6560 genRightShiftLiteral (operand * left,
6566 int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
6569 freeAsmop (right, NULL, ic);
6571 aopOp (left, ic, FALSE, FALSE);
6572 aopOp (result, ic, FALSE, FALSE);
6574 size = getSize (operandType (result));
6576 /* I suppose that the left size >= result size */
6578 if (shCount >= (size * 8)) {
6580 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6581 _moveA(aopGet (AOP (left), 0, FALSE));
6589 aopPut (AOP (result), s, size);
6596 genrshOne (result, left, shCount, sign);
6599 genrshTwo (result, left, shCount, sign);
6602 wassertl (0, "Asked to shift right a long which should be a function call");
6605 wassertl (0, "Entered default case in right shift delegate");
6608 freeAsmop (left, NULL, ic);
6609 freeAsmop (result, NULL, ic);
6612 /*-----------------------------------------------------------------*/
6613 /* genRightShift - generate code for right shifting */
6614 /*-----------------------------------------------------------------*/
6616 genRightShift (iCode * ic)
6618 operand *right, *left, *result;
6620 int size, offset, first = 1;
6624 symbol *tlbl, *tlbl1;
6626 /* if signed then we do it the hard way preserve the
6627 sign bit moving it inwards */
6628 retype = getSpec (operandType (IC_RESULT (ic)));
6630 is_signed = !SPEC_USIGN (retype);
6632 /* signed & unsigned types are treated the same : i.e. the
6633 signed is NOT propagated inwards : quoting from the
6634 ANSI - standard : "for E1 >> E2, is equivalent to division
6635 by 2**E2 if unsigned or if it has a non-negative value,
6636 otherwise the result is implementation defined ", MY definition
6637 is that the sign does not get propagated */
6639 right = IC_RIGHT (ic);
6640 left = IC_LEFT (ic);
6641 result = IC_RESULT (ic);
6643 aopOp (right, ic, FALSE, FALSE);
6645 /* if the shift count is known then do it
6646 as efficiently as possible */
6647 if (AOP_TYPE (right) == AOP_LIT)
6649 genRightShiftLiteral (left, right, result, ic, is_signed);
6653 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6655 freeAsmop (right, NULL, ic);
6657 aopOp (left, ic, FALSE, FALSE);
6658 aopOp (result, ic, FALSE, FALSE);
6660 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6663 /* now move the left to the result if they are not the
6665 if (!sameRegs (AOP (left), AOP (result)))
6668 size = AOP_SIZE (result);
6672 l = aopGet (AOP (left), offset, FALSE);
6673 aopPut (AOP (result), l, offset);
6678 tlbl = newiTempLabel (NULL);
6679 tlbl1 = newiTempLabel (NULL);
6680 size = AOP_SIZE (result);
6683 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6686 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6687 emitLabelNoSpill (tlbl->key + 100);
6690 l = aopGet (AOP (result), offset--, FALSE);
6693 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6701 emitLabelNoSpill (tlbl1->key + 100);
6703 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6705 freeAsmop (left, NULL, ic);
6706 freeAsmop (result, NULL, ic);
6710 /*-----------------------------------------------------------------*/
6711 /* genUnpackBits - generates code for unpacking bits */
6712 /*-----------------------------------------------------------------*/
6714 genUnpackBits (operand * result, int pair)
6716 int offset = 0; /* result byte offset */
6717 int rsize; /* result size */
6718 int rlen = 0; /* remaining bitfield length */
6719 sym_link *etype; /* bitfield type information */
6720 int blen; /* bitfield length */
6721 int bstr; /* bitfield starting bit within byte */
6723 emitDebug ("; genUnpackBits");
6725 etype = getSpec (operandType (result));
6726 rsize = getSize (operandType (result));
6727 blen = SPEC_BLEN (etype);
6728 bstr = SPEC_BSTR (etype);
6730 /* If the bitfield length is less than a byte */
6733 emit2 ("ld a,!*pair", _pairs[pair].name);
6735 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6736 if (!SPEC_USIGN (etype))
6738 /* signed bitfield */
6739 symbol *tlbl = newiTempLabel (NULL);
6741 emit2 ("bit %d,a", blen - 1);
6742 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6743 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6744 emitLabelNoSpill (tlbl->key + 100);
6746 aopPut (AOP (result), "a", offset++);
6750 /* TODO: what if pair == PAIR_DE ? */
6751 if (getPairId (AOP (result)) == PAIR_HL)
6753 wassertl (rsize == 2, "HL must be of size 2");
6754 emit2 ("ld a,!*hl");
6756 emit2 ("ld h,!*hl");
6759 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6760 if (!SPEC_USIGN (etype))
6762 /* signed bitfield */
6763 symbol *tlbl = newiTempLabel (NULL);
6764 emit2 ("bit %d,a", blen - 1 - 8);
6765 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6766 emit2 ("or a,!immedbyte", (unsigned char) (0xff << (blen - 8)));
6767 emitLabelNoSpill (tlbl->key + 100);
6770 spillPair (PAIR_HL);
6774 /* Bit field did not fit in a byte. Copy all
6775 but the partial byte at the end. */
6776 for (rlen=blen;rlen>=8;rlen-=8)
6778 emit2 ("ld a,!*pair", _pairs[pair].name);
6779 aopPut (AOP (result), "a", offset++);
6782 emit2 ("inc %s", _pairs[pair].name);
6783 _G.pairs[pair].offset++;
6787 /* Handle the partial byte at the end */
6790 emit2 ("ld a,!*pair", _pairs[pair].name);
6791 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6792 if (!SPEC_USIGN (etype))
6794 /* signed bitfield */
6795 symbol *tlbl = newiTempLabel (NULL);
6797 emit2 ("bit %d,a", rlen - 1);
6798 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6799 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6800 emitLabelNoSpill (tlbl->key + 100);
6802 aopPut (AOP (result), "a", offset++);
6810 if (SPEC_USIGN (etype))
6814 /* signed bitfield: sign extension with 0x00 or 0xff */
6822 aopPut (AOP (result), source, offset++);
6826 /*-----------------------------------------------------------------*/
6827 /* genGenPointerGet - get value from generic pointer space */
6828 /*-----------------------------------------------------------------*/
6830 genGenPointerGet (operand * left,
6831 operand * result, iCode * ic)
6834 sym_link *retype = getSpec (operandType (result));
6840 aopOp (left, ic, FALSE, FALSE);
6841 aopOp (result, ic, FALSE, FALSE);
6843 size = AOP_SIZE (result);
6845 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6848 if (isPtrPair (AOP (left)))
6850 tsprintf (buffer, sizeof(buffer),
6851 "!*pair", getPairName (AOP (left)));
6852 aopPut (AOP (result), buffer, 0);
6856 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6857 aopPut (AOP (result), "a", 0);
6859 freeAsmop (left, NULL, ic);
6863 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6870 tsprintf (at, sizeof(at), "!*iyx", offset);
6871 aopPut (AOP (result), at, offset);
6875 freeAsmop (left, NULL, ic);
6879 /* For now we always load into IY */
6880 /* if this is remateriazable */
6881 fetchPair (pair, AOP (left));
6883 /* if bit then unpack */
6884 if (IS_BITVAR (retype))
6886 genUnpackBits (result, pair);
6887 freeAsmop (left, NULL, ic);
6891 else if (getPairId (AOP (result)) == PAIR_HL)
6893 wassertl (size == 2, "HL must be of size 2");
6894 emit2 ("ld a,!*hl");
6896 emit2 ("ld h,!*hl");
6898 spillPair (PAIR_HL);
6900 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6902 size = AOP_SIZE (result);
6907 /* PENDING: make this better */
6908 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6910 aopPut (AOP (result), "!*hl", offset++);
6914 emit2 ("ld a,!*pair", _pairs[pair].name);
6915 aopPut (AOP (result), "a", offset++);
6919 emit2 ("inc %s", _pairs[pair].name);
6920 _G.pairs[pair].offset++;
6923 /* Fixup HL back down */
6924 for (size = AOP_SIZE (result)-1; size; size--)
6926 emit2 ("dec %s", _pairs[pair].name);
6931 size = AOP_SIZE (result);
6936 /* PENDING: make this better */
6938 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6940 aopPut (AOP (result), "!*hl", offset++);
6944 emit2 ("ld a,!*pair", _pairs[pair].name);
6945 aopPut (AOP (result), "a", offset++);
6949 emit2 ("inc %s", _pairs[pair].name);
6950 _G.pairs[pair].offset++;
6955 freeAsmop (left, NULL, ic);
6958 freeAsmop (result, NULL, ic);
6961 /*-----------------------------------------------------------------*/
6962 /* genPointerGet - generate code for pointer get */
6963 /*-----------------------------------------------------------------*/
6965 genPointerGet (iCode * ic)
6967 operand *left, *result;
6968 sym_link *type, *etype;
6970 left = IC_LEFT (ic);
6971 result = IC_RESULT (ic);
6973 /* depending on the type of pointer we need to
6974 move it to the correct pointer register */
6975 type = operandType (left);
6976 etype = getSpec (type);
6978 genGenPointerGet (left, result, ic);
6982 isRegOrLit (asmop * aop)
6984 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6990 /*-----------------------------------------------------------------*/
6991 /* genPackBits - generates code for packed bit storage */
6992 /*-----------------------------------------------------------------*/
6994 genPackBits (sym_link * etype,
6999 int offset = 0; /* source byte offset */
7000 int rlen = 0; /* remaining bitfield length */
7001 int blen; /* bitfield length */
7002 int bstr; /* bitfield starting bit within byte */
7003 int litval; /* source literal value (if AOP_LIT) */
7004 unsigned char mask; /* bitmask within current byte */
7005 int extraPair; /* a tempory register */
7006 bool needPopExtra=0; /* need to restore original value of temp reg */
7008 emitDebug ("; genPackBits","");
7010 blen = SPEC_BLEN (etype);
7011 bstr = SPEC_BSTR (etype);
7013 /* If the bitfield length is less than a byte */
7016 mask = ((unsigned char) (0xFF << (blen + bstr)) |
7017 (unsigned char) (0xFF >> (8 - bstr)));
7019 if (AOP_TYPE (right) == AOP_LIT)
7021 /* Case with a bitfield length <8 and literal source
7023 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7025 litval &= (~mask) & 0xff;
7026 emit2 ("ld a,!*pair", _pairs[pair].name);
7027 if ((mask|litval)!=0xff)
7028 emit2 ("and a,!immedbyte", mask);
7030 emit2 ("or a,!immedbyte", litval);
7031 emit2 ("ld !*pair,a", _pairs[pair].name);
7036 /* Case with a bitfield length <8 and arbitrary source
7038 _moveA (aopGet (AOP (right), 0, FALSE));
7039 /* shift and mask source value */
7041 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7043 extraPair = getFreePairId(ic);
7044 if (extraPair == PAIR_INVALID)
7046 extraPair = PAIR_BC;
7047 if (getPairId (AOP (right)) != PAIR_BC
7048 || !isLastUse (ic, right))
7054 emit2 ("ld %s,a", _pairs[extraPair].l);
7055 emit2 ("ld a,!*pair", _pairs[pair].name);
7057 emit2 ("and a,!immedbyte", mask);
7058 emit2 ("or a,%s", _pairs[extraPair].l);
7059 emit2 ("ld !*pair,a", _pairs[pair].name);
7066 /* Bit length is greater than 7 bits. In this case, copy */
7067 /* all except the partial byte at the end */
7068 for (rlen=blen;rlen>=8;rlen-=8)
7070 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
7071 emit2 ("ld !*pair,a", _pairs[pair].name);
7074 emit2 ("inc %s", _pairs[pair].name);
7075 _G.pairs[pair].offset++;
7079 /* If there was a partial byte at the end */
7082 mask = (((unsigned char) -1 << rlen) & 0xff);
7084 if (AOP_TYPE (right) == AOP_LIT)
7086 /* Case with partial byte and literal source
7088 litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
7089 litval >>= (blen-rlen);
7090 litval &= (~mask) & 0xff;
7091 emit2 ("ld a,!*pair", _pairs[pair].name);
7092 if ((mask|litval)!=0xff)
7093 emit2 ("and a,!immedbyte", mask);
7095 emit2 ("or a,!immedbyte", litval);
7099 /* Case with partial byte and arbitrary source
7101 _moveA (aopGet (AOP (right), offset++, FALSE));
7102 emit2 ("and a,!immedbyte", (~mask) & 0xff);
7104 extraPair = getFreePairId(ic);
7105 if (extraPair == PAIR_INVALID)
7107 extraPair = getPairId (AOP (right));
7108 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
7109 extraPair = PAIR_BC;
7111 if (getPairId (AOP (right)) != PAIR_BC
7112 || !isLastUse (ic, right))
7118 emit2 ("ld %s,a", _pairs[extraPair].l);
7119 emit2 ("ld a,!*pair", _pairs[pair].name);
7121 emit2 ("and a,!immedbyte", mask);
7122 emit2 ("or a,%s", _pairs[extraPair].l);
7127 emit2 ("ld !*pair,a", _pairs[pair].name);
7132 /*-----------------------------------------------------------------*/
7133 /* genGenPointerSet - stores the value into a pointer location */
7134 /*-----------------------------------------------------------------*/
7136 genGenPointerSet (operand * right,
7137 operand * result, iCode * ic)
7140 sym_link *retype = getSpec (operandType (right));
7141 sym_link *letype = getSpec (operandType (result));
7142 PAIR_ID pairId = PAIR_HL;
7145 aopOp (result, ic, FALSE, FALSE);
7146 aopOp (right, ic, FALSE, FALSE);
7151 size = AOP_SIZE (right);
7153 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
7154 emitDebug("; isBitvar = %d", isBitvar);
7156 /* Handle the exceptions first */
7157 if (isPair (AOP (result)) && size == 1 && !isBitvar)
7160 const char *l = aopGet (AOP (right), 0, FALSE);
7161 const char *pair = getPairName (AOP (result));
7162 if (canAssignToPtr (l) && isPtr (pair))
7164 emit2 ("ld !*pair,%s", pair, l);
7169 emit2 ("ld !*pair,a", pair);
7174 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
7177 const char *l = aopGet (AOP (right), 0, FALSE);
7182 if (canAssignToPtr (l))
7184 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
7188 _moveA (aopGet (AOP (right), offset, FALSE));
7189 emit2 ("ld !*iyx,a", offset);
7195 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
7202 const char *l = aopGet (AOP (right), offset, FALSE);
7203 if (isRegOrLit (AOP (right)) && !IS_GB)
7205 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
7210 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
7214 emit2 ("inc %s", _pairs[PAIR_HL].name);
7215 _G.pairs[PAIR_HL].offset++;
7220 /* Fixup HL back down */
7221 for (size = AOP_SIZE (right)-1; size; size--)
7223 emit2 ("dec %s", _pairs[PAIR_HL].name);
7228 /* if the operand is already in dptr
7229 then we do nothing else we move the value to dptr */
7230 if (AOP_TYPE (result) != AOP_STR)
7232 fetchPair (pairId, AOP (result));
7234 /* so hl now contains the address */
7235 freeAsmop (result, NULL, ic);
7237 /* if bit then unpack */
7240 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7250 const char *l = aopGet (AOP (right), offset, FALSE);
7251 if (isRegOrLit (AOP (right)) && !IS_GB)
7253 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7258 emit2 ("ld !*pair,a", _pairs[pairId].name);
7262 emit2 ("inc %s", _pairs[pairId].name);
7263 _G.pairs[pairId].offset++;
7269 freeAsmop (right, NULL, ic);
7272 /*-----------------------------------------------------------------*/
7273 /* genPointerSet - stores the value into a pointer location */
7274 /*-----------------------------------------------------------------*/
7276 genPointerSet (iCode * ic)
7278 operand *right, *result;
7279 sym_link *type, *etype;
7281 right = IC_RIGHT (ic);
7282 result = IC_RESULT (ic);
7284 /* depending on the type of pointer we need to
7285 move it to the correct pointer register */
7286 type = operandType (result);
7287 etype = getSpec (type);
7289 genGenPointerSet (right, result, ic);
7292 /*-----------------------------------------------------------------*/
7293 /* genIfx - generate code for Ifx statement */
7294 /*-----------------------------------------------------------------*/
7296 genIfx (iCode * ic, iCode * popIc)
7298 operand *cond = IC_COND (ic);
7301 aopOp (cond, ic, FALSE, TRUE);
7303 /* get the value into acc */
7304 if (AOP_TYPE (cond) != AOP_CRY)
7308 /* the result is now in the accumulator */
7309 freeAsmop (cond, NULL, ic);
7311 /* if there was something to be popped then do it */
7315 /* if the condition is a bit variable */
7316 if (isbit && IS_ITEMP (cond) &&
7318 genIfxJump (ic, SPIL_LOC (cond)->rname);
7319 else if (isbit && !IS_ITEMP (cond))
7320 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7322 genIfxJump (ic, "a");
7327 /*-----------------------------------------------------------------*/
7328 /* genAddrOf - generates code for address of */
7329 /*-----------------------------------------------------------------*/
7331 genAddrOf (iCode * ic)
7333 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7335 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7337 /* if the operand is on the stack then we
7338 need to get the stack offset of this
7344 spillPair (PAIR_HL);
7345 if (sym->stack <= 0)
7347 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7351 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7353 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7357 emit2 ("ld de,!hashedstr", sym->rname);
7358 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7363 spillPair (PAIR_HL);
7366 /* if it has an offset then we need to compute it */
7368 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7370 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7371 emit2 ("add hl,sp");
7375 emit2 ("ld hl,!hashedstr", sym->rname);
7377 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7379 freeAsmop (IC_RESULT (ic), NULL, ic);
7382 /*-----------------------------------------------------------------*/
7383 /* genAssign - generate code for assignment */
7384 /*-----------------------------------------------------------------*/
7386 genAssign (iCode * ic)
7388 operand *result, *right;
7390 unsigned long lit = 0L;
7392 result = IC_RESULT (ic);
7393 right = IC_RIGHT (ic);
7395 /* Dont bother assigning if they are the same */
7396 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7398 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7402 aopOp (right, ic, FALSE, FALSE);
7403 aopOp (result, ic, TRUE, FALSE);
7405 /* if they are the same registers */
7406 if (sameRegs (AOP (right), AOP (result)))
7408 emitDebug ("; (registers are the same)");
7412 /* if the result is a bit */
7413 if (AOP_TYPE (result) == AOP_CRY)
7415 wassertl (0, "Tried to assign to a bit");
7419 size = AOP_SIZE (result);
7422 if (AOP_TYPE (right) == AOP_LIT)
7424 lit = ulFromVal (AOP (right)->aopu.aop_lit);
7427 if (isPair (AOP (result)))
7429 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7431 else if ((size > 1) &&
7432 (AOP_TYPE (result) != AOP_REG) &&
7433 (AOP_TYPE (right) == AOP_LIT) &&
7434 !IS_FLOAT (operandType (right)) &&
7437 bool fXored = FALSE;
7439 /* Work from the top down.
7440 Done this way so that we can use the cached copy of 0
7441 in A for a fast clear */
7444 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7446 if (!fXored && size > 1)
7453 aopPut (AOP (result), "a", offset);
7457 aopPut (AOP (result), "!zero", offset);
7461 aopPut (AOP (result),
7462 aopGet (AOP (right), offset, FALSE),
7467 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7469 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7470 aopPut (AOP (result), "l", LSB);
7471 aopPut (AOP (result), "h", MSB16);
7473 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7475 /* Special case. Load into a and d, then load out. */
7476 _moveA (aopGet (AOP (right), 0, FALSE));
7477 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7478 aopPut (AOP (result), "a", 0);
7479 aopPut (AOP (result), "e", 1);
7481 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7483 /* Special case - simple memcpy */
7484 aopGet (AOP (right), LSB, FALSE);
7487 aopGet (AOP (result), LSB, FALSE);
7491 emit2 ("ld a,(de)");
7492 /* Peephole will optimise this. */
7493 emit2 ("ld (hl),a");
7501 spillPair (PAIR_HL);
7507 /* PENDING: do this check better */
7508 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7510 _moveA (aopGet (AOP (right), offset, FALSE));
7511 aopPut (AOP (result), "a", offset);
7514 aopPut (AOP (result),
7515 aopGet (AOP (right), offset, FALSE),
7522 freeAsmop (right, NULL, ic);
7523 freeAsmop (result, NULL, ic);
7526 /*-----------------------------------------------------------------*/
7527 /* genJumpTab - genrates code for jump table */
7528 /*-----------------------------------------------------------------*/
7530 genJumpTab (iCode * ic)
7535 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7536 /* get the condition into accumulator */
7537 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7540 emit2 ("ld e,%s", l);
7541 emit2 ("ld d,!zero");
7542 jtab = newiTempLabel (NULL);
7543 spillPair (PAIR_HL);
7544 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7545 emit2 ("add hl,de");
7546 emit2 ("add hl,de");
7547 emit2 ("add hl,de");
7548 freeAsmop (IC_JTCOND (ic), NULL, ic);
7552 emitLabel (jtab->key + 100);
7553 /* now generate the jump labels */
7554 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7555 jtab = setNextItem (IC_JTLABELS (ic)))
7556 emit2 ("jp !tlabel", jtab->key + 100);
7559 /*-----------------------------------------------------------------*/
7560 /* genCast - gen code for casting */
7561 /*-----------------------------------------------------------------*/
7563 genCast (iCode * ic)
7565 operand *result = IC_RESULT (ic);
7566 sym_link *rtype = operandType (IC_RIGHT (ic));
7567 operand *right = IC_RIGHT (ic);
7570 /* if they are equivalent then do nothing */
7571 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7574 aopOp (right, ic, FALSE, FALSE);
7575 aopOp (result, ic, FALSE, FALSE);
7577 /* if the result is a bit */
7578 if (AOP_TYPE (result) == AOP_CRY)
7580 wassertl (0, "Tried to cast to a bit");
7583 /* if they are the same size : or less */
7584 if (AOP_SIZE (result) <= AOP_SIZE (right))
7587 /* if they are in the same place */
7588 if (sameRegs (AOP (right), AOP (result)))
7591 /* if they in different places then copy */
7592 size = AOP_SIZE (result);
7596 aopPut (AOP (result),
7597 aopGet (AOP (right), offset, FALSE),
7604 /* So we now know that the size of destination is greater
7605 than the size of the source */
7606 /* we move to result for the size of source */
7607 size = AOP_SIZE (right);
7611 aopPut (AOP (result),
7612 aopGet (AOP (right), offset, FALSE),
7617 /* now depending on the sign of the destination */
7618 size = AOP_SIZE (result) - AOP_SIZE (right);
7619 /* Unsigned or not an integral type - right fill with zeros */
7620 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7623 aopPut (AOP (result), "!zero", offset++);
7627 /* we need to extend the sign :{ */
7628 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE);
7633 aopPut (AOP (result), "a", offset++);
7637 freeAsmop (right, NULL, ic);
7638 freeAsmop (result, NULL, ic);
7641 /*-----------------------------------------------------------------*/
7642 /* genReceive - generate code for a receive iCode */
7643 /*-----------------------------------------------------------------*/
7645 genReceive (iCode * ic)
7647 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7648 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7649 IS_TRUE_SYMOP (IC_RESULT (ic))))
7659 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7660 size = AOP_SIZE(IC_RESULT(ic));
7662 for (i = 0; i < size; i++) {
7663 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7667 freeAsmop (IC_RESULT (ic), NULL, ic);
7670 /*-----------------------------------------------------------------*/
7671 /* genDummyRead - generate code for dummy read of volatiles */
7672 /*-----------------------------------------------------------------*/
7674 genDummyRead (iCode * ic)
7680 if (op && IS_SYMOP (op))
7682 aopOp (op, ic, FALSE, FALSE);
7685 size = AOP_SIZE (op);
7690 _moveA (aopGet (AOP (op), offset, FALSE));
7694 freeAsmop (op, NULL, ic);
7698 if (op && IS_SYMOP (op))
7700 aopOp (op, ic, FALSE, FALSE);
7703 size = AOP_SIZE (op);
7708 _moveA (aopGet (AOP (op), offset, FALSE));
7712 freeAsmop (op, NULL, ic);
7716 /*-----------------------------------------------------------------*/
7717 /* genCritical - generate code for start of a critical sequence */
7718 /*-----------------------------------------------------------------*/
7720 genCritical (iCode *ic)
7722 symbol *tlbl = newiTempLabel (NULL);
7728 else if (IC_RESULT (ic))
7730 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7731 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7732 //get interrupt enable flag IFF2 into P/O
7736 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7737 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7738 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7739 emit2 ("!tlabeldef", (tlbl->key + 100));
7740 _G.lines.current->isLabel = 1;
7741 freeAsmop (IC_RESULT (ic), NULL, ic);
7745 //get interrupt enable flag IFF2 into P/O
7754 /*-----------------------------------------------------------------*/
7755 /* genEndCritical - generate code for end of a critical sequence */
7756 /*-----------------------------------------------------------------*/
7758 genEndCritical (iCode *ic)
7760 symbol *tlbl = newiTempLabel (NULL);
7766 else if (IC_RIGHT (ic))
7768 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7769 _toBoolean (IC_RIGHT (ic));
7770 //don't enable interrupts if they were off before
7771 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7773 emitLabel (tlbl->key + 100);
7774 freeAsmop (IC_RIGHT (ic), NULL, ic);
7780 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7781 //don't enable interrupts as they were off before
7782 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7784 emit2 ("!tlabeldef", (tlbl->key + 100));
7785 _G.lines.current->isLabel = 1;
7791 /** Maximum number of bytes to emit per line. */
7795 /** Context for the byte output chunker. */
7798 unsigned char buffer[DBEMIT_MAX_RUN];
7803 /** Flushes a byte chunker by writing out all in the buffer and
7807 _dbFlush(DBEMITCTX *self)
7814 sprintf(line, ".db 0x%02X", self->buffer[0]);
7816 for (i = 1; i < self->pos; i++)
7818 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7825 /** Write out another byte, buffering until a decent line is
7829 _dbEmit(DBEMITCTX *self, int c)
7831 if (self->pos == DBEMIT_MAX_RUN)
7835 self->buffer[self->pos++] = c;
7838 /** Context for a simple run length encoder. */
7842 unsigned char buffer[128];
7844 /** runLen may be equivalent to pos. */
7850 RLE_CHANGE_COST = 4,
7854 /** Flush the buffer of a run length encoder by writing out the run or
7855 data that it currently contains.
7858 _rleCommit(RLECTX *self)
7864 memset(&db, 0, sizeof(db));
7866 emit2(".db %u", self->pos);
7868 for (i = 0; i < self->pos; i++)
7870 _dbEmit(&db, self->buffer[i]);
7879 Can get either a run or a block of random stuff.
7880 Only want to change state if a good run comes in or a run ends.
7881 Detecting run end is easy.
7884 Say initial state is in run, len zero, last zero. Then if you get a
7885 few zeros then something else then a short run will be output.
7886 Seems OK. While in run mode, keep counting. While in random mode,
7887 keep a count of the run. If run hits margin, output all up to run,
7888 restart, enter run mode.
7891 /** Add another byte into the run length encoder, flushing as
7892 required. The run length encoder uses the Amiga IFF style, where
7893 a block is prefixed by its run length. A positive length means
7894 the next n bytes pass straight through. A negative length means
7895 that the next byte is repeated -n times. A zero terminates the
7899 _rleAppend(RLECTX *self, unsigned c)
7903 if (c != self->last)
7905 /* The run has stopped. See if it is worthwhile writing it out
7906 as a run. Note that the random data comes in as runs of
7909 if (self->runLen > RLE_CHANGE_COST)
7911 /* Yes, worthwhile. */
7912 /* Commit whatever was in the buffer. */
7914 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7918 /* Not worthwhile. Append to the end of the random list. */
7919 for (i = 0; i < self->runLen; i++)
7921 if (self->pos >= RLE_MAX_BLOCK)
7926 self->buffer[self->pos++] = self->last;
7934 if (self->runLen >= RLE_MAX_BLOCK)
7936 /* Commit whatever was in the buffer. */
7939 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7947 _rleFlush(RLECTX *self)
7949 _rleAppend(self, -1);
7956 /** genArrayInit - Special code for initialising an array with constant
7960 genArrayInit (iCode * ic)
7964 int elementSize = 0, eIndex, i;
7965 unsigned val, lastVal;
7969 memset(&rle, 0, sizeof(rle));
7971 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7973 _saveRegsForCall(ic, 0);
7975 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7976 emit2 ("call __initrleblock");
7978 type = operandType(IC_LEFT(ic));
7980 if (type && type->next)
7982 if (IS_SPEC(type->next) || IS_PTR(type->next))
7984 elementSize = getSize(type->next);
7986 else if (IS_ARRAY(type->next) && type->next->next)
7988 elementSize = getSize(type->next->next);
7992 printTypeChainRaw (type, NULL);
7993 wassertl (0, "Can't determine element size in genArrayInit.");
7998 wassertl (0, "Can't determine element size in genArrayInit.");
8001 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
8003 iLoop = IC_ARRAYILIST(ic);
8004 lastVal = (unsigned)-1;
8006 /* Feed all the bytes into the run length encoder which will handle
8008 This works well for mixed char data, and for random int and long
8015 for (i = 0; i < ix; i++)
8017 for (eIndex = 0; eIndex < elementSize; eIndex++)
8019 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
8020 _rleAppend(&rle, val);
8024 iLoop = iLoop->next;
8028 /* Mark the end of the run. */
8031 _restoreRegsAfterCall();
8035 freeAsmop (IC_LEFT(ic), NULL, ic);
8039 _swap (PAIR_ID one, PAIR_ID two)
8041 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
8047 emit2 ("ld a,%s", _pairs[one].l);
8048 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
8049 emit2 ("ld %s,a", _pairs[two].l);
8050 emit2 ("ld a,%s", _pairs[one].h);
8051 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
8052 emit2 ("ld %s,a", _pairs[two].h);
8057 setupForMemcpy (iCode *ic, int nparams, operand **pparams)
8059 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
8061 PAIR_DE, PAIR_HL, PAIR_BC
8063 int i, j, nunity = 0;
8064 memset (ids, PAIR_INVALID, sizeof (ids));
8067 wassert (nparams == 3);
8069 for (i = 0; i < nparams; i++)
8071 aopOp (pparams[i], ic, FALSE, FALSE);
8072 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
8075 /* Count the number of unity or iTemp assigns. */
8076 for (i = 0; i < 3; i++)
8078 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
8086 /* Any order, fall through. */
8088 else if (nunity == 2)
8090 /* Two are OK. Assign the other one. */
8091 for (i = 0; i < 3; i++)
8093 for (j = 0; j < NUM_PAIRS; j++)
8095 if (ids[dest[i]][j] == TRUE)
8097 /* Found it. See if it's the right one. */
8098 if (j == PAIR_INVALID || j == dest[i])
8104 fetchPair(dest[i], AOP (pparams[i]));
8111 else if (nunity == 1)
8113 /* One is OK. Find the other two. */
8114 for (i = 0; i < 3; i++)
8116 for (j = 0; j < NUM_PAIRS; j++)
8118 if (ids[dest[i]][j] == TRUE)
8120 if (j == PAIR_INVALID || j == dest[i])
8122 /* This one is OK. */
8127 if(ids[j][dest[i]] == TRUE)
8135 fetchPair (dest[i], AOP (pparams[i]));
8145 int next = getPairId (AOP (pparams[0]));
8146 emit2 ("push %s", _pairs[next].name);
8148 if (next == dest[1])
8150 fetchPair (dest[1], AOP (pparams[1]));
8151 fetchPair (dest[2], AOP (pparams[2]));
8155 fetchPair (dest[2], AOP (pparams[2]));
8156 fetchPair (dest[1], AOP (pparams[1]));
8158 emit2 ("pop %s", _pairs[dest[0]].name);
8161 /* Finally pull out all of the iTemps */
8162 for (i = 0; i < 3; i++)
8164 if (ids[dest[i]][PAIR_INVALID] == 1)
8166 fetchPair (dest[i], AOP (pparams[i]));
8172 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8174 operand *from, *to, *count;
8176 wassertl (nParams == 3, "Built-in memcpy() must have three parameters");
8181 _saveRegsForCall (ic, 0);
8183 setupForMemcpy (ic, nParams, pparams);
8187 freeAsmop (count, NULL, ic->next->next);
8188 freeAsmop (from, NULL, ic);
8190 spillPair (PAIR_HL);
8192 _restoreRegsAfterCall();
8194 /* if we need assign a result value */
8195 if ((IS_ITEMP (IC_RESULT (ic)) &&
8196 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8197 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8198 IS_TRUE_SYMOP (IC_RESULT (ic)))
8200 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8201 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8202 freeAsmop (IC_RESULT (ic), NULL, ic);
8205 freeAsmop (to, NULL, ic->next);
8208 /*-----------------------------------------------------------------*/
8209 /* genBuiltIn - calls the appropriate function to generating code */
8210 /* for a built in function */
8211 /*-----------------------------------------------------------------*/
8212 static void genBuiltIn (iCode *ic)
8214 operand *bi_parms[MAX_BUILTIN_ARGS];
8219 /* get all the arguments for a built in function */
8220 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8222 /* which function is it */
8223 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8225 if (strcmp(bif->name,"__builtin_memcpy")==0)
8227 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8231 wassertl (0, "Unknown builtin function encountered");
8235 /*-----------------------------------------------------------------*/
8236 /* genZ80Code - generate code for Z80 based controllers */
8237 /*-----------------------------------------------------------------*/
8239 genZ80Code (iCode * lic)
8247 _fReturn = _gbz80_return;
8248 _fTmp = _gbz80_return;
8252 _fReturn = _z80_return;
8253 _fTmp = _z80_return;
8256 _G.lines.head = _G.lines.current = NULL;
8258 /* if debug information required */
8259 if (options.debug && currFunc)
8261 debugFile->writeFunction (currFunc, lic);
8264 for (ic = lic; ic; ic = ic->next)
8266 _G.current_iCode = ic;
8268 if (ic->lineno && cln != ic->lineno)
8272 debugFile->writeCLine (ic);
8274 if (!options.noCcodeInAsm)
8276 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8277 printCLine(ic->filename, ic->lineno));
8281 if (options.iCodeInAsm)
8283 const char *iLine = printILine(ic);
8284 emit2 (";ic:%d: %s", ic->key, iLine);
8287 /* if the result is marked as
8288 spilt and rematerializable or code for
8289 this has already been generated then
8291 if (resultRemat (ic) || ic->generated)
8294 /* depending on the operation */
8298 emitDebug ("; genNot");
8303 emitDebug ("; genCpl");
8308 emitDebug ("; genUminus");
8313 emitDebug ("; genIpush");
8318 /* IPOP happens only when trying to restore a
8319 spilt live range, if there is an ifx statement
8320 following this pop then the if statement might
8321 be using some of the registers being popped which
8322 would destroy the contents of the register so
8323 we need to check for this condition and handle it */
8325 ic->next->op == IFX &&
8326 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8328 emitDebug ("; genIfx");
8329 genIfx (ic->next, ic);
8333 emitDebug ("; genIpop");
8339 emitDebug ("; genCall");
8344 emitDebug ("; genPcall");
8349 emitDebug ("; genFunction");
8354 emitDebug ("; genEndFunction");
8355 genEndFunction (ic);
8359 emitDebug ("; genRet");
8364 emitDebug ("; genLabel");
8369 emitDebug ("; genGoto");
8374 emitDebug ("; genPlus");
8379 emitDebug ("; genMinus");
8384 emitDebug ("; genMult");
8389 emitDebug ("; genDiv");
8394 emitDebug ("; genMod");
8399 emitDebug ("; genCmpGt");
8400 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8404 emitDebug ("; genCmpLt");
8405 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8412 /* note these two are xlated by algebraic equivalence
8413 during parsing SDCC.y */
8414 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8415 "got '>=' or '<=' shouldn't have come here");
8419 emitDebug ("; genCmpEq");
8420 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8424 emitDebug ("; genAndOp");
8429 emitDebug ("; genOrOp");
8434 emitDebug ("; genXor");
8435 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8439 emitDebug ("; genOr");
8440 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8444 emitDebug ("; genAnd");
8445 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8449 emitDebug ("; genInline");
8454 emitDebug ("; genRRC");
8459 emitDebug ("; genRLC");
8464 emitDebug ("; genGetHBIT");
8469 emitDebug ("; genLeftShift");
8474 emitDebug ("; genRightShift");
8478 case GET_VALUE_AT_ADDRESS:
8479 emitDebug ("; genPointerGet");
8485 if (POINTER_SET (ic))
8487 emitDebug ("; genAssign (pointer)");
8492 emitDebug ("; genAssign");
8498 emitDebug ("; genIfx");
8503 emitDebug ("; genAddrOf");
8508 emitDebug ("; genJumpTab");
8513 emitDebug ("; genCast");
8518 emitDebug ("; genReceive");
8523 if (ic->builtinSEND)
8525 emitDebug ("; genBuiltIn");
8530 emitDebug ("; addSet");
8531 addSet (&_G.sendSet, ic);
8536 emitDebug ("; genArrayInit");
8540 case DUMMY_READ_VOLATILE:
8541 emitDebug ("; genDummyRead");
8546 emitDebug ("; genCritical");
8551 emitDebug ("; genEndCritical");
8552 genEndCritical (ic);
8561 /* now we are ready to call the
8562 peep hole optimizer */
8563 if (!options.nopeep)
8564 peepHole (&_G.lines.head);
8566 /* This is unfortunate */
8567 /* now do the actual printing */
8569 struct dbuf_s *buf = codeOutBuf;
8570 if (isInHome () && codeOutBuf == &code->oBuf)
8571 codeOutBuf = &home->oBuf;
8572 printLine (_G.lines.head, codeOutBuf);
8573 if (_G.flushStatics)
8576 _G.flushStatics = 0;
8581 freeTrace(&_G.lines.trace);
8582 freeTrace(&_G.trace.aops);
8588 _isPairUsed (iCode * ic, PAIR_ID pairId)
8594 if (bitVectBitValue (ic->rMask, D_IDX))
8596 if (bitVectBitValue (ic->rMask, E_IDX))
8606 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8609 value *val = aop->aopu.aop_lit;
8611 wassert (aop->type == AOP_LIT);
8612 wassert (!IS_FLOAT (val->type));
8614 v = ulFromVal (val);
8622 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8623 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));