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 !*iyx,%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");
3631 emitDebug ("; Shift into pair idx %u", idx);
3637 setupPair (PAIR_HL, aop, 0);
3642 setupPair (PAIR_IY, aop, 0);
3644 emit2 ("pop %s", _pairs[id].name);
3648 setupPair (PAIR_IY, aop, 0);
3651 wassertl (0, "Internal error - hit default case");
3654 aop->type = AOP_PAIRPTR;
3655 aop->aopu.aop_pairId = id;
3656 _G.pairs[id].offset = 0;
3657 _G.pairs[id].last_type = aop->type;
3661 setupToPreserveCarry (iCode * ic)
3663 asmop *left = AOP (IC_LEFT (ic));
3664 asmop *right = AOP (IC_RIGHT (ic));
3665 asmop *result = AOP (IC_RESULT (ic));
3667 wassert (left && right);
3671 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3673 shiftIntoPair (0, right);
3674 /* check result again, in case right == result */
3675 if (couldDestroyCarry (result))
3677 if (!isPairInUse (PAIR_DE, ic))
3678 shiftIntoPair (1, result);
3680 shiftIntoPair (2, result);
3683 else if (couldDestroyCarry (right))
3685 if (getPairId (result) == PAIR_HL)
3686 _G.preserveCarry = TRUE;
3688 shiftIntoPair (0, right);
3690 else if (couldDestroyCarry (result))
3692 shiftIntoPair (0, result);
3701 /*-----------------------------------------------------------------*/
3702 /* genPlus - generates code for addition */
3703 /*-----------------------------------------------------------------*/
3705 genPlus (iCode * ic)
3707 int size, offset = 0;
3709 /* special cases :- */
3711 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3712 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3713 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3715 /* Swap the left and right operands if:
3717 if literal, literal on the right or
3718 if left requires ACC or right is already
3721 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3722 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3723 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3725 operand *t = IC_RIGHT (ic);
3726 IC_RIGHT (ic) = IC_LEFT (ic);
3730 /* if both left & right are in bit
3732 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3733 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3736 wassertl (0, "Tried to add two bits");
3739 /* if left in bit space & right literal */
3740 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3741 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3743 /* Can happen I guess */
3744 wassertl (0, "Tried to add a bit to a literal");
3747 /* if I can do an increment instead
3748 of add then GOOD for ME */
3749 if (genPlusIncr (ic) == TRUE)
3752 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3754 size = getDataSize (IC_RESULT (ic));
3756 /* Special case when left and right are constant */
3757 if (isPair (AOP (IC_RESULT (ic))))
3760 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3761 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3763 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3769 sprintf (buffer, "#(%s + %s)", left, right);
3770 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3775 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3777 /* Fetch into HL then do the add */
3778 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3779 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3781 spillPair (PAIR_HL);
3783 if (left == PAIR_HL && right != PAIR_INVALID)
3785 emit2 ("add hl,%s", _pairs[right].name);
3788 else if (right == PAIR_HL && left != PAIR_INVALID)
3790 emit2 ("add hl,%s", _pairs[left].name);
3793 else if (right != PAIR_INVALID && right != PAIR_HL)
3795 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3796 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3799 else if (left != PAIR_INVALID && left != PAIR_HL)
3801 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3802 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3811 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3813 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3814 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3816 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3821 ld hl,sp+n trashes C so we can't afford to do it during an
3822 add with stack based variables. Worst case is:
3835 So you can't afford to load up hl if either left, right, or result
3836 is on the stack (*sigh*) The alt is:
3844 Combinations in here are:
3845 * If left or right are in bc then the loss is small - trap later
3846 * If the result is in bc then the loss is also small
3850 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3851 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3852 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3854 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3855 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3856 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3857 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3859 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3861 /* Swap left and right */
3862 operand *t = IC_RIGHT (ic);
3863 IC_RIGHT (ic) = IC_LEFT (ic);
3866 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3868 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3869 emit2 ("add hl,bc");
3873 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3874 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3875 emit2 ("add hl,de");
3877 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3883 /* Be paranoid on the GB with 4 byte variables due to how C
3884 can be trashed by lda hl,n(sp).
3886 _gbz80_emitAddSubLong (ic, TRUE);
3891 setupToPreserveCarry (ic);
3895 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3897 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3900 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3903 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3907 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3910 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3913 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3915 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3919 _G.preserveCarry = FALSE;
3920 freeAsmop (IC_LEFT (ic), NULL, ic);
3921 freeAsmop (IC_RIGHT (ic), NULL, ic);
3922 freeAsmop (IC_RESULT (ic), NULL, ic);
3925 /*-----------------------------------------------------------------*/
3926 /* genMinusDec :- does subtraction with deccrement if possible */
3927 /*-----------------------------------------------------------------*/
3929 genMinusDec (iCode * ic)
3931 unsigned int icount;
3932 unsigned int size = getDataSize (IC_RESULT (ic));
3934 /* will try to generate an increment */
3935 /* if the right side is not a literal we cannot */
3936 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3939 /* if the literal value of the right hand side
3940 is greater than 4 then it is not worth it */
3941 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3944 size = getDataSize (IC_RESULT (ic));
3946 /* if decrement 16 bits in register */
3947 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3948 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3951 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3955 /* If result is a pair */
3956 if (isPair (AOP (IC_RESULT (ic))))
3958 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3960 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3964 /* if increment 16 bits in register */
3965 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3969 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3972 emit2 ("dec %s", _getTempPairName());
3975 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3981 /* if the sizes are greater than 1 then we cannot */
3982 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3983 AOP_SIZE (IC_LEFT (ic)) > 1)
3986 /* we can if the aops of the left & result match or if they are in
3987 registers and the registers are the same */
3988 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3991 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3998 /*-----------------------------------------------------------------*/
3999 /* genMinus - generates code for subtraction */
4000 /*-----------------------------------------------------------------*/
4002 genMinus (iCode * ic)
4004 int size, offset = 0;
4005 unsigned long lit = 0L;
4007 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4008 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4009 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4011 /* special cases :- */
4012 /* if both left & right are in bit space */
4013 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4014 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4016 wassertl (0, "Tried to subtract two bits");
4020 /* if I can do an decrement instead of subtract then GOOD for ME */
4021 if (genMinusDec (ic) == TRUE)
4024 size = getDataSize (IC_RESULT (ic));
4026 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4031 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4035 /* Same logic as genPlus */
4038 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4039 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4040 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4042 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4043 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4044 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4045 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4047 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4048 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4050 if (left == PAIR_INVALID && right == PAIR_INVALID)
4055 else if (right == PAIR_INVALID)
4057 else if (left == PAIR_INVALID)
4060 fetchPair (left, AOP (IC_LEFT (ic)));
4061 /* Order is important. Right may be HL */
4062 fetchPair (right, AOP (IC_RIGHT (ic)));
4064 emit2 ("ld a,%s", _pairs[left].l);
4065 emit2 ("sub a,%s", _pairs[right].l);
4067 emit2 ("ld a,%s", _pairs[left].h);
4068 emit2 ("sbc a,%s", _pairs[right].h);
4070 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4072 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4074 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4080 /* Be paranoid on the GB with 4 byte variables due to how C
4081 can be trashed by lda hl,n(sp).
4083 _gbz80_emitAddSubLong (ic, FALSE);
4088 setupToPreserveCarry (ic);
4090 /* if literal, add a,#-lit, else normal subb */
4093 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4094 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4098 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4101 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4105 /* first add without previous c */
4107 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4109 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4111 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4114 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4115 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4116 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4118 wassertl (0, "Tried to subtract on a long pointer");
4122 _G.preserveCarry = FALSE;
4123 freeAsmop (IC_LEFT (ic), NULL, ic);
4124 freeAsmop (IC_RIGHT (ic), NULL, ic);
4125 freeAsmop (IC_RESULT (ic), NULL, ic);
4128 /*-----------------------------------------------------------------*/
4129 /* genMult - generates code for multiplication */
4130 /*-----------------------------------------------------------------*/
4132 genMult (iCode * ic)
4136 /* If true then the final operation should be a subtract */
4137 bool active = FALSE;
4140 /* Shouldn't occur - all done through function calls */
4141 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4142 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4143 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4145 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4147 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4148 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4149 AOP_SIZE (IC_RESULT (ic)) > 2)
4151 wassertl (0, "Multiplication is handled through support function calls");
4154 /* Swap left and right such that right is a literal */
4155 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4157 operand *t = IC_RIGHT (ic);
4158 IC_RIGHT (ic) = IC_LEFT (ic);
4162 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4164 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4165 // wassertl (val > 0, "Multiply must be positive");
4166 wassertl (val != 1, "Can't multiply by 1");
4168 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4170 _G.stack.pushedDE = TRUE;
4173 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4175 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4186 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4191 /* Fully unroled version of mul.s. Not the most efficient.
4193 for (count = 0; count < 16; count++)
4195 if (count != 0 && active)
4197 emit2 ("add hl,hl");
4201 if (active == FALSE)
4209 emit2 ("add hl,de");
4218 if (IS_Z80 && _G.stack.pushedDE)
4221 _G.stack.pushedDE = FALSE;
4225 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4227 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4229 freeAsmop (IC_LEFT (ic), NULL, ic);
4230 freeAsmop (IC_RIGHT (ic), NULL, ic);
4231 freeAsmop (IC_RESULT (ic), NULL, ic);
4234 /*-----------------------------------------------------------------*/
4235 /* genDiv - generates code for division */
4236 /*-----------------------------------------------------------------*/
4240 /* Shouldn't occur - all done through function calls */
4241 wassertl (0, "Division is handled through support function calls");
4244 /*-----------------------------------------------------------------*/
4245 /* genMod - generates code for division */
4246 /*-----------------------------------------------------------------*/
4250 /* Shouldn't occur - all done through function calls */
4254 /*-----------------------------------------------------------------*/
4255 /* genIfxJump :- will create a jump depending on the ifx */
4256 /*-----------------------------------------------------------------*/
4258 genIfxJump (iCode * ic, char *jval)
4263 /* if true label then we jump if condition
4267 jlbl = IC_TRUE (ic);
4268 if (!strcmp (jval, "a"))
4272 else if (!strcmp (jval, "c"))
4276 else if (!strcmp (jval, "nc"))
4280 else if (!strcmp (jval, "m"))
4284 else if (!strcmp (jval, "p"))
4290 /* The buffer contains the bit on A that we should test */
4296 /* false label is present */
4297 jlbl = IC_FALSE (ic);
4298 if (!strcmp (jval, "a"))
4302 else if (!strcmp (jval, "c"))
4306 else if (!strcmp (jval, "nc"))
4310 else if (!strcmp (jval, "m"))
4314 else if (!strcmp (jval, "p"))
4320 /* The buffer contains the bit on A that we should test */
4324 /* Z80 can do a conditional long jump */
4325 if (!strcmp (jval, "a"))
4329 else if (!strcmp (jval, "c"))
4332 else if (!strcmp (jval, "nc"))
4335 else if (!strcmp (jval, "m"))
4338 else if (!strcmp (jval, "p"))
4343 emit2 ("bit %s,a", jval);
4345 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4347 /* mark the icode as generated */
4353 _getPairIdName (PAIR_ID id)
4355 return _pairs[id].name;
4360 /* if unsigned char cmp with lit, just compare */
4362 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4364 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4367 emit2 ("xor a,!immedbyte", 0x80);
4368 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4371 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4373 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4375 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4376 // Pull left into DE and right into HL
4377 aopGet (AOP(left), LSB, FALSE);
4380 aopGet (AOP(right), LSB, FALSE);
4384 if (size == 0 && sign)
4386 // Highest byte when signed needs the bits flipped
4389 emit2 ("ld a,(de)");
4390 emit2 ("xor !immedbyte", 0x80);
4392 emit2 ("ld a,(hl)");
4393 emit2 ("xor !immedbyte", 0x80);
4397 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4401 emit2 ("ld a,(de)");
4402 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4412 spillPair (PAIR_HL);
4414 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4416 setupPair (PAIR_HL, AOP (left), 0);
4417 aopGet (AOP(right), LSB, FALSE);
4421 if (size == 0 && sign)
4423 // Highest byte when signed needs the bits flipped
4426 emit2 ("ld a,(hl)");
4427 emit2 ("xor !immedbyte", 0x80);
4429 emit2 ("ld a,%d(iy)", offset);
4430 emit2 ("xor !immedbyte", 0x80);
4434 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4438 emit2 ("ld a,(hl)");
4439 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4448 spillPair (PAIR_HL);
4449 spillPair (PAIR_IY);
4453 if (AOP_TYPE (right) == AOP_LIT)
4455 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4456 /* optimize if(x < 0) or if(x >= 0) */
4461 /* No sign so it's always false */
4466 /* Just load in the top most bit */
4467 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4468 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4470 genIfxJump (ifx, "7");
4482 /* First setup h and l contaning the top most bytes XORed */
4483 bool fDidXor = FALSE;
4484 if (AOP_TYPE (left) == AOP_LIT)
4486 unsigned long lit = (unsigned long)
4487 floatFromVal (AOP (left)->aopu.aop_lit);
4488 emit2 ("ld %s,!immedbyte", _fTmp[0],
4489 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4493 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4494 emit2 ("xor a,!immedbyte", 0x80);
4495 emit2 ("ld %s,a", _fTmp[0]);
4498 if (AOP_TYPE (right) == AOP_LIT)
4500 unsigned long lit = (unsigned long)
4501 floatFromVal (AOP (right)->aopu.aop_lit);
4502 emit2 ("ld %s,!immedbyte", _fTmp[1],
4503 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4507 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4508 emit2 ("xor a,!immedbyte", 0x80);
4509 emit2 ("ld %s,a", _fTmp[1]);
4515 /* Do a long subtract */
4518 _moveA (aopGet (AOP (left), offset, FALSE));
4520 if (sign && size == 0)
4522 emit2 ("ld a,%s", _fTmp[0]);
4523 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4527 /* Subtract through, propagating the carry */
4528 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4536 /** Generic compare for > or <
4539 genCmp (operand * left, operand * right,
4540 operand * result, iCode * ifx, int sign)
4542 int size, offset = 0;
4543 unsigned long lit = 0L;
4544 bool swap_sense = FALSE;
4546 /* if left & right are bit variables */
4547 if (AOP_TYPE (left) == AOP_CRY &&
4548 AOP_TYPE (right) == AOP_CRY)
4550 /* Cant happen on the Z80 */
4551 wassertl (0, "Tried to compare two bits");
4555 /* Do a long subtract of right from left. */
4556 size = max (AOP_SIZE (left), AOP_SIZE (right));
4558 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4560 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4561 // Pull left into DE and right into HL
4562 aopGet (AOP(left), LSB, FALSE);
4565 aopGet (AOP(right), LSB, FALSE);
4569 emit2 ("ld a,(de)");
4570 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4579 spillPair (PAIR_HL);
4583 if (AOP_TYPE (right) == AOP_LIT)
4585 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4586 /* optimize if(x < 0) or if(x >= 0) */
4591 /* No sign so it's always false */
4596 /* Just load in the top most bit */
4597 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4598 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4600 genIfxJump (ifx, "7");
4611 genIfxJump (ifx, swap_sense ? "c" : "nc");
4622 _moveA (aopGet (AOP (left), offset, FALSE));
4623 /* Subtract through, propagating the carry */
4624 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4630 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4634 /* Shift the sign bit up into carry */
4637 outBitCLong (result, swap_sense);
4641 /* if the result is used in the next
4642 ifx conditional branch then generate
4643 code a little differently */
4651 genIfxJump (ifx, swap_sense ? "nc" : "c");
4655 genIfxJump (ifx, swap_sense ? "p" : "m");
4660 genIfxJump (ifx, swap_sense ? "nc" : "c");
4667 /* Shift the sign bit up into carry */
4670 outBitCLong (result, swap_sense);
4672 /* leave the result in acc */
4676 /*-----------------------------------------------------------------*/
4677 /* genCmpGt :- greater than comparison */
4678 /*-----------------------------------------------------------------*/
4680 genCmpGt (iCode * ic, iCode * ifx)
4682 operand *left, *right, *result;
4683 sym_link *letype, *retype;
4686 left = IC_LEFT (ic);
4687 right = IC_RIGHT (ic);
4688 result = IC_RESULT (ic);
4690 letype = getSpec (operandType (left));
4691 retype = getSpec (operandType (right));
4692 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4693 /* assign the amsops */
4694 aopOp (left, ic, FALSE, FALSE);
4695 aopOp (right, ic, FALSE, FALSE);
4696 aopOp (result, ic, TRUE, FALSE);
4698 genCmp (right, left, result, ifx, sign);
4700 freeAsmop (left, NULL, ic);
4701 freeAsmop (right, NULL, ic);
4702 freeAsmop (result, NULL, ic);
4705 /*-----------------------------------------------------------------*/
4706 /* genCmpLt - less than comparisons */
4707 /*-----------------------------------------------------------------*/
4709 genCmpLt (iCode * ic, iCode * ifx)
4711 operand *left, *right, *result;
4712 sym_link *letype, *retype;
4715 left = IC_LEFT (ic);
4716 right = IC_RIGHT (ic);
4717 result = IC_RESULT (ic);
4719 letype = getSpec (operandType (left));
4720 retype = getSpec (operandType (right));
4721 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4723 /* assign the amsops */
4724 aopOp (left, ic, FALSE, FALSE);
4725 aopOp (right, ic, FALSE, FALSE);
4726 aopOp (result, ic, TRUE, FALSE);
4728 genCmp (left, right, result, ifx, sign);
4730 freeAsmop (left, NULL, ic);
4731 freeAsmop (right, NULL, ic);
4732 freeAsmop (result, NULL, ic);
4735 /*-----------------------------------------------------------------*/
4736 /* gencjneshort - compare and jump if not equal */
4737 /*-----------------------------------------------------------------*/
4739 gencjneshort (operand * left, operand * right, symbol * lbl)
4741 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4743 unsigned long lit = 0L;
4745 /* Swap the left and right if it makes the computation easier */
4746 if (AOP_TYPE (left) == AOP_LIT)
4753 if (AOP_TYPE (right) == AOP_LIT)
4755 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4758 /* if the right side is a literal then anything goes */
4759 if (AOP_TYPE (right) == AOP_LIT &&
4760 AOP_TYPE (left) != AOP_DIR)
4764 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4769 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4776 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4782 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4783 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4786 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4787 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4792 /* if the right side is in a register or in direct space or
4793 if the left is a pointer register & right is not */
4794 else if (AOP_TYPE (right) == AOP_REG ||
4795 AOP_TYPE (right) == AOP_DIR ||
4796 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4800 _moveA (aopGet (AOP (left), offset, FALSE));
4801 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4802 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4804 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4807 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4808 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4815 /* right is a pointer reg need both a & b */
4816 /* PENDING: is this required? */
4819 _moveA (aopGet (AOP (right), offset, FALSE));
4820 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4821 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4827 /*-----------------------------------------------------------------*/
4828 /* gencjne - compare and jump if not equal */
4829 /*-----------------------------------------------------------------*/
4831 gencjne (operand * left, operand * right, symbol * lbl)
4833 symbol *tlbl = newiTempLabel (NULL);
4835 gencjneshort (left, right, lbl);
4838 emit2 ("ld a,!one");
4839 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4840 emitLabel (lbl->key + 100);
4842 emitLabel (tlbl->key + 100);
4845 /*-----------------------------------------------------------------*/
4846 /* genCmpEq - generates code for equal to */
4847 /*-----------------------------------------------------------------*/
4849 genCmpEq (iCode * ic, iCode * ifx)
4851 operand *left, *right, *result;
4853 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4854 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4855 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4857 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4859 /* Swap operands if it makes the operation easier. ie if:
4860 1. Left is a literal.
4862 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4864 operand *t = IC_RIGHT (ic);
4865 IC_RIGHT (ic) = IC_LEFT (ic);
4869 if (ifx && !AOP_SIZE (result))
4872 /* if they are both bit variables */
4873 if (AOP_TYPE (left) == AOP_CRY &&
4874 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4876 wassertl (0, "Tried to compare two bits");
4880 tlbl = newiTempLabel (NULL);
4881 gencjneshort (left, right, tlbl);
4884 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4885 emitLabel (tlbl->key + 100);
4889 /* PENDING: do this better */
4890 symbol *lbl = newiTempLabel (NULL);
4891 emit2 ("!shortjp !tlabel", lbl->key + 100);
4892 emitLabel (tlbl->key + 100);
4893 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4894 emitLabel (lbl->key + 100);
4897 /* mark the icode as generated */
4902 /* if they are both bit variables */
4903 if (AOP_TYPE (left) == AOP_CRY &&
4904 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4906 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4912 gencjne (left, right, newiTempLabel (NULL));
4913 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4920 genIfxJump (ifx, "a");
4923 /* if the result is used in an arithmetic operation
4924 then put the result in place */
4925 if (AOP_TYPE (result) != AOP_CRY)
4930 /* leave the result in acc */
4934 freeAsmop (left, NULL, ic);
4935 freeAsmop (right, NULL, ic);
4936 freeAsmop (result, NULL, ic);
4939 /*-----------------------------------------------------------------*/
4940 /* ifxForOp - returns the icode containing the ifx for operand */
4941 /*-----------------------------------------------------------------*/
4943 ifxForOp (operand * op, iCode * ic)
4945 /* if true symbol then needs to be assigned */
4946 if (IS_TRUE_SYMOP (op))
4949 /* if this has register type condition and
4950 the next instruction is ifx with the same operand
4951 and live to of the operand is upto the ifx only then */
4953 ic->next->op == IFX &&
4954 IC_COND (ic->next)->key == op->key &&
4955 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4961 /*-----------------------------------------------------------------*/
4962 /* genAndOp - for && operation */
4963 /*-----------------------------------------------------------------*/
4965 genAndOp (iCode * ic)
4967 operand *left, *right, *result;
4970 /* note here that && operations that are in an if statement are
4971 taken away by backPatchLabels only those used in arthmetic
4972 operations remain */
4973 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4974 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4975 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4977 /* if both are bit variables */
4978 if (AOP_TYPE (left) == AOP_CRY &&
4979 AOP_TYPE (right) == AOP_CRY)
4981 wassertl (0, "Tried to and two bits");
4985 tlbl = newiTempLabel (NULL);
4987 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
4989 emitLabel (tlbl->key + 100);
4993 freeAsmop (left, NULL, ic);
4994 freeAsmop (right, NULL, ic);
4995 freeAsmop (result, NULL, ic);
4998 /*-----------------------------------------------------------------*/
4999 /* genOrOp - for || operation */
5000 /*-----------------------------------------------------------------*/
5002 genOrOp (iCode * ic)
5004 operand *left, *right, *result;
5007 /* note here that || operations that are in an
5008 if statement are taken away by backPatchLabels
5009 only those used in arthmetic operations remain */
5010 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5011 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5012 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5014 /* if both are bit variables */
5015 if (AOP_TYPE (left) == AOP_CRY &&
5016 AOP_TYPE (right) == AOP_CRY)
5018 wassertl (0, "Tried to OR two bits");
5022 tlbl = newiTempLabel (NULL);
5024 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5026 emitLabel (tlbl->key + 100);
5030 freeAsmop (left, NULL, ic);
5031 freeAsmop (right, NULL, ic);
5032 freeAsmop (result, NULL, ic);
5035 /*-----------------------------------------------------------------*/
5036 /* isLiteralBit - test if lit == 2^n */
5037 /*-----------------------------------------------------------------*/
5039 isLiteralBit (unsigned long lit)
5041 unsigned long pw[32] =
5042 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5043 0x100L, 0x200L, 0x400L, 0x800L,
5044 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5045 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5046 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5047 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5048 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5051 for (idx = 0; idx < 32; idx++)
5057 /*-----------------------------------------------------------------*/
5058 /* jmpTrueOrFalse - */
5059 /*-----------------------------------------------------------------*/
5061 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5063 // ugly but optimized by peephole
5066 symbol *nlbl = newiTempLabel (NULL);
5067 emit2 ("jp !tlabel", nlbl->key + 100);
5068 emitLabel (tlbl->key + 100);
5069 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5070 emitLabel (nlbl->key + 100);
5074 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5075 emitLabel (tlbl->key + 100);
5080 /*-----------------------------------------------------------------*/
5081 /* genAnd - code for and */
5082 /*-----------------------------------------------------------------*/
5084 genAnd (iCode * ic, iCode * ifx)
5086 operand *left, *right, *result;
5087 int size, offset = 0;
5088 unsigned long lit = 0L;
5091 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5092 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5093 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5095 /* if left is a literal & right is not then exchange them */
5096 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5097 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5099 operand *tmp = right;
5104 /* if result = right then exchange them */
5105 if (sameRegs (AOP (result), AOP (right)))
5107 operand *tmp = right;
5112 /* if right is bit then exchange them */
5113 if (AOP_TYPE (right) == AOP_CRY &&
5114 AOP_TYPE (left) != AOP_CRY)
5116 operand *tmp = right;
5120 if (AOP_TYPE (right) == AOP_LIT)
5121 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5123 size = AOP_SIZE (result);
5125 if (AOP_TYPE (left) == AOP_CRY)
5127 wassertl (0, "Tried to perform an AND with a bit as an operand");
5131 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5132 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5133 if ((AOP_TYPE (right) == AOP_LIT) &&
5134 (AOP_TYPE (result) == AOP_CRY) &&
5135 (AOP_TYPE (left) != AOP_CRY))
5137 symbol *tlbl = newiTempLabel (NULL);
5138 int sizel = AOP_SIZE (left);
5141 /* PENDING: Test case for this. */
5146 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5148 _moveA (aopGet (AOP (left), offset, FALSE));
5149 if (bytelit != 0x0FFL)
5151 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5158 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5162 // bit = left & literal
5166 emit2 ("!tlabeldef", tlbl->key + 100);
5168 // if(left & literal)
5173 jmpTrueOrFalse (ifx, tlbl);
5181 /* if left is same as result */
5182 if (sameRegs (AOP (result), AOP (left)))
5184 for (; size--; offset++)
5186 if (AOP_TYPE (right) == AOP_LIT)
5188 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5193 aopPut (AOP (result), "!zero", offset);
5196 _moveA (aopGet (AOP (left), offset, FALSE));
5198 aopGet (AOP (right), offset, FALSE));
5199 aopPut (AOP (left), "a", offset);
5206 if (AOP_TYPE (left) == AOP_ACC)
5208 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5212 _moveA (aopGet (AOP (left), offset, FALSE));
5214 aopGet (AOP (right), offset, FALSE));
5215 aopPut (AOP (left), "a", offset);
5222 // left & result in different registers
5223 if (AOP_TYPE (result) == AOP_CRY)
5225 wassertl (0, "Tried to AND where the result is in carry");
5229 for (; (size--); offset++)
5232 // result = left & right
5233 if (AOP_TYPE (right) == AOP_LIT)
5235 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5237 aopPut (AOP (result),
5238 aopGet (AOP (left), offset, FALSE),
5242 else if (bytelit == 0)
5244 aopPut (AOP (result), "!zero", offset);
5248 // faster than result <- left, anl result,right
5249 // and better if result is SFR
5250 if (AOP_TYPE (left) == AOP_ACC)
5251 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5254 _moveA (aopGet (AOP (left), offset, FALSE));
5256 aopGet (AOP (right), offset, FALSE));
5258 aopPut (AOP (result), "a", offset);
5265 freeAsmop (left, NULL, ic);
5266 freeAsmop (right, NULL, ic);
5267 freeAsmop (result, NULL, ic);
5270 /*-----------------------------------------------------------------*/
5271 /* genOr - code for or */
5272 /*-----------------------------------------------------------------*/
5274 genOr (iCode * ic, iCode * ifx)
5276 operand *left, *right, *result;
5277 int size, offset = 0;
5278 unsigned long lit = 0L;
5281 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5282 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5283 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5285 /* if left is a literal & right is not then exchange them */
5286 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5287 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5289 operand *tmp = right;
5294 /* if result = right then exchange them */
5295 if (sameRegs (AOP (result), AOP (right)))
5297 operand *tmp = right;
5302 /* if right is bit then exchange them */
5303 if (AOP_TYPE (right) == AOP_CRY &&
5304 AOP_TYPE (left) != AOP_CRY)
5306 operand *tmp = right;
5310 if (AOP_TYPE (right) == AOP_LIT)
5311 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5313 size = AOP_SIZE (result);
5315 if (AOP_TYPE (left) == AOP_CRY)
5317 wassertl (0, "Tried to OR where left is a bit");
5321 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5322 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5323 if ((AOP_TYPE (right) == AOP_LIT) &&
5324 (AOP_TYPE (result) == AOP_CRY) &&
5325 (AOP_TYPE (left) != AOP_CRY))
5327 symbol *tlbl = newiTempLabel (NULL);
5328 int sizel = AOP_SIZE (left);
5332 wassertl (0, "Result is assigned to a bit");
5334 /* PENDING: Modeled after the AND code which is inefficient. */
5337 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5339 _moveA (aopGet (AOP (left), offset, FALSE));
5340 /* OR with any literal is the same as OR with itself. */
5342 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5348 jmpTrueOrFalse (ifx, tlbl);
5353 /* if left is same as result */
5354 if (sameRegs (AOP (result), AOP (left)))
5356 for (; size--; offset++)
5358 if (AOP_TYPE (right) == AOP_LIT)
5360 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5364 _moveA (aopGet (AOP (left), offset, FALSE));
5366 aopGet (AOP (right), offset, FALSE));
5367 aopPut (AOP (result), "a", offset);
5372 if (AOP_TYPE (left) == AOP_ACC)
5373 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5376 _moveA (aopGet (AOP (left), offset, FALSE));
5378 aopGet (AOP (right), offset, FALSE));
5379 aopPut (AOP (result), "a", offset);
5386 // left & result in different registers
5387 if (AOP_TYPE (result) == AOP_CRY)
5389 wassertl (0, "Result of OR is in a bit");
5392 for (; (size--); offset++)
5395 // result = left & right
5396 if (AOP_TYPE (right) == AOP_LIT)
5398 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5400 aopPut (AOP (result),
5401 aopGet (AOP (left), offset, FALSE),
5406 // faster than result <- left, anl result,right
5407 // and better if result is SFR
5408 if (AOP_TYPE (left) == AOP_ACC)
5409 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5412 _moveA (aopGet (AOP (left), offset, FALSE));
5414 aopGet (AOP (right), offset, FALSE));
5416 aopPut (AOP (result), "a", offset);
5417 /* PENDING: something weird is going on here. Add exception. */
5418 if (AOP_TYPE (result) == AOP_ACC)
5424 freeAsmop (left, NULL, ic);
5425 freeAsmop (right, NULL, ic);
5426 freeAsmop (result, NULL, ic);
5429 /*-----------------------------------------------------------------*/
5430 /* genXor - code for xclusive or */
5431 /*-----------------------------------------------------------------*/
5433 genXor (iCode * ic, iCode * ifx)
5435 operand *left, *right, *result;
5436 int size, offset = 0;
5437 unsigned long lit = 0L;
5439 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5440 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5441 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5443 /* if left is a literal & right is not then exchange them */
5444 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5445 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5447 operand *tmp = right;
5452 /* if result = right then exchange them */
5453 if (sameRegs (AOP (result), AOP (right)))
5455 operand *tmp = right;
5460 /* if right is bit then exchange them */
5461 if (AOP_TYPE (right) == AOP_CRY &&
5462 AOP_TYPE (left) != AOP_CRY)
5464 operand *tmp = right;
5468 if (AOP_TYPE (right) == AOP_LIT)
5469 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5471 size = AOP_SIZE (result);
5473 if (AOP_TYPE (left) == AOP_CRY)
5475 wassertl (0, "Tried to XOR a bit");
5479 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5480 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5481 if ((AOP_TYPE (right) == AOP_LIT) &&
5482 (AOP_TYPE (result) == AOP_CRY) &&
5483 (AOP_TYPE (left) != AOP_CRY))
5485 symbol *tlbl = newiTempLabel (NULL);
5486 int sizel = AOP_SIZE (left);
5490 /* PENDING: Test case for this. */
5491 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5495 _moveA (aopGet (AOP (left), offset, FALSE));
5496 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5497 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5502 jmpTrueOrFalse (ifx, tlbl);
5506 wassertl (0, "Result of XOR was destined for a bit");
5511 /* if left is same as result */
5512 if (sameRegs (AOP (result), AOP (left)))
5514 for (; size--; offset++)
5516 if (AOP_TYPE (right) == AOP_LIT)
5518 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5522 _moveA (aopGet (AOP (left), offset, FALSE));
5524 aopGet (AOP (right), offset, FALSE));
5525 aopPut (AOP (result), "a", offset);
5530 if (AOP_TYPE (left) == AOP_ACC)
5532 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5536 _moveA (aopGet (AOP (left), offset, FALSE));
5538 aopGet (AOP (right), offset, FALSE));
5539 aopPut (AOP (result), "a", offset);
5546 // left & result in different registers
5547 if (AOP_TYPE (result) == AOP_CRY)
5549 wassertl (0, "Result of XOR is in a bit");
5552 for (; (size--); offset++)
5555 // result = left & right
5556 if (AOP_TYPE (right) == AOP_LIT)
5558 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5560 aopPut (AOP (result),
5561 aopGet (AOP (left), offset, FALSE),
5566 // faster than result <- left, anl result,right
5567 // and better if result is SFR
5568 if (AOP_TYPE (left) == AOP_ACC)
5570 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5574 _moveA (aopGet (AOP (left), offset, FALSE));
5576 aopGet (AOP (right), offset, FALSE));
5578 aopPut (AOP (result), "a", offset);
5583 freeAsmop (left, NULL, ic);
5584 freeAsmop (right, NULL, ic);
5585 freeAsmop (result, NULL, ic);
5588 /*-----------------------------------------------------------------*/
5589 /* genInline - write the inline code out */
5590 /*-----------------------------------------------------------------*/
5592 genInline (iCode * ic)
5594 char *buffer, *bp, *bp1;
5596 _G.lines.isInline += (!options.asmpeep);
5598 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5599 strcpy (buffer, IC_INLINE (ic));
5601 /* emit each line as a code */
5626 _G.lines.isInline -= (!options.asmpeep);
5630 /*-----------------------------------------------------------------*/
5631 /* genRRC - rotate right with carry */
5632 /*-----------------------------------------------------------------*/
5639 /*-----------------------------------------------------------------*/
5640 /* genRLC - generate code for rotate left with carry */
5641 /*-----------------------------------------------------------------*/
5648 /*-----------------------------------------------------------------*/
5649 /* genGetHbit - generates code get highest order bit */
5650 /*-----------------------------------------------------------------*/
5652 genGetHbit (iCode * ic)
5654 operand *left, *result;
5655 left = IC_LEFT (ic);
5656 result = IC_RESULT (ic);
5658 aopOp (left, ic, FALSE, FALSE);
5659 aopOp (result, ic, FALSE, FALSE);
5661 /* get the highest order byte into a */
5662 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5664 if (AOP_TYPE (result) == AOP_CRY)
5672 emit2 ("and a,!one");
5677 freeAsmop (left, NULL, ic);
5678 freeAsmop (result, NULL, ic);
5682 emitRsh2 (asmop *aop, int size, int is_signed)
5688 const char *l = aopGet (aop, size, FALSE);
5691 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5701 /*-----------------------------------------------------------------*/
5702 /* shiftR2Left2Result - shift right two bytes from left to result */
5703 /*-----------------------------------------------------------------*/
5705 shiftR2Left2Result (operand * left, int offl,
5706 operand * result, int offr,
5707 int shCount, int is_signed)
5710 symbol *tlbl, *tlbl1;
5712 movLeft2Result (left, offl, result, offr, 0);
5713 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5718 /* if (AOP(result)->type == AOP_REG) { */
5720 tlbl = newiTempLabel (NULL);
5721 tlbl1 = newiTempLabel (NULL);
5723 /* Left is already in result - so now do the shift */
5728 emitRsh2 (AOP (result), size, is_signed);
5733 emit2 ("ld a,!immedbyte+1", shCount);
5734 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5735 emitLabel (tlbl->key + 100);
5737 emitRsh2 (AOP (result), size, is_signed);
5739 emitLabel (tlbl1->key + 100);
5741 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5745 /*-----------------------------------------------------------------*/
5746 /* shiftL2Left2Result - shift left two bytes from left to result */
5747 /*-----------------------------------------------------------------*/
5749 shiftL2Left2Result (operand * left, int offl,
5750 operand * result, int offr, int shCount)
5752 if (sameRegs (AOP (result), AOP (left)) &&
5753 ((offl + MSB16) == offr))
5759 /* Copy left into result */
5760 movLeft2Result (left, offl, result, offr, 0);
5761 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5767 if (getPairId (AOP (result)) == PAIR_HL)
5771 emit2 ("add hl,hl");
5778 symbol *tlbl, *tlbl1;
5781 tlbl = newiTempLabel (NULL);
5782 tlbl1 = newiTempLabel (NULL);
5784 if (AOP (result)->type == AOP_REG)
5788 for (offset = 0; offset < size; offset++)
5790 l = aopGet (AOP (result), offset, FALSE);
5794 emit2 ("sla %s", l);
5805 /* Left is already in result - so now do the shift */
5808 emit2 ("ld a,!immedbyte+1", shCount);
5809 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5810 emitLabel (tlbl->key + 100);
5815 l = aopGet (AOP (result), offset, FALSE);
5819 emit2 ("sla %s", l);
5830 emitLabel (tlbl1->key + 100);
5832 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5838 /*-----------------------------------------------------------------*/
5839 /* AccRol - rotate left accumulator by known count */
5840 /*-----------------------------------------------------------------*/
5842 AccRol (int shCount)
5844 shCount &= 0x0007; // shCount : 0..7
5921 /*-----------------------------------------------------------------*/
5922 /* AccLsh - left shift accumulator by known count */
5923 /*-----------------------------------------------------------------*/
5925 AccLsh (int shCount)
5927 static const unsigned char SLMask[] =
5929 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5938 else if (shCount == 2)
5945 /* rotate left accumulator */
5947 /* and kill the lower order bits */
5948 emit2 ("and a,!immedbyte", SLMask[shCount]);
5953 /*-----------------------------------------------------------------*/
5954 /* shiftL1Left2Result - shift left one byte from left to result */
5955 /*-----------------------------------------------------------------*/
5957 shiftL1Left2Result (operand * left, int offl,
5958 operand * result, int offr, int shCount)
5961 l = aopGet (AOP (left), offl, FALSE);
5963 /* shift left accumulator */
5965 aopPut (AOP (result), "a", offr);
5969 /*-----------------------------------------------------------------*/
5970 /* genlshTwo - left shift two bytes by known amount */
5971 /*-----------------------------------------------------------------*/
5973 genlshTwo (operand * result, operand * left, int shCount)
5975 int size = AOP_SIZE (result);
5977 wassert (size == 2);
5979 /* if shCount >= 8 */
5987 movLeft2Result (left, LSB, result, MSB16, 0);
5988 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5989 aopPut (AOP (result), "!zero", LSB);
5993 movLeft2Result (left, LSB, result, MSB16, 0);
5994 aopPut (AOP (result), "!zero", 0);
5999 aopPut (AOP (result), "!zero", LSB);
6002 /* 0 <= shCount <= 7 */
6011 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6016 /*-----------------------------------------------------------------*/
6017 /* genlshOne - left shift a one byte quantity by known count */
6018 /*-----------------------------------------------------------------*/
6020 genlshOne (operand * result, operand * left, int shCount)
6022 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6025 /*-----------------------------------------------------------------*/
6026 /* genLeftShiftLiteral - left shifting by known count */
6027 /*-----------------------------------------------------------------*/
6029 genLeftShiftLiteral (operand * left,
6034 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6037 freeAsmop (right, NULL, ic);
6039 aopOp (left, ic, FALSE, FALSE);
6040 aopOp (result, ic, FALSE, FALSE);
6042 size = getSize (operandType (result));
6044 /* I suppose that the left size >= result size */
6046 if (shCount >= (size * 8))
6050 aopPut (AOP (result), "!zero", size);
6058 genlshOne (result, left, shCount);
6061 genlshTwo (result, left, shCount);
6064 wassertl (0, "Shifting of longs is currently unsupported");
6070 freeAsmop (left, NULL, ic);
6071 freeAsmop (result, NULL, ic);
6074 /*-----------------------------------------------------------------*/
6075 /* genLeftShift - generates code for left shifting */
6076 /*-----------------------------------------------------------------*/
6078 genLeftShift (iCode * ic)
6082 symbol *tlbl, *tlbl1;
6083 operand *left, *right, *result;
6085 right = IC_RIGHT (ic);
6086 left = IC_LEFT (ic);
6087 result = IC_RESULT (ic);
6089 aopOp (right, ic, FALSE, FALSE);
6091 /* if the shift count is known then do it
6092 as efficiently as possible */
6093 if (AOP_TYPE (right) == AOP_LIT)
6095 genLeftShiftLiteral (left, right, result, ic);
6099 /* shift count is unknown then we have to form a loop get the loop
6100 count in B : Note: we take only the lower order byte since
6101 shifting more that 32 bits make no sense anyway, ( the largest
6102 size of an object can be only 32 bits ) */
6103 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6105 freeAsmop (right, NULL, ic);
6106 aopOp (left, ic, FALSE, FALSE);
6107 aopOp (result, ic, FALSE, FALSE);
6109 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6112 /* now move the left to the result if they are not the
6115 if (!sameRegs (AOP (left), AOP (result)))
6118 size = AOP_SIZE (result);
6122 l = aopGet (AOP (left), offset, FALSE);
6123 aopPut (AOP (result), l, offset);
6128 tlbl = newiTempLabel (NULL);
6129 size = AOP_SIZE (result);
6131 tlbl1 = newiTempLabel (NULL);
6133 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6136 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6137 emitLabel (tlbl->key + 100);
6138 l = aopGet (AOP (result), offset, FALSE);
6142 l = aopGet (AOP (result), offset, FALSE);
6146 emit2 ("sla %s", l);
6154 emitLabel (tlbl1->key + 100);
6156 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6158 freeAsmop (left, NULL, ic);
6159 freeAsmop (result, NULL, ic);
6162 /*-----------------------------------------------------------------*/
6163 /* genrshOne - left shift two bytes by known amount != 0 */
6164 /*-----------------------------------------------------------------*/
6166 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6169 int size = AOP_SIZE (result);
6172 wassert (size == 1);
6173 wassert (shCount < 8);
6175 l = aopGet (AOP (left), 0, FALSE);
6177 if (AOP (result)->type == AOP_REG)
6179 aopPut (AOP (result), l, 0);
6180 l = aopGet (AOP (result), 0, FALSE);
6183 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6191 emit2 ("%s a", is_signed ? "sra" : "srl");
6193 aopPut (AOP (result), "a", 0);
6197 /*-----------------------------------------------------------------*/
6198 /* AccRsh - right shift accumulator by known count */
6199 /*-----------------------------------------------------------------*/
6201 AccRsh (int shCount)
6203 static const unsigned char SRMask[] =
6205 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6210 /* rotate right accumulator */
6211 AccRol (8 - shCount);
6212 /* and kill the higher order bits */
6213 emit2 ("and a,!immedbyte", SRMask[shCount]);
6217 /*-----------------------------------------------------------------*/
6218 /* shiftR1Left2Result - shift right one byte from left to result */
6219 /*-----------------------------------------------------------------*/
6221 shiftR1Left2Result (operand * left, int offl,
6222 operand * result, int offr,
6223 int shCount, int sign)
6225 _moveA (aopGet (AOP (left), offl, FALSE));
6230 emit2 ("%s a", sign ? "sra" : "srl");
6237 aopPut (AOP (result), "a", offr);
6240 /*-----------------------------------------------------------------*/
6241 /* genrshTwo - right shift two bytes by known amount */
6242 /*-----------------------------------------------------------------*/
6244 genrshTwo (operand * result, operand * left,
6245 int shCount, int sign)
6247 /* if shCount >= 8 */
6253 shiftR1Left2Result (left, MSB16, result, LSB,
6258 movLeft2Result (left, MSB16, result, LSB, sign);
6262 /* Sign extend the result */
6263 _moveA(aopGet (AOP (result), 0, FALSE));
6267 aopPut (AOP (result), ACC_NAME, MSB16);
6271 aopPut (AOP (result), "!zero", 1);
6274 /* 0 <= shCount <= 7 */
6277 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6281 /*-----------------------------------------------------------------*/
6282 /* genRightShiftLiteral - left shifting by known count */
6283 /*-----------------------------------------------------------------*/
6285 genRightShiftLiteral (operand * left,
6291 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6294 freeAsmop (right, NULL, ic);
6296 aopOp (left, ic, FALSE, FALSE);
6297 aopOp (result, ic, FALSE, FALSE);
6299 size = getSize (operandType (result));
6301 /* I suppose that the left size >= result size */
6303 if (shCount >= (size * 8)) {
6305 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6306 _moveA(aopGet (AOP (left), 0, FALSE));
6314 aopPut (AOP (result), s, size);
6321 genrshOne (result, left, shCount, sign);
6324 genrshTwo (result, left, shCount, sign);
6327 wassertl (0, "Asked to shift right a long which should be a function call");
6330 wassertl (0, "Entered default case in right shift delegate");
6333 freeAsmop (left, NULL, ic);
6334 freeAsmop (result, NULL, ic);
6337 /*-----------------------------------------------------------------*/
6338 /* genRightShift - generate code for right shifting */
6339 /*-----------------------------------------------------------------*/
6341 genRightShift (iCode * ic)
6343 operand *right, *left, *result;
6345 int size, offset, first = 1;
6349 symbol *tlbl, *tlbl1;
6351 /* if signed then we do it the hard way preserve the
6352 sign bit moving it inwards */
6353 retype = getSpec (operandType (IC_RESULT (ic)));
6355 is_signed = !SPEC_USIGN (retype);
6357 /* signed & unsigned types are treated the same : i.e. the
6358 signed is NOT propagated inwards : quoting from the
6359 ANSI - standard : "for E1 >> E2, is equivalent to division
6360 by 2**E2 if unsigned or if it has a non-negative value,
6361 otherwise the result is implementation defined ", MY definition
6362 is that the sign does not get propagated */
6364 right = IC_RIGHT (ic);
6365 left = IC_LEFT (ic);
6366 result = IC_RESULT (ic);
6368 aopOp (right, ic, FALSE, FALSE);
6370 /* if the shift count is known then do it
6371 as efficiently as possible */
6372 if (AOP_TYPE (right) == AOP_LIT)
6374 genRightShiftLiteral (left, right, result, ic, is_signed);
6378 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6380 freeAsmop (right, NULL, ic);
6382 aopOp (left, ic, FALSE, FALSE);
6383 aopOp (result, ic, FALSE, FALSE);
6385 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6388 /* now move the left to the result if they are not the
6390 if (!sameRegs (AOP (left), AOP (result)))
6393 size = AOP_SIZE (result);
6397 l = aopGet (AOP (left), offset, FALSE);
6398 aopPut (AOP (result), l, offset);
6403 tlbl = newiTempLabel (NULL);
6404 tlbl1 = newiTempLabel (NULL);
6405 size = AOP_SIZE (result);
6408 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6411 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6412 emitLabel (tlbl->key + 100);
6415 l = aopGet (AOP (result), offset--, FALSE);
6418 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6426 emitLabel (tlbl1->key + 100);
6428 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6430 freeAsmop (left, NULL, ic);
6431 freeAsmop (result, NULL, ic);
6435 /*-----------------------------------------------------------------*/
6436 /* genUnpackBits - generates code for unpacking bits */
6437 /*-----------------------------------------------------------------*/
6439 genUnpackBits (operand * result, int pair)
6441 int offset = 0; /* result byte offset */
6442 int rsize; /* result size */
6443 int rlen = 0; /* remaining bitfield length */
6444 sym_link *etype; /* bitfield type information */
6445 int blen; /* bitfield length */
6446 int bstr; /* bitfield starting bit within byte */
6448 emitDebug ("; genUnpackBits");
6450 etype = getSpec (operandType (result));
6451 rsize = getSize (operandType (result));
6452 blen = SPEC_BLEN (etype);
6453 bstr = SPEC_BSTR (etype);
6455 /* If the bitfield length is less than a byte */
6458 emit2 ("ld a,!*pair", _pairs[pair].name);
6460 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6461 if (!SPEC_USIGN (etype))
6463 /* signed bitfield */
6464 symbol *tlbl = newiTempLabel (NULL);
6466 emit2 ("bit %d,a", blen - 1);
6467 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6468 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6469 emitLabel (tlbl->key + 100);
6471 aopPut (AOP (result), "a", offset++);
6475 /* TODO: what if pair == PAIR_DE ? */
6476 if (getPairId (AOP (result)) == PAIR_HL)
6478 wassertl (rsize == 2, "HL must be of size 2");
6479 emit2 ("ld a,!*hl");
6481 emit2 ("ld h,!*hl");
6484 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6485 if (!SPEC_USIGN (etype))
6487 /* signed bitfield */
6488 symbol *tlbl = newiTempLabel (NULL);
6490 emit2 ("bit %d,a", blen - 1);
6491 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6492 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6493 emitLabel (tlbl->key + 100);
6496 spillPair (PAIR_HL);
6500 /* Bit field did not fit in a byte. Copy all
6501 but the partial byte at the end. */
6502 for (rlen=blen;rlen>=8;rlen-=8)
6504 emit2 ("ld a,!*pair", _pairs[pair].name);
6505 aopPut (AOP (result), "a", offset++);
6508 emit2 ("inc %s", _pairs[pair].name);
6509 _G.pairs[pair].offset++;
6513 /* Handle the partial byte at the end */
6516 emit2 ("ld a,!*pair", _pairs[pair].name);
6517 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6518 if (!SPEC_USIGN (etype))
6520 /* signed bitfield */
6521 symbol *tlbl = newiTempLabel (NULL);
6523 emit2 ("bit %d,a", rlen - 1);
6524 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6525 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6526 emitLabel (tlbl->key + 100);
6528 aopPut (AOP (result), "a", offset++);
6536 if (SPEC_USIGN (etype))
6540 /* signed bitfield: sign extension with 0x00 or 0xff */
6548 aopPut (AOP (result), source, offset++);
6552 /*-----------------------------------------------------------------*/
6553 /* genGenPointerGet - get value from generic pointer space */
6554 /*-----------------------------------------------------------------*/
6556 genGenPointerGet (operand * left,
6557 operand * result, iCode * ic)
6560 sym_link *retype = getSpec (operandType (result));
6566 aopOp (left, ic, FALSE, FALSE);
6567 aopOp (result, ic, FALSE, FALSE);
6569 size = AOP_SIZE (result);
6571 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6574 if (isPtrPair (AOP (left)))
6576 tsprintf (buffer, sizeof(buffer),
6577 "!*pair", getPairName (AOP (left)));
6578 aopPut (AOP (result), buffer, 0);
6582 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6583 aopPut (AOP (result), "a", 0);
6585 freeAsmop (left, NULL, ic);
6589 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6596 tsprintf (at, sizeof(at), "!*iyx", offset);
6597 aopPut (AOP (result), at, offset);
6601 freeAsmop (left, NULL, ic);
6605 /* For now we always load into IY */
6606 /* if this is remateriazable */
6607 fetchPair (pair, AOP (left));
6609 /* if bit then unpack */
6610 if (IS_BITVAR (retype))
6612 genUnpackBits (result, pair);
6613 freeAsmop (left, NULL, ic);
6617 else if (getPairId (AOP (result)) == PAIR_HL)
6619 wassertl (size == 2, "HL must be of size 2");
6620 emit2 ("ld a,!*hl");
6622 emit2 ("ld h,!*hl");
6624 spillPair (PAIR_HL);
6626 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6628 size = AOP_SIZE (result);
6633 /* PENDING: make this better */
6634 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6636 aopPut (AOP (result), "!*hl", offset++);
6640 emit2 ("ld a,!*pair", _pairs[pair].name);
6641 aopPut (AOP (result), "a", offset++);
6645 emit2 ("inc %s", _pairs[pair].name);
6646 _G.pairs[pair].offset++;
6649 /* Fixup HL back down */
6650 for (size = AOP_SIZE (result)-1; size; size--)
6652 emit2 ("dec %s", _pairs[pair].name);
6657 size = AOP_SIZE (result);
6662 /* PENDING: make this better */
6664 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6666 aopPut (AOP (result), "!*hl", offset++);
6670 emit2 ("ld a,!*pair", _pairs[pair].name);
6671 aopPut (AOP (result), "a", offset++);
6675 emit2 ("inc %s", _pairs[pair].name);
6676 _G.pairs[pair].offset++;
6681 freeAsmop (left, NULL, ic);
6684 freeAsmop (result, NULL, ic);
6687 /*-----------------------------------------------------------------*/
6688 /* genPointerGet - generate code for pointer get */
6689 /*-----------------------------------------------------------------*/
6691 genPointerGet (iCode * ic)
6693 operand *left, *result;
6694 sym_link *type, *etype;
6696 left = IC_LEFT (ic);
6697 result = IC_RESULT (ic);
6699 /* depending on the type of pointer we need to
6700 move it to the correct pointer register */
6701 type = operandType (left);
6702 etype = getSpec (type);
6704 genGenPointerGet (left, result, ic);
6708 isRegOrLit (asmop * aop)
6710 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6716 /*-----------------------------------------------------------------*/
6717 /* genPackBits - generates code for packed bit storage */
6718 /*-----------------------------------------------------------------*/
6720 genPackBits (sym_link * etype,
6725 int offset = 0; /* source byte offset */
6726 int rlen = 0; /* remaining bitfield length */
6727 int blen; /* bitfield length */
6728 int bstr; /* bitfield starting bit within byte */
6729 int litval; /* source literal value (if AOP_LIT) */
6730 unsigned char mask; /* bitmask within current byte */
6731 int extraPair; /* a tempory register */
6732 bool needPopExtra=0; /* need to restore original value of temp reg */
6734 emitDebug ("; genPackBits","");
6736 blen = SPEC_BLEN (etype);
6737 bstr = SPEC_BSTR (etype);
6739 /* If the bitfield length is less than a byte */
6742 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6743 (unsigned char) (0xFF >> (8 - bstr)));
6745 if (AOP_TYPE (right) == AOP_LIT)
6747 /* Case with a bitfield length <8 and literal source
6749 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6751 litval &= (~mask) & 0xff;
6752 emit2 ("ld a,!*pair", _pairs[pair].name);
6753 if ((mask|litval)!=0xff)
6754 emit2 ("and a,!immedbyte", mask);
6756 emit2 ("or a,!immedbyte", litval);
6757 emit2 ("ld !*pair,a", _pairs[pair].name);
6762 /* Case with a bitfield length <8 and arbitrary source
6764 _moveA (aopGet (AOP (right), 0, FALSE));
6765 /* shift and mask source value */
6767 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6769 extraPair = getFreePairId(ic);
6770 if (extraPair == PAIR_INVALID)
6772 extraPair = PAIR_BC;
6773 if (getPairId (AOP (right)) != PAIR_BC
6774 || !isLastUse (ic, right))
6780 emit2 ("ld %s,a", _pairs[extraPair].l);
6781 emit2 ("ld a,!*pair", _pairs[pair].name);
6783 emit2 ("and a,!immedbyte", mask);
6784 emit2 ("or a,%s", _pairs[extraPair].l);
6785 emit2 ("ld !*pair,a", _pairs[pair].name);
6792 /* Bit length is greater than 7 bits. In this case, copy */
6793 /* all except the partial byte at the end */
6794 for (rlen=blen;rlen>=8;rlen-=8)
6796 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6797 emit2 ("ld !*pair,a", _pairs[pair].name);
6800 emit2 ("inc %s", _pairs[pair].name);
6801 _G.pairs[pair].offset++;
6805 /* If there was a partial byte at the end */
6808 mask = (((unsigned char) -1 << rlen) & 0xff);
6810 if (AOP_TYPE (right) == AOP_LIT)
6812 /* Case with partial byte and literal source
6814 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6815 litval >>= (blen-rlen);
6816 litval &= (~mask) & 0xff;
6817 emit2 ("ld a,!*pair", _pairs[pair].name);
6818 if ((mask|litval)!=0xff)
6819 emit2 ("and a,!immedbyte", mask);
6821 emit2 ("or a,!immedbyte", litval);
6825 /* Case with partial byte and arbitrary source
6827 _moveA (aopGet (AOP (right), offset++, FALSE));
6828 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6830 extraPair = getFreePairId(ic);
6831 if (extraPair == PAIR_INVALID)
6833 extraPair = getPairId (AOP (right));
6834 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6835 extraPair = PAIR_BC;
6837 if (getPairId (AOP (right)) != PAIR_BC
6838 || !isLastUse (ic, right))
6844 emit2 ("ld %s,a", _pairs[extraPair].l);
6845 emit2 ("ld a,!*pair", _pairs[pair].name);
6847 emit2 ("and a,!immedbyte", mask);
6848 emit2 ("or a,%s", _pairs[extraPair].l);
6853 emit2 ("ld !*pair,a", _pairs[pair].name);
6858 /*-----------------------------------------------------------------*/
6859 /* genGenPointerSet - stores the value into a pointer location */
6860 /*-----------------------------------------------------------------*/
6862 genGenPointerSet (operand * right,
6863 operand * result, iCode * ic)
6866 sym_link *retype = getSpec (operandType (right));
6867 sym_link *letype = getSpec (operandType (result));
6868 PAIR_ID pairId = PAIR_HL;
6871 aopOp (result, ic, FALSE, FALSE);
6872 aopOp (right, ic, FALSE, FALSE);
6877 size = AOP_SIZE (right);
6879 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6880 emitDebug("; isBitvar = %d", isBitvar);
6882 /* Handle the exceptions first */
6883 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6886 const char *l = aopGet (AOP (right), 0, FALSE);
6887 const char *pair = getPairName (AOP (result));
6888 if (canAssignToPtr (l) && isPtr (pair))
6890 emit2 ("ld !*pair,%s", pair, l);
6895 emit2 ("ld !*pair,a", pair);
6900 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6903 const char *l = aopGet (AOP (right), 0, FALSE);
6908 if (canAssignToPtr (l))
6910 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6914 _moveA (aopGet (AOP (right), offset, FALSE));
6915 emit2 ("ld !*iyx,a", offset);
6921 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6928 const char *l = aopGet (AOP (right), offset, FALSE);
6929 if (isRegOrLit (AOP (right)) && !IS_GB)
6931 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6936 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6940 emit2 ("inc %s", _pairs[PAIR_HL].name);
6941 _G.pairs[PAIR_HL].offset++;
6946 /* Fixup HL back down */
6947 for (size = AOP_SIZE (right)-1; size; size--)
6949 emit2 ("dec %s", _pairs[PAIR_HL].name);
6954 /* if the operand is already in dptr
6955 then we do nothing else we move the value to dptr */
6956 if (AOP_TYPE (result) != AOP_STR)
6958 fetchPair (pairId, AOP (result));
6960 /* so hl now contains the address */
6961 freeAsmop (result, NULL, ic);
6963 /* if bit then unpack */
6966 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6976 const char *l = aopGet (AOP (right), offset, FALSE);
6977 if (isRegOrLit (AOP (right)) && !IS_GB)
6979 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6984 emit2 ("ld !*pair,a", _pairs[pairId].name);
6988 emit2 ("inc %s", _pairs[pairId].name);
6989 _G.pairs[pairId].offset++;
6995 freeAsmop (right, NULL, ic);
6998 /*-----------------------------------------------------------------*/
6999 /* genPointerSet - stores the value into a pointer location */
7000 /*-----------------------------------------------------------------*/
7002 genPointerSet (iCode * ic)
7004 operand *right, *result;
7005 sym_link *type, *etype;
7007 right = IC_RIGHT (ic);
7008 result = IC_RESULT (ic);
7010 /* depending on the type of pointer we need to
7011 move it to the correct pointer register */
7012 type = operandType (result);
7013 etype = getSpec (type);
7015 genGenPointerSet (right, result, ic);
7018 /*-----------------------------------------------------------------*/
7019 /* genIfx - generate code for Ifx statement */
7020 /*-----------------------------------------------------------------*/
7022 genIfx (iCode * ic, iCode * popIc)
7024 operand *cond = IC_COND (ic);
7027 aopOp (cond, ic, FALSE, TRUE);
7029 /* get the value into acc */
7030 if (AOP_TYPE (cond) != AOP_CRY)
7034 /* the result is now in the accumulator */
7035 freeAsmop (cond, NULL, ic);
7037 /* if there was something to be popped then do it */
7041 /* if the condition is a bit variable */
7042 if (isbit && IS_ITEMP (cond) &&
7044 genIfxJump (ic, SPIL_LOC (cond)->rname);
7045 else if (isbit && !IS_ITEMP (cond))
7046 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7048 genIfxJump (ic, "a");
7053 /*-----------------------------------------------------------------*/
7054 /* genAddrOf - generates code for address of */
7055 /*-----------------------------------------------------------------*/
7057 genAddrOf (iCode * ic)
7059 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7061 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7063 /* if the operand is on the stack then we
7064 need to get the stack offset of this
7071 if (sym->stack <= 0)
7073 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7077 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7079 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7083 emit2 ("ld de,!hashedstr", sym->rname);
7084 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7092 /* if it has an offset then we need to compute it */
7094 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7096 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7097 emit2 ("add hl,sp");
7101 emit2 ("ld hl,!hashedstr", sym->rname);
7103 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7105 freeAsmop (IC_RESULT (ic), NULL, ic);
7108 /*-----------------------------------------------------------------*/
7109 /* genAssign - generate code for assignment */
7110 /*-----------------------------------------------------------------*/
7112 genAssign (iCode * ic)
7114 operand *result, *right;
7116 unsigned long lit = 0L;
7118 result = IC_RESULT (ic);
7119 right = IC_RIGHT (ic);
7121 /* Dont bother assigning if they are the same */
7122 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7124 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7128 aopOp (right, ic, FALSE, FALSE);
7129 aopOp (result, ic, TRUE, FALSE);
7131 /* if they are the same registers */
7132 if (sameRegs (AOP (right), AOP (result)))
7134 emitDebug ("; (registers are the same)");
7138 /* if the result is a bit */
7139 if (AOP_TYPE (result) == AOP_CRY)
7141 wassertl (0, "Tried to assign to a bit");
7145 size = AOP_SIZE (result);
7148 if (AOP_TYPE (right) == AOP_LIT)
7150 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7153 if (isPair (AOP (result)))
7155 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7157 else if ((size > 1) &&
7158 (AOP_TYPE (result) != AOP_REG) &&
7159 (AOP_TYPE (right) == AOP_LIT) &&
7160 !IS_FLOAT (operandType (right)) &&
7163 bool fXored = FALSE;
7165 /* Work from the top down.
7166 Done this way so that we can use the cached copy of 0
7167 in A for a fast clear */
7170 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7172 if (!fXored && size > 1)
7179 aopPut (AOP (result), "a", offset);
7183 aopPut (AOP (result), "!zero", offset);
7187 aopPut (AOP (result),
7188 aopGet (AOP (right), offset, FALSE),
7193 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7195 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7196 aopPut (AOP (result), "l", LSB);
7197 aopPut (AOP (result), "h", MSB16);
7199 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7201 /* Special case. Load into a and d, then load out. */
7202 _moveA (aopGet (AOP (right), 0, FALSE));
7203 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7204 aopPut (AOP (result), "a", 0);
7205 aopPut (AOP (result), "e", 1);
7207 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7209 /* Special case - simple memcpy */
7210 aopGet (AOP (right), LSB, FALSE);
7213 aopGet (AOP (result), LSB, FALSE);
7217 emit2 ("ld a,(de)");
7218 /* Peephole will optimise this. */
7219 emit2 ("ld (hl),a");
7227 spillPair (PAIR_HL);
7233 /* PENDING: do this check better */
7234 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7236 _moveA (aopGet (AOP (right), offset, FALSE));
7237 aopPut (AOP (result), "a", offset);
7240 aopPut (AOP (result),
7241 aopGet (AOP (right), offset, FALSE),
7248 freeAsmop (right, NULL, ic);
7249 freeAsmop (result, NULL, ic);
7252 /*-----------------------------------------------------------------*/
7253 /* genJumpTab - genrates code for jump table */
7254 /*-----------------------------------------------------------------*/
7256 genJumpTab (iCode * ic)
7261 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7262 /* get the condition into accumulator */
7263 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7266 emit2 ("ld e,%s", l);
7267 emit2 ("ld d,!zero");
7268 jtab = newiTempLabel (NULL);
7270 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7271 emit2 ("add hl,de");
7272 emit2 ("add hl,de");
7273 emit2 ("add hl,de");
7274 freeAsmop (IC_JTCOND (ic), NULL, ic);
7278 emitLabel (jtab->key + 100);
7279 /* now generate the jump labels */
7280 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7281 jtab = setNextItem (IC_JTLABELS (ic)))
7282 emit2 ("jp !tlabel", jtab->key + 100);
7285 /*-----------------------------------------------------------------*/
7286 /* genCast - gen code for casting */
7287 /*-----------------------------------------------------------------*/
7289 genCast (iCode * ic)
7291 operand *result = IC_RESULT (ic);
7292 sym_link *rtype = operandType (IC_RIGHT (ic));
7293 operand *right = IC_RIGHT (ic);
7296 /* if they are equivalent then do nothing */
7297 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7300 aopOp (right, ic, FALSE, FALSE);
7301 aopOp (result, ic, FALSE, FALSE);
7303 /* if the result is a bit */
7304 if (AOP_TYPE (result) == AOP_CRY)
7306 wassertl (0, "Tried to cast to a bit");
7309 /* if they are the same size : or less */
7310 if (AOP_SIZE (result) <= AOP_SIZE (right))
7313 /* if they are in the same place */
7314 if (sameRegs (AOP (right), AOP (result)))
7317 /* if they in different places then copy */
7318 size = AOP_SIZE (result);
7322 aopPut (AOP (result),
7323 aopGet (AOP (right), offset, FALSE),
7330 /* So we now know that the size of destination is greater
7331 than the size of the source */
7332 /* we move to result for the size of source */
7333 size = AOP_SIZE (right);
7337 aopPut (AOP (result),
7338 aopGet (AOP (right), offset, FALSE),
7343 /* now depending on the sign of the destination */
7344 size = AOP_SIZE (result) - AOP_SIZE (right);
7345 /* Unsigned or not an integral type - right fill with zeros */
7346 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7349 aopPut (AOP (result), "!zero", offset++);
7353 /* we need to extend the sign :{ */
7354 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7360 aopPut (AOP (result), "a", offset++);
7364 freeAsmop (right, NULL, ic);
7365 freeAsmop (result, NULL, ic);
7368 /*-----------------------------------------------------------------*/
7369 /* genReceive - generate code for a receive iCode */
7370 /*-----------------------------------------------------------------*/
7372 genReceive (iCode * ic)
7374 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7375 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7376 IS_TRUE_SYMOP (IC_RESULT (ic))))
7386 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7387 size = AOP_SIZE(IC_RESULT(ic));
7389 for (i = 0; i < size; i++) {
7390 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7394 freeAsmop (IC_RESULT (ic), NULL, ic);
7397 /*-----------------------------------------------------------------*/
7398 /* genDummyRead - generate code for dummy read of volatiles */
7399 /*-----------------------------------------------------------------*/
7401 genDummyRead (iCode * ic)
7407 if (op && IS_SYMOP (op))
7409 aopOp (op, ic, FALSE, FALSE);
7412 size = AOP_SIZE (op);
7417 _moveA (aopGet (AOP (op), offset, FALSE));
7421 freeAsmop (op, NULL, ic);
7425 if (op && IS_SYMOP (op))
7427 aopOp (op, ic, FALSE, FALSE);
7430 size = AOP_SIZE (op);
7435 _moveA (aopGet (AOP (op), offset, FALSE));
7439 freeAsmop (op, NULL, ic);
7443 /*-----------------------------------------------------------------*/
7444 /* genCritical - generate code for start of a critical sequence */
7445 /*-----------------------------------------------------------------*/
7447 genCritical (iCode *ic)
7449 symbol *tlbl = newiTempLabel (NULL);
7455 else if (IC_RESULT (ic))
7457 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7458 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7459 //get interrupt enable flag IFF2 into P/O
7463 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7464 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7465 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7466 emit2 ("!tlabeldef", (tlbl->key + 100));
7467 freeAsmop (IC_RESULT (ic), NULL, ic);
7471 //get interrupt enable flag IFF2 into P/O
7480 /*-----------------------------------------------------------------*/
7481 /* genEndCritical - generate code for end of a critical sequence */
7482 /*-----------------------------------------------------------------*/
7484 genEndCritical (iCode *ic)
7486 symbol *tlbl = newiTempLabel (NULL);
7492 else if (IC_RIGHT (ic))
7494 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7495 _toBoolean (IC_RIGHT (ic));
7496 //don't enable interrupts if they were off before
7497 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7499 emitLabel (tlbl->key + 100);
7500 freeAsmop (IC_RIGHT (ic), NULL, ic);
7506 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7507 //don't enable interrupts as they were off before
7508 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7510 emit2 ("!tlabeldef", (tlbl->key + 100));
7516 /** Maximum number of bytes to emit per line. */
7520 /** Context for the byte output chunker. */
7523 unsigned char buffer[DBEMIT_MAX_RUN];
7528 /** Flushes a byte chunker by writing out all in the buffer and
7532 _dbFlush(DBEMITCTX *self)
7539 sprintf(line, ".db 0x%02X", self->buffer[0]);
7541 for (i = 1; i < self->pos; i++)
7543 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7550 /** Write out another byte, buffering until a decent line is
7554 _dbEmit(DBEMITCTX *self, int c)
7556 if (self->pos == DBEMIT_MAX_RUN)
7560 self->buffer[self->pos++] = c;
7563 /** Context for a simple run length encoder. */
7567 unsigned char buffer[128];
7569 /** runLen may be equivalent to pos. */
7575 RLE_CHANGE_COST = 4,
7579 /** Flush the buffer of a run length encoder by writing out the run or
7580 data that it currently contains.
7583 _rleCommit(RLECTX *self)
7589 memset(&db, 0, sizeof(db));
7591 emit2(".db %u", self->pos);
7593 for (i = 0; i < self->pos; i++)
7595 _dbEmit(&db, self->buffer[i]);
7604 Can get either a run or a block of random stuff.
7605 Only want to change state if a good run comes in or a run ends.
7606 Detecting run end is easy.
7609 Say initial state is in run, len zero, last zero. Then if you get a
7610 few zeros then something else then a short run will be output.
7611 Seems OK. While in run mode, keep counting. While in random mode,
7612 keep a count of the run. If run hits margin, output all up to run,
7613 restart, enter run mode.
7616 /** Add another byte into the run length encoder, flushing as
7617 required. The run length encoder uses the Amiga IFF style, where
7618 a block is prefixed by its run length. A positive length means
7619 the next n bytes pass straight through. A negative length means
7620 that the next byte is repeated -n times. A zero terminates the
7624 _rleAppend(RLECTX *self, unsigned c)
7628 if (c != self->last)
7630 /* The run has stopped. See if it is worthwhile writing it out
7631 as a run. Note that the random data comes in as runs of
7634 if (self->runLen > RLE_CHANGE_COST)
7636 /* Yes, worthwhile. */
7637 /* Commit whatever was in the buffer. */
7639 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7643 /* Not worthwhile. Append to the end of the random list. */
7644 for (i = 0; i < self->runLen; i++)
7646 if (self->pos >= RLE_MAX_BLOCK)
7651 self->buffer[self->pos++] = self->last;
7659 if (self->runLen >= RLE_MAX_BLOCK)
7661 /* Commit whatever was in the buffer. */
7664 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7672 _rleFlush(RLECTX *self)
7674 _rleAppend(self, -1);
7681 /** genArrayInit - Special code for initialising an array with constant
7685 genArrayInit (iCode * ic)
7689 int elementSize = 0, eIndex, i;
7690 unsigned val, lastVal;
7694 memset(&rle, 0, sizeof(rle));
7696 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7698 _saveRegsForCall(ic, 0);
7700 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7701 emit2 ("call __initrleblock");
7703 type = operandType(IC_LEFT(ic));
7705 if (type && type->next)
7707 if (IS_SPEC(type->next) || IS_PTR(type->next))
7709 elementSize = getSize(type->next);
7711 else if (IS_ARRAY(type->next) && type->next->next)
7713 elementSize = getSize(type->next->next);
7717 printTypeChainRaw (type, NULL);
7718 wassertl (0, "Can't determine element size in genArrayInit.");
7723 wassertl (0, "Can't determine element size in genArrayInit.");
7726 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7728 iLoop = IC_ARRAYILIST(ic);
7729 lastVal = (unsigned)-1;
7731 /* Feed all the bytes into the run length encoder which will handle
7733 This works well for mixed char data, and for random int and long
7740 for (i = 0; i < ix; i++)
7742 for (eIndex = 0; eIndex < elementSize; eIndex++)
7744 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7745 _rleAppend(&rle, val);
7749 iLoop = iLoop->next;
7753 /* Mark the end of the run. */
7756 _restoreRegsAfterCall();
7760 freeAsmop (IC_LEFT(ic), NULL, ic);
7764 _swap (PAIR_ID one, PAIR_ID two)
7766 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7772 emit2 ("ld a,%s", _pairs[one].l);
7773 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7774 emit2 ("ld %s,a", _pairs[two].l);
7775 emit2 ("ld a,%s", _pairs[one].h);
7776 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7777 emit2 ("ld %s,a", _pairs[two].h);
7781 /* The problem is that we may have all three pairs used and they may
7782 be needed in a different order.
7787 hl = hl => unity, fine
7791 hl = hl hl = hl, swap de <=> bc
7799 hl = bc de = de, swap bc <=> hl
7807 hl = de bc = bc, swap hl <=> de
7812 * Any pair = pair are done last
7813 * Any pair = iTemp are done last
7814 * Any swaps can be done any time
7822 So how do we detect the cases?
7823 How about a 3x3 matrix?
7827 x x x x (Fourth for iTemp/other)
7829 First determin which mode to use by counting the number of unity and
7832 Two - Assign the pair first, then the rest
7833 One - Swap the two, then the rest
7837 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7839 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7841 PAIR_BC, PAIR_HL, PAIR_DE
7843 int i, j, nunity = 0;
7844 memset (ids, PAIR_INVALID, sizeof (ids));
7847 wassert (nparams == 3);
7849 /* First save everything that needs to be saved. */
7850 _saveRegsForCall (ic, 0);
7852 /* Loading HL first means that DE is always fine. */
7853 for (i = 0; i < nparams; i++)
7855 aopOp (pparams[i], ic, FALSE, FALSE);
7856 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7859 /* Count the number of unity or iTemp assigns. */
7860 for (i = 0; i < 3; i++)
7862 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7870 /* Any order, fall through. */
7872 else if (nunity == 2)
7874 /* One is assigned. Pull it out and assign. */
7875 for (i = 0; i < 3; i++)
7877 for (j = 0; j < NUM_PAIRS; j++)
7879 if (ids[dest[i]][j] == TRUE)
7881 /* Found it. See if it's the right one. */
7882 if (j == PAIR_INVALID || j == dest[i])
7888 fetchPair(dest[i], AOP (pparams[i]));
7895 else if (nunity == 1)
7897 /* Find the pairs to swap. */
7898 for (i = 0; i < 3; i++)
7900 for (j = 0; j < NUM_PAIRS; j++)
7902 if (ids[dest[i]][j] == TRUE)
7904 if (j == PAIR_INVALID || j == dest[i])
7919 int next = getPairId (AOP (pparams[0]));
7920 emit2 ("push %s", _pairs[next].name);
7922 if (next == dest[1])
7924 fetchPair (dest[1], AOP (pparams[1]));
7925 fetchPair (dest[2], AOP (pparams[2]));
7929 fetchPair (dest[2], AOP (pparams[2]));
7930 fetchPair (dest[1], AOP (pparams[1]));
7932 emit2 ("pop %s", _pairs[dest[0]].name);
7935 /* Finally pull out all of the iTemps */
7936 for (i = 0; i < 3; i++)
7938 if (ids[dest[i]][PAIR_INVALID] == 1)
7940 fetchPair (dest[i], AOP (pparams[i]));
7946 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7952 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7956 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7958 setupForBuiltin3 (ic, nParams, pparams);
7960 label = newiTempLabel(NULL);
7962 emitLabel (label->key);
7963 emit2 ("ld a,(hl)");
7966 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
7968 freeAsmop (from, NULL, ic->next);
7969 freeAsmop (to, NULL, ic);
7973 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7975 operand *from, *to, *count;
7978 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7983 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7985 setupForBuiltin3 (ic, nParams, pparams);
7989 freeAsmop (count, NULL, ic->next->next);
7990 freeAsmop (from, NULL, ic);
7992 _restoreRegsAfterCall();
7994 /* if we need assign a result value */
7995 if ((IS_ITEMP (IC_RESULT (ic)) &&
7996 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7997 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7998 IS_TRUE_SYMOP (IC_RESULT (ic)))
8000 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8001 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8002 freeAsmop (IC_RESULT (ic), NULL, ic);
8005 freeAsmop (to, NULL, ic->next);
8008 /*-----------------------------------------------------------------*/
8009 /* genBuiltIn - calls the appropriate function to generating code */
8010 /* for a built in function */
8011 /*-----------------------------------------------------------------*/
8012 static void genBuiltIn (iCode *ic)
8014 operand *bi_parms[MAX_BUILTIN_ARGS];
8019 /* get all the arguments for a built in function */
8020 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8022 /* which function is it */
8023 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8025 if (strcmp(bif->name,"__builtin_strcpy")==0)
8027 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8029 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8031 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8035 wassertl (0, "Unknown builtin function encountered");
8039 /*-----------------------------------------------------------------*/
8040 /* genZ80Code - generate code for Z80 based controllers */
8041 /*-----------------------------------------------------------------*/
8043 genZ80Code (iCode * lic)
8051 _fReturn = _gbz80_return;
8052 _fTmp = _gbz80_return;
8056 _fReturn = _z80_return;
8057 _fTmp = _z80_return;
8060 _G.lines.head = _G.lines.current = NULL;
8062 /* if debug information required */
8063 if (options.debug && currFunc)
8065 debugFile->writeFunction (currFunc, lic);
8068 for (ic = lic; ic; ic = ic->next)
8070 _G.current_iCode = ic;
8072 if (ic->lineno && cln != ic->lineno)
8076 debugFile->writeCLine (ic);
8078 if (!options.noCcodeInAsm)
8080 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8081 printCLine(ic->filename, ic->lineno));
8085 if (options.iCodeInAsm)
8087 emit2 (";ic:%d: %s", ic->key, printILine(ic));
8089 /* if the result is marked as
8090 spilt and rematerializable or code for
8091 this has already been generated then
8093 if (resultRemat (ic) || ic->generated)
8096 /* depending on the operation */
8100 emitDebug ("; genNot");
8105 emitDebug ("; genCpl");
8110 emitDebug ("; genUminus");
8115 emitDebug ("; genIpush");
8120 /* IPOP happens only when trying to restore a
8121 spilt live range, if there is an ifx statement
8122 following this pop then the if statement might
8123 be using some of the registers being popped which
8124 would destory the contents of the register so
8125 we need to check for this condition and handle it */
8127 ic->next->op == IFX &&
8128 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8130 emitDebug ("; genIfx");
8131 genIfx (ic->next, ic);
8135 emitDebug ("; genIpop");
8141 emitDebug ("; genCall");
8146 emitDebug ("; genPcall");
8151 emitDebug ("; genFunction");
8156 emitDebug ("; genEndFunction");
8157 genEndFunction (ic);
8161 emitDebug ("; genRet");
8166 emitDebug ("; genLabel");
8171 emitDebug ("; genGoto");
8176 emitDebug ("; genPlus");
8181 emitDebug ("; genMinus");
8186 emitDebug ("; genMult");
8191 emitDebug ("; genDiv");
8196 emitDebug ("; genMod");
8201 emitDebug ("; genCmpGt");
8202 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8206 emitDebug ("; genCmpLt");
8207 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8214 /* note these two are xlated by algebraic equivalence
8215 during parsing SDCC.y */
8216 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8217 "got '>=' or '<=' shouldn't have come here");
8221 emitDebug ("; genCmpEq");
8222 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8226 emitDebug ("; genAndOp");
8231 emitDebug ("; genOrOp");
8236 emitDebug ("; genXor");
8237 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8241 emitDebug ("; genOr");
8242 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8246 emitDebug ("; genAnd");
8247 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8251 emitDebug ("; genInline");
8256 emitDebug ("; genRRC");
8261 emitDebug ("; genRLC");
8266 emitDebug ("; genGetHBIT");
8271 emitDebug ("; genLeftShift");
8276 emitDebug ("; genRightShift");
8280 case GET_VALUE_AT_ADDRESS:
8281 emitDebug ("; genPointerGet");
8287 if (POINTER_SET (ic))
8289 emitDebug ("; genAssign (pointer)");
8294 emitDebug ("; genAssign");
8300 emitDebug ("; genIfx");
8305 emitDebug ("; genAddrOf");
8310 emitDebug ("; genJumpTab");
8315 emitDebug ("; genCast");
8320 emitDebug ("; genReceive");
8325 if (ic->builtinSEND)
8327 emitDebug ("; genBuiltIn");
8332 emitDebug ("; addSet");
8333 addSet (&_G.sendSet, ic);
8338 emitDebug ("; genArrayInit");
8342 case DUMMY_READ_VOLATILE:
8343 emitDebug ("; genDummyRead");
8348 emitDebug ("; genCritical");
8353 emitDebug ("; genEndCritical");
8354 genEndCritical (ic);
8363 /* now we are ready to call the
8364 peep hole optimizer */
8365 if (!options.nopeep)
8366 peepHole (&_G.lines.head);
8368 /* This is unfortunate */
8369 /* now do the actual printing */
8371 FILE *fp = codeOutFile;
8372 if (isInHome () && codeOutFile == code->oFile)
8373 codeOutFile = home->oFile;
8374 printLine (_G.lines.head, codeOutFile);
8375 if (_G.flushStatics)
8378 _G.flushStatics = 0;
8383 freeTrace(&_G.lines.trace);
8384 freeTrace(&_G.trace.aops);
8390 _isPairUsed (iCode * ic, PAIR_ID pairId)
8396 if (bitVectBitValue (ic->rMask, D_IDX))
8398 if (bitVectBitValue (ic->rMask, E_IDX))
8408 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8411 value *val = aop->aopu.aop_lit;
8413 wassert (aop->type == AOP_LIT);
8414 wassert (!IS_FLOAT (val->type));
8416 v = (unsigned long) floatFromVal (val);
8424 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8425 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));