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 _moveA (aopGet (AOP (left), offset, FALSE));
4783 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4786 emit2 ("sub 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))
4805 /* MB: pending what? doesn't this need "or a,a"? */
4806 /* and I don't think AOP_TYPE(left) has anything to do with this */
4808 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4812 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4813 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4820 /* right is a pointer reg need both a & b */
4821 /* PENDING: is this required? */
4824 _moveA (aopGet (AOP (right), offset, FALSE));
4825 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4826 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4832 /*-----------------------------------------------------------------*/
4833 /* gencjne - compare and jump if not equal */
4834 /*-----------------------------------------------------------------*/
4836 gencjne (operand * left, operand * right, symbol * lbl)
4838 symbol *tlbl = newiTempLabel (NULL);
4840 gencjneshort (left, right, lbl);
4843 emit2 ("ld a,!one");
4844 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4845 emitLabel (lbl->key + 100);
4847 emitLabel (tlbl->key + 100);
4850 /*-----------------------------------------------------------------*/
4851 /* genCmpEq - generates code for equal to */
4852 /*-----------------------------------------------------------------*/
4854 genCmpEq (iCode * ic, iCode * ifx)
4856 operand *left, *right, *result;
4858 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4859 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4860 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4862 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4864 /* Swap operands if it makes the operation easier. ie if:
4865 1. Left is a literal.
4867 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4869 operand *t = IC_RIGHT (ic);
4870 IC_RIGHT (ic) = IC_LEFT (ic);
4874 if (ifx && !AOP_SIZE (result))
4877 /* if they are both bit variables */
4878 if (AOP_TYPE (left) == AOP_CRY &&
4879 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4881 wassertl (0, "Tried to compare two bits");
4885 tlbl = newiTempLabel (NULL);
4886 gencjneshort (left, right, tlbl);
4889 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4890 emitLabel (tlbl->key + 100);
4894 /* PENDING: do this better */
4895 symbol *lbl = newiTempLabel (NULL);
4896 emit2 ("!shortjp !tlabel", lbl->key + 100);
4897 emitLabel (tlbl->key + 100);
4898 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4899 emitLabel (lbl->key + 100);
4902 /* mark the icode as generated */
4907 /* if they are both bit variables */
4908 if (AOP_TYPE (left) == AOP_CRY &&
4909 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4911 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4917 gencjne (left, right, newiTempLabel (NULL));
4918 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4925 genIfxJump (ifx, "a");
4928 /* if the result is used in an arithmetic operation
4929 then put the result in place */
4930 if (AOP_TYPE (result) != AOP_CRY)
4935 /* leave the result in acc */
4939 freeAsmop (left, NULL, ic);
4940 freeAsmop (right, NULL, ic);
4941 freeAsmop (result, NULL, ic);
4944 /*-----------------------------------------------------------------*/
4945 /* ifxForOp - returns the icode containing the ifx for operand */
4946 /*-----------------------------------------------------------------*/
4948 ifxForOp (operand * op, iCode * ic)
4950 /* if true symbol then needs to be assigned */
4951 if (IS_TRUE_SYMOP (op))
4954 /* if this has register type condition and
4955 the next instruction is ifx with the same operand
4956 and live to of the operand is upto the ifx only then */
4958 ic->next->op == IFX &&
4959 IC_COND (ic->next)->key == op->key &&
4960 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4966 /*-----------------------------------------------------------------*/
4967 /* genAndOp - for && operation */
4968 /*-----------------------------------------------------------------*/
4970 genAndOp (iCode * ic)
4972 operand *left, *right, *result;
4975 /* note here that && operations that are in an if statement are
4976 taken away by backPatchLabels only those used in arthmetic
4977 operations remain */
4978 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4979 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4980 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4982 /* if both are bit variables */
4983 if (AOP_TYPE (left) == AOP_CRY &&
4984 AOP_TYPE (right) == AOP_CRY)
4986 wassertl (0, "Tried to and two bits");
4990 tlbl = newiTempLabel (NULL);
4992 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
4994 emitLabel (tlbl->key + 100);
4998 freeAsmop (left, NULL, ic);
4999 freeAsmop (right, NULL, ic);
5000 freeAsmop (result, NULL, ic);
5003 /*-----------------------------------------------------------------*/
5004 /* genOrOp - for || operation */
5005 /*-----------------------------------------------------------------*/
5007 genOrOp (iCode * ic)
5009 operand *left, *right, *result;
5012 /* note here that || operations that are in an
5013 if statement are taken away by backPatchLabels
5014 only those used in arthmetic operations remain */
5015 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5016 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5017 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5019 /* if both are bit variables */
5020 if (AOP_TYPE (left) == AOP_CRY &&
5021 AOP_TYPE (right) == AOP_CRY)
5023 wassertl (0, "Tried to OR two bits");
5027 tlbl = newiTempLabel (NULL);
5029 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5031 emitLabel (tlbl->key + 100);
5035 freeAsmop (left, NULL, ic);
5036 freeAsmop (right, NULL, ic);
5037 freeAsmop (result, NULL, ic);
5040 /*-----------------------------------------------------------------*/
5041 /* isLiteralBit - test if lit == 2^n */
5042 /*-----------------------------------------------------------------*/
5044 isLiteralBit (unsigned long lit)
5046 unsigned long pw[32] =
5047 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5048 0x100L, 0x200L, 0x400L, 0x800L,
5049 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5050 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5051 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5052 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5053 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5056 for (idx = 0; idx < 32; idx++)
5062 /*-----------------------------------------------------------------*/
5063 /* jmpTrueOrFalse - */
5064 /*-----------------------------------------------------------------*/
5066 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5068 // ugly but optimized by peephole
5071 symbol *nlbl = newiTempLabel (NULL);
5072 emit2 ("jp !tlabel", nlbl->key + 100);
5073 emitLabel (tlbl->key + 100);
5074 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5075 emitLabel (nlbl->key + 100);
5079 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5080 emitLabel (tlbl->key + 100);
5085 /*-----------------------------------------------------------------*/
5086 /* genAnd - code for and */
5087 /*-----------------------------------------------------------------*/
5089 genAnd (iCode * ic, iCode * ifx)
5091 operand *left, *right, *result;
5092 int size, offset = 0;
5093 unsigned long lit = 0L;
5096 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5097 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5098 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5100 /* if left is a literal & right is not then exchange them */
5101 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5102 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5104 operand *tmp = right;
5109 /* if result = right then exchange them */
5110 if (sameRegs (AOP (result), AOP (right)))
5112 operand *tmp = right;
5117 /* if right is bit then exchange them */
5118 if (AOP_TYPE (right) == AOP_CRY &&
5119 AOP_TYPE (left) != AOP_CRY)
5121 operand *tmp = right;
5125 if (AOP_TYPE (right) == AOP_LIT)
5126 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5128 size = AOP_SIZE (result);
5130 if (AOP_TYPE (left) == AOP_CRY)
5132 wassertl (0, "Tried to perform an AND with a bit as an operand");
5136 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5137 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5138 if ((AOP_TYPE (right) == AOP_LIT) &&
5139 (AOP_TYPE (result) == AOP_CRY) &&
5140 (AOP_TYPE (left) != AOP_CRY))
5142 symbol *tlbl = newiTempLabel (NULL);
5143 int sizel = AOP_SIZE (left);
5146 /* PENDING: Test case for this. */
5151 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5153 _moveA (aopGet (AOP (left), offset, FALSE));
5154 if (bytelit != 0x0FFL)
5156 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5163 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5167 // bit = left & literal
5171 emit2 ("!tlabeldef", tlbl->key + 100);
5173 // if(left & literal)
5178 jmpTrueOrFalse (ifx, tlbl);
5186 /* if left is same as result */
5187 if (sameRegs (AOP (result), AOP (left)))
5189 for (; size--; offset++)
5191 if (AOP_TYPE (right) == AOP_LIT)
5193 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5198 aopPut (AOP (result), "!zero", offset);
5201 _moveA (aopGet (AOP (left), offset, FALSE));
5203 aopGet (AOP (right), offset, FALSE));
5204 aopPut (AOP (left), "a", offset);
5211 if (AOP_TYPE (left) == AOP_ACC)
5213 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5217 _moveA (aopGet (AOP (left), offset, FALSE));
5219 aopGet (AOP (right), offset, FALSE));
5220 aopPut (AOP (left), "a", offset);
5227 // left & result in different registers
5228 if (AOP_TYPE (result) == AOP_CRY)
5230 wassertl (0, "Tried to AND where the result is in carry");
5234 for (; (size--); offset++)
5237 // result = left & right
5238 if (AOP_TYPE (right) == AOP_LIT)
5240 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5242 aopPut (AOP (result),
5243 aopGet (AOP (left), offset, FALSE),
5247 else if (bytelit == 0)
5249 aopPut (AOP (result), "!zero", offset);
5253 // faster than result <- left, anl result,right
5254 // and better if result is SFR
5255 if (AOP_TYPE (left) == AOP_ACC)
5256 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5259 _moveA (aopGet (AOP (left), offset, FALSE));
5261 aopGet (AOP (right), offset, FALSE));
5263 aopPut (AOP (result), "a", offset);
5270 freeAsmop (left, NULL, ic);
5271 freeAsmop (right, NULL, ic);
5272 freeAsmop (result, NULL, ic);
5275 /*-----------------------------------------------------------------*/
5276 /* genOr - code for or */
5277 /*-----------------------------------------------------------------*/
5279 genOr (iCode * ic, iCode * ifx)
5281 operand *left, *right, *result;
5282 int size, offset = 0;
5283 unsigned long lit = 0L;
5286 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5287 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5288 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5290 /* if left is a literal & right is not then exchange them */
5291 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5292 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5294 operand *tmp = right;
5299 /* if result = right then exchange them */
5300 if (sameRegs (AOP (result), AOP (right)))
5302 operand *tmp = right;
5307 /* if right is bit then exchange them */
5308 if (AOP_TYPE (right) == AOP_CRY &&
5309 AOP_TYPE (left) != AOP_CRY)
5311 operand *tmp = right;
5315 if (AOP_TYPE (right) == AOP_LIT)
5316 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5318 size = AOP_SIZE (result);
5320 if (AOP_TYPE (left) == AOP_CRY)
5322 wassertl (0, "Tried to OR where left is a bit");
5326 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5327 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5328 if ((AOP_TYPE (right) == AOP_LIT) &&
5329 (AOP_TYPE (result) == AOP_CRY) &&
5330 (AOP_TYPE (left) != AOP_CRY))
5332 symbol *tlbl = newiTempLabel (NULL);
5333 int sizel = AOP_SIZE (left);
5337 wassertl (0, "Result is assigned to a bit");
5339 /* PENDING: Modeled after the AND code which is inefficient. */
5342 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5344 _moveA (aopGet (AOP (left), offset, FALSE));
5345 /* OR with any literal is the same as OR with itself. */
5347 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5353 jmpTrueOrFalse (ifx, tlbl);
5358 /* if left is same as result */
5359 if (sameRegs (AOP (result), AOP (left)))
5361 for (; size--; offset++)
5363 if (AOP_TYPE (right) == AOP_LIT)
5365 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5369 _moveA (aopGet (AOP (left), offset, FALSE));
5371 aopGet (AOP (right), offset, FALSE));
5372 aopPut (AOP (result), "a", offset);
5377 if (AOP_TYPE (left) == AOP_ACC)
5378 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5381 _moveA (aopGet (AOP (left), offset, FALSE));
5383 aopGet (AOP (right), offset, FALSE));
5384 aopPut (AOP (result), "a", offset);
5391 // left & result in different registers
5392 if (AOP_TYPE (result) == AOP_CRY)
5394 wassertl (0, "Result of OR is in a bit");
5397 for (; (size--); offset++)
5400 // result = left & right
5401 if (AOP_TYPE (right) == AOP_LIT)
5403 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5405 aopPut (AOP (result),
5406 aopGet (AOP (left), offset, FALSE),
5411 // faster than result <- left, anl result,right
5412 // and better if result is SFR
5413 if (AOP_TYPE (left) == AOP_ACC)
5414 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5417 _moveA (aopGet (AOP (left), offset, FALSE));
5419 aopGet (AOP (right), offset, FALSE));
5421 aopPut (AOP (result), "a", offset);
5422 /* PENDING: something weird is going on here. Add exception. */
5423 if (AOP_TYPE (result) == AOP_ACC)
5429 freeAsmop (left, NULL, ic);
5430 freeAsmop (right, NULL, ic);
5431 freeAsmop (result, NULL, ic);
5434 /*-----------------------------------------------------------------*/
5435 /* genXor - code for xclusive or */
5436 /*-----------------------------------------------------------------*/
5438 genXor (iCode * ic, iCode * ifx)
5440 operand *left, *right, *result;
5441 int size, offset = 0;
5442 unsigned long lit = 0L;
5444 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5445 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5446 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5448 /* if left is a literal & right is not then exchange them */
5449 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5450 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5452 operand *tmp = right;
5457 /* if result = right then exchange them */
5458 if (sameRegs (AOP (result), AOP (right)))
5460 operand *tmp = right;
5465 /* if right is bit then exchange them */
5466 if (AOP_TYPE (right) == AOP_CRY &&
5467 AOP_TYPE (left) != AOP_CRY)
5469 operand *tmp = right;
5473 if (AOP_TYPE (right) == AOP_LIT)
5474 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5476 size = AOP_SIZE (result);
5478 if (AOP_TYPE (left) == AOP_CRY)
5480 wassertl (0, "Tried to XOR a bit");
5484 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5485 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5486 if ((AOP_TYPE (right) == AOP_LIT) &&
5487 (AOP_TYPE (result) == AOP_CRY) &&
5488 (AOP_TYPE (left) != AOP_CRY))
5490 symbol *tlbl = newiTempLabel (NULL);
5491 int sizel = AOP_SIZE (left);
5495 /* PENDING: Test case for this. */
5496 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5500 _moveA (aopGet (AOP (left), offset, FALSE));
5501 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5502 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5507 jmpTrueOrFalse (ifx, tlbl);
5511 wassertl (0, "Result of XOR was destined for a bit");
5516 /* if left is same as result */
5517 if (sameRegs (AOP (result), AOP (left)))
5519 for (; size--; offset++)
5521 if (AOP_TYPE (right) == AOP_LIT)
5523 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5527 _moveA (aopGet (AOP (left), offset, FALSE));
5529 aopGet (AOP (right), offset, FALSE));
5530 aopPut (AOP (result), "a", offset);
5535 if (AOP_TYPE (left) == AOP_ACC)
5537 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5541 _moveA (aopGet (AOP (left), offset, FALSE));
5543 aopGet (AOP (right), offset, FALSE));
5544 aopPut (AOP (result), "a", offset);
5551 // left & result in different registers
5552 if (AOP_TYPE (result) == AOP_CRY)
5554 wassertl (0, "Result of XOR is in a bit");
5557 for (; (size--); offset++)
5560 // result = left & right
5561 if (AOP_TYPE (right) == AOP_LIT)
5563 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5565 aopPut (AOP (result),
5566 aopGet (AOP (left), offset, FALSE),
5571 // faster than result <- left, anl result,right
5572 // and better if result is SFR
5573 if (AOP_TYPE (left) == AOP_ACC)
5575 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5579 _moveA (aopGet (AOP (left), offset, FALSE));
5581 aopGet (AOP (right), offset, FALSE));
5583 aopPut (AOP (result), "a", offset);
5588 freeAsmop (left, NULL, ic);
5589 freeAsmop (right, NULL, ic);
5590 freeAsmop (result, NULL, ic);
5593 /*-----------------------------------------------------------------*/
5594 /* genInline - write the inline code out */
5595 /*-----------------------------------------------------------------*/
5597 genInline (iCode * ic)
5599 char *buffer, *bp, *bp1;
5601 _G.lines.isInline += (!options.asmpeep);
5603 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5604 strcpy (buffer, IC_INLINE (ic));
5606 /* emit each line as a code */
5631 _G.lines.isInline -= (!options.asmpeep);
5635 /*-----------------------------------------------------------------*/
5636 /* genRRC - rotate right with carry */
5637 /*-----------------------------------------------------------------*/
5644 /*-----------------------------------------------------------------*/
5645 /* genRLC - generate code for rotate left with carry */
5646 /*-----------------------------------------------------------------*/
5653 /*-----------------------------------------------------------------*/
5654 /* genGetHbit - generates code get highest order bit */
5655 /*-----------------------------------------------------------------*/
5657 genGetHbit (iCode * ic)
5659 operand *left, *result;
5660 left = IC_LEFT (ic);
5661 result = IC_RESULT (ic);
5663 aopOp (left, ic, FALSE, FALSE);
5664 aopOp (result, ic, FALSE, FALSE);
5666 /* get the highest order byte into a */
5667 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5669 if (AOP_TYPE (result) == AOP_CRY)
5677 emit2 ("and a,!one");
5682 freeAsmop (left, NULL, ic);
5683 freeAsmop (result, NULL, ic);
5687 emitRsh2 (asmop *aop, int size, int is_signed)
5693 const char *l = aopGet (aop, size, FALSE);
5696 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5706 /*-----------------------------------------------------------------*/
5707 /* shiftR2Left2Result - shift right two bytes from left to result */
5708 /*-----------------------------------------------------------------*/
5710 shiftR2Left2Result (operand * left, int offl,
5711 operand * result, int offr,
5712 int shCount, int is_signed)
5715 symbol *tlbl, *tlbl1;
5717 movLeft2Result (left, offl, result, offr, 0);
5718 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5723 /* if (AOP(result)->type == AOP_REG) { */
5725 tlbl = newiTempLabel (NULL);
5726 tlbl1 = newiTempLabel (NULL);
5728 /* Left is already in result - so now do the shift */
5733 emitRsh2 (AOP (result), size, is_signed);
5738 emit2 ("ld a,!immedbyte+1", shCount);
5739 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5740 emitLabel (tlbl->key + 100);
5742 emitRsh2 (AOP (result), size, is_signed);
5744 emitLabel (tlbl1->key + 100);
5746 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5750 /*-----------------------------------------------------------------*/
5751 /* shiftL2Left2Result - shift left two bytes from left to result */
5752 /*-----------------------------------------------------------------*/
5754 shiftL2Left2Result (operand * left, int offl,
5755 operand * result, int offr, int shCount)
5757 if (sameRegs (AOP (result), AOP (left)) &&
5758 ((offl + MSB16) == offr))
5764 /* Copy left into result */
5765 movLeft2Result (left, offl, result, offr, 0);
5766 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5772 if (getPairId (AOP (result)) == PAIR_HL)
5776 emit2 ("add hl,hl");
5783 symbol *tlbl, *tlbl1;
5786 tlbl = newiTempLabel (NULL);
5787 tlbl1 = newiTempLabel (NULL);
5789 if (AOP (result)->type == AOP_REG)
5793 for (offset = 0; offset < size; offset++)
5795 l = aopGet (AOP (result), offset, FALSE);
5799 emit2 ("sla %s", l);
5810 /* Left is already in result - so now do the shift */
5813 emit2 ("ld a,!immedbyte+1", shCount);
5814 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5815 emitLabel (tlbl->key + 100);
5820 l = aopGet (AOP (result), offset, FALSE);
5824 emit2 ("sla %s", l);
5835 emitLabel (tlbl1->key + 100);
5837 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5843 /*-----------------------------------------------------------------*/
5844 /* AccRol - rotate left accumulator by known count */
5845 /*-----------------------------------------------------------------*/
5847 AccRol (int shCount)
5849 shCount &= 0x0007; // shCount : 0..7
5926 /*-----------------------------------------------------------------*/
5927 /* AccLsh - left shift accumulator by known count */
5928 /*-----------------------------------------------------------------*/
5930 AccLsh (int shCount)
5932 static const unsigned char SLMask[] =
5934 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5943 else if (shCount == 2)
5950 /* rotate left accumulator */
5952 /* and kill the lower order bits */
5953 emit2 ("and a,!immedbyte", SLMask[shCount]);
5958 /*-----------------------------------------------------------------*/
5959 /* shiftL1Left2Result - shift left one byte from left to result */
5960 /*-----------------------------------------------------------------*/
5962 shiftL1Left2Result (operand * left, int offl,
5963 operand * result, int offr, int shCount)
5966 l = aopGet (AOP (left), offl, FALSE);
5968 /* shift left accumulator */
5970 aopPut (AOP (result), "a", offr);
5974 /*-----------------------------------------------------------------*/
5975 /* genlshTwo - left shift two bytes by known amount */
5976 /*-----------------------------------------------------------------*/
5978 genlshTwo (operand * result, operand * left, int shCount)
5980 int size = AOP_SIZE (result);
5982 wassert (size == 2);
5984 /* if shCount >= 8 */
5992 movLeft2Result (left, LSB, result, MSB16, 0);
5993 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5994 aopPut (AOP (result), "!zero", LSB);
5998 movLeft2Result (left, LSB, result, MSB16, 0);
5999 aopPut (AOP (result), "!zero", 0);
6004 aopPut (AOP (result), "!zero", LSB);
6007 /* 0 <= shCount <= 7 */
6016 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6021 /*-----------------------------------------------------------------*/
6022 /* genlshOne - left shift a one byte quantity by known count */
6023 /*-----------------------------------------------------------------*/
6025 genlshOne (operand * result, operand * left, int shCount)
6027 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6030 /*-----------------------------------------------------------------*/
6031 /* genLeftShiftLiteral - left shifting by known count */
6032 /*-----------------------------------------------------------------*/
6034 genLeftShiftLiteral (operand * left,
6039 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6042 freeAsmop (right, NULL, ic);
6044 aopOp (left, ic, FALSE, FALSE);
6045 aopOp (result, ic, FALSE, FALSE);
6047 size = getSize (operandType (result));
6049 /* I suppose that the left size >= result size */
6051 if (shCount >= (size * 8))
6055 aopPut (AOP (result), "!zero", size);
6063 genlshOne (result, left, shCount);
6066 genlshTwo (result, left, shCount);
6069 wassertl (0, "Shifting of longs is currently unsupported");
6075 freeAsmop (left, NULL, ic);
6076 freeAsmop (result, NULL, ic);
6079 /*-----------------------------------------------------------------*/
6080 /* genLeftShift - generates code for left shifting */
6081 /*-----------------------------------------------------------------*/
6083 genLeftShift (iCode * ic)
6087 symbol *tlbl, *tlbl1;
6088 operand *left, *right, *result;
6090 right = IC_RIGHT (ic);
6091 left = IC_LEFT (ic);
6092 result = IC_RESULT (ic);
6094 aopOp (right, ic, FALSE, FALSE);
6096 /* if the shift count is known then do it
6097 as efficiently as possible */
6098 if (AOP_TYPE (right) == AOP_LIT)
6100 genLeftShiftLiteral (left, right, result, ic);
6104 /* shift count is unknown then we have to form a loop get the loop
6105 count in B : Note: we take only the lower order byte since
6106 shifting more that 32 bits make no sense anyway, ( the largest
6107 size of an object can be only 32 bits ) */
6108 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6110 freeAsmop (right, NULL, ic);
6111 aopOp (left, ic, FALSE, FALSE);
6112 aopOp (result, ic, FALSE, FALSE);
6114 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6117 /* now move the left to the result if they are not the
6120 if (!sameRegs (AOP (left), AOP (result)))
6123 size = AOP_SIZE (result);
6127 l = aopGet (AOP (left), offset, FALSE);
6128 aopPut (AOP (result), l, offset);
6133 tlbl = newiTempLabel (NULL);
6134 size = AOP_SIZE (result);
6136 tlbl1 = newiTempLabel (NULL);
6138 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6141 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6142 emitLabel (tlbl->key + 100);
6143 l = aopGet (AOP (result), offset, FALSE);
6147 l = aopGet (AOP (result), offset, FALSE);
6151 emit2 ("sla %s", l);
6159 emitLabel (tlbl1->key + 100);
6161 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6163 freeAsmop (left, NULL, ic);
6164 freeAsmop (result, NULL, ic);
6167 /*-----------------------------------------------------------------*/
6168 /* genrshOne - left shift two bytes by known amount != 0 */
6169 /*-----------------------------------------------------------------*/
6171 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6174 int size = AOP_SIZE (result);
6177 wassert (size == 1);
6178 wassert (shCount < 8);
6180 l = aopGet (AOP (left), 0, FALSE);
6182 if (AOP (result)->type == AOP_REG)
6184 aopPut (AOP (result), l, 0);
6185 l = aopGet (AOP (result), 0, FALSE);
6188 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6196 emit2 ("%s a", is_signed ? "sra" : "srl");
6198 aopPut (AOP (result), "a", 0);
6202 /*-----------------------------------------------------------------*/
6203 /* AccRsh - right shift accumulator by known count */
6204 /*-----------------------------------------------------------------*/
6206 AccRsh (int shCount)
6208 static const unsigned char SRMask[] =
6210 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6215 /* rotate right accumulator */
6216 AccRol (8 - shCount);
6217 /* and kill the higher order bits */
6218 emit2 ("and a,!immedbyte", SRMask[shCount]);
6222 /*-----------------------------------------------------------------*/
6223 /* shiftR1Left2Result - shift right one byte from left to result */
6224 /*-----------------------------------------------------------------*/
6226 shiftR1Left2Result (operand * left, int offl,
6227 operand * result, int offr,
6228 int shCount, int sign)
6230 _moveA (aopGet (AOP (left), offl, FALSE));
6235 emit2 ("%s a", sign ? "sra" : "srl");
6242 aopPut (AOP (result), "a", offr);
6245 /*-----------------------------------------------------------------*/
6246 /* genrshTwo - right shift two bytes by known amount */
6247 /*-----------------------------------------------------------------*/
6249 genrshTwo (operand * result, operand * left,
6250 int shCount, int sign)
6252 /* if shCount >= 8 */
6258 shiftR1Left2Result (left, MSB16, result, LSB,
6263 movLeft2Result (left, MSB16, result, LSB, sign);
6267 /* Sign extend the result */
6268 _moveA(aopGet (AOP (result), 0, FALSE));
6272 aopPut (AOP (result), ACC_NAME, MSB16);
6276 aopPut (AOP (result), "!zero", 1);
6279 /* 0 <= shCount <= 7 */
6282 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6286 /*-----------------------------------------------------------------*/
6287 /* genRightShiftLiteral - left shifting by known count */
6288 /*-----------------------------------------------------------------*/
6290 genRightShiftLiteral (operand * left,
6296 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6299 freeAsmop (right, NULL, ic);
6301 aopOp (left, ic, FALSE, FALSE);
6302 aopOp (result, ic, FALSE, FALSE);
6304 size = getSize (operandType (result));
6306 /* I suppose that the left size >= result size */
6308 if (shCount >= (size * 8)) {
6310 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6311 _moveA(aopGet (AOP (left), 0, FALSE));
6319 aopPut (AOP (result), s, size);
6326 genrshOne (result, left, shCount, sign);
6329 genrshTwo (result, left, shCount, sign);
6332 wassertl (0, "Asked to shift right a long which should be a function call");
6335 wassertl (0, "Entered default case in right shift delegate");
6338 freeAsmop (left, NULL, ic);
6339 freeAsmop (result, NULL, ic);
6342 /*-----------------------------------------------------------------*/
6343 /* genRightShift - generate code for right shifting */
6344 /*-----------------------------------------------------------------*/
6346 genRightShift (iCode * ic)
6348 operand *right, *left, *result;
6350 int size, offset, first = 1;
6354 symbol *tlbl, *tlbl1;
6356 /* if signed then we do it the hard way preserve the
6357 sign bit moving it inwards */
6358 retype = getSpec (operandType (IC_RESULT (ic)));
6360 is_signed = !SPEC_USIGN (retype);
6362 /* signed & unsigned types are treated the same : i.e. the
6363 signed is NOT propagated inwards : quoting from the
6364 ANSI - standard : "for E1 >> E2, is equivalent to division
6365 by 2**E2 if unsigned or if it has a non-negative value,
6366 otherwise the result is implementation defined ", MY definition
6367 is that the sign does not get propagated */
6369 right = IC_RIGHT (ic);
6370 left = IC_LEFT (ic);
6371 result = IC_RESULT (ic);
6373 aopOp (right, ic, FALSE, FALSE);
6375 /* if the shift count is known then do it
6376 as efficiently as possible */
6377 if (AOP_TYPE (right) == AOP_LIT)
6379 genRightShiftLiteral (left, right, result, ic, is_signed);
6383 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6385 freeAsmop (right, NULL, ic);
6387 aopOp (left, ic, FALSE, FALSE);
6388 aopOp (result, ic, FALSE, FALSE);
6390 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6393 /* now move the left to the result if they are not the
6395 if (!sameRegs (AOP (left), AOP (result)))
6398 size = AOP_SIZE (result);
6402 l = aopGet (AOP (left), offset, FALSE);
6403 aopPut (AOP (result), l, offset);
6408 tlbl = newiTempLabel (NULL);
6409 tlbl1 = newiTempLabel (NULL);
6410 size = AOP_SIZE (result);
6413 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6416 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6417 emitLabel (tlbl->key + 100);
6420 l = aopGet (AOP (result), offset--, FALSE);
6423 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6431 emitLabel (tlbl1->key + 100);
6433 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6435 freeAsmop (left, NULL, ic);
6436 freeAsmop (result, NULL, ic);
6440 /*-----------------------------------------------------------------*/
6441 /* genUnpackBits - generates code for unpacking bits */
6442 /*-----------------------------------------------------------------*/
6444 genUnpackBits (operand * result, int pair)
6446 int offset = 0; /* result byte offset */
6447 int rsize; /* result size */
6448 int rlen = 0; /* remaining bitfield length */
6449 sym_link *etype; /* bitfield type information */
6450 int blen; /* bitfield length */
6451 int bstr; /* bitfield starting bit within byte */
6453 emitDebug ("; genUnpackBits");
6455 etype = getSpec (operandType (result));
6456 rsize = getSize (operandType (result));
6457 blen = SPEC_BLEN (etype);
6458 bstr = SPEC_BSTR (etype);
6460 /* If the bitfield length is less than a byte */
6463 emit2 ("ld a,!*pair", _pairs[pair].name);
6465 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6466 if (!SPEC_USIGN (etype))
6468 /* signed bitfield */
6469 symbol *tlbl = newiTempLabel (NULL);
6471 emit2 ("bit %d,a", blen - 1);
6472 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6473 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6474 emitLabel (tlbl->key + 100);
6476 aopPut (AOP (result), "a", offset++);
6480 /* TODO: what if pair == PAIR_DE ? */
6481 if (getPairId (AOP (result)) == PAIR_HL)
6483 wassertl (rsize == 2, "HL must be of size 2");
6484 emit2 ("ld a,!*hl");
6486 emit2 ("ld h,!*hl");
6489 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6490 if (!SPEC_USIGN (etype))
6492 /* signed bitfield */
6493 symbol *tlbl = newiTempLabel (NULL);
6495 emit2 ("bit %d,a", blen - 1);
6496 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6497 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6498 emitLabel (tlbl->key + 100);
6501 spillPair (PAIR_HL);
6505 /* Bit field did not fit in a byte. Copy all
6506 but the partial byte at the end. */
6507 for (rlen=blen;rlen>=8;rlen-=8)
6509 emit2 ("ld a,!*pair", _pairs[pair].name);
6510 aopPut (AOP (result), "a", offset++);
6513 emit2 ("inc %s", _pairs[pair].name);
6514 _G.pairs[pair].offset++;
6518 /* Handle the partial byte at the end */
6521 emit2 ("ld a,!*pair", _pairs[pair].name);
6522 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6523 if (!SPEC_USIGN (etype))
6525 /* signed bitfield */
6526 symbol *tlbl = newiTempLabel (NULL);
6528 emit2 ("bit %d,a", rlen - 1);
6529 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6530 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6531 emitLabel (tlbl->key + 100);
6533 aopPut (AOP (result), "a", offset++);
6541 if (SPEC_USIGN (etype))
6545 /* signed bitfield: sign extension with 0x00 or 0xff */
6553 aopPut (AOP (result), source, offset++);
6557 /*-----------------------------------------------------------------*/
6558 /* genGenPointerGet - get value from generic pointer space */
6559 /*-----------------------------------------------------------------*/
6561 genGenPointerGet (operand * left,
6562 operand * result, iCode * ic)
6565 sym_link *retype = getSpec (operandType (result));
6571 aopOp (left, ic, FALSE, FALSE);
6572 aopOp (result, ic, FALSE, FALSE);
6574 size = AOP_SIZE (result);
6576 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6579 if (isPtrPair (AOP (left)))
6581 tsprintf (buffer, sizeof(buffer),
6582 "!*pair", getPairName (AOP (left)));
6583 aopPut (AOP (result), buffer, 0);
6587 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6588 aopPut (AOP (result), "a", 0);
6590 freeAsmop (left, NULL, ic);
6594 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6601 tsprintf (at, sizeof(at), "!*iyx", offset);
6602 aopPut (AOP (result), at, offset);
6606 freeAsmop (left, NULL, ic);
6610 /* For now we always load into IY */
6611 /* if this is remateriazable */
6612 fetchPair (pair, AOP (left));
6614 /* if bit then unpack */
6615 if (IS_BITVAR (retype))
6617 genUnpackBits (result, pair);
6618 freeAsmop (left, NULL, ic);
6622 else if (getPairId (AOP (result)) == PAIR_HL)
6624 wassertl (size == 2, "HL must be of size 2");
6625 emit2 ("ld a,!*hl");
6627 emit2 ("ld h,!*hl");
6629 spillPair (PAIR_HL);
6631 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6633 size = AOP_SIZE (result);
6638 /* PENDING: make this better */
6639 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6641 aopPut (AOP (result), "!*hl", offset++);
6645 emit2 ("ld a,!*pair", _pairs[pair].name);
6646 aopPut (AOP (result), "a", offset++);
6650 emit2 ("inc %s", _pairs[pair].name);
6651 _G.pairs[pair].offset++;
6654 /* Fixup HL back down */
6655 for (size = AOP_SIZE (result)-1; size; size--)
6657 emit2 ("dec %s", _pairs[pair].name);
6662 size = AOP_SIZE (result);
6667 /* PENDING: make this better */
6669 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6671 aopPut (AOP (result), "!*hl", offset++);
6675 emit2 ("ld a,!*pair", _pairs[pair].name);
6676 aopPut (AOP (result), "a", offset++);
6680 emit2 ("inc %s", _pairs[pair].name);
6681 _G.pairs[pair].offset++;
6686 freeAsmop (left, NULL, ic);
6689 freeAsmop (result, NULL, ic);
6692 /*-----------------------------------------------------------------*/
6693 /* genPointerGet - generate code for pointer get */
6694 /*-----------------------------------------------------------------*/
6696 genPointerGet (iCode * ic)
6698 operand *left, *result;
6699 sym_link *type, *etype;
6701 left = IC_LEFT (ic);
6702 result = IC_RESULT (ic);
6704 /* depending on the type of pointer we need to
6705 move it to the correct pointer register */
6706 type = operandType (left);
6707 etype = getSpec (type);
6709 genGenPointerGet (left, result, ic);
6713 isRegOrLit (asmop * aop)
6715 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6721 /*-----------------------------------------------------------------*/
6722 /* genPackBits - generates code for packed bit storage */
6723 /*-----------------------------------------------------------------*/
6725 genPackBits (sym_link * etype,
6730 int offset = 0; /* source byte offset */
6731 int rlen = 0; /* remaining bitfield length */
6732 int blen; /* bitfield length */
6733 int bstr; /* bitfield starting bit within byte */
6734 int litval; /* source literal value (if AOP_LIT) */
6735 unsigned char mask; /* bitmask within current byte */
6736 int extraPair; /* a tempory register */
6737 bool needPopExtra=0; /* need to restore original value of temp reg */
6739 emitDebug ("; genPackBits","");
6741 blen = SPEC_BLEN (etype);
6742 bstr = SPEC_BSTR (etype);
6744 /* If the bitfield length is less than a byte */
6747 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6748 (unsigned char) (0xFF >> (8 - bstr)));
6750 if (AOP_TYPE (right) == AOP_LIT)
6752 /* Case with a bitfield length <8 and literal source
6754 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6756 litval &= (~mask) & 0xff;
6757 emit2 ("ld a,!*pair", _pairs[pair].name);
6758 if ((mask|litval)!=0xff)
6759 emit2 ("and a,!immedbyte", mask);
6761 emit2 ("or a,!immedbyte", litval);
6762 emit2 ("ld !*pair,a", _pairs[pair].name);
6767 /* Case with a bitfield length <8 and arbitrary source
6769 _moveA (aopGet (AOP (right), 0, FALSE));
6770 /* shift and mask source value */
6772 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6774 extraPair = getFreePairId(ic);
6775 if (extraPair == PAIR_INVALID)
6777 extraPair = PAIR_BC;
6778 if (getPairId (AOP (right)) != PAIR_BC
6779 || !isLastUse (ic, right))
6785 emit2 ("ld %s,a", _pairs[extraPair].l);
6786 emit2 ("ld a,!*pair", _pairs[pair].name);
6788 emit2 ("and a,!immedbyte", mask);
6789 emit2 ("or a,%s", _pairs[extraPair].l);
6790 emit2 ("ld !*pair,a", _pairs[pair].name);
6797 /* Bit length is greater than 7 bits. In this case, copy */
6798 /* all except the partial byte at the end */
6799 for (rlen=blen;rlen>=8;rlen-=8)
6801 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6802 emit2 ("ld !*pair,a", _pairs[pair].name);
6805 emit2 ("inc %s", _pairs[pair].name);
6806 _G.pairs[pair].offset++;
6810 /* If there was a partial byte at the end */
6813 mask = (((unsigned char) -1 << rlen) & 0xff);
6815 if (AOP_TYPE (right) == AOP_LIT)
6817 /* Case with partial byte and literal source
6819 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6820 litval >>= (blen-rlen);
6821 litval &= (~mask) & 0xff;
6822 emit2 ("ld a,!*pair", _pairs[pair].name);
6823 if ((mask|litval)!=0xff)
6824 emit2 ("and a,!immedbyte", mask);
6826 emit2 ("or a,!immedbyte", litval);
6830 /* Case with partial byte and arbitrary source
6832 _moveA (aopGet (AOP (right), offset++, FALSE));
6833 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6835 extraPair = getFreePairId(ic);
6836 if (extraPair == PAIR_INVALID)
6838 extraPair = getPairId (AOP (right));
6839 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6840 extraPair = PAIR_BC;
6842 if (getPairId (AOP (right)) != PAIR_BC
6843 || !isLastUse (ic, right))
6849 emit2 ("ld %s,a", _pairs[extraPair].l);
6850 emit2 ("ld a,!*pair", _pairs[pair].name);
6852 emit2 ("and a,!immedbyte", mask);
6853 emit2 ("or a,%s", _pairs[extraPair].l);
6858 emit2 ("ld !*pair,a", _pairs[pair].name);
6863 /*-----------------------------------------------------------------*/
6864 /* genGenPointerSet - stores the value into a pointer location */
6865 /*-----------------------------------------------------------------*/
6867 genGenPointerSet (operand * right,
6868 operand * result, iCode * ic)
6871 sym_link *retype = getSpec (operandType (right));
6872 sym_link *letype = getSpec (operandType (result));
6873 PAIR_ID pairId = PAIR_HL;
6876 aopOp (result, ic, FALSE, FALSE);
6877 aopOp (right, ic, FALSE, FALSE);
6882 size = AOP_SIZE (right);
6884 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6885 emitDebug("; isBitvar = %d", isBitvar);
6887 /* Handle the exceptions first */
6888 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6891 const char *l = aopGet (AOP (right), 0, FALSE);
6892 const char *pair = getPairName (AOP (result));
6893 if (canAssignToPtr (l) && isPtr (pair))
6895 emit2 ("ld !*pair,%s", pair, l);
6900 emit2 ("ld !*pair,a", pair);
6905 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6908 const char *l = aopGet (AOP (right), 0, FALSE);
6913 if (canAssignToPtr (l))
6915 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6919 _moveA (aopGet (AOP (right), offset, FALSE));
6920 emit2 ("ld !*iyx,a", offset);
6926 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6933 const char *l = aopGet (AOP (right), offset, FALSE);
6934 if (isRegOrLit (AOP (right)) && !IS_GB)
6936 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6941 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6945 emit2 ("inc %s", _pairs[PAIR_HL].name);
6946 _G.pairs[PAIR_HL].offset++;
6951 /* Fixup HL back down */
6952 for (size = AOP_SIZE (right)-1; size; size--)
6954 emit2 ("dec %s", _pairs[PAIR_HL].name);
6959 /* if the operand is already in dptr
6960 then we do nothing else we move the value to dptr */
6961 if (AOP_TYPE (result) != AOP_STR)
6963 fetchPair (pairId, AOP (result));
6965 /* so hl now contains the address */
6966 freeAsmop (result, NULL, ic);
6968 /* if bit then unpack */
6971 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6981 const char *l = aopGet (AOP (right), offset, FALSE);
6982 if (isRegOrLit (AOP (right)) && !IS_GB)
6984 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6989 emit2 ("ld !*pair,a", _pairs[pairId].name);
6993 emit2 ("inc %s", _pairs[pairId].name);
6994 _G.pairs[pairId].offset++;
7000 freeAsmop (right, NULL, ic);
7003 /*-----------------------------------------------------------------*/
7004 /* genPointerSet - stores the value into a pointer location */
7005 /*-----------------------------------------------------------------*/
7007 genPointerSet (iCode * ic)
7009 operand *right, *result;
7010 sym_link *type, *etype;
7012 right = IC_RIGHT (ic);
7013 result = IC_RESULT (ic);
7015 /* depending on the type of pointer we need to
7016 move it to the correct pointer register */
7017 type = operandType (result);
7018 etype = getSpec (type);
7020 genGenPointerSet (right, result, ic);
7023 /*-----------------------------------------------------------------*/
7024 /* genIfx - generate code for Ifx statement */
7025 /*-----------------------------------------------------------------*/
7027 genIfx (iCode * ic, iCode * popIc)
7029 operand *cond = IC_COND (ic);
7032 aopOp (cond, ic, FALSE, TRUE);
7034 /* get the value into acc */
7035 if (AOP_TYPE (cond) != AOP_CRY)
7039 /* the result is now in the accumulator */
7040 freeAsmop (cond, NULL, ic);
7042 /* if there was something to be popped then do it */
7046 /* if the condition is a bit variable */
7047 if (isbit && IS_ITEMP (cond) &&
7049 genIfxJump (ic, SPIL_LOC (cond)->rname);
7050 else if (isbit && !IS_ITEMP (cond))
7051 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7053 genIfxJump (ic, "a");
7058 /*-----------------------------------------------------------------*/
7059 /* genAddrOf - generates code for address of */
7060 /*-----------------------------------------------------------------*/
7062 genAddrOf (iCode * ic)
7064 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7066 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7068 /* if the operand is on the stack then we
7069 need to get the stack offset of this
7076 if (sym->stack <= 0)
7078 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7082 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7084 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7088 emit2 ("ld de,!hashedstr", sym->rname);
7089 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7097 /* if it has an offset then we need to compute it */
7099 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7101 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7102 emit2 ("add hl,sp");
7106 emit2 ("ld hl,!hashedstr", sym->rname);
7108 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7110 freeAsmop (IC_RESULT (ic), NULL, ic);
7113 /*-----------------------------------------------------------------*/
7114 /* genAssign - generate code for assignment */
7115 /*-----------------------------------------------------------------*/
7117 genAssign (iCode * ic)
7119 operand *result, *right;
7121 unsigned long lit = 0L;
7123 result = IC_RESULT (ic);
7124 right = IC_RIGHT (ic);
7126 /* Dont bother assigning if they are the same */
7127 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7129 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7133 aopOp (right, ic, FALSE, FALSE);
7134 aopOp (result, ic, TRUE, FALSE);
7136 /* if they are the same registers */
7137 if (sameRegs (AOP (right), AOP (result)))
7139 emitDebug ("; (registers are the same)");
7143 /* if the result is a bit */
7144 if (AOP_TYPE (result) == AOP_CRY)
7146 wassertl (0, "Tried to assign to a bit");
7150 size = AOP_SIZE (result);
7153 if (AOP_TYPE (right) == AOP_LIT)
7155 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7158 if (isPair (AOP (result)))
7160 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7162 else if ((size > 1) &&
7163 (AOP_TYPE (result) != AOP_REG) &&
7164 (AOP_TYPE (right) == AOP_LIT) &&
7165 !IS_FLOAT (operandType (right)) &&
7168 bool fXored = FALSE;
7170 /* Work from the top down.
7171 Done this way so that we can use the cached copy of 0
7172 in A for a fast clear */
7175 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7177 if (!fXored && size > 1)
7184 aopPut (AOP (result), "a", offset);
7188 aopPut (AOP (result), "!zero", offset);
7192 aopPut (AOP (result),
7193 aopGet (AOP (right), offset, FALSE),
7198 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7200 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7201 aopPut (AOP (result), "l", LSB);
7202 aopPut (AOP (result), "h", MSB16);
7204 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7206 /* Special case. Load into a and d, then load out. */
7207 _moveA (aopGet (AOP (right), 0, FALSE));
7208 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7209 aopPut (AOP (result), "a", 0);
7210 aopPut (AOP (result), "e", 1);
7212 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7214 /* Special case - simple memcpy */
7215 aopGet (AOP (right), LSB, FALSE);
7218 aopGet (AOP (result), LSB, FALSE);
7222 emit2 ("ld a,(de)");
7223 /* Peephole will optimise this. */
7224 emit2 ("ld (hl),a");
7232 spillPair (PAIR_HL);
7238 /* PENDING: do this check better */
7239 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7241 _moveA (aopGet (AOP (right), offset, FALSE));
7242 aopPut (AOP (result), "a", offset);
7245 aopPut (AOP (result),
7246 aopGet (AOP (right), offset, FALSE),
7253 freeAsmop (right, NULL, ic);
7254 freeAsmop (result, NULL, ic);
7257 /*-----------------------------------------------------------------*/
7258 /* genJumpTab - genrates code for jump table */
7259 /*-----------------------------------------------------------------*/
7261 genJumpTab (iCode * ic)
7266 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7267 /* get the condition into accumulator */
7268 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7271 emit2 ("ld e,%s", l);
7272 emit2 ("ld d,!zero");
7273 jtab = newiTempLabel (NULL);
7275 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7276 emit2 ("add hl,de");
7277 emit2 ("add hl,de");
7278 emit2 ("add hl,de");
7279 freeAsmop (IC_JTCOND (ic), NULL, ic);
7283 emitLabel (jtab->key + 100);
7284 /* now generate the jump labels */
7285 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7286 jtab = setNextItem (IC_JTLABELS (ic)))
7287 emit2 ("jp !tlabel", jtab->key + 100);
7290 /*-----------------------------------------------------------------*/
7291 /* genCast - gen code for casting */
7292 /*-----------------------------------------------------------------*/
7294 genCast (iCode * ic)
7296 operand *result = IC_RESULT (ic);
7297 sym_link *rtype = operandType (IC_RIGHT (ic));
7298 operand *right = IC_RIGHT (ic);
7301 /* if they are equivalent then do nothing */
7302 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7305 aopOp (right, ic, FALSE, FALSE);
7306 aopOp (result, ic, FALSE, FALSE);
7308 /* if the result is a bit */
7309 if (AOP_TYPE (result) == AOP_CRY)
7311 wassertl (0, "Tried to cast to a bit");
7314 /* if they are the same size : or less */
7315 if (AOP_SIZE (result) <= AOP_SIZE (right))
7318 /* if they are in the same place */
7319 if (sameRegs (AOP (right), AOP (result)))
7322 /* if they in different places then copy */
7323 size = AOP_SIZE (result);
7327 aopPut (AOP (result),
7328 aopGet (AOP (right), offset, FALSE),
7335 /* So we now know that the size of destination is greater
7336 than the size of the source */
7337 /* we move to result for the size of source */
7338 size = AOP_SIZE (right);
7342 aopPut (AOP (result),
7343 aopGet (AOP (right), offset, FALSE),
7348 /* now depending on the sign of the destination */
7349 size = AOP_SIZE (result) - AOP_SIZE (right);
7350 /* Unsigned or not an integral type - right fill with zeros */
7351 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7354 aopPut (AOP (result), "!zero", offset++);
7358 /* we need to extend the sign :{ */
7359 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7365 aopPut (AOP (result), "a", offset++);
7369 freeAsmop (right, NULL, ic);
7370 freeAsmop (result, NULL, ic);
7373 /*-----------------------------------------------------------------*/
7374 /* genReceive - generate code for a receive iCode */
7375 /*-----------------------------------------------------------------*/
7377 genReceive (iCode * ic)
7379 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7380 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7381 IS_TRUE_SYMOP (IC_RESULT (ic))))
7391 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7392 size = AOP_SIZE(IC_RESULT(ic));
7394 for (i = 0; i < size; i++) {
7395 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7399 freeAsmop (IC_RESULT (ic), NULL, ic);
7402 /*-----------------------------------------------------------------*/
7403 /* genDummyRead - generate code for dummy read of volatiles */
7404 /*-----------------------------------------------------------------*/
7406 genDummyRead (iCode * ic)
7412 if (op && IS_SYMOP (op))
7414 aopOp (op, ic, FALSE, FALSE);
7417 size = AOP_SIZE (op);
7422 _moveA (aopGet (AOP (op), offset, FALSE));
7426 freeAsmop (op, NULL, ic);
7430 if (op && IS_SYMOP (op))
7432 aopOp (op, ic, FALSE, FALSE);
7435 size = AOP_SIZE (op);
7440 _moveA (aopGet (AOP (op), offset, FALSE));
7444 freeAsmop (op, NULL, ic);
7448 /*-----------------------------------------------------------------*/
7449 /* genCritical - generate code for start of a critical sequence */
7450 /*-----------------------------------------------------------------*/
7452 genCritical (iCode *ic)
7454 symbol *tlbl = newiTempLabel (NULL);
7460 else if (IC_RESULT (ic))
7462 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7463 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7464 //get interrupt enable flag IFF2 into P/O
7468 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7469 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7470 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7471 emit2 ("!tlabeldef", (tlbl->key + 100));
7472 freeAsmop (IC_RESULT (ic), NULL, ic);
7476 //get interrupt enable flag IFF2 into P/O
7485 /*-----------------------------------------------------------------*/
7486 /* genEndCritical - generate code for end of a critical sequence */
7487 /*-----------------------------------------------------------------*/
7489 genEndCritical (iCode *ic)
7491 symbol *tlbl = newiTempLabel (NULL);
7497 else if (IC_RIGHT (ic))
7499 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7500 _toBoolean (IC_RIGHT (ic));
7501 //don't enable interrupts if they were off before
7502 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7504 emitLabel (tlbl->key + 100);
7505 freeAsmop (IC_RIGHT (ic), NULL, ic);
7511 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7512 //don't enable interrupts as they were off before
7513 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7515 emit2 ("!tlabeldef", (tlbl->key + 100));
7521 /** Maximum number of bytes to emit per line. */
7525 /** Context for the byte output chunker. */
7528 unsigned char buffer[DBEMIT_MAX_RUN];
7533 /** Flushes a byte chunker by writing out all in the buffer and
7537 _dbFlush(DBEMITCTX *self)
7544 sprintf(line, ".db 0x%02X", self->buffer[0]);
7546 for (i = 1; i < self->pos; i++)
7548 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7555 /** Write out another byte, buffering until a decent line is
7559 _dbEmit(DBEMITCTX *self, int c)
7561 if (self->pos == DBEMIT_MAX_RUN)
7565 self->buffer[self->pos++] = c;
7568 /** Context for a simple run length encoder. */
7572 unsigned char buffer[128];
7574 /** runLen may be equivalent to pos. */
7580 RLE_CHANGE_COST = 4,
7584 /** Flush the buffer of a run length encoder by writing out the run or
7585 data that it currently contains.
7588 _rleCommit(RLECTX *self)
7594 memset(&db, 0, sizeof(db));
7596 emit2(".db %u", self->pos);
7598 for (i = 0; i < self->pos; i++)
7600 _dbEmit(&db, self->buffer[i]);
7609 Can get either a run or a block of random stuff.
7610 Only want to change state if a good run comes in or a run ends.
7611 Detecting run end is easy.
7614 Say initial state is in run, len zero, last zero. Then if you get a
7615 few zeros then something else then a short run will be output.
7616 Seems OK. While in run mode, keep counting. While in random mode,
7617 keep a count of the run. If run hits margin, output all up to run,
7618 restart, enter run mode.
7621 /** Add another byte into the run length encoder, flushing as
7622 required. The run length encoder uses the Amiga IFF style, where
7623 a block is prefixed by its run length. A positive length means
7624 the next n bytes pass straight through. A negative length means
7625 that the next byte is repeated -n times. A zero terminates the
7629 _rleAppend(RLECTX *self, unsigned c)
7633 if (c != self->last)
7635 /* The run has stopped. See if it is worthwhile writing it out
7636 as a run. Note that the random data comes in as runs of
7639 if (self->runLen > RLE_CHANGE_COST)
7641 /* Yes, worthwhile. */
7642 /* Commit whatever was in the buffer. */
7644 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7648 /* Not worthwhile. Append to the end of the random list. */
7649 for (i = 0; i < self->runLen; i++)
7651 if (self->pos >= RLE_MAX_BLOCK)
7656 self->buffer[self->pos++] = self->last;
7664 if (self->runLen >= RLE_MAX_BLOCK)
7666 /* Commit whatever was in the buffer. */
7669 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7677 _rleFlush(RLECTX *self)
7679 _rleAppend(self, -1);
7686 /** genArrayInit - Special code for initialising an array with constant
7690 genArrayInit (iCode * ic)
7694 int elementSize = 0, eIndex, i;
7695 unsigned val, lastVal;
7699 memset(&rle, 0, sizeof(rle));
7701 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7703 _saveRegsForCall(ic, 0);
7705 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7706 emit2 ("call __initrleblock");
7708 type = operandType(IC_LEFT(ic));
7710 if (type && type->next)
7712 if (IS_SPEC(type->next) || IS_PTR(type->next))
7714 elementSize = getSize(type->next);
7716 else if (IS_ARRAY(type->next) && type->next->next)
7718 elementSize = getSize(type->next->next);
7722 printTypeChainRaw (type, NULL);
7723 wassertl (0, "Can't determine element size in genArrayInit.");
7728 wassertl (0, "Can't determine element size in genArrayInit.");
7731 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7733 iLoop = IC_ARRAYILIST(ic);
7734 lastVal = (unsigned)-1;
7736 /* Feed all the bytes into the run length encoder which will handle
7738 This works well for mixed char data, and for random int and long
7745 for (i = 0; i < ix; i++)
7747 for (eIndex = 0; eIndex < elementSize; eIndex++)
7749 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7750 _rleAppend(&rle, val);
7754 iLoop = iLoop->next;
7758 /* Mark the end of the run. */
7761 _restoreRegsAfterCall();
7765 freeAsmop (IC_LEFT(ic), NULL, ic);
7769 _swap (PAIR_ID one, PAIR_ID two)
7771 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7777 emit2 ("ld a,%s", _pairs[one].l);
7778 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7779 emit2 ("ld %s,a", _pairs[two].l);
7780 emit2 ("ld a,%s", _pairs[one].h);
7781 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7782 emit2 ("ld %s,a", _pairs[two].h);
7786 /* The problem is that we may have all three pairs used and they may
7787 be needed in a different order.
7792 hl = hl => unity, fine
7796 hl = hl hl = hl, swap de <=> bc
7804 hl = bc de = de, swap bc <=> hl
7812 hl = de bc = bc, swap hl <=> de
7817 * Any pair = pair are done last
7818 * Any pair = iTemp are done last
7819 * Any swaps can be done any time
7827 So how do we detect the cases?
7828 How about a 3x3 matrix?
7832 x x x x (Fourth for iTemp/other)
7834 First determin which mode to use by counting the number of unity and
7837 Two - Assign the pair first, then the rest
7838 One - Swap the two, then the rest
7842 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7844 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7846 PAIR_BC, PAIR_HL, PAIR_DE
7848 int i, j, nunity = 0;
7849 memset (ids, PAIR_INVALID, sizeof (ids));
7852 wassert (nparams == 3);
7854 /* First save everything that needs to be saved. */
7855 _saveRegsForCall (ic, 0);
7857 /* Loading HL first means that DE is always fine. */
7858 for (i = 0; i < nparams; i++)
7860 aopOp (pparams[i], ic, FALSE, FALSE);
7861 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7864 /* Count the number of unity or iTemp assigns. */
7865 for (i = 0; i < 3; i++)
7867 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7875 /* Any order, fall through. */
7877 else if (nunity == 2)
7879 /* One is assigned. Pull it out and assign. */
7880 for (i = 0; i < 3; i++)
7882 for (j = 0; j < NUM_PAIRS; j++)
7884 if (ids[dest[i]][j] == TRUE)
7886 /* Found it. See if it's the right one. */
7887 if (j == PAIR_INVALID || j == dest[i])
7893 fetchPair(dest[i], AOP (pparams[i]));
7900 else if (nunity == 1)
7902 /* Find the pairs to swap. */
7903 for (i = 0; i < 3; i++)
7905 for (j = 0; j < NUM_PAIRS; j++)
7907 if (ids[dest[i]][j] == TRUE)
7909 if (j == PAIR_INVALID || j == dest[i])
7924 int next = getPairId (AOP (pparams[0]));
7925 emit2 ("push %s", _pairs[next].name);
7927 if (next == dest[1])
7929 fetchPair (dest[1], AOP (pparams[1]));
7930 fetchPair (dest[2], AOP (pparams[2]));
7934 fetchPair (dest[2], AOP (pparams[2]));
7935 fetchPair (dest[1], AOP (pparams[1]));
7937 emit2 ("pop %s", _pairs[dest[0]].name);
7940 /* Finally pull out all of the iTemps */
7941 for (i = 0; i < 3; i++)
7943 if (ids[dest[i]][PAIR_INVALID] == 1)
7945 fetchPair (dest[i], AOP (pparams[i]));
7951 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7957 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7961 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7963 setupForBuiltin3 (ic, nParams, pparams);
7965 label = newiTempLabel(NULL);
7967 emitLabel (label->key);
7968 emit2 ("ld a,(hl)");
7971 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
7973 freeAsmop (from, NULL, ic->next);
7974 freeAsmop (to, NULL, ic);
7978 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7980 operand *from, *to, *count;
7983 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7988 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7990 setupForBuiltin3 (ic, nParams, pparams);
7994 freeAsmop (count, NULL, ic->next->next);
7995 freeAsmop (from, NULL, ic);
7997 _restoreRegsAfterCall();
7999 /* if we need assign a result value */
8000 if ((IS_ITEMP (IC_RESULT (ic)) &&
8001 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8002 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8003 IS_TRUE_SYMOP (IC_RESULT (ic)))
8005 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8006 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8007 freeAsmop (IC_RESULT (ic), NULL, ic);
8010 freeAsmop (to, NULL, ic->next);
8013 /*-----------------------------------------------------------------*/
8014 /* genBuiltIn - calls the appropriate function to generating code */
8015 /* for a built in function */
8016 /*-----------------------------------------------------------------*/
8017 static void genBuiltIn (iCode *ic)
8019 operand *bi_parms[MAX_BUILTIN_ARGS];
8024 /* get all the arguments for a built in function */
8025 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8027 /* which function is it */
8028 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8030 if (strcmp(bif->name,"__builtin_strcpy")==0)
8032 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8034 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8036 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8040 wassertl (0, "Unknown builtin function encountered");
8044 /*-----------------------------------------------------------------*/
8045 /* genZ80Code - generate code for Z80 based controllers */
8046 /*-----------------------------------------------------------------*/
8048 genZ80Code (iCode * lic)
8056 _fReturn = _gbz80_return;
8057 _fTmp = _gbz80_return;
8061 _fReturn = _z80_return;
8062 _fTmp = _z80_return;
8065 _G.lines.head = _G.lines.current = NULL;
8067 /* if debug information required */
8068 if (options.debug && currFunc)
8070 debugFile->writeFunction (currFunc, lic);
8073 for (ic = lic; ic; ic = ic->next)
8075 _G.current_iCode = ic;
8077 if (ic->lineno && cln != ic->lineno)
8081 debugFile->writeCLine (ic);
8083 if (!options.noCcodeInAsm)
8085 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8086 printCLine(ic->filename, ic->lineno));
8090 if (options.iCodeInAsm)
8092 emit2 (";ic:%d: %s", ic->key, printILine(ic));
8094 /* if the result is marked as
8095 spilt and rematerializable or code for
8096 this has already been generated then
8098 if (resultRemat (ic) || ic->generated)
8101 /* depending on the operation */
8105 emitDebug ("; genNot");
8110 emitDebug ("; genCpl");
8115 emitDebug ("; genUminus");
8120 emitDebug ("; genIpush");
8125 /* IPOP happens only when trying to restore a
8126 spilt live range, if there is an ifx statement
8127 following this pop then the if statement might
8128 be using some of the registers being popped which
8129 would destory the contents of the register so
8130 we need to check for this condition and handle it */
8132 ic->next->op == IFX &&
8133 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8135 emitDebug ("; genIfx");
8136 genIfx (ic->next, ic);
8140 emitDebug ("; genIpop");
8146 emitDebug ("; genCall");
8151 emitDebug ("; genPcall");
8156 emitDebug ("; genFunction");
8161 emitDebug ("; genEndFunction");
8162 genEndFunction (ic);
8166 emitDebug ("; genRet");
8171 emitDebug ("; genLabel");
8176 emitDebug ("; genGoto");
8181 emitDebug ("; genPlus");
8186 emitDebug ("; genMinus");
8191 emitDebug ("; genMult");
8196 emitDebug ("; genDiv");
8201 emitDebug ("; genMod");
8206 emitDebug ("; genCmpGt");
8207 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8211 emitDebug ("; genCmpLt");
8212 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8219 /* note these two are xlated by algebraic equivalence
8220 during parsing SDCC.y */
8221 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8222 "got '>=' or '<=' shouldn't have come here");
8226 emitDebug ("; genCmpEq");
8227 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8231 emitDebug ("; genAndOp");
8236 emitDebug ("; genOrOp");
8241 emitDebug ("; genXor");
8242 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8246 emitDebug ("; genOr");
8247 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8251 emitDebug ("; genAnd");
8252 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8256 emitDebug ("; genInline");
8261 emitDebug ("; genRRC");
8266 emitDebug ("; genRLC");
8271 emitDebug ("; genGetHBIT");
8276 emitDebug ("; genLeftShift");
8281 emitDebug ("; genRightShift");
8285 case GET_VALUE_AT_ADDRESS:
8286 emitDebug ("; genPointerGet");
8292 if (POINTER_SET (ic))
8294 emitDebug ("; genAssign (pointer)");
8299 emitDebug ("; genAssign");
8305 emitDebug ("; genIfx");
8310 emitDebug ("; genAddrOf");
8315 emitDebug ("; genJumpTab");
8320 emitDebug ("; genCast");
8325 emitDebug ("; genReceive");
8330 if (ic->builtinSEND)
8332 emitDebug ("; genBuiltIn");
8337 emitDebug ("; addSet");
8338 addSet (&_G.sendSet, ic);
8343 emitDebug ("; genArrayInit");
8347 case DUMMY_READ_VOLATILE:
8348 emitDebug ("; genDummyRead");
8353 emitDebug ("; genCritical");
8358 emitDebug ("; genEndCritical");
8359 genEndCritical (ic);
8368 /* now we are ready to call the
8369 peep hole optimizer */
8370 if (!options.nopeep)
8371 peepHole (&_G.lines.head);
8373 /* This is unfortunate */
8374 /* now do the actual printing */
8376 FILE *fp = codeOutFile;
8377 if (isInHome () && codeOutFile == code->oFile)
8378 codeOutFile = home->oFile;
8379 printLine (_G.lines.head, codeOutFile);
8380 if (_G.flushStatics)
8383 _G.flushStatics = 0;
8388 freeTrace(&_G.lines.trace);
8389 freeTrace(&_G.trace.aops);
8395 _isPairUsed (iCode * ic, PAIR_ID pairId)
8401 if (bitVectBitValue (ic->rMask, D_IDX))
8403 if (bitVectBitValue (ic->rMask, E_IDX))
8413 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8416 value *val = aop->aopu.aop_lit;
8418 wassert (aop->type == AOP_LIT);
8419 wassert (!IS_FLOAT (val->type));
8421 v = (unsigned long) floatFromVal (val);
8429 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8430 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));