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.
90 #if defined(__BORLANDC__) || defined(_MSC_VER)
91 #define STRCASECMP stricmp
93 #define STRCASECMP strcasecmp
97 #include "SDCCglobl.h"
98 #include "SDCCpeeph.h"
100 #include "SDCCglue.h"
101 #include "newalloc.h"
103 /* This is the down and dirty file with all kinds of kludgy & hacky
104 stuff. This is what it is all about CODE GENERATION for a specific MCU.
105 Some of the routines may be reusable, will have to see */
107 /* Z80 calling convention description.
108 Parameters are passed right to left. As the stack grows downwards,
109 the parameters are arranged in left to right in memory.
110 Parameters may be passed in the HL and DE registers with one
112 PENDING: What if the parameter is a long?
113 Everything is caller saves. i.e. the caller must save any registers
114 that it wants to preserve over the call.
115 GB: The return value is returned in DEHL. DE is normally used as a
116 working register pair. Caller saves allows it to be used for a
118 va args functions do not use register parameters. All arguments
119 are passed on the stack.
120 IX is used as an index register to the top of the local variable
121 area. ix-0 is the top most local variable.
126 /* Set to enable debugging trace statements in the output assembly code. */
130 static char *_z80_return[] =
131 {"l", "h", "e", "d"};
132 static char *_gbz80_return[] =
133 {"e", "d", "l", "h"};
134 static char *_fReceive[] =
135 { "c", "b", "e", "d" };
137 static char **_fReturn;
140 extern FILE *codeOutFile;
148 /** Enum covering all the possible register pairs.
167 } _pairs[NUM_PAIRS] = {
168 { "??1", "?2", "?3" },
173 { "iy", "iyl", "iyh" },
174 { "ix", "ixl", "ixh" }
178 #define ACC_NAME _pairs[PAIR_AF].h
188 /** Code generator persistent data.
192 /** Used to optimised setting up of a pair by remebering what it
193 contains and adjusting instead of reloading where possible.
222 const char *lastFunctionName;
223 iCode *current_iCode;
230 /** TRUE if the registers have already been saved. */
249 static const char *aopGet (asmop * aop, int offset, bool bit16);
251 static const char *aopNames[] = {
272 isLastUse (iCode *ic, operand *op)
274 bitVect *uses = bitVectCopy (OP_USES (op));
276 while (!bitVectIsZero (uses))
278 if (bitVectFirstBit (uses) == ic->key)
280 if (bitVectnBitsOn (uses) == 1)
289 bitVectUnSetBit (uses, bitVectFirstBit (uses));
309 _getTempPairName(void)
311 return _pairs[_getTempPairId()].name;
315 isPairInUse (PAIR_ID id, iCode *ic)
319 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
321 else if (id == PAIR_BC)
323 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
327 wassertl (0, "Only implemented for DE and BC");
333 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
337 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
341 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
345 wassertl (0, "Only implemented for DE");
351 getFreePairId (iCode *ic)
353 if (!isPairInUse (PAIR_BC, ic))
357 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
370 /* Clean up the line so that it is 'prettier' */
371 if (strchr (buf, ':'))
373 /* Is a label - cant do anything */
376 /* Change the first (and probably only) ' ' to a tab so
391 _newLineNode (char *line)
395 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
396 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
402 _vemit2 (const char *szFormat, va_list ap)
404 char buffer[INITIAL_INLINEASM];
406 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
409 _G.lines.current = (_G.lines.current ?
410 connectLine (_G.lines.current, _newLineNode (buffer)) :
411 (_G.lines.head = _newLineNode (buffer)));
413 _G.lines.current->isInline = _G.lines.isInline;
414 _G.lines.current->isDebug = _G.lines.isDebug;
415 _G.lines.current->ic = _G.current_iCode;
419 emit2 (const char *szFormat,...)
423 va_start (ap, szFormat);
425 _vemit2 (szFormat, ap);
431 emitDebug (const char *szFormat,...)
437 va_start (ap, szFormat);
439 _vemit2 (szFormat, ap);
445 /*-----------------------------------------------------------------*/
446 /* z80_emitDebuggerSymbol - associate the current code location */
447 /* with a debugger symbol */
448 /*-----------------------------------------------------------------*/
450 z80_emitDebuggerSymbol (char * debugSym)
452 _G.lines.isDebug = 1;
453 emit2 ("%s !equ .", debugSym);
454 emit2 ("!global", debugSym);
455 _G.lines.isDebug = 0;
458 /*-----------------------------------------------------------------*/
459 /* emit2 - writes the code into a file : for now it is simple */
460 /*-----------------------------------------------------------------*/
462 _emit2 (const char *inst, const char *fmt,...)
465 char lb[INITIAL_INLINEASM];
472 sprintf (lb, "%s\t", inst);
473 vsprintf (lb + (strlen (lb)), fmt, ap);
476 vsprintf (lb, fmt, ap);
478 while (isspace (*lbp))
483 _G.lines.current = (_G.lines.current ?
484 connectLine (_G.lines.current, _newLineNode (lb)) :
485 (_G.lines.head = _newLineNode (lb)));
487 _G.lines.current->isInline = _G.lines.isInline;
488 _G.lines.current->ic = _G.current_iCode;
493 _emitMove(const char *to, const char *from)
495 if (STRCASECMP(to, from) != 0)
497 emit2("ld %s,%s", to, from);
502 // Could leave this to the peephole, but sometimes the peephole is inhibited.
507 aopDump(const char *plabel, asmop *aop)
513 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
518 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
521 for (i=aop->size-1;i>=0;i--)
522 *rbp++ = *(aop->aopu.aop_reg[i]->name);
524 emitDebug("; reg = %s", regbuf);
527 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
530 /* No information. */
536 _moveA(const char *moveFrom)
538 // Let the peephole optimiser take care of redundent loads
539 _emitMove(ACC_NAME, moveFrom);
549 getPairName (asmop * aop)
551 if (aop->type == AOP_REG)
553 switch (aop->aopu.aop_reg[0]->rIdx)
566 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
569 for (i = 0; i < NUM_PAIRS; i++)
571 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
573 return _pairs[i].name;
577 wassertl (0, "Tried to get the pair name of something that isn't a pair");
582 getPairId (asmop * aop)
586 if (aop->type == AOP_REG)
588 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
592 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
596 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
601 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
604 for (i = 0; i < NUM_PAIRS; i++)
606 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
616 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
620 return (getPairId (aop) != PAIR_INVALID);
623 /** Returns TRUE if the registers used in aop cannot be split into high
626 isUnsplitable (asmop * aop)
628 switch (getPairId (aop))
640 isPtrPair (asmop * aop)
642 PAIR_ID pairId = getPairId (aop);
655 spillPair (PAIR_ID pairId)
657 _G.pairs[pairId].last_type = AOP_INVALID;
658 _G.pairs[pairId].base = NULL;
661 /* Given a register name, spill the pair (if any) the register is part of */
663 spillPairReg (const char *regname)
665 if (strlen(regname)==1)
685 /** Push a register pair onto the stack */
687 genPairPush (asmop * aop)
689 emit2 ("push %s", getPairName (aop));
693 _push (PAIR_ID pairId)
695 emit2 ("push %s", _pairs[pairId].name);
696 _G.stack.pushed += 2;
700 _pop (PAIR_ID pairId)
702 emit2 ("pop %s", _pairs[pairId].name);
703 _G.stack.pushed -= 2;
708 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
721 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
728 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
729 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
732 wassertl (0, "Tried to move a nonphysical pair");
734 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
735 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
736 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
740 /*-----------------------------------------------------------------*/
741 /* newAsmop - creates a new asmOp */
742 /*-----------------------------------------------------------------*/
744 newAsmop (short type)
748 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
753 /*-----------------------------------------------------------------*/
754 /* aopForSym - for a true symbol */
755 /*-----------------------------------------------------------------*/
757 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
764 wassert (sym->etype);
766 space = SPEC_OCLS (sym->etype);
768 /* if already has one */
774 /* Assign depending on the storage class */
775 if (sym->onStack || sym->iaccess)
777 /* The pointer that is used depends on how big the offset is.
778 Normally everything is AOP_STK, but for offsets of < -128 or
779 > 127 on the Z80 an extended stack pointer is used.
781 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
783 emitDebug ("; AOP_EXSTK for %s", sym->rname);
784 sym->aop = aop = newAsmop (AOP_EXSTK);
788 emitDebug ("; AOP_STK for %s", sym->rname);
789 sym->aop = aop = newAsmop (AOP_STK);
792 aop->size = getSize (sym->type);
793 aop->aopu.aop_stk = sym->stack;
797 /* special case for a function */
798 if (IS_FUNC (sym->type))
800 sym->aop = aop = newAsmop (AOP_IMMD);
801 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
806 if( IN_REGSP( space ))
807 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
810 /* if it is in direct space */
813 sym->aop = aop = newAsmop (AOP_SFR);
814 aop->aopu.aop_dir = sym->rname;
815 aop->size = getSize (sym->type);
816 emitDebug ("; AOP_SFR for %s", sym->rname);
821 { /*.p.t.20030716 adding SFR support to the Z80 port */
822 aop = newAsmop (AOP_SFR);
824 aop->aopu.aop_dir = sym->rname;
825 aop->size = getSize( sym->type );
826 aop->paged = FUNC_REGBANK(sym->type);
827 aop->bcInUse = isPairInUse( PAIR_BC, ic );
828 aop->deInUse = isPairInUse( PAIR_DE, ic );
829 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
835 /* only remaining is far space */
836 /* in which case DPTR gets the address */
839 emitDebug ("; AOP_HL for %s", sym->rname);
840 sym->aop = aop = newAsmop (AOP_HL);
844 sym->aop = aop = newAsmop (AOP_IY);
846 aop->size = getSize (sym->type);
847 aop->aopu.aop_dir = sym->rname;
849 /* if it is in code space */
850 if (IN_CODESPACE (space))
856 /*-----------------------------------------------------------------*/
857 /* aopForRemat - rematerialzes an object */
858 /*-----------------------------------------------------------------*/
860 aopForRemat (symbol * sym)
863 iCode *ic = sym->rematiCode;
864 asmop *aop = newAsmop (AOP_IMMD);
868 /* if plus or minus print the right hand side */
869 if (ic->op == '+' || ic->op == '-')
871 /* PENDING: for re-target */
872 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
875 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
878 /* we reached the end */
879 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
883 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
887 /*-----------------------------------------------------------------*/
888 /* regsInCommon - two operands have some registers in common */
889 /*-----------------------------------------------------------------*/
891 regsInCommon (operand * op1, operand * op2)
896 /* if they have registers in common */
897 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
900 sym1 = OP_SYMBOL (op1);
901 sym2 = OP_SYMBOL (op2);
903 if (sym1->nRegs == 0 || sym2->nRegs == 0)
906 for (i = 0; i < sym1->nRegs; i++)
912 for (j = 0; j < sym2->nRegs; j++)
917 if (sym2->regs[j] == sym1->regs[i])
925 /*-----------------------------------------------------------------*/
926 /* operandsEqu - equivalent */
927 /*-----------------------------------------------------------------*/
929 operandsEqu (operand * op1, operand * op2)
933 /* if they not symbols */
934 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
937 sym1 = OP_SYMBOL (op1);
938 sym2 = OP_SYMBOL (op2);
940 /* if both are itemps & one is spilt
941 and the other is not then false */
942 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
943 sym1->isspilt != sym2->isspilt)
946 /* if they are the same */
950 if (sym1->rname[0] && sym2->rname[0]
951 && strcmp (sym1->rname, sym2->rname) == 0)
954 /* if left is a tmp & right is not */
955 if (IS_ITEMP (op1) &&
958 (sym1->usl.spillLoc == sym2))
961 if (IS_ITEMP (op2) &&
965 (sym2->usl.spillLoc == sym1))
971 /*-----------------------------------------------------------------*/
972 /* sameRegs - two asmops have the same registers */
973 /*-----------------------------------------------------------------*/
975 sameRegs (asmop * aop1, asmop * aop2)
979 if (aop1->type == AOP_SFR ||
980 aop2->type == AOP_SFR)
986 if (aop1->type != AOP_REG ||
987 aop2->type != AOP_REG)
990 if (aop1->size != aop2->size)
993 for (i = 0; i < aop1->size; i++)
994 if (aop1->aopu.aop_reg[i] !=
995 aop2->aopu.aop_reg[i])
1001 /*-----------------------------------------------------------------*/
1002 /* aopOp - allocates an asmop for an operand : */
1003 /*-----------------------------------------------------------------*/
1005 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1014 /* if this a literal */
1015 if (IS_OP_LITERAL (op))
1017 op->aop = aop = newAsmop (AOP_LIT);
1018 aop->aopu.aop_lit = op->operand.valOperand;
1019 aop->size = getSize (operandType (op));
1023 /* if already has a asmop then continue */
1026 if (op->aop->type == AOP_SFR)
1028 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1029 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1034 /* if the underlying symbol has a aop */
1035 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1037 op->aop = OP_SYMBOL (op)->aop;
1038 if (op->aop->type == AOP_SFR)
1040 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1041 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1046 /* if this is a true symbol */
1047 if (IS_TRUE_SYMOP (op))
1049 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1053 /* this is a temporary : this has
1059 e) can be a return use only */
1061 sym = OP_SYMBOL (op);
1063 /* if the type is a conditional */
1064 if (sym->regType == REG_CND)
1066 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1071 /* if it is spilt then two situations
1073 b) has a spill location */
1074 if (sym->isspilt || sym->nRegs == 0)
1076 /* rematerialize it NOW */
1079 sym->aop = op->aop = aop =
1081 aop->size = getSize (sym->type);
1088 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1089 aop->size = getSize (sym->type);
1090 for (i = 0; i < 4; i++)
1091 aop->aopu.aop_str[i] = _fReturn[i];
1097 if (sym->accuse == ACCUSE_A)
1099 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1100 aop->size = getSize (sym->type);
1101 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1103 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1105 else if (sym->accuse == ACCUSE_SCRATCH)
1107 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1108 aop->size = getSize (sym->type);
1109 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1110 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1111 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1113 else if (sym->accuse == ACCUSE_IY)
1115 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1116 aop->size = getSize (sym->type);
1117 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1118 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1119 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1123 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1128 if (sym->usl.spillLoc)
1130 asmop *oldAsmOp = NULL;
1132 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1134 /* force a new aop if sizes differ */
1135 oldAsmOp = sym->usl.spillLoc->aop;
1136 sym->usl.spillLoc->aop = NULL;
1138 sym->aop = op->aop = aop =
1139 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1140 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1142 /* Don't reuse the new aop, go with the last one */
1143 sym->usl.spillLoc->aop = oldAsmOp;
1145 aop->size = getSize (sym->type);
1149 /* else must be a dummy iTemp */
1150 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1151 aop->size = getSize (sym->type);
1155 /* must be in a register */
1156 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1157 aop->size = sym->nRegs;
1158 for (i = 0; i < sym->nRegs; i++)
1159 aop->aopu.aop_reg[i] = sym->regs[i];
1162 /*-----------------------------------------------------------------*/
1163 /* freeAsmop - free up the asmop given to an operand */
1164 /*----------------------------------------------------------------*/
1166 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1183 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1185 _pop (aop->aopu.aop_pairId);
1188 if (getPairId (aop) == PAIR_HL)
1190 spillPair (PAIR_HL);
1194 /* all other cases just dealloc */
1200 OP_SYMBOL (op)->aop = NULL;
1201 /* if the symbol has a spill */
1203 SPIL_LOC (op)->aop = NULL;
1210 isLitWord (asmop * aop)
1212 /* if (aop->size != 2)
1225 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1227 /* depending on type */
1233 /* PENDING: for re-target */
1236 tsprintf (buffer, sizeof(buffer),
1237 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1239 else if (offset == 0)
1241 tsprintf (buffer, sizeof(buffer),
1242 "%s", aop->aopu.aop_immd);
1246 tsprintf (buffer, sizeof(buffer),
1247 "%s + %d", aop->aopu.aop_immd, offset);
1249 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1253 value *val = aop->aopu.aop_lit;
1254 /* if it is a float then it gets tricky */
1255 /* otherwise it is fairly simple */
1256 if (!IS_FLOAT (val->type))
1258 unsigned long v = (unsigned long) floatFromVal (val);
1264 else if (offset == 0)
1270 wassertl(0, "Encountered an invalid offset while fetching a literal");
1274 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1276 tsprintf (buffer, sizeof(buffer), "!constword", v);
1278 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1289 /* it is type float */
1290 fl.f = (float) floatFromVal (val);
1292 #ifdef WORDS_BIGENDIAN
1293 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1295 i = fl.c[offset] | (fl.c[offset+1]<<8);
1298 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1300 tsprintf (buffer, sizeof(buffer), "!constword", i);
1302 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1311 aopGetWord (asmop * aop, int offset)
1313 return aopGetLitWordLong (aop, offset, TRUE);
1317 isPtr (const char *s)
1319 if (!strcmp (s, "hl"))
1321 if (!strcmp (s, "ix"))
1323 if (!strcmp (s, "iy"))
1329 adjustPair (const char *pair, int *pold, int new)
1335 emit2 ("inc %s", pair);
1340 emit2 ("dec %s", pair);
1348 spillPair (PAIR_HL);
1349 spillPair (PAIR_IY);
1353 requiresHL (asmop * aop)
1369 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1371 const char *l, *base;
1372 const char *pair = _pairs[pairId].name;
1373 l = aopGetLitWordLong (left, offset, FALSE);
1374 base = aopGetLitWordLong (left, 0, FALSE);
1375 wassert (l && pair && base);
1379 if (pairId == PAIR_HL || pairId == PAIR_IY)
1381 if (_G.pairs[pairId].last_type == left->type)
1383 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1385 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1387 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1390 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1397 _G.pairs[pairId].last_type = left->type;
1398 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1399 _G.pairs[pairId].offset = offset;
1401 /* Both a lit on the right and a true symbol on the left */
1402 emit2 ("ld %s,!hashedstr", pair, l);
1406 makeFreePairId (iCode *ic, bool *pisUsed)
1412 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1416 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1434 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1436 /* if this is remateriazable */
1437 if (isLitWord (aop)) {
1438 fetchLitPair (pairId, aop, offset);
1442 if (getPairId (aop) == pairId)
1446 /* we need to get it byte by byte */
1447 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1448 aopGet (aop, offset, FALSE);
1449 switch (aop->size - offset) {
1451 emit2 ("ld l,!*hl");
1452 emit2 ("ld h,!immedbyte", 0);
1455 // PENDING: Requires that you are only fetching two bytes.
1458 emit2 ("ld h,!*hl");
1462 wassertl (0, "Attempted to fetch too much data into HL");
1466 else if (IS_Z80 && aop->type == AOP_IY) {
1467 /* Instead of fetching relative to IY, just grab directly
1468 from the address IY refers to */
1469 char *l = aopGetLitWordLong (aop, offset, FALSE);
1471 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1473 if (aop->size < 2) {
1474 emit2("ld %s,!zero", _pairs[pairId].h);
1477 else if (pairId == PAIR_IY)
1481 emit2 ("push %s", _pairs[getPairId(aop)].name);
1487 PAIR_ID id = makeFreePairId (ic, &isUsed);
1490 /* Can't load into parts, so load into HL then exchange. */
1491 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1492 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1493 emit2 ("push %s", _pairs[id].name);
1499 else if (isUnsplitable(aop))
1501 emit2("push %s", _pairs[getPairId(aop)].name);
1502 emit2("pop %s", _pairs[pairId].name);
1506 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1507 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1509 /* PENDING: check? */
1510 if (pairId == PAIR_HL)
1511 spillPair (PAIR_HL);
1516 fetchPair (PAIR_ID pairId, asmop * aop)
1518 fetchPairLong (pairId, aop, NULL, 0);
1522 fetchHL (asmop * aop)
1524 fetchPair (PAIR_HL, aop);
1528 setupPairFromSP (PAIR_ID id, int offset)
1530 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1532 if (_G.preserveCarry)
1538 if (offset < INT8MIN || offset > INT8MAX)
1540 emit2 ("ld hl,!immedword", offset);
1541 emit2 ("add hl,sp");
1545 emit2 ("!ldahlsp", offset);
1548 if (_G.preserveCarry)
1556 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1561 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1562 fetchLitPair (pairId, aop, 0);
1566 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1568 fetchLitPair (pairId, aop, offset);
1569 _G.pairs[pairId].offset = offset;
1573 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1574 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1577 int offset = aop->aopu.aop_stk + _G.stack.offset;
1579 if (_G.pairs[pairId].last_type == aop->type &&
1580 _G.pairs[pairId].offset == offset)
1586 /* PENDING: Do this better. */
1587 if (_G.preserveCarry)
1589 sprintf (buffer, "%d", offset + _G.stack.pushed);
1590 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1591 emit2 ("add %s,sp", _pairs[pairId].name);
1592 _G.pairs[pairId].last_type = aop->type;
1593 _G.pairs[pairId].offset = offset;
1594 if (_G.preserveCarry)
1602 /* Doesnt include _G.stack.pushed */
1603 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1605 if (aop->aopu.aop_stk > 0)
1607 abso += _G.stack.param_offset;
1609 assert (pairId == PAIR_HL);
1610 /* In some cases we can still inc or dec hl */
1611 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1613 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1617 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1619 _G.pairs[pairId].offset = abso;
1624 if (pairId != aop->aopu.aop_pairId)
1625 genMovePairPair(aop->aopu.aop_pairId, pairId);
1626 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1632 _G.pairs[pairId].last_type = aop->type;
1638 emit2 ("!tlabeldef", key);
1642 /*-----------------------------------------------------------------*/
1643 /* aopGet - for fetching value of the aop */
1644 /*-----------------------------------------------------------------*/
1646 aopGet (asmop * aop, int offset, bool bit16)
1648 // char *s = buffer;
1650 /* offset is greater than size then zero */
1651 /* PENDING: this seems a bit screwed in some pointer cases. */
1652 if (offset > (aop->size - 1) &&
1653 aop->type != AOP_LIT)
1655 tsprintf (buffer, sizeof(buffer), "!zero");
1656 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1659 /* depending on type */
1663 tsprintf (buffer, sizeof(buffer), "!zero");
1664 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1667 /* PENDING: re-target */
1669 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1674 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1677 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1680 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1683 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1686 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1690 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1691 SNPRINTF (buffer, sizeof(buffer), "a");
1693 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1699 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1700 SNPRINTF (buffer, sizeof(buffer), "a");
1702 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1705 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1708 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1709 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1710 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1712 else if( z80_opts.port_mode == 180 )
1713 { /* z180 in0/out0 mode */
1714 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1718 emit2( "in a,(%s)", aop->aopu.aop_dir );
1721 SNPRINTF (buffer, sizeof(buffer), "a");
1723 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1727 return aop->aopu.aop_reg[offset]->name;
1731 setupPair (PAIR_HL, aop, offset);
1732 tsprintf (buffer, sizeof(buffer), "!*hl");
1734 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1738 setupPair (PAIR_IY, aop, offset);
1739 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1741 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1745 setupPair (PAIR_IY, aop, offset);
1746 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1748 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1753 setupPair (PAIR_HL, aop, offset);
1754 tsprintf (buffer, sizeof(buffer), "!*hl");
1758 if (aop->aopu.aop_stk >= 0)
1759 offset += _G.stack.param_offset;
1760 tsprintf (buffer, sizeof(buffer),
1761 "!*ixx", aop->aopu.aop_stk + offset);
1764 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1767 wassertl (0, "Tried to fetch from a bit variable");
1776 tsprintf(buffer, sizeof(buffer), "!zero");
1777 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1781 wassert (offset < 2);
1782 return aop->aopu.aop_str[offset];
1785 return aopLiteral (aop->aopu.aop_lit, offset);
1789 unsigned long v = aop->aopu.aop_simplelit;
1792 tsprintf (buffer, sizeof(buffer),
1793 "!immedbyte", (unsigned int) v & 0xff);
1795 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1799 return aop->aopu.aop_str[offset];
1802 setupPair (aop->aopu.aop_pairId, aop, offset);
1803 if (aop->aopu.aop_pairId==PAIR_IX)
1804 SNPRINTF (buffer, sizeof(buffer),
1806 else if (aop->aopu.aop_pairId==PAIR_IY)
1807 SNPRINTF (buffer, sizeof(buffer),
1810 SNPRINTF (buffer, sizeof(buffer),
1811 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1813 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1818 wassertl (0, "aopget got unsupported aop->type");
1823 isRegString (const char *s)
1825 if (!strcmp (s, "b") ||
1837 isConstant (const char *s)
1839 /* This is a bit of a hack... */
1840 return (*s == '#' || *s == '$');
1844 canAssignToPtr (const char *s)
1846 if (isRegString (s))
1853 /*-----------------------------------------------------------------*/
1854 /* aopPut - puts a string for a aop */
1855 /*-----------------------------------------------------------------*/
1857 aopPut (asmop * aop, const char *s, int offset)
1861 if (aop->size && offset > (aop->size - 1))
1863 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1864 "aopPut got offset > aop->size");
1869 tsprintf(buffer2, sizeof(buffer2), s);
1872 /* will assign value to value */
1873 /* depending on where it is ofcourse */
1877 _moveA (s); /* in case s is volatile */
1883 if (strcmp (s, "a"))
1884 emit2 ("ld a,%s", s);
1885 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1892 if (strcmp (s, "a"))
1893 emit2 ("ld a,%s", s);
1894 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1897 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1904 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1905 && s[0] != 'h' && s[0] != 'l'))
1907 emit2( "ld a,%s", s );
1911 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1912 emit2( "out (c),%s", s );
1917 spillPair (PAIR_BC);
1919 else if( z80_opts.port_mode == 180 )
1920 { /* z180 in0/out0 mode */
1921 emit2( "ld a,%s", s );
1922 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1926 emit2( "ld a,%s", s );
1927 emit2( "out (%s),a", aop->aopu.aop_dir );
1933 if (!strcmp (s, "!*hl"))
1934 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1937 aop->aopu.aop_reg[offset]->name, s);
1938 spillPairReg(aop->aopu.aop_reg[offset]->name);
1943 if (!canAssignToPtr (s))
1945 emit2 ("ld a,%s", s);
1946 setupPair (PAIR_IY, aop, offset);
1947 emit2 ("ld !*iyx,a", offset);
1951 setupPair (PAIR_IY, aop, offset);
1952 emit2 ("ld !*iyx,%s", offset, s);
1958 /* PENDING: for re-target */
1959 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1961 emit2 ("ld a,!*hl");
1964 setupPair (PAIR_HL, aop, offset);
1966 emit2 ("ld !*hl,%s", s);
1971 if (!canAssignToPtr (s))
1973 emit2 ("ld a,%s", s);
1974 setupPair (PAIR_IY, aop, offset);
1975 emit2 ("ld !*iyx,a", offset);
1979 setupPair (PAIR_IY, aop, offset);
1980 emit2 ("ld !*iyx,%s", offset, s);
1987 /* PENDING: re-target */
1988 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1990 emit2 ("ld a,!*hl");
1993 setupPair (PAIR_HL, aop, offset);
1994 if (!canAssignToPtr (s))
1996 emit2 ("ld a,%s", s);
1997 emit2 ("ld !*hl,a");
2000 emit2 ("ld !*hl,%s", s);
2004 if (aop->aopu.aop_stk >= 0)
2005 offset += _G.stack.param_offset;
2006 if (!canAssignToPtr (s))
2008 emit2 ("ld a,%s", s);
2009 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2013 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2019 /* if bit variable */
2020 if (!aop->aopu.aop_dir)
2022 emit2 ("ld a,!zero");
2027 /* In bit space but not in C - cant happen */
2028 wassertl (0, "Tried to write into a bit variable");
2034 if (strcmp (aop->aopu.aop_str[offset], s))
2036 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2038 spillPairReg(aop->aopu.aop_str[offset]);
2043 if (!offset && (strcmp (s, "acc") == 0))
2047 wassertl (0, "Tried to access past the end of A");
2051 if (strcmp (aop->aopu.aop_str[offset], s))
2053 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2054 spillPairReg(aop->aopu.aop_str[offset]);
2060 wassert (offset < 2);
2061 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2062 spillPairReg(aop->aopu.aop_str[offset]);
2066 setupPair (aop->aopu.aop_pairId, aop, offset);
2067 if (aop->aopu.aop_pairId==PAIR_IX)
2068 emit2 ("ld !*ixx,%s", 0, s);
2069 else if (aop->aopu.aop_pairId==PAIR_IY)
2070 emit2 ("ld !*ixy,%s", 0, s);
2072 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2076 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2077 "aopPut got unsupported aop->type");
2082 #define AOP(op) op->aop
2083 #define AOP_TYPE(op) AOP(op)->type
2084 #define AOP_SIZE(op) AOP(op)->size
2085 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2088 commitPair (asmop * aop, PAIR_ID id)
2090 /* PENDING: Verify this. */
2091 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2095 aopPut (aop, "a", 0);
2096 aopPut (aop, "d", 1);
2101 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2103 char *l = aopGetLitWordLong (aop, 0, FALSE);
2106 emit2 ("ld (%s),%s", l, _pairs[id].name);
2110 aopPut (aop, _pairs[id].l, 0);
2111 aopPut (aop, _pairs[id].h, 1);
2116 /*-----------------------------------------------------------------*/
2117 /* getDataSize - get the operand data size */
2118 /*-----------------------------------------------------------------*/
2120 getDataSize (operand * op)
2123 size = AOP_SIZE (op);
2127 wassertl (0, "Somehow got a three byte data pointer");
2132 /*-----------------------------------------------------------------*/
2133 /* movLeft2Result - move byte from left to result */
2134 /*-----------------------------------------------------------------*/
2136 movLeft2Result (operand * left, int offl,
2137 operand * result, int offr, int sign)
2141 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2143 l = aopGet (AOP (left), offl, FALSE);
2147 aopPut (AOP (result), l, offr);
2151 if (getDataSize (left) == offl + 1)
2153 emit2 ("ld a,%s", l);
2154 aopPut (AOP (result), "a", offr);
2161 movLeft2ResultLong (operand * left, int offl,
2162 operand * result, int offr, int sign,
2167 movLeft2Result (left, offl, result, offr, sign);
2171 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2172 wassertl (size == 2, "Only implemented for two bytes or one");
2174 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2176 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2177 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2179 spillPair (PAIR_HL);
2181 else if ( getPairId ( AOP (result)) == PAIR_IY)
2183 PAIR_ID id = getPairId (AOP (left));
2184 if (id != PAIR_INVALID)
2186 emit2("push %s", _pairs[id].name);
2197 movLeft2Result (left, offl, result, offr, sign);
2198 movLeft2Result (left, offl+1, result, offr+1, sign);
2203 /** Put Acc into a register set
2206 outAcc (operand * result)
2209 size = getDataSize (result);
2212 aopPut (AOP (result), "a", 0);
2215 /* unsigned or positive */
2218 aopPut (AOP (result), "!zero", offset++);
2223 /** Take the value in carry and put it into a register
2226 outBitCLong (operand * result, bool swap_sense)
2228 /* if the result is bit */
2229 if (AOP_TYPE (result) == AOP_CRY)
2231 wassertl (0, "Tried to write carry to a bit");
2235 emit2 ("ld a,!zero");
2238 emit2 ("xor a,!immedbyte", 1);
2244 outBitC (operand * result)
2246 outBitCLong (result, FALSE);
2249 /*-----------------------------------------------------------------*/
2250 /* toBoolean - emit code for orl a,operator(sizeop) */
2251 /*-----------------------------------------------------------------*/
2253 _toBoolean (operand * oper)
2255 int size = AOP_SIZE (oper);
2259 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2262 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2266 if (AOP (oper)->type != AOP_ACC)
2269 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2275 /*-----------------------------------------------------------------*/
2276 /* genNot - generate code for ! operation */
2277 /*-----------------------------------------------------------------*/
2282 /* assign asmOps to operand & result */
2283 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2284 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2286 /* if in bit space then a special case */
2287 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2289 wassertl (0, "Tried to negate a bit");
2292 _toBoolean (IC_LEFT (ic));
2297 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2298 emit2 ("sub a,!one");
2299 outBitC (IC_RESULT (ic));
2301 /* release the aops */
2302 freeAsmop (IC_LEFT (ic), NULL, ic);
2303 freeAsmop (IC_RESULT (ic), NULL, ic);
2306 /*-----------------------------------------------------------------*/
2307 /* genCpl - generate code for complement */
2308 /*-----------------------------------------------------------------*/
2316 /* assign asmOps to operand & result */
2317 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2318 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2320 /* if both are in bit space then
2322 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2323 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2325 wassertl (0, "Left and the result are in bit space");
2328 size = AOP_SIZE (IC_RESULT (ic));
2331 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2334 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2337 /* release the aops */
2338 freeAsmop (IC_LEFT (ic), NULL, ic);
2339 freeAsmop (IC_RESULT (ic), NULL, ic);
2343 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2350 store de into result
2355 store de into result
2357 const char *first = isAdd ? "add" : "sub";
2358 const char *later = isAdd ? "adc" : "sbc";
2360 wassertl (IS_GB, "Code is only relevent to the gbz80");
2361 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2363 fetchPair (PAIR_DE, left);
2366 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2369 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2372 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2373 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2375 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2376 aopGet (right, MSB24, FALSE);
2380 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2383 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2385 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2386 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2390 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2392 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2395 /*-----------------------------------------------------------------*/
2396 /* genUminusFloat - unary minus for floating points */
2397 /*-----------------------------------------------------------------*/
2399 genUminusFloat (operand * op, operand * result)
2401 int size, offset = 0;
2403 emitDebug("; genUminusFloat");
2405 /* for this we just need to flip the
2406 first bit then copy the rest in place */
2407 size = AOP_SIZE (op) - 1;
2409 _moveA(aopGet (AOP (op), MSB32, FALSE));
2411 emit2("xor a,!immedbyte", 0x80);
2412 aopPut (AOP (result), "a", MSB32);
2416 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2421 /*-----------------------------------------------------------------*/
2422 /* genUminus - unary minus code generation */
2423 /*-----------------------------------------------------------------*/
2425 genUminus (iCode * ic)
2428 sym_link *optype, *rtype;
2431 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2432 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2434 /* if both in bit space then special
2436 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2437 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2439 wassertl (0, "Left and right are in bit space");
2443 optype = operandType (IC_LEFT (ic));
2444 rtype = operandType (IC_RESULT (ic));
2446 /* if float then do float stuff */
2447 if (IS_FLOAT (optype))
2449 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2453 /* otherwise subtract from zero */
2454 size = AOP_SIZE (IC_LEFT (ic));
2456 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2458 /* Create a new asmop with value zero */
2459 asmop *azero = newAsmop (AOP_SIMPLELIT);
2460 azero->aopu.aop_simplelit = 0;
2462 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2470 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2471 emit2 ("ld a,!zero");
2472 emit2 ("sbc a,%s", l);
2473 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2476 /* if any remaining bytes in the result */
2477 /* we just need to propagate the sign */
2478 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2483 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2487 /* release the aops */
2488 freeAsmop (IC_LEFT (ic), NULL, ic);
2489 freeAsmop (IC_RESULT (ic), NULL, ic);
2492 /*-----------------------------------------------------------------*/
2493 /* assignResultValue - */
2494 /*-----------------------------------------------------------------*/
2496 assignResultValue (operand * oper)
2498 int size = AOP_SIZE (oper);
2501 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2502 topInA = requiresHL (AOP (oper));
2504 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2506 /* We do it the hard way here. */
2508 aopPut (AOP (oper), _fReturn[0], 0);
2509 aopPut (AOP (oper), _fReturn[1], 1);
2511 aopPut (AOP (oper), _fReturn[0], 2);
2512 aopPut (AOP (oper), _fReturn[1], 3);
2518 aopPut (AOP (oper), _fReturn[size], size);
2523 /** Simple restore that doesn't take into account what is used in the
2527 _restoreRegsAfterCall(void)
2529 if (_G.stack.pushedDE)
2532 _G.stack.pushedDE = FALSE;
2534 if (_G.stack.pushedBC)
2537 _G.stack.pushedBC = FALSE;
2539 _G.saves.saved = FALSE;
2543 _saveRegsForCall(iCode *ic, int sendSetSize)
2546 o Stack parameters are pushed before this function enters
2547 o DE and BC may be used in this function.
2548 o HL and DE may be used to return the result.
2549 o HL and DE may be used to send variables.
2550 o DE and BC may be used to store the result value.
2551 o HL may be used in computing the sent value of DE
2552 o The iPushes for other parameters occur before any addSets
2554 Logic: (to be run inside the first iPush or if none, before sending)
2555 o Compute if DE and/or BC are in use over the call
2556 o Compute if DE is used in the send set
2557 o Compute if DE and/or BC are used to hold the result value
2558 o If (DE is used, or in the send set) and is not used in the result, push.
2559 o If BC is used and is not in the result, push
2561 o If DE is used in the send set, fetch
2562 o If HL is used in the send set, fetch
2566 if (_G.saves.saved == FALSE) {
2567 bool deInUse, bcInUse;
2569 bool bcInRet = FALSE, deInRet = FALSE;
2572 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2573 z80_rUmaskForOp (IC_RESULT(ic)));
2575 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2576 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2578 deSending = (sendSetSize > 1);
2580 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2582 if (bcInUse && bcInRet == FALSE) {
2584 _G.stack.pushedBC = TRUE;
2586 if (deInUse && deInRet == FALSE) {
2588 _G.stack.pushedDE = TRUE;
2591 _G.saves.saved = TRUE;
2594 /* Already saved. */
2598 /*-----------------------------------------------------------------*/
2599 /* genIpush - genrate code for pushing this gets a little complex */
2600 /*-----------------------------------------------------------------*/
2602 genIpush (iCode * ic)
2604 int size, offset = 0;
2607 /* if this is not a parm push : ie. it is spill push
2608 and spill push is always done on the local stack */
2611 wassertl(0, "Encountered an unsupported spill push.");
2615 if (_G.saves.saved == FALSE) {
2616 /* Caller saves, and this is the first iPush. */
2617 /* Scan ahead until we find the function that we are pushing parameters to.
2618 Count the number of addSets on the way to figure out what registers
2619 are used in the send set.
2622 iCode *walk = ic->next;
2625 if (walk->op == SEND) {
2628 else if (walk->op == CALL || walk->op == PCALL) {
2637 _saveRegsForCall(walk, nAddSets);
2640 /* Already saved by another iPush. */
2643 /* then do the push */
2644 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2646 size = AOP_SIZE (IC_LEFT (ic));
2648 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2650 _G.stack.pushed += 2;
2651 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2657 fetchHL (AOP (IC_LEFT (ic)));
2659 spillPair (PAIR_HL);
2660 _G.stack.pushed += 2;
2665 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2667 spillPair (PAIR_HL);
2668 _G.stack.pushed += 2;
2669 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2671 spillPair (PAIR_HL);
2672 _G.stack.pushed += 2;
2678 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2680 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2682 emit2 ("ld a,(%s)", l);
2686 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2687 emit2 ("ld a,%s", l);
2695 freeAsmop (IC_LEFT (ic), NULL, ic);
2698 /*-----------------------------------------------------------------*/
2699 /* genIpop - recover the registers: can happen only for spilling */
2700 /*-----------------------------------------------------------------*/
2702 genIpop (iCode * ic)
2707 /* if the temp was not pushed then */
2708 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2711 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2712 size = AOP_SIZE (IC_LEFT (ic));
2713 offset = (size - 1);
2714 if (isPair (AOP (IC_LEFT (ic))))
2716 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2724 spillPair (PAIR_HL);
2725 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2729 freeAsmop (IC_LEFT (ic), NULL, ic);
2732 /* This is quite unfortunate */
2734 setArea (int inHome)
2737 static int lastArea = 0;
2739 if (_G.in_home != inHome) {
2741 const char *sz = port->mem.code_name;
2742 port->mem.code_name = "HOME";
2743 emit2("!area", CODE_NAME);
2744 port->mem.code_name = sz;
2747 emit2("!area", CODE_NAME); */
2748 _G.in_home = inHome;
2759 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2763 symbol *sym = OP_SYMBOL (op);
2765 if (sym->isspilt || sym->nRegs == 0)
2768 aopOp (op, ic, FALSE, FALSE);
2771 if (aop->type == AOP_REG)
2774 for (i = 0; i < aop->size; i++)
2776 if (pairId == PAIR_DE)
2778 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2779 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2781 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2784 else if (pairId == PAIR_BC)
2786 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2787 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2789 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2799 freeAsmop (IC_LEFT (ic), NULL, ic);
2803 /** Emit the code for a call statement
2806 emitCall (iCode * ic, bool ispcall)
2808 bool bInRet, cInRet, dInRet, eInRet;
2809 sym_link *dtype = operandType (IC_LEFT (ic));
2811 /* if caller saves & we have not saved then */
2817 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2819 /* if send set is not empty then assign */
2824 int nSend = elementsInSet(_G.sendSet);
2825 bool swapped = FALSE;
2827 int _z80_sendOrder[] = {
2832 /* Check if the parameters are swapped. If so route through hl instead. */
2833 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2835 sic = setFirstItem(_G.sendSet);
2836 sic = setNextItem(_G.sendSet);
2838 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2839 /* The second send value is loaded from one the one that holds the first
2840 send, i.e. it is overwritten. */
2841 /* Cache the first in HL, and load the second from HL instead. */
2842 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2843 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2849 for (sic = setFirstItem (_G.sendSet); sic;
2850 sic = setNextItem (_G.sendSet))
2853 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2855 size = AOP_SIZE (IC_LEFT (sic));
2856 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2857 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2859 // PENDING: Mild hack
2860 if (swapped == TRUE && send == 1) {
2862 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2865 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2867 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2870 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2874 freeAsmop (IC_LEFT (sic), NULL, sic);
2881 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2883 werror (W_INDIR_BANKED);
2885 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2887 if (isLitWord (AOP (IC_LEFT (ic))))
2889 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2893 symbol *rlbl = newiTempLabel (NULL);
2894 spillPair (PAIR_HL);
2895 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2897 _G.stack.pushed += 2;
2899 fetchHL (AOP (IC_LEFT (ic)));
2901 emit2 ("!tlabeldef", (rlbl->key + 100));
2902 _G.stack.pushed -= 2;
2904 freeAsmop (IC_LEFT (ic), NULL, ic);
2908 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2909 OP_SYMBOL (IC_LEFT (ic))->rname :
2910 OP_SYMBOL (IC_LEFT (ic))->name;
2911 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2913 emit2 ("call banked_call");
2914 emit2 ("!dws", name);
2915 emit2 ("!dw !bankimmeds", name);
2920 emit2 ("call %s", name);
2925 /* Mark the registers as restored. */
2926 _G.saves.saved = FALSE;
2928 /* if we need assign a result value */
2929 if ((IS_ITEMP (IC_RESULT (ic)) &&
2930 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2931 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2932 IS_TRUE_SYMOP (IC_RESULT (ic)))
2935 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2937 assignResultValue (IC_RESULT (ic));
2939 freeAsmop (IC_RESULT (ic), NULL, ic);
2942 /* adjust the stack for parameters if required */
2945 int i = ic->parmBytes;
2947 _G.stack.pushed -= i;
2950 emit2 ("!ldaspsp", i);
2957 emit2 ("ld iy,!immedword", i);
2958 emit2 ("add iy,sp");
2979 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2980 bInRet = bitVectBitValue(result, B_IDX);
2981 cInRet = bitVectBitValue(result, C_IDX);
2982 dInRet = bitVectBitValue(result, D_IDX);
2983 eInRet = bitVectBitValue(result, E_IDX);
2993 if (_G.stack.pushedDE)
2995 if (dInRet && eInRet)
2997 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3001 /* Only restore E */
3008 /* Only restore D */
3016 _G.stack.pushedDE = FALSE;
3019 if (_G.stack.pushedBC)
3021 if (bInRet && cInRet)
3023 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3027 /* Only restore C */
3034 /* Only restore B */
3042 _G.stack.pushedBC = FALSE;
3046 /*-----------------------------------------------------------------*/
3047 /* genCall - generates a call statement */
3048 /*-----------------------------------------------------------------*/
3050 genCall (iCode * ic)
3052 emitCall (ic, FALSE);
3055 /*-----------------------------------------------------------------*/
3056 /* genPcall - generates a call by pointer statement */
3057 /*-----------------------------------------------------------------*/
3059 genPcall (iCode * ic)
3061 emitCall (ic, TRUE);
3064 /*-----------------------------------------------------------------*/
3065 /* resultRemat - result is rematerializable */
3066 /*-----------------------------------------------------------------*/
3068 resultRemat (iCode * ic)
3070 if (SKIP_IC (ic) || ic->op == IFX)
3073 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3075 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3076 if (sym->remat && !POINTER_SET (ic))
3083 extern set *publics;
3085 /*-----------------------------------------------------------------*/
3086 /* genFunction - generated code for function entry */
3087 /*-----------------------------------------------------------------*/
3089 genFunction (iCode * ic)
3093 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3096 bool bcInUse = FALSE;
3097 bool deInUse = FALSE;
3099 setArea (IFFUNC_NONBANKED (sym->type));
3101 /* PENDING: Reset the receive offset as it
3102 doesn't seem to get reset anywhere else.
3104 _G.receiveOffset = 0;
3106 /* Record the last function name for debugging. */
3107 _G.lastFunctionName = sym->rname;
3109 /* Create the function header */
3110 emit2 ("!functionheader", sym->name);
3111 if (!IS_STATIC(sym->etype))
3113 sprintf (buffer, "%s_start", sym->rname);
3114 emit2 ("!labeldef", buffer);
3116 emit2 ("!functionlabeldef", sym->rname);
3118 ftype = operandType (IC_LEFT (ic));
3120 if (IFFUNC_ISNAKED(ftype))
3122 emitDebug("; naked function: no prologue.");
3126 /* if this is an interrupt service routine
3127 then save all potentially used registers. */
3128 if (IFFUNC_ISISR (sym->type))
3130 /* If critical function then turn interrupts off */
3131 /* except when no interrupt number is given then it implies the NMI handler */
3132 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3141 /* This is a non-ISR function.
3142 If critical function then turn interrupts off */
3143 if (IFFUNC_ISCRITICAL (sym->type))
3151 //get interrupt enable flag IFF2 into P/O
3160 if (options.profile)
3162 emit2 ("!profileenter");
3165 /* PENDING: callee-save etc */
3167 _G.stack.param_offset = 0;
3169 if (z80_opts.calleeSavesBC)
3174 /* Detect which registers are used. */
3175 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3178 for (i = 0; i < sym->regsUsed->size; i++)
3180 if (bitVectBitValue (sym->regsUsed, i))
3194 /* Other systems use DE as a temporary. */
3205 _G.stack.param_offset += 2;
3208 _G.calleeSaves.pushedBC = bcInUse;
3213 _G.stack.param_offset += 2;
3216 _G.calleeSaves.pushedDE = deInUse;
3218 /* adjust the stack for the function */
3219 _G.stack.last = sym->stack;
3222 for (sym = setFirstItem (istack->syms); sym;
3223 sym = setNextItem (istack->syms))
3225 if (sym->_isparm && !IS_REGPARM (sym->etype))
3231 sym = OP_SYMBOL (IC_LEFT (ic));
3233 _G.omitFramePtr = options.ommitFramePtr;
3234 if (IS_Z80 && !stackParm && !sym->stack)
3236 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3237 /* the above !sym->stack condition can be removed. -- EEP */
3239 emit2 ("!ldaspsp", -sym->stack);
3240 _G.omitFramePtr = TRUE;
3242 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3243 emit2 ("!enterxl", sym->stack);
3244 else if (sym->stack)
3245 emit2 ("!enterx", sym->stack);
3249 _G.stack.offset = sym->stack;
3252 /*-----------------------------------------------------------------*/
3253 /* genEndFunction - generates epilogue for functions */
3254 /*-----------------------------------------------------------------*/
3256 genEndFunction (iCode * ic)
3258 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3260 if (IFFUNC_ISNAKED(sym->type))
3262 emitDebug("; naked function: no epilogue.");
3266 /* PENDING: calleeSave */
3267 if (IS_Z80 && _G.omitFramePtr)
3269 if (_G.stack.offset)
3270 emit2 ("!ldaspsp", _G.stack.offset);
3272 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3274 emit2 ("!leavexl", _G.stack.offset);
3276 else if (_G.stack.offset)
3278 emit2 ("!leavex", _G.stack.offset);
3285 if (_G.calleeSaves.pushedDE)
3288 _G.calleeSaves.pushedDE = FALSE;
3291 if (_G.calleeSaves.pushedBC)
3294 _G.calleeSaves.pushedBC = FALSE;
3297 if (options.profile)
3299 emit2 ("!profileexit");
3302 /* if this is an interrupt service routine
3303 then save all potentially used registers. */
3304 if (IFFUNC_ISISR (sym->type))
3308 /* If critical function then turn interrupts back on */
3309 /* except when no interrupt number is given then it implies the NMI handler */
3310 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3317 /* This is a non-ISR function.
3318 If critical function then turn interrupts back on */
3319 if (IFFUNC_ISCRITICAL (sym->type))
3327 symbol *tlbl = newiTempLabel (NULL);
3330 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3331 //don't enable interrupts as they were off before
3332 emit2 ("jp po,!tlabel", tlbl->key + 100);
3334 emit2 ("!tlabeldef", (tlbl->key + 100));
3339 if (options.debug && currFunc)
3341 debugFile->writeEndFunction (currFunc, ic, 1);
3344 if (IFFUNC_ISISR (sym->type))
3346 /* "critical interrupt" is used to imply NMI handler */
3347 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3354 /* Both banked and non-banked just ret */
3358 if (!IS_STATIC(sym->etype))
3360 sprintf (buffer, "%s_end", sym->rname);
3361 emit2 ("!labeldef", buffer);
3364 _G.flushStatics = 1;
3365 _G.stack.pushed = 0;
3366 _G.stack.offset = 0;
3369 /*-----------------------------------------------------------------*/
3370 /* genRet - generate code for return statement */
3371 /*-----------------------------------------------------------------*/
3376 /* Errk. This is a hack until I can figure out how
3377 to cause dehl to spill on a call */
3378 int size, offset = 0;
3380 /* if we have no return value then
3381 just generate the "ret" */
3385 /* we have something to return then
3386 move the return value into place */
3387 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3388 size = AOP_SIZE (IC_LEFT (ic));
3390 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3393 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3397 emit2 ("ld de,%s", l);
3401 emit2 ("ld hl,%s", l);
3407 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3411 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3413 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3414 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3420 l = aopGet (AOP (IC_LEFT (ic)), offset,
3422 if (strcmp (_fReturn[offset], l))
3423 emit2 ("ld %s,%s", _fReturn[offset], l);
3428 freeAsmop (IC_LEFT (ic), NULL, ic);
3431 /* generate a jump to the return label
3432 if the next is not the return statement */
3433 if (!(ic->next && ic->next->op == LABEL &&
3434 IC_LABEL (ic->next) == returnLabel))
3436 emit2 ("jp !tlabel", returnLabel->key + 100);
3439 /*-----------------------------------------------------------------*/
3440 /* genLabel - generates a label */
3441 /*-----------------------------------------------------------------*/
3443 genLabel (iCode * ic)
3445 /* special case never generate */
3446 if (IC_LABEL (ic) == entryLabel)
3449 emitLabel (IC_LABEL (ic)->key + 100);
3452 /*-----------------------------------------------------------------*/
3453 /* genGoto - generates a ljmp */
3454 /*-----------------------------------------------------------------*/
3456 genGoto (iCode * ic)
3458 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3461 /*-----------------------------------------------------------------*/
3462 /* genPlusIncr :- does addition with increment if possible */
3463 /*-----------------------------------------------------------------*/
3465 genPlusIncr (iCode * ic)
3467 unsigned int icount;
3468 unsigned int size = getDataSize (IC_RESULT (ic));
3469 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3471 /* will try to generate an increment */
3472 /* if the right side is not a literal
3474 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3477 emitDebug ("; genPlusIncr");
3479 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3481 /* If result is a pair */
3482 if (resultId != PAIR_INVALID)
3484 if (isLitWord (AOP (IC_LEFT (ic))))
3486 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3489 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3491 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3493 PAIR_ID freep = getFreePairId (ic);
3494 if (freep != PAIR_INVALID)
3496 fetchPair (freep, AOP (IC_RIGHT (ic)));
3497 emit2 ("add hl,%s", _pairs[freep].name);
3503 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3504 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3511 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3515 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3519 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3524 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3526 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3527 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3531 /* if the literal value of the right hand side
3532 is greater than 4 then it is not worth it */
3536 /* if increment 16 bits in register */
3537 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3543 symbol *tlbl = NULL;
3544 tlbl = newiTempLabel (NULL);
3547 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3550 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3553 emitLabel (tlbl->key + 100);
3557 /* if the sizes are greater than 1 then we cannot */
3558 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3559 AOP_SIZE (IC_LEFT (ic)) > 1)
3562 /* If the result is in a register then we can load then increment.
3564 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3566 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3569 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3574 /* we can if the aops of the left & result match or
3575 if they are in registers and the registers are the
3577 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3581 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3589 /*-----------------------------------------------------------------*/
3590 /* outBitAcc - output a bit in acc */
3591 /*-----------------------------------------------------------------*/
3593 outBitAcc (operand * result)
3595 symbol *tlbl = newiTempLabel (NULL);
3596 /* if the result is a bit */
3597 if (AOP_TYPE (result) == AOP_CRY)
3599 wassertl (0, "Tried to write A into a bit");
3603 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3604 emit2 ("ld a,!one");
3605 emitLabel (tlbl->key + 100);
3611 couldDestroyCarry (asmop *aop)
3615 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3624 shiftIntoPair (int idx, asmop *aop)
3626 PAIR_ID id = PAIR_INVALID;
3628 wassertl (IS_Z80, "Only implemented for the Z80");
3629 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3641 wassertl (0, "Internal error - hit default case");
3644 emitDebug ("; Shift into pair idx %u", idx);
3648 setupPair (PAIR_HL, aop, 0);
3652 setupPair (PAIR_IY, aop, 0);
3654 emit2 ("pop %s", _pairs[id].name);
3657 aop->type = AOP_PAIRPTR;
3658 aop->aopu.aop_pairId = id;
3659 _G.pairs[id].offset = 0;
3660 _G.pairs[id].last_type = aop->type;
3664 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3666 wassert (left && right);
3670 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3672 shiftIntoPair (0, right);
3673 /* check result again, in case right == result */
3674 if (couldDestroyCarry (result))
3675 shiftIntoPair (1, result);
3677 else if (couldDestroyCarry (right))
3679 if (getPairId (result) == PAIR_HL)
3680 _G.preserveCarry = TRUE;
3682 shiftIntoPair (0, right);
3684 else if (couldDestroyCarry (result))
3686 shiftIntoPair (0, result);
3695 /*-----------------------------------------------------------------*/
3696 /* genPlus - generates code for addition */
3697 /*-----------------------------------------------------------------*/
3699 genPlus (iCode * ic)
3701 int size, offset = 0;
3703 /* special cases :- */
3705 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3706 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3707 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3709 /* Swap the left and right operands if:
3711 if literal, literal on the right or
3712 if left requires ACC or right is already
3715 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3716 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3717 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3719 operand *t = IC_RIGHT (ic);
3720 IC_RIGHT (ic) = IC_LEFT (ic);
3724 /* if both left & right are in bit
3726 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3727 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3730 wassertl (0, "Tried to add two bits");
3733 /* if left in bit space & right literal */
3734 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3735 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3737 /* Can happen I guess */
3738 wassertl (0, "Tried to add a bit to a literal");
3741 /* if I can do an increment instead
3742 of add then GOOD for ME */
3743 if (genPlusIncr (ic) == TRUE)
3746 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3748 size = getDataSize (IC_RESULT (ic));
3750 /* Special case when left and right are constant */
3751 if (isPair (AOP (IC_RESULT (ic))))
3754 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3755 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3757 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3763 sprintf (buffer, "#(%s + %s)", left, right);
3764 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3769 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3771 /* Fetch into HL then do the add */
3772 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3773 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3775 spillPair (PAIR_HL);
3777 if (left == PAIR_HL && right != PAIR_INVALID)
3779 emit2 ("add hl,%s", _pairs[right].name);
3782 else if (right == PAIR_HL && left != PAIR_INVALID)
3784 emit2 ("add hl,%s", _pairs[left].name);
3787 else if (right != PAIR_INVALID && right != PAIR_HL)
3789 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3790 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3793 else if (left != PAIR_INVALID && left != PAIR_HL)
3795 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3796 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3805 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3807 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3808 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3810 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3815 ld hl,sp+n trashes C so we cant afford to do it during an
3816 add with stack based varibles. Worst case is:
3829 So you cant afford to load up hl if either left, right, or result
3830 is on the stack (*sigh*) The alt is:
3838 Combinations in here are:
3839 * If left or right are in bc then the loss is small - trap later
3840 * If the result is in bc then the loss is also small
3844 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3845 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3846 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3848 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3849 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3850 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3851 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3853 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3855 /* Swap left and right */
3856 operand *t = IC_RIGHT (ic);
3857 IC_RIGHT (ic) = IC_LEFT (ic);
3860 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3862 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3863 emit2 ("add hl,bc");
3867 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3868 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3869 emit2 ("add hl,de");
3871 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3877 /* Be paranoid on the GB with 4 byte variables due to how C
3878 can be trashed by lda hl,n(sp).
3880 _gbz80_emitAddSubLong (ic, TRUE);
3885 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3889 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3891 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3894 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3897 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3901 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3904 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3907 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3909 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3913 _G.preserveCarry = FALSE;
3914 freeAsmop (IC_LEFT (ic), NULL, ic);
3915 freeAsmop (IC_RIGHT (ic), NULL, ic);
3916 freeAsmop (IC_RESULT (ic), NULL, ic);
3920 /*-----------------------------------------------------------------*/
3921 /* genMinusDec :- does subtraction with deccrement if possible */
3922 /*-----------------------------------------------------------------*/
3924 genMinusDec (iCode * ic)
3926 unsigned int icount;
3927 unsigned int size = getDataSize (IC_RESULT (ic));
3929 /* will try to generate an increment */
3930 /* if the right side is not a literal we cannot */
3931 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3934 /* if the literal value of the right hand side
3935 is greater than 4 then it is not worth it */
3936 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3939 size = getDataSize (IC_RESULT (ic));
3941 /* if decrement 16 bits in register */
3942 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3943 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3946 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3950 /* If result is a pair */
3951 if (isPair (AOP (IC_RESULT (ic))))
3953 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3955 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3959 /* if increment 16 bits in register */
3960 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3964 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3967 emit2 ("dec %s", _getTempPairName());
3970 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3976 /* if the sizes are greater than 1 then we cannot */
3977 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3978 AOP_SIZE (IC_LEFT (ic)) > 1)
3981 /* we can if the aops of the left & result match or if they are in
3982 registers and the registers are the same */
3983 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3986 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3993 /*-----------------------------------------------------------------*/
3994 /* genMinus - generates code for subtraction */
3995 /*-----------------------------------------------------------------*/
3997 genMinus (iCode * ic)
3999 int size, offset = 0;
4000 unsigned long lit = 0L;
4002 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4003 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4004 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4006 /* special cases :- */
4007 /* if both left & right are in bit space */
4008 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4009 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4011 wassertl (0, "Tried to subtract two bits");
4015 /* if I can do an decrement instead of subtract then GOOD for ME */
4016 if (genMinusDec (ic) == TRUE)
4019 size = getDataSize (IC_RESULT (ic));
4021 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4026 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4030 /* Same logic as genPlus */
4033 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4034 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4035 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4037 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4038 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4039 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4040 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4042 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4043 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4045 if (left == PAIR_INVALID && right == PAIR_INVALID)
4050 else if (right == PAIR_INVALID)
4052 else if (left == PAIR_INVALID)
4055 fetchPair (left, AOP (IC_LEFT (ic)));
4056 /* Order is important. Right may be HL */
4057 fetchPair (right, AOP (IC_RIGHT (ic)));
4059 emit2 ("ld a,%s", _pairs[left].l);
4060 emit2 ("sub a,%s", _pairs[right].l);
4062 emit2 ("ld a,%s", _pairs[left].h);
4063 emit2 ("sbc a,%s", _pairs[right].h);
4065 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4067 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4069 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4075 /* Be paranoid on the GB with 4 byte variables due to how C
4076 can be trashed by lda hl,n(sp).
4078 _gbz80_emitAddSubLong (ic, FALSE);
4083 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
4085 /* if literal, add a,#-lit, else normal subb */
4088 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4089 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4093 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4096 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4100 /* first add without previous c */
4102 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4104 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4106 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4109 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4110 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4111 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4113 wassertl (0, "Tried to subtract on a long pointer");
4117 _G.preserveCarry = FALSE;
4118 freeAsmop (IC_LEFT (ic), NULL, ic);
4119 freeAsmop (IC_RIGHT (ic), NULL, ic);
4120 freeAsmop (IC_RESULT (ic), NULL, ic);
4123 /*-----------------------------------------------------------------*/
4124 /* genMult - generates code for multiplication */
4125 /*-----------------------------------------------------------------*/
4127 genMult (iCode * ic)
4131 /* If true then the final operation should be a subtract */
4132 bool active = FALSE;
4135 /* Shouldn't occur - all done through function calls */
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 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4142 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4143 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4144 AOP_SIZE (IC_RESULT (ic)) > 2)
4146 wassertl (0, "Multiplication is handled through support function calls");
4149 /* Swap left and right such that right is a literal */
4150 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4152 operand *t = IC_RIGHT (ic);
4153 IC_RIGHT (ic) = IC_LEFT (ic);
4157 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4159 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4160 // wassertl (val > 0, "Multiply must be positive");
4161 wassertl (val != 1, "Can't multiply by 1");
4163 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4165 _G.stack.pushedDE = TRUE;
4168 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4170 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4181 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4186 /* Fully unroled version of mul.s. Not the most efficient.
4188 for (count = 0; count < 16; count++)
4190 if (count != 0 && active)
4192 emit2 ("add hl,hl");
4196 if (active == FALSE)
4204 emit2 ("add hl,de");
4213 if (IS_Z80 && _G.stack.pushedDE)
4216 _G.stack.pushedDE = FALSE;
4220 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4222 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4224 freeAsmop (IC_LEFT (ic), NULL, ic);
4225 freeAsmop (IC_RIGHT (ic), NULL, ic);
4226 freeAsmop (IC_RESULT (ic), NULL, ic);
4229 /*-----------------------------------------------------------------*/
4230 /* genDiv - generates code for division */
4231 /*-----------------------------------------------------------------*/
4235 /* Shouldn't occur - all done through function calls */
4236 wassertl (0, "Division is handled through support function calls");
4239 /*-----------------------------------------------------------------*/
4240 /* genMod - generates code for division */
4241 /*-----------------------------------------------------------------*/
4245 /* Shouldn't occur - all done through function calls */
4249 /*-----------------------------------------------------------------*/
4250 /* genIfxJump :- will create a jump depending on the ifx */
4251 /*-----------------------------------------------------------------*/
4253 genIfxJump (iCode * ic, char *jval)
4258 /* if true label then we jump if condition
4262 jlbl = IC_TRUE (ic);
4263 if (!strcmp (jval, "a"))
4267 else if (!strcmp (jval, "c"))
4271 else if (!strcmp (jval, "nc"))
4275 else if (!strcmp (jval, "m"))
4279 else if (!strcmp (jval, "p"))
4285 /* The buffer contains the bit on A that we should test */
4291 /* false label is present */
4292 jlbl = IC_FALSE (ic);
4293 if (!strcmp (jval, "a"))
4297 else if (!strcmp (jval, "c"))
4301 else if (!strcmp (jval, "nc"))
4305 else if (!strcmp (jval, "m"))
4309 else if (!strcmp (jval, "p"))
4315 /* The buffer contains the bit on A that we should test */
4319 /* Z80 can do a conditional long jump */
4320 if (!strcmp (jval, "a"))
4324 else if (!strcmp (jval, "c"))
4327 else if (!strcmp (jval, "nc"))
4330 else if (!strcmp (jval, "m"))
4333 else if (!strcmp (jval, "p"))
4338 emit2 ("bit %s,a", jval);
4340 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4342 /* mark the icode as generated */
4348 _getPairIdName (PAIR_ID id)
4350 return _pairs[id].name;
4355 /* if unsigned char cmp with lit, just compare */
4357 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4359 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4362 emit2 ("xor a,!immedbyte", 0x80);
4363 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4366 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4368 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4370 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4371 // Pull left into DE and right into HL
4372 aopGet (AOP(left), LSB, FALSE);
4375 aopGet (AOP(right), LSB, FALSE);
4379 if (size == 0 && sign)
4381 // Highest byte when signed needs the bits flipped
4384 emit2 ("ld a,(de)");
4385 emit2 ("xor !immedbyte", 0x80);
4387 emit2 ("ld a,(hl)");
4388 emit2 ("xor !immedbyte", 0x80);
4392 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4396 emit2 ("ld a,(de)");
4397 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4407 spillPair (PAIR_HL);
4409 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4411 setupPair (PAIR_HL, AOP (left), 0);
4412 aopGet (AOP(right), LSB, FALSE);
4416 if (size == 0 && sign)
4418 // Highest byte when signed needs the bits flipped
4421 emit2 ("ld a,(hl)");
4422 emit2 ("xor !immedbyte", 0x80);
4424 emit2 ("ld a,%d(iy)", offset);
4425 emit2 ("xor !immedbyte", 0x80);
4429 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4433 emit2 ("ld a,(hl)");
4434 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4443 spillPair (PAIR_HL);
4444 spillPair (PAIR_IY);
4448 if (AOP_TYPE (right) == AOP_LIT)
4450 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4451 /* optimize if(x < 0) or if(x >= 0) */
4456 /* No sign so it's always false */
4461 /* Just load in the top most bit */
4462 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4463 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4465 genIfxJump (ifx, "7");
4477 /* First setup h and l contaning the top most bytes XORed */
4478 bool fDidXor = FALSE;
4479 if (AOP_TYPE (left) == AOP_LIT)
4481 unsigned long lit = (unsigned long)
4482 floatFromVal (AOP (left)->aopu.aop_lit);
4483 emit2 ("ld %s,!immedbyte", _fTmp[0],
4484 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4488 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4489 emit2 ("xor a,!immedbyte", 0x80);
4490 emit2 ("ld %s,a", _fTmp[0]);
4493 if (AOP_TYPE (right) == AOP_LIT)
4495 unsigned long lit = (unsigned long)
4496 floatFromVal (AOP (right)->aopu.aop_lit);
4497 emit2 ("ld %s,!immedbyte", _fTmp[1],
4498 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4502 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4503 emit2 ("xor a,!immedbyte", 0x80);
4504 emit2 ("ld %s,a", _fTmp[1]);
4510 /* Do a long subtract */
4513 _moveA (aopGet (AOP (left), offset, FALSE));
4515 if (sign && size == 0)
4517 emit2 ("ld a,%s", _fTmp[0]);
4518 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4522 /* Subtract through, propagating the carry */
4523 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4531 /** Generic compare for > or <
4534 genCmp (operand * left, operand * right,
4535 operand * result, iCode * ifx, int sign)
4537 int size, offset = 0;
4538 unsigned long lit = 0L;
4539 bool swap_sense = FALSE;
4541 /* if left & right are bit variables */
4542 if (AOP_TYPE (left) == AOP_CRY &&
4543 AOP_TYPE (right) == AOP_CRY)
4545 /* Cant happen on the Z80 */
4546 wassertl (0, "Tried to compare two bits");
4550 /* Do a long subtract of right from left. */
4551 size = max (AOP_SIZE (left), AOP_SIZE (right));
4553 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4555 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4556 // Pull left into DE and right into HL
4557 aopGet (AOP(left), LSB, FALSE);
4560 aopGet (AOP(right), LSB, FALSE);
4564 emit2 ("ld a,(de)");
4565 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4574 spillPair (PAIR_HL);
4578 if (AOP_TYPE (right) == AOP_LIT)
4580 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4581 /* optimize if(x < 0) or if(x >= 0) */
4586 /* No sign so it's always false */
4591 /* Just load in the top most bit */
4592 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4593 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4595 genIfxJump (ifx, "7");
4606 genIfxJump (ifx, swap_sense ? "c" : "nc");
4617 _moveA (aopGet (AOP (left), offset, FALSE));
4618 /* Subtract through, propagating the carry */
4619 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4625 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4629 /* Shift the sign bit up into carry */
4632 outBitCLong (result, swap_sense);
4636 /* if the result is used in the next
4637 ifx conditional branch then generate
4638 code a little differently */
4646 genIfxJump (ifx, swap_sense ? "nc" : "c");
4650 genIfxJump (ifx, swap_sense ? "p" : "m");
4655 genIfxJump (ifx, swap_sense ? "nc" : "c");
4662 /* Shift the sign bit up into carry */
4665 outBitCLong (result, swap_sense);
4667 /* leave the result in acc */
4671 /*-----------------------------------------------------------------*/
4672 /* genCmpGt :- greater than comparison */
4673 /*-----------------------------------------------------------------*/
4675 genCmpGt (iCode * ic, iCode * ifx)
4677 operand *left, *right, *result;
4678 sym_link *letype, *retype;
4681 left = IC_LEFT (ic);
4682 right = IC_RIGHT (ic);
4683 result = IC_RESULT (ic);
4685 letype = getSpec (operandType (left));
4686 retype = getSpec (operandType (right));
4687 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4688 /* assign the amsops */
4689 aopOp (left, ic, FALSE, FALSE);
4690 aopOp (right, ic, FALSE, FALSE);
4691 aopOp (result, ic, TRUE, FALSE);
4693 genCmp (right, left, result, ifx, sign);
4695 freeAsmop (left, NULL, ic);
4696 freeAsmop (right, NULL, ic);
4697 freeAsmop (result, NULL, ic);
4700 /*-----------------------------------------------------------------*/
4701 /* genCmpLt - less than comparisons */
4702 /*-----------------------------------------------------------------*/
4704 genCmpLt (iCode * ic, iCode * ifx)
4706 operand *left, *right, *result;
4707 sym_link *letype, *retype;
4710 left = IC_LEFT (ic);
4711 right = IC_RIGHT (ic);
4712 result = IC_RESULT (ic);
4714 letype = getSpec (operandType (left));
4715 retype = getSpec (operandType (right));
4716 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4718 /* assign the amsops */
4719 aopOp (left, ic, FALSE, FALSE);
4720 aopOp (right, ic, FALSE, FALSE);
4721 aopOp (result, ic, TRUE, FALSE);
4723 genCmp (left, right, result, ifx, sign);
4725 freeAsmop (left, NULL, ic);
4726 freeAsmop (right, NULL, ic);
4727 freeAsmop (result, NULL, ic);
4730 /*-----------------------------------------------------------------*/
4731 /* gencjneshort - compare and jump if not equal */
4732 /*-----------------------------------------------------------------*/
4734 gencjneshort (operand * left, operand * right, symbol * lbl)
4736 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4738 unsigned long lit = 0L;
4740 /* Swap the left and right if it makes the computation easier */
4741 if (AOP_TYPE (left) == AOP_LIT)
4748 if (AOP_TYPE (right) == AOP_LIT)
4750 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4753 /* if the right side is a literal then anything goes */
4754 if (AOP_TYPE (right) == AOP_LIT &&
4755 AOP_TYPE (left) != AOP_DIR)
4759 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4764 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4771 emit2 ("jp nz,!tlabel", lbl->key + 100);
4777 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4778 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4781 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4782 emit2 ("jp nz,!tlabel", lbl->key + 100);
4787 /* if the right side is in a register or in direct space or
4788 if the left is a pointer register & right is not */
4789 else if (AOP_TYPE (right) == AOP_REG ||
4790 AOP_TYPE (right) == AOP_DIR ||
4791 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4795 _moveA (aopGet (AOP (left), offset, FALSE));
4796 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4797 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4799 emit2 ("jp nz,!tlabel", lbl->key + 100);
4802 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4803 emit2 ("jp nz,!tlabel", lbl->key + 100);
4810 /* right is a pointer reg need both a & b */
4811 /* PENDING: is this required? */
4814 _moveA (aopGet (AOP (right), offset, FALSE));
4815 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4816 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4822 /*-----------------------------------------------------------------*/
4823 /* gencjne - compare and jump if not equal */
4824 /*-----------------------------------------------------------------*/
4826 gencjne (operand * left, operand * right, symbol * lbl)
4828 symbol *tlbl = newiTempLabel (NULL);
4830 gencjneshort (left, right, lbl);
4833 emit2 ("ld a,!one");
4834 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4835 emitLabel (lbl->key + 100);
4837 emitLabel (tlbl->key + 100);
4840 /*-----------------------------------------------------------------*/
4841 /* genCmpEq - generates code for equal to */
4842 /*-----------------------------------------------------------------*/
4844 genCmpEq (iCode * ic, iCode * ifx)
4846 operand *left, *right, *result;
4848 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4849 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4850 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4852 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4854 /* Swap operands if it makes the operation easier. ie if:
4855 1. Left is a literal.
4857 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4859 operand *t = IC_RIGHT (ic);
4860 IC_RIGHT (ic) = IC_LEFT (ic);
4864 if (ifx && !AOP_SIZE (result))
4867 /* if they are both bit variables */
4868 if (AOP_TYPE (left) == AOP_CRY &&
4869 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4871 wassertl (0, "Tried to compare two bits");
4875 tlbl = newiTempLabel (NULL);
4876 gencjneshort (left, right, tlbl);
4879 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4880 emitLabel (tlbl->key + 100);
4884 /* PENDING: do this better */
4885 symbol *lbl = newiTempLabel (NULL);
4886 emit2 ("!shortjp !tlabel", lbl->key + 100);
4887 emitLabel (tlbl->key + 100);
4888 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4889 emitLabel (lbl->key + 100);
4892 /* mark the icode as generated */
4897 /* if they are both bit variables */
4898 if (AOP_TYPE (left) == AOP_CRY &&
4899 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4901 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4907 gencjne (left, right, newiTempLabel (NULL));
4908 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4915 genIfxJump (ifx, "a");
4918 /* if the result is used in an arithmetic operation
4919 then put the result in place */
4920 if (AOP_TYPE (result) != AOP_CRY)
4925 /* leave the result in acc */
4929 freeAsmop (left, NULL, ic);
4930 freeAsmop (right, NULL, ic);
4931 freeAsmop (result, NULL, ic);
4934 /*-----------------------------------------------------------------*/
4935 /* ifxForOp - returns the icode containing the ifx for operand */
4936 /*-----------------------------------------------------------------*/
4938 ifxForOp (operand * op, iCode * ic)
4940 /* if true symbol then needs to be assigned */
4941 if (IS_TRUE_SYMOP (op))
4944 /* if this has register type condition and
4945 the next instruction is ifx with the same operand
4946 and live to of the operand is upto the ifx only then */
4948 ic->next->op == IFX &&
4949 IC_COND (ic->next)->key == op->key &&
4950 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4956 /*-----------------------------------------------------------------*/
4957 /* genAndOp - for && operation */
4958 /*-----------------------------------------------------------------*/
4960 genAndOp (iCode * ic)
4962 operand *left, *right, *result;
4965 /* note here that && operations that are in an if statement are
4966 taken away by backPatchLabels only those used in arthmetic
4967 operations remain */
4968 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4969 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4970 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4972 /* if both are bit variables */
4973 if (AOP_TYPE (left) == AOP_CRY &&
4974 AOP_TYPE (right) == AOP_CRY)
4976 wassertl (0, "Tried to and two bits");
4980 tlbl = newiTempLabel (NULL);
4982 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4984 emitLabel (tlbl->key + 100);
4988 freeAsmop (left, NULL, ic);
4989 freeAsmop (right, NULL, ic);
4990 freeAsmop (result, NULL, ic);
4993 /*-----------------------------------------------------------------*/
4994 /* genOrOp - for || operation */
4995 /*-----------------------------------------------------------------*/
4997 genOrOp (iCode * ic)
4999 operand *left, *right, *result;
5002 /* note here that || operations that are in an
5003 if statement are taken away by backPatchLabels
5004 only those used in arthmetic operations remain */
5005 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5006 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5007 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5009 /* if both are bit variables */
5010 if (AOP_TYPE (left) == AOP_CRY &&
5011 AOP_TYPE (right) == AOP_CRY)
5013 wassertl (0, "Tried to OR two bits");
5017 tlbl = newiTempLabel (NULL);
5019 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5021 emitLabel (tlbl->key + 100);
5025 freeAsmop (left, NULL, ic);
5026 freeAsmop (right, NULL, ic);
5027 freeAsmop (result, NULL, ic);
5030 /*-----------------------------------------------------------------*/
5031 /* isLiteralBit - test if lit == 2^n */
5032 /*-----------------------------------------------------------------*/
5034 isLiteralBit (unsigned long lit)
5036 unsigned long pw[32] =
5037 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5038 0x100L, 0x200L, 0x400L, 0x800L,
5039 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5040 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5041 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5042 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5043 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5046 for (idx = 0; idx < 32; idx++)
5052 /*-----------------------------------------------------------------*/
5053 /* jmpTrueOrFalse - */
5054 /*-----------------------------------------------------------------*/
5056 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5058 // ugly but optimized by peephole
5061 symbol *nlbl = newiTempLabel (NULL);
5062 emit2 ("jp !tlabel", nlbl->key + 100);
5063 emitLabel (tlbl->key + 100);
5064 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5065 emitLabel (nlbl->key + 100);
5069 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5070 emitLabel (tlbl->key + 100);
5075 /*-----------------------------------------------------------------*/
5076 /* genAnd - code for and */
5077 /*-----------------------------------------------------------------*/
5079 genAnd (iCode * ic, iCode * ifx)
5081 operand *left, *right, *result;
5082 int size, offset = 0;
5083 unsigned long lit = 0L;
5086 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5087 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5088 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5090 /* if left is a literal & right is not then exchange them */
5091 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5092 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5094 operand *tmp = right;
5099 /* if result = right then exchange them */
5100 if (sameRegs (AOP (result), AOP (right)))
5102 operand *tmp = right;
5107 /* if right is bit then exchange them */
5108 if (AOP_TYPE (right) == AOP_CRY &&
5109 AOP_TYPE (left) != AOP_CRY)
5111 operand *tmp = right;
5115 if (AOP_TYPE (right) == AOP_LIT)
5116 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5118 size = AOP_SIZE (result);
5120 if (AOP_TYPE (left) == AOP_CRY)
5122 wassertl (0, "Tried to perform an AND with a bit as an operand");
5126 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5127 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5128 if ((AOP_TYPE (right) == AOP_LIT) &&
5129 (AOP_TYPE (result) == AOP_CRY) &&
5130 (AOP_TYPE (left) != AOP_CRY))
5132 symbol *tlbl = newiTempLabel (NULL);
5133 int sizel = AOP_SIZE (left);
5136 /* PENDING: Test case for this. */
5141 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5143 _moveA (aopGet (AOP (left), offset, FALSE));
5144 if (bytelit != 0x0FFL)
5146 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5153 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5157 // bit = left & literal
5161 emit2 ("!tlabeldef", tlbl->key + 100);
5163 // if(left & literal)
5168 jmpTrueOrFalse (ifx, tlbl);
5176 /* if left is same as result */
5177 if (sameRegs (AOP (result), AOP (left)))
5179 for (; size--; offset++)
5181 if (AOP_TYPE (right) == AOP_LIT)
5183 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5188 aopPut (AOP (result), "!zero", offset);
5191 _moveA (aopGet (AOP (left), offset, FALSE));
5193 aopGet (AOP (right), offset, FALSE));
5194 aopPut (AOP (left), "a", offset);
5201 if (AOP_TYPE (left) == AOP_ACC)
5203 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5207 _moveA (aopGet (AOP (left), offset, FALSE));
5209 aopGet (AOP (right), offset, FALSE));
5210 aopPut (AOP (left), "a", offset);
5217 // left & result in different registers
5218 if (AOP_TYPE (result) == AOP_CRY)
5220 wassertl (0, "Tried to AND where the result is in carry");
5224 for (; (size--); offset++)
5227 // result = left & right
5228 if (AOP_TYPE (right) == AOP_LIT)
5230 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5232 aopPut (AOP (result),
5233 aopGet (AOP (left), offset, FALSE),
5237 else if (bytelit == 0)
5239 aopPut (AOP (result), "!zero", offset);
5243 // faster than result <- left, anl result,right
5244 // and better if result is SFR
5245 if (AOP_TYPE (left) == AOP_ACC)
5246 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5249 _moveA (aopGet (AOP (left), offset, FALSE));
5251 aopGet (AOP (right), offset, FALSE));
5253 aopPut (AOP (result), "a", offset);
5260 freeAsmop (left, NULL, ic);
5261 freeAsmop (right, NULL, ic);
5262 freeAsmop (result, NULL, ic);
5265 /*-----------------------------------------------------------------*/
5266 /* genOr - code for or */
5267 /*-----------------------------------------------------------------*/
5269 genOr (iCode * ic, iCode * ifx)
5271 operand *left, *right, *result;
5272 int size, offset = 0;
5273 unsigned long lit = 0L;
5276 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5277 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5278 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5280 /* if left is a literal & right is not then exchange them */
5281 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5282 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5284 operand *tmp = right;
5289 /* if result = right then exchange them */
5290 if (sameRegs (AOP (result), AOP (right)))
5292 operand *tmp = right;
5297 /* if right is bit then exchange them */
5298 if (AOP_TYPE (right) == AOP_CRY &&
5299 AOP_TYPE (left) != AOP_CRY)
5301 operand *tmp = right;
5305 if (AOP_TYPE (right) == AOP_LIT)
5306 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5308 size = AOP_SIZE (result);
5310 if (AOP_TYPE (left) == AOP_CRY)
5312 wassertl (0, "Tried to OR where left is a bit");
5316 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5317 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5318 if ((AOP_TYPE (right) == AOP_LIT) &&
5319 (AOP_TYPE (result) == AOP_CRY) &&
5320 (AOP_TYPE (left) != AOP_CRY))
5322 symbol *tlbl = newiTempLabel (NULL);
5323 int sizel = AOP_SIZE (left);
5327 wassertl (0, "Result is assigned to a bit");
5329 /* PENDING: Modeled after the AND code which is inefficient. */
5332 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5334 _moveA (aopGet (AOP (left), offset, FALSE));
5335 /* OR with any literal is the same as OR with itself. */
5337 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5343 jmpTrueOrFalse (ifx, tlbl);
5348 /* if left is same as result */
5349 if (sameRegs (AOP (result), AOP (left)))
5351 for (; size--; offset++)
5353 if (AOP_TYPE (right) == AOP_LIT)
5355 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5359 _moveA (aopGet (AOP (left), offset, FALSE));
5361 aopGet (AOP (right), offset, FALSE));
5362 aopPut (AOP (result), "a", offset);
5367 if (AOP_TYPE (left) == AOP_ACC)
5368 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5371 _moveA (aopGet (AOP (left), offset, FALSE));
5373 aopGet (AOP (right), offset, FALSE));
5374 aopPut (AOP (result), "a", offset);
5381 // left & result in different registers
5382 if (AOP_TYPE (result) == AOP_CRY)
5384 wassertl (0, "Result of OR is in a bit");
5387 for (; (size--); offset++)
5390 // result = left & right
5391 if (AOP_TYPE (right) == AOP_LIT)
5393 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5395 aopPut (AOP (result),
5396 aopGet (AOP (left), offset, FALSE),
5401 // faster than result <- left, anl result,right
5402 // and better if result is SFR
5403 if (AOP_TYPE (left) == AOP_ACC)
5404 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5407 _moveA (aopGet (AOP (left), offset, FALSE));
5409 aopGet (AOP (right), offset, FALSE));
5411 aopPut (AOP (result), "a", offset);
5412 /* PENDING: something weird is going on here. Add exception. */
5413 if (AOP_TYPE (result) == AOP_ACC)
5419 freeAsmop (left, NULL, ic);
5420 freeAsmop (right, NULL, ic);
5421 freeAsmop (result, NULL, ic);
5424 /*-----------------------------------------------------------------*/
5425 /* genXor - code for xclusive or */
5426 /*-----------------------------------------------------------------*/
5428 genXor (iCode * ic, iCode * ifx)
5430 operand *left, *right, *result;
5431 int size, offset = 0;
5432 unsigned long lit = 0L;
5434 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5435 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5436 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5438 /* if left is a literal & right is not then exchange them */
5439 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5440 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5442 operand *tmp = right;
5447 /* if result = right then exchange them */
5448 if (sameRegs (AOP (result), AOP (right)))
5450 operand *tmp = right;
5455 /* if right is bit then exchange them */
5456 if (AOP_TYPE (right) == AOP_CRY &&
5457 AOP_TYPE (left) != AOP_CRY)
5459 operand *tmp = right;
5463 if (AOP_TYPE (right) == AOP_LIT)
5464 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5466 size = AOP_SIZE (result);
5468 if (AOP_TYPE (left) == AOP_CRY)
5470 wassertl (0, "Tried to XOR a bit");
5474 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5475 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5476 if ((AOP_TYPE (right) == AOP_LIT) &&
5477 (AOP_TYPE (result) == AOP_CRY) &&
5478 (AOP_TYPE (left) != AOP_CRY))
5480 symbol *tlbl = newiTempLabel (NULL);
5481 int sizel = AOP_SIZE (left);
5485 /* PENDING: Test case for this. */
5486 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5490 _moveA (aopGet (AOP (left), offset, FALSE));
5491 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5492 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5497 jmpTrueOrFalse (ifx, tlbl);
5501 wassertl (0, "Result of XOR was destined for a bit");
5506 /* if left is same as result */
5507 if (sameRegs (AOP (result), AOP (left)))
5509 for (; size--; offset++)
5511 if (AOP_TYPE (right) == AOP_LIT)
5513 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5517 _moveA (aopGet (AOP (left), offset, FALSE));
5519 aopGet (AOP (right), offset, FALSE));
5520 aopPut (AOP (result), "a", offset);
5525 if (AOP_TYPE (left) == AOP_ACC)
5527 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5531 _moveA (aopGet (AOP (left), offset, FALSE));
5533 aopGet (AOP (right), offset, FALSE));
5534 aopPut (AOP (result), "a", offset);
5541 // left & result in different registers
5542 if (AOP_TYPE (result) == AOP_CRY)
5544 wassertl (0, "Result of XOR is in a bit");
5547 for (; (size--); offset++)
5550 // result = left & right
5551 if (AOP_TYPE (right) == AOP_LIT)
5553 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5555 aopPut (AOP (result),
5556 aopGet (AOP (left), offset, FALSE),
5561 // faster than result <- left, anl result,right
5562 // and better if result is SFR
5563 if (AOP_TYPE (left) == AOP_ACC)
5565 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5569 _moveA (aopGet (AOP (left), offset, FALSE));
5571 aopGet (AOP (right), offset, FALSE));
5573 aopPut (AOP (result), "a", offset);
5578 freeAsmop (left, NULL, ic);
5579 freeAsmop (right, NULL, ic);
5580 freeAsmop (result, NULL, ic);
5583 /*-----------------------------------------------------------------*/
5584 /* genInline - write the inline code out */
5585 /*-----------------------------------------------------------------*/
5587 genInline (iCode * ic)
5589 char *buffer, *bp, *bp1;
5591 _G.lines.isInline += (!options.asmpeep);
5593 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5594 strcpy (buffer, IC_INLINE (ic));
5596 /* emit each line as a code */
5621 _G.lines.isInline -= (!options.asmpeep);
5625 /*-----------------------------------------------------------------*/
5626 /* genRRC - rotate right with carry */
5627 /*-----------------------------------------------------------------*/
5634 /*-----------------------------------------------------------------*/
5635 /* genRLC - generate code for rotate left with carry */
5636 /*-----------------------------------------------------------------*/
5643 /*-----------------------------------------------------------------*/
5644 /* genGetHbit - generates code get highest order bit */
5645 /*-----------------------------------------------------------------*/
5647 genGetHbit (iCode * ic)
5649 operand *left, *result;
5650 left = IC_LEFT (ic);
5651 result = IC_RESULT (ic);
5653 aopOp (left, ic, FALSE, FALSE);
5654 aopOp (result, ic, FALSE, FALSE);
5656 /* get the highest order byte into a */
5657 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5659 if (AOP_TYPE (result) == AOP_CRY)
5667 emit2 ("and a,!one");
5672 freeAsmop (left, NULL, ic);
5673 freeAsmop (result, NULL, ic);
5677 emitRsh2 (asmop *aop, int size, int is_signed)
5683 const char *l = aopGet (aop, size, FALSE);
5686 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5696 /*-----------------------------------------------------------------*/
5697 /* shiftR2Left2Result - shift right two bytes from left to result */
5698 /*-----------------------------------------------------------------*/
5700 shiftR2Left2Result (operand * left, int offl,
5701 operand * result, int offr,
5702 int shCount, int is_signed)
5705 symbol *tlbl, *tlbl1;
5707 movLeft2Result (left, offl, result, offr, 0);
5708 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5713 /* if (AOP(result)->type == AOP_REG) { */
5715 tlbl = newiTempLabel (NULL);
5716 tlbl1 = newiTempLabel (NULL);
5718 /* Left is already in result - so now do the shift */
5723 emitRsh2 (AOP (result), size, is_signed);
5728 emit2 ("ld a,!immedbyte+1", shCount);
5729 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5730 emitLabel (tlbl->key + 100);
5732 emitRsh2 (AOP (result), size, is_signed);
5734 emitLabel (tlbl1->key + 100);
5736 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5740 /*-----------------------------------------------------------------*/
5741 /* shiftL2Left2Result - shift left two bytes from left to result */
5742 /*-----------------------------------------------------------------*/
5744 shiftL2Left2Result (operand * left, int offl,
5745 operand * result, int offr, int shCount)
5747 if (sameRegs (AOP (result), AOP (left)) &&
5748 ((offl + MSB16) == offr))
5754 /* Copy left into result */
5755 movLeft2Result (left, offl, result, offr, 0);
5756 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5762 if (getPairId (AOP (result)) == PAIR_HL)
5766 emit2 ("add hl,hl");
5773 symbol *tlbl, *tlbl1;
5776 tlbl = newiTempLabel (NULL);
5777 tlbl1 = newiTempLabel (NULL);
5779 if (AOP (result)->type == AOP_REG)
5783 for (offset = 0; offset < size; offset++)
5785 l = aopGet (AOP (result), offset, FALSE);
5789 emit2 ("sla %s", l);
5800 /* Left is already in result - so now do the shift */
5803 emit2 ("ld a,!immedbyte+1", shCount);
5804 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5805 emitLabel (tlbl->key + 100);
5810 l = aopGet (AOP (result), offset, FALSE);
5814 emit2 ("sla %s", l);
5825 emitLabel (tlbl1->key + 100);
5827 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5833 /*-----------------------------------------------------------------*/
5834 /* AccRol - rotate left accumulator by known count */
5835 /*-----------------------------------------------------------------*/
5837 AccRol (int shCount)
5839 shCount &= 0x0007; // shCount : 0..7
5916 /*-----------------------------------------------------------------*/
5917 /* AccLsh - left shift accumulator by known count */
5918 /*-----------------------------------------------------------------*/
5920 AccLsh (int shCount)
5922 static const unsigned char SLMask[] =
5924 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5933 else if (shCount == 2)
5940 /* rotate left accumulator */
5942 /* and kill the lower order bits */
5943 emit2 ("and a,!immedbyte", SLMask[shCount]);
5948 /*-----------------------------------------------------------------*/
5949 /* shiftL1Left2Result - shift left one byte from left to result */
5950 /*-----------------------------------------------------------------*/
5952 shiftL1Left2Result (operand * left, int offl,
5953 operand * result, int offr, int shCount)
5956 l = aopGet (AOP (left), offl, FALSE);
5958 /* shift left accumulator */
5960 aopPut (AOP (result), "a", offr);
5964 /*-----------------------------------------------------------------*/
5965 /* genlshTwo - left shift two bytes by known amount */
5966 /*-----------------------------------------------------------------*/
5968 genlshTwo (operand * result, operand * left, int shCount)
5970 int size = AOP_SIZE (result);
5972 wassert (size == 2);
5974 /* if shCount >= 8 */
5982 movLeft2Result (left, LSB, result, MSB16, 0);
5983 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5984 aopPut (AOP (result), "!zero", LSB);
5988 movLeft2Result (left, LSB, result, MSB16, 0);
5989 aopPut (AOP (result), "!zero", 0);
5994 aopPut (AOP (result), "!zero", LSB);
5997 /* 0 <= shCount <= 7 */
6006 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6011 /*-----------------------------------------------------------------*/
6012 /* genlshOne - left shift a one byte quantity by known count */
6013 /*-----------------------------------------------------------------*/
6015 genlshOne (operand * result, operand * left, int shCount)
6017 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6020 /*-----------------------------------------------------------------*/
6021 /* genLeftShiftLiteral - left shifting by known count */
6022 /*-----------------------------------------------------------------*/
6024 genLeftShiftLiteral (operand * left,
6029 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6032 freeAsmop (right, NULL, ic);
6034 aopOp (left, ic, FALSE, FALSE);
6035 aopOp (result, ic, FALSE, FALSE);
6037 size = getSize (operandType (result));
6039 /* I suppose that the left size >= result size */
6041 if (shCount >= (size * 8))
6045 aopPut (AOP (result), "!zero", size);
6053 genlshOne (result, left, shCount);
6056 genlshTwo (result, left, shCount);
6059 wassertl (0, "Shifting of longs is currently unsupported");
6065 freeAsmop (left, NULL, ic);
6066 freeAsmop (result, NULL, ic);
6069 /*-----------------------------------------------------------------*/
6070 /* genLeftShift - generates code for left shifting */
6071 /*-----------------------------------------------------------------*/
6073 genLeftShift (iCode * ic)
6077 symbol *tlbl, *tlbl1;
6078 operand *left, *right, *result;
6080 right = IC_RIGHT (ic);
6081 left = IC_LEFT (ic);
6082 result = IC_RESULT (ic);
6084 aopOp (right, ic, FALSE, FALSE);
6086 /* if the shift count is known then do it
6087 as efficiently as possible */
6088 if (AOP_TYPE (right) == AOP_LIT)
6090 genLeftShiftLiteral (left, right, result, ic);
6094 /* shift count is unknown then we have to form a loop get the loop
6095 count in B : Note: we take only the lower order byte since
6096 shifting more that 32 bits make no sense anyway, ( the largest
6097 size of an object can be only 32 bits ) */
6098 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6100 freeAsmop (right, NULL, ic);
6101 aopOp (left, ic, FALSE, FALSE);
6102 aopOp (result, ic, FALSE, FALSE);
6104 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6107 /* now move the left to the result if they are not the
6110 if (!sameRegs (AOP (left), AOP (result)))
6113 size = AOP_SIZE (result);
6117 l = aopGet (AOP (left), offset, FALSE);
6118 aopPut (AOP (result), l, offset);
6123 tlbl = newiTempLabel (NULL);
6124 size = AOP_SIZE (result);
6126 tlbl1 = newiTempLabel (NULL);
6128 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6131 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6132 emitLabel (tlbl->key + 100);
6133 l = aopGet (AOP (result), offset, FALSE);
6137 l = aopGet (AOP (result), offset, FALSE);
6141 emit2 ("sla %s", l);
6149 emitLabel (tlbl1->key + 100);
6151 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6153 freeAsmop (left, NULL, ic);
6154 freeAsmop (result, NULL, ic);
6157 /*-----------------------------------------------------------------*/
6158 /* genrshOne - left shift two bytes by known amount != 0 */
6159 /*-----------------------------------------------------------------*/
6161 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6164 int size = AOP_SIZE (result);
6167 wassert (size == 1);
6168 wassert (shCount < 8);
6170 l = aopGet (AOP (left), 0, FALSE);
6172 if (AOP (result)->type == AOP_REG)
6174 aopPut (AOP (result), l, 0);
6175 l = aopGet (AOP (result), 0, FALSE);
6178 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6186 emit2 ("%s a", is_signed ? "sra" : "srl");
6188 aopPut (AOP (result), "a", 0);
6192 /*-----------------------------------------------------------------*/
6193 /* AccRsh - right shift accumulator by known count */
6194 /*-----------------------------------------------------------------*/
6196 AccRsh (int shCount)
6198 static const unsigned char SRMask[] =
6200 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6205 /* rotate right accumulator */
6206 AccRol (8 - shCount);
6207 /* and kill the higher order bits */
6208 emit2 ("and a,!immedbyte", SRMask[shCount]);
6212 /*-----------------------------------------------------------------*/
6213 /* shiftR1Left2Result - shift right one byte from left to result */
6214 /*-----------------------------------------------------------------*/
6216 shiftR1Left2Result (operand * left, int offl,
6217 operand * result, int offr,
6218 int shCount, int sign)
6220 _moveA (aopGet (AOP (left), offl, FALSE));
6225 emit2 ("%s a", sign ? "sra" : "srl");
6232 aopPut (AOP (result), "a", offr);
6235 /*-----------------------------------------------------------------*/
6236 /* genrshTwo - right shift two bytes by known amount */
6237 /*-----------------------------------------------------------------*/
6239 genrshTwo (operand * result, operand * left,
6240 int shCount, int sign)
6242 /* if shCount >= 8 */
6248 shiftR1Left2Result (left, MSB16, result, LSB,
6253 movLeft2Result (left, MSB16, result, LSB, sign);
6257 /* Sign extend the result */
6258 _moveA(aopGet (AOP (result), 0, FALSE));
6262 aopPut (AOP (result), ACC_NAME, MSB16);
6266 aopPut (AOP (result), "!zero", 1);
6269 /* 0 <= shCount <= 7 */
6272 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6276 /*-----------------------------------------------------------------*/
6277 /* genRightShiftLiteral - left shifting by known count */
6278 /*-----------------------------------------------------------------*/
6280 genRightShiftLiteral (operand * left,
6286 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6289 freeAsmop (right, NULL, ic);
6291 aopOp (left, ic, FALSE, FALSE);
6292 aopOp (result, ic, FALSE, FALSE);
6294 size = getSize (operandType (result));
6296 /* I suppose that the left size >= result size */
6298 if (shCount >= (size * 8)) {
6300 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6301 _moveA(aopGet (AOP (left), 0, FALSE));
6309 aopPut (AOP (result), s, size);
6316 genrshOne (result, left, shCount, sign);
6319 genrshTwo (result, left, shCount, sign);
6322 wassertl (0, "Asked to shift right a long which should be a function call");
6325 wassertl (0, "Entered default case in right shift delegate");
6328 freeAsmop (left, NULL, ic);
6329 freeAsmop (result, NULL, ic);
6332 /*-----------------------------------------------------------------*/
6333 /* genRightShift - generate code for right shifting */
6334 /*-----------------------------------------------------------------*/
6336 genRightShift (iCode * ic)
6338 operand *right, *left, *result;
6340 int size, offset, first = 1;
6344 symbol *tlbl, *tlbl1;
6346 /* if signed then we do it the hard way preserve the
6347 sign bit moving it inwards */
6348 retype = getSpec (operandType (IC_RESULT (ic)));
6350 is_signed = !SPEC_USIGN (retype);
6352 /* signed & unsigned types are treated the same : i.e. the
6353 signed is NOT propagated inwards : quoting from the
6354 ANSI - standard : "for E1 >> E2, is equivalent to division
6355 by 2**E2 if unsigned or if it has a non-negative value,
6356 otherwise the result is implementation defined ", MY definition
6357 is that the sign does not get propagated */
6359 right = IC_RIGHT (ic);
6360 left = IC_LEFT (ic);
6361 result = IC_RESULT (ic);
6363 aopOp (right, ic, FALSE, FALSE);
6365 /* if the shift count is known then do it
6366 as efficiently as possible */
6367 if (AOP_TYPE (right) == AOP_LIT)
6369 genRightShiftLiteral (left, right, result, ic, is_signed);
6373 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6375 freeAsmop (right, NULL, ic);
6377 aopOp (left, ic, FALSE, FALSE);
6378 aopOp (result, ic, FALSE, FALSE);
6380 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6383 /* now move the left to the result if they are not the
6385 if (!sameRegs (AOP (left), AOP (result)))
6388 size = AOP_SIZE (result);
6392 l = aopGet (AOP (left), offset, FALSE);
6393 aopPut (AOP (result), l, offset);
6398 tlbl = newiTempLabel (NULL);
6399 tlbl1 = newiTempLabel (NULL);
6400 size = AOP_SIZE (result);
6403 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6406 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6407 emitLabel (tlbl->key + 100);
6410 l = aopGet (AOP (result), offset--, FALSE);
6413 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6421 emitLabel (tlbl1->key + 100);
6423 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6425 freeAsmop (left, NULL, ic);
6426 freeAsmop (result, NULL, ic);
6430 /*-----------------------------------------------------------------*/
6431 /* genUnpackBits - generates code for unpacking bits */
6432 /*-----------------------------------------------------------------*/
6434 genUnpackBits (operand * result, int pair)
6436 int offset = 0; /* result byte offset */
6437 int rsize; /* result size */
6438 int rlen = 0; /* remaining bitfield length */
6439 sym_link *etype; /* bitfield type information */
6440 int blen; /* bitfield length */
6441 int bstr; /* bitfield starting bit within byte */
6443 emitDebug ("; genUnpackBits");
6445 etype = getSpec (operandType (result));
6446 rsize = getSize (operandType (result));
6447 blen = SPEC_BLEN (etype);
6448 bstr = SPEC_BSTR (etype);
6450 /* If the bitfield length is less than a byte */
6453 emit2 ("ld a,!*pair", _pairs[pair].name);
6455 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6456 if (!SPEC_USIGN (etype))
6458 /* signed bitfield */
6459 symbol *tlbl = newiTempLabel (NULL);
6461 emit2 ("bit %d,a", blen - 1);
6462 emit2 ("jp z,!tlabel", tlbl->key + 100);
6463 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6464 emitLabel (tlbl->key + 100);
6466 aopPut (AOP (result), "a", offset++);
6470 /* TODO: what if pair == PAIR_DE ? */
6471 if (getPairId (AOP (result)) == PAIR_HL)
6473 wassertl (rsize == 2, "HL must be of size 2");
6474 emit2 ("ld a,!*hl");
6476 emit2 ("ld h,!*hl");
6479 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6480 if (!SPEC_USIGN (etype))
6482 /* signed bitfield */
6483 symbol *tlbl = newiTempLabel (NULL);
6485 emit2 ("bit %d,a", blen - 1);
6486 emit2 ("jp z,!tlabel", tlbl->key + 100);
6487 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6488 emitLabel (tlbl->key + 100);
6491 spillPair (PAIR_HL);
6495 /* Bit field did not fit in a byte. Copy all
6496 but the partial byte at the end. */
6497 for (rlen=blen;rlen>=8;rlen-=8)
6499 emit2 ("ld a,!*pair", _pairs[pair].name);
6500 aopPut (AOP (result), "a", offset++);
6503 emit2 ("inc %s", _pairs[pair].name);
6504 _G.pairs[pair].offset++;
6508 /* Handle the partial byte at the end */
6511 emit2 ("ld a,!*pair", _pairs[pair].name);
6512 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6513 if (!SPEC_USIGN (etype))
6515 /* signed bitfield */
6516 symbol *tlbl = newiTempLabel (NULL);
6518 emit2 ("bit %d,a", rlen - 1);
6519 emit2 ("jp z,!tlabel", tlbl->key + 100);
6520 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6521 emitLabel (tlbl->key + 100);
6523 aopPut (AOP (result), "a", offset++);
6531 if (SPEC_USIGN (etype))
6535 /* signed bitfield: sign extension with 0x00 or 0xff */
6543 aopPut (AOP (result), source, offset++);
6547 /*-----------------------------------------------------------------*/
6548 /* genGenPointerGet - get value from generic pointer space */
6549 /*-----------------------------------------------------------------*/
6551 genGenPointerGet (operand * left,
6552 operand * result, iCode * ic)
6555 sym_link *retype = getSpec (operandType (result));
6561 aopOp (left, ic, FALSE, FALSE);
6562 aopOp (result, ic, FALSE, FALSE);
6564 size = AOP_SIZE (result);
6566 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6569 if (isPtrPair (AOP (left)))
6571 tsprintf (buffer, sizeof(buffer),
6572 "!*pair", getPairName (AOP (left)));
6573 aopPut (AOP (result), buffer, 0);
6577 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6578 aopPut (AOP (result), "a", 0);
6580 freeAsmop (left, NULL, ic);
6584 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6591 tsprintf (at, sizeof(at), "!*iyx", offset);
6592 aopPut (AOP (result), at, offset);
6596 freeAsmop (left, NULL, ic);
6600 /* For now we always load into IY */
6601 /* if this is remateriazable */
6602 fetchPair (pair, AOP (left));
6604 /* if bit then unpack */
6605 if (IS_BITVAR (retype))
6607 genUnpackBits (result, pair);
6608 freeAsmop (left, NULL, ic);
6612 else if (getPairId (AOP (result)) == PAIR_HL)
6614 wassertl (size == 2, "HL must be of size 2");
6615 emit2 ("ld a,!*hl");
6617 emit2 ("ld h,!*hl");
6619 spillPair (PAIR_HL);
6621 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6623 size = AOP_SIZE (result);
6628 /* PENDING: make this better */
6629 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6631 aopPut (AOP (result), "!*hl", offset++);
6635 emit2 ("ld a,!*pair", _pairs[pair].name);
6636 aopPut (AOP (result), "a", offset++);
6640 emit2 ("inc %s", _pairs[pair].name);
6641 _G.pairs[pair].offset++;
6644 /* Fixup HL back down */
6645 for (size = AOP_SIZE (result)-1; size; size--)
6647 emit2 ("dec %s", _pairs[pair].name);
6652 size = AOP_SIZE (result);
6657 /* PENDING: make this better */
6659 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6661 aopPut (AOP (result), "!*hl", offset++);
6665 emit2 ("ld a,!*pair", _pairs[pair].name);
6666 aopPut (AOP (result), "a", offset++);
6670 emit2 ("inc %s", _pairs[pair].name);
6671 _G.pairs[pair].offset++;
6676 freeAsmop (left, NULL, ic);
6679 freeAsmop (result, NULL, ic);
6682 /*-----------------------------------------------------------------*/
6683 /* genPointerGet - generate code for pointer get */
6684 /*-----------------------------------------------------------------*/
6686 genPointerGet (iCode * ic)
6688 operand *left, *result;
6689 sym_link *type, *etype;
6691 left = IC_LEFT (ic);
6692 result = IC_RESULT (ic);
6694 /* depending on the type of pointer we need to
6695 move it to the correct pointer register */
6696 type = operandType (left);
6697 etype = getSpec (type);
6699 genGenPointerGet (left, result, ic);
6703 isRegOrLit (asmop * aop)
6705 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6711 /*-----------------------------------------------------------------*/
6712 /* genPackBits - generates code for packed bit storage */
6713 /*-----------------------------------------------------------------*/
6715 genPackBits (sym_link * etype,
6720 int offset = 0; /* source byte offset */
6721 int rlen = 0; /* remaining bitfield length */
6722 int blen; /* bitfield length */
6723 int bstr; /* bitfield starting bit within byte */
6724 int litval; /* source literal value (if AOP_LIT) */
6725 unsigned char mask; /* bitmask within current byte */
6726 int extraPair; /* a tempory register */
6727 bool needPopExtra=0; /* need to restore original value of temp reg */
6729 emitDebug ("; genPackBits","");
6731 blen = SPEC_BLEN (etype);
6732 bstr = SPEC_BSTR (etype);
6734 /* If the bitfield length is less than a byte */
6737 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6738 (unsigned char) (0xFF >> (8 - bstr)));
6740 if (AOP_TYPE (right) == AOP_LIT)
6742 /* Case with a bitfield length <8 and literal source
6744 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6746 litval &= (~mask) & 0xff;
6747 emit2 ("ld a,!*pair", _pairs[pair].name);
6748 if ((mask|litval)!=0xff)
6749 emit2 ("and a,!immedbyte", mask);
6751 emit2 ("or a,!immedbyte", litval);
6752 emit2 ("ld !*pair,a", _pairs[pair].name);
6757 /* Case with a bitfield length <8 and arbitrary source
6759 _moveA (aopGet (AOP (right), 0, FALSE));
6760 /* shift and mask source value */
6762 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6764 extraPair = getFreePairId(ic);
6765 if (extraPair == PAIR_INVALID)
6767 extraPair = PAIR_BC;
6768 if (getPairId (AOP (right)) != PAIR_BC
6769 || !isLastUse (ic, right))
6775 emit2 ("ld %s,a", _pairs[extraPair].l);
6776 emit2 ("ld a,!*pair", _pairs[pair].name);
6778 emit2 ("and a,!immedbyte", mask);
6779 emit2 ("or a,%s", _pairs[extraPair].l);
6780 emit2 ("ld !*pair,a", _pairs[pair].name);
6787 /* Bit length is greater than 7 bits. In this case, copy */
6788 /* all except the partial byte at the end */
6789 for (rlen=blen;rlen>=8;rlen-=8)
6791 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6792 emit2 ("ld !*pair,a", _pairs[pair].name);
6795 emit2 ("inc %s", _pairs[pair].name);
6796 _G.pairs[pair].offset++;
6800 /* If there was a partial byte at the end */
6803 mask = (((unsigned char) -1 << rlen) & 0xff);
6805 if (AOP_TYPE (right) == AOP_LIT)
6807 /* Case with partial byte and literal source
6809 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6810 litval >>= (blen-rlen);
6811 litval &= (~mask) & 0xff;
6812 emit2 ("ld a,!*pair", _pairs[pair].name);
6813 if ((mask|litval)!=0xff)
6814 emit2 ("and a,!immedbyte", mask);
6816 emit2 ("or a,!immedbyte", litval);
6820 /* Case with partial byte and arbitrary source
6822 _moveA (aopGet (AOP (right), offset++, FALSE));
6823 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6825 extraPair = getFreePairId(ic);
6826 if (extraPair == PAIR_INVALID)
6828 extraPair = getPairId (AOP (right));
6829 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6830 extraPair = PAIR_BC;
6832 if (getPairId (AOP (right)) != PAIR_BC
6833 || !isLastUse (ic, right))
6839 emit2 ("ld %s,a", _pairs[extraPair].l);
6840 emit2 ("ld a,!*pair", _pairs[pair].name);
6842 emit2 ("and a,!immedbyte", mask);
6843 emit2 ("or a,%s", _pairs[extraPair].l);
6848 emit2 ("ld !*pair,a", _pairs[pair].name);
6853 /*-----------------------------------------------------------------*/
6854 /* genGenPointerSet - stores the value into a pointer location */
6855 /*-----------------------------------------------------------------*/
6857 genGenPointerSet (operand * right,
6858 operand * result, iCode * ic)
6861 sym_link *retype = getSpec (operandType (right));
6862 sym_link *letype = getSpec (operandType (result));
6863 PAIR_ID pairId = PAIR_HL;
6866 aopOp (result, ic, FALSE, FALSE);
6867 aopOp (right, ic, FALSE, FALSE);
6872 size = AOP_SIZE (right);
6874 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6875 emitDebug("; isBitvar = %d", isBitvar);
6877 /* Handle the exceptions first */
6878 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6881 const char *l = aopGet (AOP (right), 0, FALSE);
6882 const char *pair = getPairName (AOP (result));
6883 if (canAssignToPtr (l) && isPtr (pair))
6885 emit2 ("ld !*pair,%s", pair, l);
6890 emit2 ("ld !*pair,a", pair);
6895 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6898 const char *l = aopGet (AOP (right), 0, FALSE);
6903 if (canAssignToPtr (l))
6905 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6909 _moveA (aopGet (AOP (right), offset, FALSE));
6910 emit2 ("ld !*iyx,a", offset);
6916 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6923 const char *l = aopGet (AOP (right), offset, FALSE);
6924 if (isRegOrLit (AOP (right)) && !IS_GB)
6926 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6931 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6935 emit2 ("inc %s", _pairs[PAIR_HL].name);
6936 _G.pairs[PAIR_HL].offset++;
6941 /* Fixup HL back down */
6942 for (size = AOP_SIZE (right)-1; size; size--)
6944 emit2 ("dec %s", _pairs[PAIR_HL].name);
6949 /* if the operand is already in dptr
6950 then we do nothing else we move the value to dptr */
6951 if (AOP_TYPE (result) != AOP_STR)
6953 fetchPair (pairId, AOP (result));
6955 /* so hl now contains the address */
6956 freeAsmop (result, NULL, ic);
6958 /* if bit then unpack */
6961 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6971 const char *l = aopGet (AOP (right), offset, FALSE);
6972 if (isRegOrLit (AOP (right)) && !IS_GB)
6974 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6979 emit2 ("ld !*pair,a", _pairs[pairId].name);
6983 emit2 ("inc %s", _pairs[pairId].name);
6984 _G.pairs[pairId].offset++;
6990 freeAsmop (right, NULL, ic);
6993 /*-----------------------------------------------------------------*/
6994 /* genPointerSet - stores the value into a pointer location */
6995 /*-----------------------------------------------------------------*/
6997 genPointerSet (iCode * ic)
6999 operand *right, *result;
7000 sym_link *type, *etype;
7002 right = IC_RIGHT (ic);
7003 result = IC_RESULT (ic);
7005 /* depending on the type of pointer we need to
7006 move it to the correct pointer register */
7007 type = operandType (result);
7008 etype = getSpec (type);
7010 genGenPointerSet (right, result, ic);
7013 /*-----------------------------------------------------------------*/
7014 /* genIfx - generate code for Ifx statement */
7015 /*-----------------------------------------------------------------*/
7017 genIfx (iCode * ic, iCode * popIc)
7019 operand *cond = IC_COND (ic);
7022 aopOp (cond, ic, FALSE, TRUE);
7024 /* get the value into acc */
7025 if (AOP_TYPE (cond) != AOP_CRY)
7029 /* the result is now in the accumulator */
7030 freeAsmop (cond, NULL, ic);
7032 /* if there was something to be popped then do it */
7036 /* if the condition is a bit variable */
7037 if (isbit && IS_ITEMP (cond) &&
7039 genIfxJump (ic, SPIL_LOC (cond)->rname);
7040 else if (isbit && !IS_ITEMP (cond))
7041 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7043 genIfxJump (ic, "a");
7048 /*-----------------------------------------------------------------*/
7049 /* genAddrOf - generates code for address of */
7050 /*-----------------------------------------------------------------*/
7052 genAddrOf (iCode * ic)
7054 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7056 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7058 /* if the operand is on the stack then we
7059 need to get the stack offset of this
7066 if (sym->stack <= 0)
7068 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7072 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7074 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7078 emit2 ("ld de,!hashedstr", sym->rname);
7079 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7087 /* if it has an offset then we need to compute it */
7089 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7091 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7092 emit2 ("add hl,sp");
7096 emit2 ("ld hl,!hashedstr", sym->rname);
7098 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7100 freeAsmop (IC_RESULT (ic), NULL, ic);
7103 /*-----------------------------------------------------------------*/
7104 /* genAssign - generate code for assignment */
7105 /*-----------------------------------------------------------------*/
7107 genAssign (iCode * ic)
7109 operand *result, *right;
7111 unsigned long lit = 0L;
7113 result = IC_RESULT (ic);
7114 right = IC_RIGHT (ic);
7116 /* Dont bother assigning if they are the same */
7117 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7119 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7123 aopOp (right, ic, FALSE, FALSE);
7124 aopOp (result, ic, TRUE, FALSE);
7126 /* if they are the same registers */
7127 if (sameRegs (AOP (right), AOP (result)))
7129 emitDebug ("; (registers are the same)");
7133 /* if the result is a bit */
7134 if (AOP_TYPE (result) == AOP_CRY)
7136 wassertl (0, "Tried to assign to a bit");
7140 size = AOP_SIZE (result);
7143 if (AOP_TYPE (right) == AOP_LIT)
7145 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7148 if (isPair (AOP (result)))
7150 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7152 else if ((size > 1) &&
7153 (AOP_TYPE (result) != AOP_REG) &&
7154 (AOP_TYPE (right) == AOP_LIT) &&
7155 !IS_FLOAT (operandType (right)) &&
7158 bool fXored = FALSE;
7160 /* Work from the top down.
7161 Done this way so that we can use the cached copy of 0
7162 in A for a fast clear */
7165 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7167 if (!fXored && size > 1)
7174 aopPut (AOP (result), "a", offset);
7178 aopPut (AOP (result), "!zero", offset);
7182 aopPut (AOP (result),
7183 aopGet (AOP (right), offset, FALSE),
7188 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7190 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7191 aopPut (AOP (result), "l", LSB);
7192 aopPut (AOP (result), "h", MSB16);
7194 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7196 /* Special case. Load into a and d, then load out. */
7197 _moveA (aopGet (AOP (right), 0, FALSE));
7198 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7199 aopPut (AOP (result), "a", 0);
7200 aopPut (AOP (result), "e", 1);
7202 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7204 /* Special case - simple memcpy */
7205 aopGet (AOP (right), LSB, FALSE);
7208 aopGet (AOP (result), LSB, FALSE);
7212 emit2 ("ld a,(de)");
7213 /* Peephole will optimise this. */
7214 emit2 ("ld (hl),a");
7222 spillPair (PAIR_HL);
7228 /* PENDING: do this check better */
7229 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7231 _moveA (aopGet (AOP (right), offset, FALSE));
7232 aopPut (AOP (result), "a", offset);
7235 aopPut (AOP (result),
7236 aopGet (AOP (right), offset, FALSE),
7243 freeAsmop (right, NULL, ic);
7244 freeAsmop (result, NULL, ic);
7247 /*-----------------------------------------------------------------*/
7248 /* genJumpTab - genrates code for jump table */
7249 /*-----------------------------------------------------------------*/
7251 genJumpTab (iCode * ic)
7256 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7257 /* get the condition into accumulator */
7258 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7261 emit2 ("ld e,%s", l);
7262 emit2 ("ld d,!zero");
7263 jtab = newiTempLabel (NULL);
7265 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7266 emit2 ("add hl,de");
7267 emit2 ("add hl,de");
7268 emit2 ("add hl,de");
7269 freeAsmop (IC_JTCOND (ic), NULL, ic);
7273 emitLabel (jtab->key + 100);
7274 /* now generate the jump labels */
7275 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7276 jtab = setNextItem (IC_JTLABELS (ic)))
7277 emit2 ("jp !tlabel", jtab->key + 100);
7280 /*-----------------------------------------------------------------*/
7281 /* genCast - gen code for casting */
7282 /*-----------------------------------------------------------------*/
7284 genCast (iCode * ic)
7286 operand *result = IC_RESULT (ic);
7287 sym_link *rtype = operandType (IC_RIGHT (ic));
7288 operand *right = IC_RIGHT (ic);
7291 /* if they are equivalent then do nothing */
7292 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7295 aopOp (right, ic, FALSE, FALSE);
7296 aopOp (result, ic, FALSE, FALSE);
7298 /* if the result is a bit */
7299 if (AOP_TYPE (result) == AOP_CRY)
7301 wassertl (0, "Tried to cast to a bit");
7304 /* if they are the same size : or less */
7305 if (AOP_SIZE (result) <= AOP_SIZE (right))
7308 /* if they are in the same place */
7309 if (sameRegs (AOP (right), AOP (result)))
7312 /* if they in different places then copy */
7313 size = AOP_SIZE (result);
7317 aopPut (AOP (result),
7318 aopGet (AOP (right), offset, FALSE),
7325 /* So we now know that the size of destination is greater
7326 than the size of the source */
7327 /* we move to result for the size of source */
7328 size = AOP_SIZE (right);
7332 aopPut (AOP (result),
7333 aopGet (AOP (right), offset, FALSE),
7338 /* now depending on the sign of the destination */
7339 size = AOP_SIZE (result) - AOP_SIZE (right);
7340 /* Unsigned or not an integral type - right fill with zeros */
7341 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7344 aopPut (AOP (result), "!zero", offset++);
7348 /* we need to extend the sign :{ */
7349 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7355 aopPut (AOP (result), "a", offset++);
7359 freeAsmop (right, NULL, ic);
7360 freeAsmop (result, NULL, ic);
7363 /*-----------------------------------------------------------------*/
7364 /* genReceive - generate code for a receive iCode */
7365 /*-----------------------------------------------------------------*/
7367 genReceive (iCode * ic)
7369 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7370 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7371 IS_TRUE_SYMOP (IC_RESULT (ic))))
7381 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7382 size = AOP_SIZE(IC_RESULT(ic));
7384 for (i = 0; i < size; i++) {
7385 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7389 freeAsmop (IC_RESULT (ic), NULL, ic);
7392 /*-----------------------------------------------------------------*/
7393 /* genDummyRead - generate code for dummy read of volatiles */
7394 /*-----------------------------------------------------------------*/
7396 genDummyRead (iCode * ic)
7402 if (op && IS_SYMOP (op))
7404 aopOp (op, ic, FALSE, FALSE);
7407 size = AOP_SIZE (op);
7412 _moveA (aopGet (AOP (op), offset, FALSE));
7416 freeAsmop (op, NULL, ic);
7420 if (op && IS_SYMOP (op))
7422 aopOp (op, ic, FALSE, FALSE);
7425 size = AOP_SIZE (op);
7430 _moveA (aopGet (AOP (op), offset, FALSE));
7434 freeAsmop (op, NULL, ic);
7438 /*-----------------------------------------------------------------*/
7439 /* genCritical - generate code for start of a critical sequence */
7440 /*-----------------------------------------------------------------*/
7442 genCritical (iCode *ic)
7444 symbol *tlbl = newiTempLabel (NULL);
7450 else if (IC_RESULT (ic))
7452 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7453 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7454 //get interrupt enable flag IFF2 into P/O
7458 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7459 emit2 ("jp po,!tlabel", tlbl->key + 100);
7460 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7461 emit2 ("!tlabeldef", (tlbl->key + 100));
7462 freeAsmop (IC_RESULT (ic), NULL, ic);
7466 //get interrupt enable flag IFF2 into P/O
7475 /*-----------------------------------------------------------------*/
7476 /* genEndCritical - generate code for end of a critical sequence */
7477 /*-----------------------------------------------------------------*/
7479 genEndCritical (iCode *ic)
7481 symbol *tlbl = newiTempLabel (NULL);
7487 else if (IC_RIGHT (ic))
7489 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7490 _toBoolean (IC_RIGHT (ic));
7491 //don't enable interrupts if they were off before
7492 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
7494 emitLabel (tlbl->key + 100);
7495 freeAsmop (IC_RIGHT (ic), NULL, ic);
7501 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7502 //don't enable interrupts as they were off before
7503 emit2 ("jp po,!tlabel", tlbl->key + 100);
7505 emit2 ("!tlabeldef", (tlbl->key + 100));
7511 /** Maximum number of bytes to emit per line. */
7515 /** Context for the byte output chunker. */
7518 unsigned char buffer[DBEMIT_MAX_RUN];
7523 /** Flushes a byte chunker by writing out all in the buffer and
7527 _dbFlush(DBEMITCTX *self)
7534 sprintf(line, ".db 0x%02X", self->buffer[0]);
7536 for (i = 1; i < self->pos; i++)
7538 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7545 /** Write out another byte, buffering until a decent line is
7549 _dbEmit(DBEMITCTX *self, int c)
7551 if (self->pos == DBEMIT_MAX_RUN)
7555 self->buffer[self->pos++] = c;
7558 /** Context for a simple run length encoder. */
7562 unsigned char buffer[128];
7564 /** runLen may be equivalent to pos. */
7570 RLE_CHANGE_COST = 4,
7574 /** Flush the buffer of a run length encoder by writing out the run or
7575 data that it currently contains.
7578 _rleCommit(RLECTX *self)
7584 memset(&db, 0, sizeof(db));
7586 emit2(".db %u", self->pos);
7588 for (i = 0; i < self->pos; i++)
7590 _dbEmit(&db, self->buffer[i]);
7599 Can get either a run or a block of random stuff.
7600 Only want to change state if a good run comes in or a run ends.
7601 Detecting run end is easy.
7604 Say initial state is in run, len zero, last zero. Then if you get a
7605 few zeros then something else then a short run will be output.
7606 Seems OK. While in run mode, keep counting. While in random mode,
7607 keep a count of the run. If run hits margin, output all up to run,
7608 restart, enter run mode.
7611 /** Add another byte into the run length encoder, flushing as
7612 required. The run length encoder uses the Amiga IFF style, where
7613 a block is prefixed by its run length. A positive length means
7614 the next n bytes pass straight through. A negative length means
7615 that the next byte is repeated -n times. A zero terminates the
7619 _rleAppend(RLECTX *self, unsigned c)
7623 if (c != self->last)
7625 /* The run has stopped. See if it is worthwhile writing it out
7626 as a run. Note that the random data comes in as runs of
7629 if (self->runLen > RLE_CHANGE_COST)
7631 /* Yes, worthwhile. */
7632 /* Commit whatever was in the buffer. */
7634 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7638 /* Not worthwhile. Append to the end of the random list. */
7639 for (i = 0; i < self->runLen; i++)
7641 if (self->pos >= RLE_MAX_BLOCK)
7646 self->buffer[self->pos++] = self->last;
7654 if (self->runLen >= RLE_MAX_BLOCK)
7656 /* Commit whatever was in the buffer. */
7659 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7667 _rleFlush(RLECTX *self)
7669 _rleAppend(self, -1);
7676 /** genArrayInit - Special code for initialising an array with constant
7680 genArrayInit (iCode * ic)
7684 int elementSize = 0, eIndex, i;
7685 unsigned val, lastVal;
7689 memset(&rle, 0, sizeof(rle));
7691 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7693 _saveRegsForCall(ic, 0);
7695 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7696 emit2 ("call __initrleblock");
7698 type = operandType(IC_LEFT(ic));
7700 if (type && type->next)
7702 if (IS_SPEC(type->next) || IS_PTR(type->next))
7704 elementSize = getSize(type->next);
7706 else if (IS_ARRAY(type->next) && type->next->next)
7708 elementSize = getSize(type->next->next);
7712 printTypeChainRaw (type, NULL);
7713 wassertl (0, "Can't determine element size in genArrayInit.");
7718 wassertl (0, "Can't determine element size in genArrayInit.");
7721 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7723 iLoop = IC_ARRAYILIST(ic);
7724 lastVal = (unsigned)-1;
7726 /* Feed all the bytes into the run length encoder which will handle
7728 This works well for mixed char data, and for random int and long
7735 for (i = 0; i < ix; i++)
7737 for (eIndex = 0; eIndex < elementSize; eIndex++)
7739 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7740 _rleAppend(&rle, val);
7744 iLoop = iLoop->next;
7748 /* Mark the end of the run. */
7751 _restoreRegsAfterCall();
7755 freeAsmop (IC_LEFT(ic), NULL, ic);
7759 _swap (PAIR_ID one, PAIR_ID two)
7761 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7767 emit2 ("ld a,%s", _pairs[one].l);
7768 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7769 emit2 ("ld %s,a", _pairs[two].l);
7770 emit2 ("ld a,%s", _pairs[one].h);
7771 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7772 emit2 ("ld %s,a", _pairs[two].h);
7776 /* The problem is that we may have all three pairs used and they may
7777 be needed in a different order.
7782 hl = hl => unity, fine
7786 hl = hl hl = hl, swap de <=> bc
7794 hl = bc de = de, swap bc <=> hl
7802 hl = de bc = bc, swap hl <=> de
7807 * Any pair = pair are done last
7808 * Any pair = iTemp are done last
7809 * Any swaps can be done any time
7817 So how do we detect the cases?
7818 How about a 3x3 matrix?
7822 x x x x (Fourth for iTemp/other)
7824 First determin which mode to use by counting the number of unity and
7827 Two - Assign the pair first, then the rest
7828 One - Swap the two, then the rest
7832 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7834 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7836 PAIR_BC, PAIR_HL, PAIR_DE
7838 int i, j, nunity = 0;
7839 memset (ids, PAIR_INVALID, sizeof (ids));
7842 wassert (nparams == 3);
7844 /* First save everything that needs to be saved. */
7845 _saveRegsForCall (ic, 0);
7847 /* Loading HL first means that DE is always fine. */
7848 for (i = 0; i < nparams; i++)
7850 aopOp (pparams[i], ic, FALSE, FALSE);
7851 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7854 /* Count the number of unity or iTemp assigns. */
7855 for (i = 0; i < 3; i++)
7857 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7865 /* Any order, fall through. */
7867 else if (nunity == 2)
7869 /* One is assigned. Pull it out and assign. */
7870 for (i = 0; i < 3; i++)
7872 for (j = 0; j < NUM_PAIRS; j++)
7874 if (ids[dest[i]][j] == TRUE)
7876 /* Found it. See if it's the right one. */
7877 if (j == PAIR_INVALID || j == dest[i])
7883 fetchPair(dest[i], AOP (pparams[i]));
7890 else if (nunity == 1)
7892 /* Find the pairs to swap. */
7893 for (i = 0; i < 3; i++)
7895 for (j = 0; j < NUM_PAIRS; j++)
7897 if (ids[dest[i]][j] == TRUE)
7899 if (j == PAIR_INVALID || j == dest[i])
7914 int next = getPairId (AOP (pparams[0]));
7915 emit2 ("push %s", _pairs[next].name);
7917 if (next == dest[1])
7919 fetchPair (dest[1], AOP (pparams[1]));
7920 fetchPair (dest[2], AOP (pparams[2]));
7924 fetchPair (dest[2], AOP (pparams[2]));
7925 fetchPair (dest[1], AOP (pparams[1]));
7927 emit2 ("pop %s", _pairs[dest[0]].name);
7930 /* Finally pull out all of the iTemps */
7931 for (i = 0; i < 3; i++)
7933 if (ids[dest[i]][PAIR_INVALID] == 1)
7935 fetchPair (dest[i], AOP (pparams[i]));
7941 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7947 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7951 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7953 setupForBuiltin3 (ic, nParams, pparams);
7955 label = newiTempLabel(NULL);
7957 emitLabel (label->key);
7958 emit2 ("ld a,(hl)");
7961 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7963 freeAsmop (from, NULL, ic->next);
7964 freeAsmop (to, NULL, ic);
7968 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7970 operand *from, *to, *count;
7973 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7978 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7980 setupForBuiltin3 (ic, nParams, pparams);
7984 freeAsmop (count, NULL, ic->next->next);
7985 freeAsmop (from, NULL, ic);
7987 _restoreRegsAfterCall();
7989 /* if we need assign a result value */
7990 if ((IS_ITEMP (IC_RESULT (ic)) &&
7991 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7992 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7993 IS_TRUE_SYMOP (IC_RESULT (ic)))
7995 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7996 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7997 freeAsmop (IC_RESULT (ic), NULL, ic);
8000 freeAsmop (to, NULL, ic->next);
8003 /*-----------------------------------------------------------------*/
8004 /* genBuiltIn - calls the appropriate function to generating code */
8005 /* for a built in function */
8006 /*-----------------------------------------------------------------*/
8007 static void genBuiltIn (iCode *ic)
8009 operand *bi_parms[MAX_BUILTIN_ARGS];
8014 /* get all the arguments for a built in function */
8015 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8017 /* which function is it */
8018 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8020 if (strcmp(bif->name,"__builtin_strcpy")==0)
8022 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8024 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8026 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8030 wassertl (0, "Unknown builtin function encountered");
8034 /*-----------------------------------------------------------------*/
8035 /* genZ80Code - generate code for Z80 based controllers */
8036 /*-----------------------------------------------------------------*/
8038 genZ80Code (iCode * lic)
8046 _fReturn = _gbz80_return;
8047 _fTmp = _gbz80_return;
8051 _fReturn = _z80_return;
8052 _fTmp = _z80_return;
8055 _G.lines.head = _G.lines.current = NULL;
8057 /* if debug information required */
8058 if (options.debug && currFunc)
8060 debugFile->writeFunction (currFunc, lic);
8063 for (ic = lic; ic; ic = ic->next)
8065 _G.current_iCode = ic;
8067 if (ic->lineno && cln != ic->lineno)
8071 debugFile->writeCLine (ic);
8073 if (!options.noCcodeInAsm)
8075 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8076 printCLine(ic->filename, ic->lineno));
8080 if (options.iCodeInAsm)
8082 emit2 (";ic:%d: %s", ic->key, printILine(ic));
8084 /* if the result is marked as
8085 spilt and rematerializable or code for
8086 this has already been generated then
8088 if (resultRemat (ic) || ic->generated)
8091 /* depending on the operation */
8095 emitDebug ("; genNot");
8100 emitDebug ("; genCpl");
8105 emitDebug ("; genUminus");
8110 emitDebug ("; genIpush");
8115 /* IPOP happens only when trying to restore a
8116 spilt live range, if there is an ifx statement
8117 following this pop then the if statement might
8118 be using some of the registers being popped which
8119 would destory the contents of the register so
8120 we need to check for this condition and handle it */
8122 ic->next->op == IFX &&
8123 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8125 emitDebug ("; genIfx");
8126 genIfx (ic->next, ic);
8130 emitDebug ("; genIpop");
8136 emitDebug ("; genCall");
8141 emitDebug ("; genPcall");
8146 emitDebug ("; genFunction");
8151 emitDebug ("; genEndFunction");
8152 genEndFunction (ic);
8156 emitDebug ("; genRet");
8161 emitDebug ("; genLabel");
8166 emitDebug ("; genGoto");
8171 emitDebug ("; genPlus");
8176 emitDebug ("; genMinus");
8181 emitDebug ("; genMult");
8186 emitDebug ("; genDiv");
8191 emitDebug ("; genMod");
8196 emitDebug ("; genCmpGt");
8197 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8201 emitDebug ("; genCmpLt");
8202 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8209 /* note these two are xlated by algebraic equivalence
8210 during parsing SDCC.y */
8211 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8212 "got '>=' or '<=' shouldn't have come here");
8216 emitDebug ("; genCmpEq");
8217 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8221 emitDebug ("; genAndOp");
8226 emitDebug ("; genOrOp");
8231 emitDebug ("; genXor");
8232 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8236 emitDebug ("; genOr");
8237 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8241 emitDebug ("; genAnd");
8242 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8246 emitDebug ("; genInline");
8251 emitDebug ("; genRRC");
8256 emitDebug ("; genRLC");
8261 emitDebug ("; genGetHBIT");
8266 emitDebug ("; genLeftShift");
8271 emitDebug ("; genRightShift");
8275 case GET_VALUE_AT_ADDRESS:
8276 emitDebug ("; genPointerGet");
8282 if (POINTER_SET (ic))
8284 emitDebug ("; genAssign (pointer)");
8289 emitDebug ("; genAssign");
8295 emitDebug ("; genIfx");
8300 emitDebug ("; genAddrOf");
8305 emitDebug ("; genJumpTab");
8310 emitDebug ("; genCast");
8315 emitDebug ("; genReceive");
8320 if (ic->builtinSEND)
8322 emitDebug ("; genBuiltIn");
8327 emitDebug ("; addSet");
8328 addSet (&_G.sendSet, ic);
8333 emitDebug ("; genArrayInit");
8337 case DUMMY_READ_VOLATILE:
8338 emitDebug ("; genDummyRead");
8343 emitDebug ("; genCritical");
8348 emitDebug ("; genEndCritical");
8349 genEndCritical (ic);
8358 /* now we are ready to call the
8359 peep hole optimizer */
8360 if (!options.nopeep)
8361 peepHole (&_G.lines.head);
8363 /* This is unfortunate */
8364 /* now do the actual printing */
8366 FILE *fp = codeOutFile;
8367 if (isInHome () && codeOutFile == code->oFile)
8368 codeOutFile = home->oFile;
8369 printLine (_G.lines.head, codeOutFile);
8370 if (_G.flushStatics)
8373 _G.flushStatics = 0;
8378 freeTrace(&_G.lines.trace);
8379 freeTrace(&_G.trace.aops);
8385 _isPairUsed (iCode * ic, PAIR_ID pairId)
8391 if (bitVectBitValue (ic->rMask, D_IDX))
8393 if (bitVectBitValue (ic->rMask, E_IDX))
8403 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8406 value *val = aop->aopu.aop_lit;
8408 wassert (aop->type == AOP_LIT);
8409 wassert (!IS_FLOAT (val->type));
8411 v = (unsigned long) floatFromVal (val);
8419 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8420 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));