1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
91 #include "SDCCglobl.h"
92 #include "SDCCpeeph.h"
97 /* This is the down and dirty file with all kinds of kludgy & hacky
98 stuff. This is what it is all about CODE GENERATION for a specific MCU.
99 Some of the routines may be reusable, will have to see */
101 /* Z80 calling convention description.
102 Parameters are passed right to left. As the stack grows downwards,
103 the parameters are arranged in left to right in memory.
104 Parameters may be passed in the HL and DE registers with one
106 PENDING: What if the parameter is a long?
107 Everything is caller saves. i.e. the caller must save any registers
108 that it wants to preserve over the call.
109 GB: The return value is returned in DEHL. DE is normally used as a
110 working register pair. Caller saves allows it to be used for a
112 va args functions do not use register parameters. All arguments
113 are passed on the stack.
114 IX is used as an index register to the top of the local variable
115 area. ix-0 is the top most local variable.
120 /* Set to enable debugging trace statements in the output assembly code. */
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129 { "c", "b", "e", "d" };
131 static char **_fReturn;
134 extern struct dbuf_s *codeOutBuf;
142 /** Enum covering all the possible register pairs.
161 } _pairs[NUM_PAIRS] = {
162 { "??1", "?2", "?3" },
167 { "iy", "iyl", "iyh" },
168 { "ix", "ixl", "ixh" }
172 #define ACC_NAME _pairs[PAIR_AF].h
182 /** Code generator persistent data.
186 /** Used to optimised setting up of a pair by remebering what it
187 contains and adjusting instead of reloading where possible.
216 const char *lastFunctionName;
217 iCode *current_iCode;
224 /** TRUE if the registers have already been saved. */
243 static const char *aopGet (asmop * aop, int offset, bool bit16);
245 static const char *aopNames[] = {
266 isLastUse (iCode *ic, operand *op)
268 bitVect *uses = bitVectCopy (OP_USES (op));
270 while (!bitVectIsZero (uses))
272 if (bitVectFirstBit (uses) == ic->key)
274 if (bitVectnBitsOn (uses) == 1)
283 bitVectUnSetBit (uses, bitVectFirstBit (uses));
303 _getTempPairName(void)
305 return _pairs[_getTempPairId()].name;
309 isPairInUse (PAIR_ID id, iCode *ic)
313 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
315 else if (id == PAIR_BC)
317 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
321 wassertl (0, "Only implemented for DE and BC");
327 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
331 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
335 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
339 wassertl (0, "Only implemented for DE");
345 getFreePairId (iCode *ic)
347 if (!isPairInUse (PAIR_BC, ic))
351 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
364 /* Clean up the line so that it is 'prettier' */
365 if (strchr (buf, ':'))
367 /* Is a label - cant do anything */
370 /* Change the first (and probably only) ' ' to a tab so
385 _newLineNode (const char *line)
389 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
390 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
396 _vemit2 (const char *szFormat, va_list ap)
401 dbuf_init(&dbuf, INITIAL_INLINEASM);
403 dbuf_tvprintf (&dbuf, szFormat, ap);
405 buffer = dbuf_c_str(&dbuf);
407 _tidyUp ((char *)buffer);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
413 _G.lines.current->isDebug = _G.lines.isDebug;
414 _G.lines.current->ic = _G.current_iCode;
415 _G.lines.current->isComment = (*buffer == ';');
421 emit2 (const char *szFormat,...)
425 va_start (ap, szFormat);
427 _vemit2 (szFormat, ap);
433 emitDebug (const char *szFormat,...)
439 va_start (ap, szFormat);
441 _vemit2 (szFormat, ap);
447 /*-----------------------------------------------------------------*/
448 /* z80_emitDebuggerSymbol - associate the current code location */
449 /* with a debugger symbol */
450 /*-----------------------------------------------------------------*/
452 z80_emitDebuggerSymbol (char * debugSym)
454 _G.lines.isDebug = 1;
455 emit2 ("%s !equ .", debugSym);
456 emit2 ("!global", debugSym);
457 _G.lines.isDebug = 0;
460 /*-----------------------------------------------------------------*/
461 /* emit2 - writes the code into a file : for now it is simple */
462 /*-----------------------------------------------------------------*/
464 _emit2 (const char *inst, const char *fmt,...)
467 char lb[INITIAL_INLINEASM];
474 sprintf (lb, "%s\t", inst);
475 vsprintf (lb + (strlen (lb)), fmt, ap);
478 vsprintf (lb, fmt, ap);
480 while (isspace (*lbp))
485 _G.lines.current = (_G.lines.current ?
486 connectLine (_G.lines.current, _newLineNode (lb)) :
487 (_G.lines.head = _newLineNode (lb)));
489 _G.lines.current->isInline = _G.lines.isInline;
490 _G.lines.current->ic = _G.current_iCode;
495 _emitMove(const char *to, const char *from)
497 if (STRCASECMP(to, from) != 0)
499 emit2("ld %s,%s", to, from);
504 // Could leave this to the peephole, but sometimes the peephole is inhibited.
509 aopDump(const char *plabel, asmop *aop)
515 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
520 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
523 for (i=aop->size-1;i>=0;i--)
524 *rbp++ = *(aop->aopu.aop_reg[i]->name);
526 emitDebug("; reg = %s", regbuf);
529 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
532 /* No information. */
538 _moveA(const char *moveFrom)
540 // Let the peephole optimiser take care of redundent loads
541 _emitMove(ACC_NAME, moveFrom);
551 getPairName (asmop * aop)
553 if (aop->type == AOP_REG)
555 switch (aop->aopu.aop_reg[0]->rIdx)
568 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
571 for (i = 0; i < NUM_PAIRS; i++)
573 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
575 return _pairs[i].name;
579 wassertl (0, "Tried to get the pair name of something that isn't a pair");
584 getPairId (asmop * aop)
588 if (aop->type == AOP_REG)
590 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
594 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
598 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
603 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
606 for (i = 0; i < NUM_PAIRS; i++)
608 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
618 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
622 return (getPairId (aop) != PAIR_INVALID);
625 /** Returns TRUE if the registers used in aop cannot be split into high
628 isUnsplitable (asmop * aop)
630 switch (getPairId (aop))
642 isPtrPair (asmop * aop)
644 PAIR_ID pairId = getPairId (aop);
657 spillPair (PAIR_ID pairId)
659 _G.pairs[pairId].last_type = AOP_INVALID;
660 _G.pairs[pairId].base = NULL;
663 /* Given a register name, spill the pair (if any) the register is part of */
665 spillPairReg (const char *regname)
667 if (strlen(regname)==1)
687 /** Push a register pair onto the stack */
689 genPairPush (asmop * aop)
691 emit2 ("push %s", getPairName (aop));
695 _push (PAIR_ID pairId)
697 emit2 ("push %s", _pairs[pairId].name);
698 _G.stack.pushed += 2;
702 _pop (PAIR_ID pairId)
704 emit2 ("pop %s", _pairs[pairId].name);
705 _G.stack.pushed -= 2;
710 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
723 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
730 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
731 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
734 wassertl (0, "Tried to move a nonphysical pair");
736 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
737 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
738 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
742 /*-----------------------------------------------------------------*/
743 /* newAsmop - creates a new asmOp */
744 /*-----------------------------------------------------------------*/
746 newAsmop (short type)
750 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
755 /*-----------------------------------------------------------------*/
756 /* aopForSym - for a true symbol */
757 /*-----------------------------------------------------------------*/
759 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
766 wassert (sym->etype);
768 space = SPEC_OCLS (sym->etype);
770 /* if already has one */
776 /* Assign depending on the storage class */
777 if (sym->onStack || sym->iaccess)
779 /* The pointer that is used depends on how big the offset is.
780 Normally everything is AOP_STK, but for offsets of < -128 or
781 > 127 on the Z80 an extended stack pointer is used.
783 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
785 emitDebug ("; AOP_EXSTK for %s", sym->rname);
786 sym->aop = aop = newAsmop (AOP_EXSTK);
790 emitDebug ("; AOP_STK for %s", sym->rname);
791 sym->aop = aop = newAsmop (AOP_STK);
794 aop->size = getSize (sym->type);
795 aop->aopu.aop_stk = sym->stack;
799 /* special case for a function */
800 if (IS_FUNC (sym->type))
802 sym->aop = aop = newAsmop (AOP_IMMD);
803 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
808 if( IN_REGSP( space ))
809 { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
812 /* if it is in direct space */
815 sym->aop = aop = newAsmop (AOP_SFR);
816 aop->aopu.aop_dir = sym->rname;
817 aop->size = getSize (sym->type);
818 emitDebug ("; AOP_SFR for %s", sym->rname);
823 { /*.p.t.20030716 adding SFR support to the Z80 port */
824 aop = newAsmop (AOP_SFR);
826 aop->aopu.aop_dir = sym->rname;
827 aop->size = getSize( sym->type );
828 aop->paged = FUNC_REGBANK(sym->type);
829 aop->bcInUse = isPairInUse( PAIR_BC, ic );
830 aop->deInUse = isPairInUse( PAIR_DE, ic );
831 emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
837 /* only remaining is far space */
838 /* in which case DPTR gets the address */
841 emitDebug ("; AOP_HL for %s", sym->rname);
842 sym->aop = aop = newAsmop (AOP_HL);
846 sym->aop = aop = newAsmop (AOP_IY);
848 aop->size = getSize (sym->type);
849 aop->aopu.aop_dir = sym->rname;
851 /* if it is in code space */
852 if (IN_CODESPACE (space))
858 /*-----------------------------------------------------------------*/
859 /* aopForRemat - rematerialzes an object */
860 /*-----------------------------------------------------------------*/
862 aopForRemat (symbol * sym)
865 iCode *ic = sym->rematiCode;
866 asmop *aop = newAsmop (AOP_IMMD);
870 /* if plus or minus print the right hand side */
871 if (ic->op == '+' || ic->op == '-')
873 /* PENDING: for re-target */
874 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
877 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
880 /* we reached the end */
881 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
885 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
889 /*-----------------------------------------------------------------*/
890 /* regsInCommon - two operands have some registers in common */
891 /*-----------------------------------------------------------------*/
893 regsInCommon (operand * op1, operand * op2)
898 /* if they have registers in common */
899 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
902 sym1 = OP_SYMBOL (op1);
903 sym2 = OP_SYMBOL (op2);
905 if (sym1->nRegs == 0 || sym2->nRegs == 0)
908 for (i = 0; i < sym1->nRegs; i++)
914 for (j = 0; j < sym2->nRegs; j++)
919 if (sym2->regs[j] == sym1->regs[i])
927 /*-----------------------------------------------------------------*/
928 /* operandsEqu - equivalent */
929 /*-----------------------------------------------------------------*/
931 operandsEqu (operand * op1, operand * op2)
935 /* if they not symbols */
936 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
939 sym1 = OP_SYMBOL (op1);
940 sym2 = OP_SYMBOL (op2);
942 /* if both are itemps & one is spilt
943 and the other is not then false */
944 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
945 sym1->isspilt != sym2->isspilt)
948 /* if they are the same */
952 if (sym1->rname[0] && sym2->rname[0]
953 && strcmp (sym1->rname, sym2->rname) == 0)
956 /* if left is a tmp & right is not */
957 if (IS_ITEMP (op1) &&
960 (sym1->usl.spillLoc == sym2))
963 if (IS_ITEMP (op2) &&
967 (sym2->usl.spillLoc == sym1))
973 /*-----------------------------------------------------------------*/
974 /* sameRegs - two asmops have the same registers */
975 /*-----------------------------------------------------------------*/
977 sameRegs (asmop * aop1, asmop * aop2)
981 if (aop1->type == AOP_SFR ||
982 aop2->type == AOP_SFR)
988 if (aop1->type != AOP_REG ||
989 aop2->type != AOP_REG)
992 if (aop1->size != aop2->size)
995 for (i = 0; i < aop1->size; i++)
996 if (aop1->aopu.aop_reg[i] !=
997 aop2->aopu.aop_reg[i])
1003 /*-----------------------------------------------------------------*/
1004 /* aopOp - allocates an asmop for an operand : */
1005 /*-----------------------------------------------------------------*/
1007 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1016 /* if this a literal */
1017 if (IS_OP_LITERAL (op))
1019 op->aop = aop = newAsmop (AOP_LIT);
1020 aop->aopu.aop_lit = op->operand.valOperand;
1021 aop->size = getSize (operandType (op));
1025 /* if already has a asmop then continue */
1028 if (op->aop->type == AOP_SFR)
1030 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1031 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1036 /* if the underlying symbol has a aop */
1037 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1039 op->aop = OP_SYMBOL (op)->aop;
1040 if (op->aop->type == AOP_SFR)
1042 op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1043 op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1048 /* if this is a true symbol */
1049 if (IS_TRUE_SYMOP (op))
1051 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1055 /* this is a temporary : this has
1061 e) can be a return use only */
1063 sym = OP_SYMBOL (op);
1065 /* if the type is a conditional */
1066 if (sym->regType == REG_CND)
1068 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1073 /* if it is spilt then two situations
1075 b) has a spill location */
1076 if (sym->isspilt || sym->nRegs == 0)
1078 /* rematerialize it NOW */
1081 sym->aop = op->aop = aop =
1083 aop->size = getSize (sym->type);
1090 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1091 aop->size = getSize (sym->type);
1092 for (i = 0; i < 4; i++)
1093 aop->aopu.aop_str[i] = _fReturn[i];
1099 if (sym->accuse == ACCUSE_A)
1101 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1102 aop->size = getSize (sym->type);
1103 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1105 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1107 else if (sym->accuse == ACCUSE_SCRATCH)
1109 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1110 aop->size = getSize (sym->type);
1111 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1112 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1113 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1115 else if (sym->accuse == ACCUSE_IY)
1117 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1118 aop->size = getSize (sym->type);
1119 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1120 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1121 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1125 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1130 if (sym->usl.spillLoc)
1132 asmop *oldAsmOp = NULL;
1134 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1136 /* force a new aop if sizes differ */
1137 oldAsmOp = sym->usl.spillLoc->aop;
1138 sym->usl.spillLoc->aop = NULL;
1140 sym->aop = op->aop = aop =
1141 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1142 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1144 /* Don't reuse the new aop, go with the last one */
1145 sym->usl.spillLoc->aop = oldAsmOp;
1147 aop->size = getSize (sym->type);
1151 /* else must be a dummy iTemp */
1152 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1153 aop->size = getSize (sym->type);
1157 /* must be in a register */
1158 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1159 aop->size = sym->nRegs;
1160 for (i = 0; i < sym->nRegs; i++)
1161 aop->aopu.aop_reg[i] = sym->regs[i];
1164 /*-----------------------------------------------------------------*/
1165 /* freeAsmop - free up the asmop given to an operand */
1166 /*----------------------------------------------------------------*/
1168 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1185 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1187 _pop (aop->aopu.aop_pairId);
1190 if (getPairId (aop) == PAIR_HL)
1192 spillPair (PAIR_HL);
1196 /* all other cases just dealloc */
1202 OP_SYMBOL (op)->aop = NULL;
1203 /* if the symbol has a spill */
1205 SPIL_LOC (op)->aop = NULL;
1212 isLitWord (asmop * aop)
1214 /* if (aop->size != 2)
1227 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1229 /* depending on type */
1235 /* PENDING: for re-target */
1238 tsprintf (buffer, sizeof(buffer),
1239 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1241 else if (offset == 0)
1243 tsprintf (buffer, sizeof(buffer),
1244 "%s", aop->aopu.aop_immd);
1248 tsprintf (buffer, sizeof(buffer),
1249 "%s + %d", aop->aopu.aop_immd, offset);
1251 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1255 value *val = aop->aopu.aop_lit;
1256 /* if it is a float then it gets tricky */
1257 /* otherwise it is fairly simple */
1258 if (!IS_FLOAT (val->type))
1260 unsigned long v = (unsigned long) floatFromVal (val);
1266 else if (offset == 0)
1272 wassertl(0, "Encountered an invalid offset while fetching a literal");
1276 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1278 tsprintf (buffer, sizeof(buffer), "!constword", v);
1280 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1291 /* it is type float */
1292 fl.f = (float) floatFromVal (val);
1294 #ifdef WORDS_BIGENDIAN
1295 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1297 i = fl.c[offset] | (fl.c[offset+1]<<8);
1300 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1302 tsprintf (buffer, sizeof(buffer), "!constword", i);
1304 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1313 aopGetWord (asmop * aop, int offset)
1315 return aopGetLitWordLong (aop, offset, TRUE);
1319 isPtr (const char *s)
1321 if (!strcmp (s, "hl"))
1323 if (!strcmp (s, "ix"))
1325 if (!strcmp (s, "iy"))
1331 adjustPair (const char *pair, int *pold, int new)
1337 emit2 ("inc %s", pair);
1342 emit2 ("dec %s", pair);
1350 spillPair (PAIR_HL);
1351 spillPair (PAIR_IY);
1355 requiresHL (asmop * aop)
1371 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1373 const char *l, *base;
1374 const char *pair = _pairs[pairId].name;
1375 l = aopGetLitWordLong (left, offset, FALSE);
1376 base = aopGetLitWordLong (left, 0, FALSE);
1377 wassert (l && pair && base);
1381 if (pairId == PAIR_HL || pairId == PAIR_IY)
1383 if (_G.pairs[pairId].last_type == left->type)
1385 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1387 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1389 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1392 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1399 _G.pairs[pairId].last_type = left->type;
1400 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1401 _G.pairs[pairId].offset = offset;
1403 /* Both a lit on the right and a true symbol on the left */
1404 emit2 ("ld %s,!hashedstr", pair, l);
1408 makeFreePairId (iCode *ic, bool *pisUsed)
1414 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1418 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1436 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1438 /* if this is remateriazable */
1439 if (isLitWord (aop)) {
1440 fetchLitPair (pairId, aop, offset);
1444 if (getPairId (aop) == pairId)
1448 /* we need to get it byte by byte */
1449 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1450 aopGet (aop, offset, FALSE);
1451 switch (aop->size - offset) {
1453 emit2 ("ld l,!*hl");
1454 emit2 ("ld h,!immedbyte", 0);
1457 // PENDING: Requires that you are only fetching two bytes.
1460 emit2 ("ld h,!*hl");
1464 wassertl (0, "Attempted to fetch too much data into HL");
1468 else if (IS_Z80 && aop->type == AOP_IY) {
1469 /* Instead of fetching relative to IY, just grab directly
1470 from the address IY refers to */
1471 char *l = aopGetLitWordLong (aop, offset, FALSE);
1473 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1475 if (aop->size < 2) {
1476 emit2("ld %s,!zero", _pairs[pairId].h);
1479 else if (pairId == PAIR_IY)
1483 emit2 ("push %s", _pairs[getPairId(aop)].name);
1489 PAIR_ID id = makeFreePairId (ic, &isUsed);
1492 /* Can't load into parts, so load into HL then exchange. */
1493 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1494 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1495 emit2 ("push %s", _pairs[id].name);
1501 else if (isUnsplitable(aop))
1503 emit2("push %s", _pairs[getPairId(aop)].name);
1504 emit2("pop %s", _pairs[pairId].name);
1508 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1509 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1511 /* PENDING: check? */
1512 if (pairId == PAIR_HL)
1513 spillPair (PAIR_HL);
1518 fetchPair (PAIR_ID pairId, asmop * aop)
1520 fetchPairLong (pairId, aop, NULL, 0);
1524 fetchHL (asmop * aop)
1526 fetchPair (PAIR_HL, aop);
1530 setupPairFromSP (PAIR_ID id, int offset)
1532 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1534 if (_G.preserveCarry)
1540 if (offset < INT8MIN || offset > INT8MAX)
1542 emit2 ("ld hl,!immedword", offset);
1543 emit2 ("add hl,sp");
1547 emit2 ("!ldahlsp", offset);
1550 if (_G.preserveCarry)
1558 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1563 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1564 fetchLitPair (pairId, aop, 0);
1568 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1570 fetchLitPair (pairId, aop, offset);
1571 _G.pairs[pairId].offset = offset;
1575 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1576 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1579 int offset = aop->aopu.aop_stk + _G.stack.offset;
1581 if (_G.pairs[pairId].last_type == aop->type &&
1582 _G.pairs[pairId].offset == offset)
1588 /* PENDING: Do this better. */
1589 if (_G.preserveCarry)
1591 sprintf (buffer, "%d", offset + _G.stack.pushed);
1592 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1593 emit2 ("add %s,sp", _pairs[pairId].name);
1594 _G.pairs[pairId].last_type = aop->type;
1595 _G.pairs[pairId].offset = offset;
1596 if (_G.preserveCarry)
1604 /* Doesnt include _G.stack.pushed */
1605 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1607 if (aop->aopu.aop_stk > 0)
1609 abso += _G.stack.param_offset;
1611 assert (pairId == PAIR_HL);
1612 /* In some cases we can still inc or dec hl */
1613 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1615 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1619 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1621 _G.pairs[pairId].offset = abso;
1626 if (pairId != aop->aopu.aop_pairId)
1627 genMovePairPair(aop->aopu.aop_pairId, pairId);
1628 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1634 _G.pairs[pairId].last_type = aop->type;
1640 emit2 ("!tlabeldef", key);
1641 _G.lines.current->isLabel = 1;
1645 /*-----------------------------------------------------------------*/
1646 /* aopGet - for fetching value of the aop */
1647 /*-----------------------------------------------------------------*/
1649 aopGet (asmop * aop, int offset, bool bit16)
1651 // char *s = buffer;
1653 /* offset is greater than size then zero */
1654 /* PENDING: this seems a bit screwed in some pointer cases. */
1655 if (offset > (aop->size - 1) &&
1656 aop->type != AOP_LIT)
1658 tsprintf (buffer, sizeof(buffer), "!zero");
1659 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1662 /* depending on type */
1666 tsprintf (buffer, sizeof(buffer), "!zero");
1667 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1670 /* PENDING: re-target */
1672 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1677 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1680 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1683 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1686 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1689 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1693 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1694 SNPRINTF (buffer, sizeof(buffer), "a");
1696 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1702 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1703 SNPRINTF (buffer, sizeof(buffer), "a");
1705 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1708 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1711 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1712 emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1713 emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1715 else if( z80_opts.port_mode == 180 )
1716 { /* z180 in0/out0 mode */
1717 emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1721 emit2( "in a,(%s)", aop->aopu.aop_dir );
1724 SNPRINTF (buffer, sizeof(buffer), "a");
1726 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1730 return aop->aopu.aop_reg[offset]->name;
1734 setupPair (PAIR_HL, aop, offset);
1735 tsprintf (buffer, sizeof(buffer), "!*hl");
1737 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1741 setupPair (PAIR_IY, aop, offset);
1742 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1744 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1748 setupPair (PAIR_IY, aop, offset);
1749 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1751 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1756 setupPair (PAIR_HL, aop, offset);
1757 tsprintf (buffer, sizeof(buffer), "!*hl");
1761 if (aop->aopu.aop_stk >= 0)
1762 offset += _G.stack.param_offset;
1763 tsprintf (buffer, sizeof(buffer),
1764 "!*ixx", aop->aopu.aop_stk + offset);
1767 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1770 wassertl (0, "Tried to fetch from a bit variable");
1779 tsprintf(buffer, sizeof(buffer), "!zero");
1780 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1784 wassert (offset < 2);
1785 return aop->aopu.aop_str[offset];
1788 return aopLiteral (aop->aopu.aop_lit, offset);
1792 unsigned long v = aop->aopu.aop_simplelit;
1795 tsprintf (buffer, sizeof(buffer),
1796 "!immedbyte", (unsigned int) v & 0xff);
1798 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1802 return aop->aopu.aop_str[offset];
1805 setupPair (aop->aopu.aop_pairId, aop, offset);
1806 if (aop->aopu.aop_pairId==PAIR_IX)
1807 SNPRINTF (buffer, sizeof(buffer),
1809 else if (aop->aopu.aop_pairId==PAIR_IY)
1810 SNPRINTF (buffer, sizeof(buffer),
1813 SNPRINTF (buffer, sizeof(buffer),
1814 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1816 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1821 wassertl (0, "aopget got unsupported aop->type");
1826 isRegString (const char *s)
1828 if (!strcmp (s, "b") ||
1840 isConstant (const char *s)
1842 /* This is a bit of a hack... */
1843 return (*s == '#' || *s == '$');
1847 canAssignToPtr (const char *s)
1849 if (isRegString (s))
1856 /*-----------------------------------------------------------------*/
1857 /* aopPut - puts a string for a aop */
1858 /*-----------------------------------------------------------------*/
1860 aopPut (asmop * aop, const char *s, int offset)
1864 if (aop->size && offset > (aop->size - 1))
1866 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1867 "aopPut got offset > aop->size");
1872 tsprintf(buffer2, sizeof(buffer2), s);
1875 /* will assign value to value */
1876 /* depending on where it is ofcourse */
1880 _moveA (s); /* in case s is volatile */
1886 if (strcmp (s, "a"))
1887 emit2 ("ld a,%s", s);
1888 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1895 if (strcmp (s, "a"))
1896 emit2 ("ld a,%s", s);
1897 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1900 { /*.p.t.20030716 handling for i/o port read access for Z80 */
1907 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
1908 && s[0] != 'h' && s[0] != 'l'))
1910 emit2( "ld a,%s", s );
1914 emit2( "ld bc,#%s", aop->aopu.aop_dir );
1915 emit2( "out (c),%s", s );
1920 spillPair (PAIR_BC);
1922 else if( z80_opts.port_mode == 180 )
1923 { /* z180 in0/out0 mode */
1924 emit2( "ld a,%s", s );
1925 emit2( "out0 (%s),a", aop->aopu.aop_dir );
1929 emit2( "ld a,%s", s );
1930 emit2( "out (%s),a", aop->aopu.aop_dir );
1936 if (!strcmp (s, "!*hl"))
1937 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1940 aop->aopu.aop_reg[offset]->name, s);
1941 spillPairReg(aop->aopu.aop_reg[offset]->name);
1946 if (!canAssignToPtr (s))
1948 emit2 ("ld a,%s", s);
1949 setupPair (PAIR_IY, aop, offset);
1950 emit2 ("ld !*iyx,a", offset);
1954 setupPair (PAIR_IY, aop, offset);
1955 emit2 ("ld !*iyx,%s", offset, s);
1961 /* PENDING: for re-target */
1962 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1964 emit2 ("ld a,!*hl");
1967 setupPair (PAIR_HL, aop, offset);
1969 emit2 ("ld !*hl,%s", s);
1974 if (!canAssignToPtr (s))
1976 emit2 ("ld a,%s", s);
1977 setupPair (PAIR_IY, aop, offset);
1978 emit2 ("ld !*iyx,a", offset);
1982 setupPair (PAIR_IY, aop, offset);
1983 emit2 ("ld !*iyx,%s", offset, s);
1990 /* PENDING: re-target */
1991 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1993 emit2 ("ld a,!*hl");
1996 setupPair (PAIR_HL, aop, offset);
1997 if (!canAssignToPtr (s))
1999 emit2 ("ld a,%s", s);
2000 emit2 ("ld !*hl,a");
2003 emit2 ("ld !*hl,%s", s);
2007 if (aop->aopu.aop_stk >= 0)
2008 offset += _G.stack.param_offset;
2009 if (!canAssignToPtr (s))
2011 emit2 ("ld a,%s", s);
2012 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2016 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2022 /* if bit variable */
2023 if (!aop->aopu.aop_dir)
2025 emit2 ("ld a,!zero");
2030 /* In bit space but not in C - cant happen */
2031 wassertl (0, "Tried to write into a bit variable");
2037 if (strcmp (aop->aopu.aop_str[offset], s))
2039 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2041 spillPairReg(aop->aopu.aop_str[offset]);
2046 if (!offset && (strcmp (s, "acc") == 0))
2050 wassertl (0, "Tried to access past the end of A");
2054 if (strcmp (aop->aopu.aop_str[offset], s))
2056 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2057 spillPairReg(aop->aopu.aop_str[offset]);
2063 wassert (offset < 2);
2064 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2065 spillPairReg(aop->aopu.aop_str[offset]);
2069 setupPair (aop->aopu.aop_pairId, aop, offset);
2070 if (aop->aopu.aop_pairId==PAIR_IX)
2071 emit2 ("ld !*ixx,%s", 0, s);
2072 else if (aop->aopu.aop_pairId==PAIR_IY)
2073 emit2 ("ld !*iyx,%s", 0, s);
2075 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2079 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2080 "aopPut got unsupported aop->type");
2085 #define AOP(op) op->aop
2086 #define AOP_TYPE(op) AOP(op)->type
2087 #define AOP_SIZE(op) AOP(op)->size
2088 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2091 commitPair (asmop * aop, PAIR_ID id)
2093 /* PENDING: Verify this. */
2094 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2098 aopPut (aop, "a", 0);
2099 aopPut (aop, "d", 1);
2104 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2106 char *l = aopGetLitWordLong (aop, 0, FALSE);
2109 emit2 ("ld (%s),%s", l, _pairs[id].name);
2113 aopPut (aop, _pairs[id].l, 0);
2114 aopPut (aop, _pairs[id].h, 1);
2119 /*-----------------------------------------------------------------*/
2120 /* getDataSize - get the operand data size */
2121 /*-----------------------------------------------------------------*/
2123 getDataSize (operand * op)
2126 size = AOP_SIZE (op);
2130 wassertl (0, "Somehow got a three byte data pointer");
2135 /*-----------------------------------------------------------------*/
2136 /* movLeft2Result - move byte from left to result */
2137 /*-----------------------------------------------------------------*/
2139 movLeft2Result (operand * left, int offl,
2140 operand * result, int offr, int sign)
2144 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2146 l = aopGet (AOP (left), offl, FALSE);
2150 aopPut (AOP (result), l, offr);
2154 if (getDataSize (left) == offl + 1)
2156 emit2 ("ld a,%s", l);
2157 aopPut (AOP (result), "a", offr);
2164 movLeft2ResultLong (operand * left, int offl,
2165 operand * result, int offr, int sign,
2170 movLeft2Result (left, offl, result, offr, sign);
2174 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2175 wassertl (size == 2, "Only implemented for two bytes or one");
2177 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2179 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2180 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2182 spillPair (PAIR_HL);
2184 else if ( getPairId ( AOP (result)) == PAIR_IY)
2186 PAIR_ID id = getPairId (AOP (left));
2187 if (id != PAIR_INVALID)
2189 emit2("push %s", _pairs[id].name);
2200 movLeft2Result (left, offl, result, offr, sign);
2201 movLeft2Result (left, offl+1, result, offr+1, sign);
2206 /** Put Acc into a register set
2209 outAcc (operand * result)
2212 size = getDataSize (result);
2215 aopPut (AOP (result), "a", 0);
2218 /* unsigned or positive */
2221 aopPut (AOP (result), "!zero", offset++);
2226 /** Take the value in carry and put it into a register
2229 outBitCLong (operand * result, bool swap_sense)
2231 /* if the result is bit */
2232 if (AOP_TYPE (result) == AOP_CRY)
2234 wassertl (0, "Tried to write carry to a bit");
2238 emit2 ("ld a,!zero");
2241 emit2 ("xor a,!immedbyte", 1);
2247 outBitC (operand * result)
2249 outBitCLong (result, FALSE);
2252 /*-----------------------------------------------------------------*/
2253 /* toBoolean - emit code for orl a,operator(sizeop) */
2254 /*-----------------------------------------------------------------*/
2256 _toBoolean (operand * oper)
2258 int size = AOP_SIZE (oper);
2262 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2265 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2269 if (AOP (oper)->type != AOP_ACC)
2272 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2278 /*-----------------------------------------------------------------*/
2279 /* genNot - generate code for ! operation */
2280 /*-----------------------------------------------------------------*/
2285 /* assign asmOps to operand & result */
2286 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2287 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2289 /* if in bit space then a special case */
2290 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2292 wassertl (0, "Tried to negate a bit");
2295 _toBoolean (IC_LEFT (ic));
2300 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2301 emit2 ("sub a,!one");
2302 outBitC (IC_RESULT (ic));
2304 /* release the aops */
2305 freeAsmop (IC_LEFT (ic), NULL, ic);
2306 freeAsmop (IC_RESULT (ic), NULL, ic);
2309 /*-----------------------------------------------------------------*/
2310 /* genCpl - generate code for complement */
2311 /*-----------------------------------------------------------------*/
2319 /* assign asmOps to operand & result */
2320 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2321 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2323 /* if both are in bit space then
2325 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2326 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2328 wassertl (0, "Left and the result are in bit space");
2331 size = AOP_SIZE (IC_RESULT (ic));
2334 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2337 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2340 /* release the aops */
2341 freeAsmop (IC_LEFT (ic), NULL, ic);
2342 freeAsmop (IC_RESULT (ic), NULL, ic);
2346 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2353 store de into result
2358 store de into result
2360 const char *first = isAdd ? "add" : "sub";
2361 const char *later = isAdd ? "adc" : "sbc";
2363 wassertl (IS_GB, "Code is only relevent to the gbz80");
2364 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2366 fetchPair (PAIR_DE, left);
2369 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2372 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2375 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2376 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2378 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2379 aopGet (right, MSB24, FALSE);
2383 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2386 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2388 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2389 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2393 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2395 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2398 /*-----------------------------------------------------------------*/
2399 /* genUminusFloat - unary minus for floating points */
2400 /*-----------------------------------------------------------------*/
2402 genUminusFloat (operand * op, operand * result)
2404 int size, offset = 0;
2406 emitDebug("; genUminusFloat");
2408 /* for this we just need to flip the
2409 first bit then copy the rest in place */
2410 size = AOP_SIZE (op) - 1;
2412 _moveA(aopGet (AOP (op), MSB32, FALSE));
2414 emit2("xor a,!immedbyte", 0x80);
2415 aopPut (AOP (result), "a", MSB32);
2419 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2424 /*-----------------------------------------------------------------*/
2425 /* genUminus - unary minus code generation */
2426 /*-----------------------------------------------------------------*/
2428 genUminus (iCode * ic)
2431 sym_link *optype, *rtype;
2434 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2435 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2437 /* if both in bit space then special
2439 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2440 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2442 wassertl (0, "Left and right are in bit space");
2446 optype = operandType (IC_LEFT (ic));
2447 rtype = operandType (IC_RESULT (ic));
2449 /* if float then do float stuff */
2450 if (IS_FLOAT (optype))
2452 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2456 /* otherwise subtract from zero */
2457 size = AOP_SIZE (IC_LEFT (ic));
2459 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2461 /* Create a new asmop with value zero */
2462 asmop *azero = newAsmop (AOP_SIMPLELIT);
2463 azero->aopu.aop_simplelit = 0;
2465 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2473 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2474 emit2 ("ld a,!zero");
2475 emit2 ("sbc a,%s", l);
2476 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2479 /* if any remaining bytes in the result */
2480 /* we just need to propagate the sign */
2481 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2486 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2490 /* release the aops */
2491 freeAsmop (IC_LEFT (ic), NULL, ic);
2492 freeAsmop (IC_RESULT (ic), NULL, ic);
2495 /*-----------------------------------------------------------------*/
2496 /* assignResultValue - */
2497 /*-----------------------------------------------------------------*/
2499 assignResultValue (operand * oper)
2501 int size = AOP_SIZE (oper);
2504 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2505 topInA = requiresHL (AOP (oper));
2507 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2509 /* We do it the hard way here. */
2511 aopPut (AOP (oper), _fReturn[0], 0);
2512 aopPut (AOP (oper), _fReturn[1], 1);
2514 aopPut (AOP (oper), _fReturn[0], 2);
2515 aopPut (AOP (oper), _fReturn[1], 3);
2519 if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
2520 !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
2523 _emitMove ("a", _fReturn[size-1]);
2524 _emitMove (_fReturn[size-1], _fReturn[size]);
2525 _emitMove (_fReturn[size], "a");
2526 aopPut (AOP (oper), _fReturn[size], size-1);
2531 aopPut (AOP (oper), _fReturn[size], size);
2536 /** Simple restore that doesn't take into account what is used in the
2540 _restoreRegsAfterCall(void)
2542 if (_G.stack.pushedDE)
2545 _G.stack.pushedDE = FALSE;
2547 if (_G.stack.pushedBC)
2550 _G.stack.pushedBC = FALSE;
2552 _G.saves.saved = FALSE;
2556 _saveRegsForCall(iCode *ic, int sendSetSize)
2559 o Stack parameters are pushed before this function enters
2560 o DE and BC may be used in this function.
2561 o HL and DE may be used to return the result.
2562 o HL and DE may be used to send variables.
2563 o DE and BC may be used to store the result value.
2564 o HL may be used in computing the sent value of DE
2565 o The iPushes for other parameters occur before any addSets
2567 Logic: (to be run inside the first iPush or if none, before sending)
2568 o Compute if DE and/or BC are in use over the call
2569 o Compute if DE is used in the send set
2570 o Compute if DE and/or BC are used to hold the result value
2571 o If (DE is used, or in the send set) and is not used in the result, push.
2572 o If BC is used and is not in the result, push
2574 o If DE is used in the send set, fetch
2575 o If HL is used in the send set, fetch
2579 if (_G.saves.saved == FALSE) {
2580 bool deInUse, bcInUse;
2582 bool bcInRet = FALSE, deInRet = FALSE;
2585 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2586 z80_rUmaskForOp (IC_RESULT(ic)));
2588 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2589 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2591 deSending = (sendSetSize > 1);
2593 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2595 if (bcInUse && bcInRet == FALSE) {
2597 _G.stack.pushedBC = TRUE;
2599 if (deInUse && deInRet == FALSE) {
2601 _G.stack.pushedDE = TRUE;
2604 _G.saves.saved = TRUE;
2607 /* Already saved. */
2611 /*-----------------------------------------------------------------*/
2612 /* genIpush - genrate code for pushing this gets a little complex */
2613 /*-----------------------------------------------------------------*/
2615 genIpush (iCode * ic)
2617 int size, offset = 0;
2620 /* if this is not a parm push : ie. it is spill push
2621 and spill push is always done on the local stack */
2624 wassertl(0, "Encountered an unsupported spill push.");
2628 if (_G.saves.saved == FALSE) {
2629 /* Caller saves, and this is the first iPush. */
2630 /* Scan ahead until we find the function that we are pushing parameters to.
2631 Count the number of addSets on the way to figure out what registers
2632 are used in the send set.
2635 iCode *walk = ic->next;
2638 if (walk->op == SEND) {
2641 else if (walk->op == CALL || walk->op == PCALL) {
2650 _saveRegsForCall(walk, nAddSets);
2653 /* Already saved by another iPush. */
2656 /* then do the push */
2657 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2659 size = AOP_SIZE (IC_LEFT (ic));
2661 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2663 _G.stack.pushed += 2;
2664 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2670 fetchHL (AOP (IC_LEFT (ic)));
2672 spillPair (PAIR_HL);
2673 _G.stack.pushed += 2;
2678 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2680 spillPair (PAIR_HL);
2681 _G.stack.pushed += 2;
2682 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2684 spillPair (PAIR_HL);
2685 _G.stack.pushed += 2;
2691 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2693 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2695 emit2 ("ld a,(%s)", l);
2699 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2700 emit2 ("ld a,%s", l);
2708 freeAsmop (IC_LEFT (ic), NULL, ic);
2711 /*-----------------------------------------------------------------*/
2712 /* genIpop - recover the registers: can happen only for spilling */
2713 /*-----------------------------------------------------------------*/
2715 genIpop (iCode * ic)
2720 /* if the temp was not pushed then */
2721 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2724 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2725 size = AOP_SIZE (IC_LEFT (ic));
2726 offset = (size - 1);
2727 if (isPair (AOP (IC_LEFT (ic))))
2729 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2737 spillPair (PAIR_HL);
2738 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2742 freeAsmop (IC_LEFT (ic), NULL, ic);
2745 /* This is quite unfortunate */
2747 setArea (int inHome)
2750 static int lastArea = 0;
2752 if (_G.in_home != inHome) {
2754 const char *sz = port->mem.code_name;
2755 port->mem.code_name = "HOME";
2756 emit2("!area", CODE_NAME);
2757 port->mem.code_name = sz;
2760 emit2("!area", CODE_NAME); */
2761 _G.in_home = inHome;
2772 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2776 symbol *sym = OP_SYMBOL (op);
2778 if (sym->isspilt || sym->nRegs == 0)
2781 aopOp (op, ic, FALSE, FALSE);
2784 if (aop->type == AOP_REG)
2787 for (i = 0; i < aop->size; i++)
2789 if (pairId == PAIR_DE)
2791 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2792 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2794 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2797 else if (pairId == PAIR_BC)
2799 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2800 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2802 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2812 freeAsmop (IC_LEFT (ic), NULL, ic);
2816 /** Emit the code for a call statement
2819 emitCall (iCode * ic, bool ispcall)
2821 bool bInRet, cInRet, dInRet, eInRet;
2822 sym_link *dtype = operandType (IC_LEFT (ic));
2824 /* if caller saves & we have not saved then */
2830 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2832 /* if send set is not empty then assign */
2837 int nSend = elementsInSet(_G.sendSet);
2838 bool swapped = FALSE;
2840 int _z80_sendOrder[] = {
2845 /* Check if the parameters are swapped. If so route through hl instead. */
2846 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2848 sic = setFirstItem(_G.sendSet);
2849 sic = setNextItem(_G.sendSet);
2851 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2852 /* The second send value is loaded from one the one that holds the first
2853 send, i.e. it is overwritten. */
2854 /* Cache the first in HL, and load the second from HL instead. */
2855 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2856 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2862 for (sic = setFirstItem (_G.sendSet); sic;
2863 sic = setNextItem (_G.sendSet))
2866 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2868 size = AOP_SIZE (IC_LEFT (sic));
2869 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2870 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2872 // PENDING: Mild hack
2873 if (swapped == TRUE && send == 1) {
2875 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2878 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2880 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2883 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2887 freeAsmop (IC_LEFT (sic), NULL, sic);
2894 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2896 werror (W_INDIR_BANKED);
2898 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2900 if (isLitWord (AOP (IC_LEFT (ic))))
2902 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2906 symbol *rlbl = newiTempLabel (NULL);
2907 spillPair (PAIR_HL);
2908 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2910 _G.stack.pushed += 2;
2912 fetchHL (AOP (IC_LEFT (ic)));
2914 emit2 ("!tlabeldef", (rlbl->key + 100));
2915 _G.lines.current->isLabel = 1;
2916 _G.stack.pushed -= 2;
2918 freeAsmop (IC_LEFT (ic), NULL, ic);
2922 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2923 OP_SYMBOL (IC_LEFT (ic))->rname :
2924 OP_SYMBOL (IC_LEFT (ic))->name;
2925 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2927 emit2 ("call banked_call");
2928 emit2 ("!dws", name);
2929 emit2 ("!dw !bankimmeds", name);
2934 emit2 ("call %s", name);
2939 /* Mark the registers as restored. */
2940 _G.saves.saved = FALSE;
2942 /* if we need assign a result value */
2943 if ((IS_ITEMP (IC_RESULT (ic)) &&
2944 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2945 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2946 IS_TRUE_SYMOP (IC_RESULT (ic)))
2949 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2951 assignResultValue (IC_RESULT (ic));
2953 freeAsmop (IC_RESULT (ic), NULL, ic);
2956 /* adjust the stack for parameters if required */
2959 int i = ic->parmBytes;
2961 _G.stack.pushed -= i;
2964 emit2 ("!ldaspsp", i);
2971 emit2 ("ld iy,!immedword", i);
2972 emit2 ("add iy,sp");
2993 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2994 bInRet = bitVectBitValue(result, B_IDX);
2995 cInRet = bitVectBitValue(result, C_IDX);
2996 dInRet = bitVectBitValue(result, D_IDX);
2997 eInRet = bitVectBitValue(result, E_IDX);
3007 if (_G.stack.pushedDE)
3009 if (dInRet && eInRet)
3011 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
3015 /* Only restore E */
3022 /* Only restore D */
3030 _G.stack.pushedDE = FALSE;
3033 if (_G.stack.pushedBC)
3035 if (bInRet && cInRet)
3037 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3041 /* Only restore C */
3048 /* Only restore B */
3056 _G.stack.pushedBC = FALSE;
3060 /*-----------------------------------------------------------------*/
3061 /* genCall - generates a call statement */
3062 /*-----------------------------------------------------------------*/
3064 genCall (iCode * ic)
3066 emitCall (ic, FALSE);
3069 /*-----------------------------------------------------------------*/
3070 /* genPcall - generates a call by pointer statement */
3071 /*-----------------------------------------------------------------*/
3073 genPcall (iCode * ic)
3075 emitCall (ic, TRUE);
3078 /*-----------------------------------------------------------------*/
3079 /* resultRemat - result is rematerializable */
3080 /*-----------------------------------------------------------------*/
3082 resultRemat (iCode * ic)
3084 if (SKIP_IC (ic) || ic->op == IFX)
3087 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3089 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3090 if (sym->remat && !POINTER_SET (ic))
3097 extern set *publics;
3099 /*-----------------------------------------------------------------*/
3100 /* genFunction - generated code for function entry */
3101 /*-----------------------------------------------------------------*/
3103 genFunction (iCode * ic)
3107 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3110 bool bcInUse = FALSE;
3111 bool deInUse = FALSE;
3113 setArea (IFFUNC_NONBANKED (sym->type));
3115 /* PENDING: Reset the receive offset as it
3116 doesn't seem to get reset anywhere else.
3118 _G.receiveOffset = 0;
3120 /* Record the last function name for debugging. */
3121 _G.lastFunctionName = sym->rname;
3123 /* Create the function header */
3124 emit2 ("!functionheader", sym->name);
3125 if (!IS_STATIC(sym->etype))
3127 sprintf (buffer, "%s_start", sym->rname);
3128 emit2 ("!labeldef", buffer);
3129 _G.lines.current->isLabel = 1;
3131 emit2 ("!functionlabeldef", sym->rname);
3132 _G.lines.current->isLabel = 1;
3134 ftype = operandType (IC_LEFT (ic));
3136 if (IFFUNC_ISNAKED(ftype))
3138 emitDebug("; naked function: no prologue.");
3142 /* if this is an interrupt service routine
3143 then save all potentially used registers. */
3144 if (IFFUNC_ISISR (sym->type))
3146 /* If critical function then turn interrupts off */
3147 /* except when no interrupt number is given then it implies the NMI handler */
3148 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3157 /* This is a non-ISR function.
3158 If critical function then turn interrupts off */
3159 if (IFFUNC_ISCRITICAL (sym->type))
3167 //get interrupt enable flag IFF2 into P/O
3176 if (options.profile)
3178 emit2 ("!profileenter");
3181 /* PENDING: callee-save etc */
3183 _G.stack.param_offset = 0;
3185 if (z80_opts.calleeSavesBC)
3190 /* Detect which registers are used. */
3191 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3194 for (i = 0; i < sym->regsUsed->size; i++)
3196 if (bitVectBitValue (sym->regsUsed, i))
3210 /* Other systems use DE as a temporary. */
3221 _G.stack.param_offset += 2;
3224 _G.calleeSaves.pushedBC = bcInUse;
3229 _G.stack.param_offset += 2;
3232 _G.calleeSaves.pushedDE = deInUse;
3234 /* adjust the stack for the function */
3235 _G.stack.last = sym->stack;
3238 for (sym = setFirstItem (istack->syms); sym;
3239 sym = setNextItem (istack->syms))
3241 if (sym->_isparm && !IS_REGPARM (sym->etype))
3247 sym = OP_SYMBOL (IC_LEFT (ic));
3249 _G.omitFramePtr = options.ommitFramePtr;
3250 if (IS_Z80 && !stackParm && !sym->stack)
3252 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3253 /* the above !sym->stack condition can be removed. -- EEP */
3255 emit2 ("!ldaspsp", -sym->stack);
3256 _G.omitFramePtr = TRUE;
3258 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3259 emit2 ("!enterxl", sym->stack);
3260 else if (sym->stack)
3261 emit2 ("!enterx", sym->stack);
3265 _G.stack.offset = sym->stack;
3268 /*-----------------------------------------------------------------*/
3269 /* genEndFunction - generates epilogue for functions */
3270 /*-----------------------------------------------------------------*/
3272 genEndFunction (iCode * ic)
3274 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3276 if (IFFUNC_ISNAKED(sym->type))
3278 emitDebug("; naked function: no epilogue.");
3282 /* PENDING: calleeSave */
3283 if (IS_Z80 && _G.omitFramePtr)
3285 if (_G.stack.offset)
3286 emit2 ("!ldaspsp", _G.stack.offset);
3288 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3290 emit2 ("!leavexl", _G.stack.offset);
3292 else if (_G.stack.offset)
3294 emit2 ("!leavex", _G.stack.offset);
3301 if (_G.calleeSaves.pushedDE)
3304 _G.calleeSaves.pushedDE = FALSE;
3307 if (_G.calleeSaves.pushedBC)
3310 _G.calleeSaves.pushedBC = FALSE;
3313 if (options.profile)
3315 emit2 ("!profileexit");
3318 /* if this is an interrupt service routine
3319 then save all potentially used registers. */
3320 if (IFFUNC_ISISR (sym->type))
3324 /* If critical function then turn interrupts back on */
3325 /* except when no interrupt number is given then it implies the NMI handler */
3326 if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
3333 /* This is a non-ISR function.
3334 If critical function then turn interrupts back on */
3335 if (IFFUNC_ISCRITICAL (sym->type))
3343 symbol *tlbl = newiTempLabel (NULL);
3346 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
3347 //don't enable interrupts as they were off before
3348 emit2 ("jp PO,!tlabel", tlbl->key + 100);
3350 emit2 ("!tlabeldef", (tlbl->key + 100));
3351 _G.lines.current->isLabel = 1;
3356 if (options.debug && currFunc)
3358 debugFile->writeEndFunction (currFunc, ic, 1);
3361 if (IFFUNC_ISISR (sym->type))
3363 /* "critical interrupt" is used to imply NMI handler */
3364 if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
3371 /* Both banked and non-banked just ret */
3375 if (!IS_STATIC(sym->etype))
3377 sprintf (buffer, "%s_end", sym->rname);
3378 emit2 ("!labeldef", buffer);
3379 _G.lines.current->isLabel = 1;
3382 _G.flushStatics = 1;
3383 _G.stack.pushed = 0;
3384 _G.stack.offset = 0;
3387 /*-----------------------------------------------------------------*/
3388 /* genRet - generate code for return statement */
3389 /*-----------------------------------------------------------------*/
3394 /* Errk. This is a hack until I can figure out how
3395 to cause dehl to spill on a call */
3396 int size, offset = 0;
3398 /* if we have no return value then
3399 just generate the "ret" */
3403 /* we have something to return then
3404 move the return value into place */
3405 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3406 size = AOP_SIZE (IC_LEFT (ic));
3408 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3411 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3415 emit2 ("ld de,%s", l);
3419 emit2 ("ld hl,%s", l);
3425 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3429 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3431 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3432 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3438 l = aopGet (AOP (IC_LEFT (ic)), offset,
3440 if (strcmp (_fReturn[offset], l))
3441 emit2 ("ld %s,%s", _fReturn[offset], l);
3446 freeAsmop (IC_LEFT (ic), NULL, ic);
3449 /* generate a jump to the return label
3450 if the next is not the return statement */
3451 if (!(ic->next && ic->next->op == LABEL &&
3452 IC_LABEL (ic->next) == returnLabel))
3454 emit2 ("jp !tlabel", returnLabel->key + 100);
3457 /*-----------------------------------------------------------------*/
3458 /* genLabel - generates a label */
3459 /*-----------------------------------------------------------------*/
3461 genLabel (iCode * ic)
3463 /* special case never generate */
3464 if (IC_LABEL (ic) == entryLabel)
3467 emitLabel (IC_LABEL (ic)->key + 100);
3470 /*-----------------------------------------------------------------*/
3471 /* genGoto - generates a ljmp */
3472 /*-----------------------------------------------------------------*/
3474 genGoto (iCode * ic)
3476 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3479 /*-----------------------------------------------------------------*/
3480 /* genPlusIncr :- does addition with increment if possible */
3481 /*-----------------------------------------------------------------*/
3483 genPlusIncr (iCode * ic)
3485 unsigned int icount;
3486 unsigned int size = getDataSize (IC_RESULT (ic));
3487 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3489 /* will try to generate an increment */
3490 /* if the right side is not a literal
3492 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3495 emitDebug ("; genPlusIncr");
3497 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3499 /* If result is a pair */
3500 if (resultId != PAIR_INVALID)
3502 if (isLitWord (AOP (IC_LEFT (ic))))
3504 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3507 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3509 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3511 PAIR_ID freep = getFreePairId (ic);
3512 if (freep != PAIR_INVALID)
3514 fetchPair (freep, AOP (IC_RIGHT (ic)));
3515 emit2 ("add hl,%s", _pairs[freep].name);
3521 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3522 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3529 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3533 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3537 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3542 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3544 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3545 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3549 /* if the literal value of the right hand side
3550 is greater than 4 then it is not worth it */
3554 /* if increment 16 bits in register */
3555 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3561 symbol *tlbl = NULL;
3562 tlbl = newiTempLabel (NULL);
3565 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3568 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
3571 emitLabel (tlbl->key + 100);
3575 /* if the sizes are greater than 1 then we cannot */
3576 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3577 AOP_SIZE (IC_LEFT (ic)) > 1)
3580 /* If the result is in a register then we can load then increment.
3582 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3584 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3587 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3592 /* we can if the aops of the left & result match or
3593 if they are in registers and the registers are the
3595 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3599 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3607 /*-----------------------------------------------------------------*/
3608 /* outBitAcc - output a bit in acc */
3609 /*-----------------------------------------------------------------*/
3611 outBitAcc (operand * result)
3613 symbol *tlbl = newiTempLabel (NULL);
3614 /* if the result is a bit */
3615 if (AOP_TYPE (result) == AOP_CRY)
3617 wassertl (0, "Tried to write A into a bit");
3621 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
3622 emit2 ("ld a,!one");
3623 emitLabel (tlbl->key + 100);
3629 couldDestroyCarry (asmop *aop)
3633 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3642 shiftIntoPair (int idx, asmop *aop)
3644 PAIR_ID id = PAIR_INVALID;
3646 wassertl (IS_Z80, "Only implemented for the Z80");
3647 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3649 emitDebug ("; Shift into pair idx %u", idx);
3655 setupPair (PAIR_HL, aop, 0);
3660 setupPair (PAIR_IY, aop, 0);
3662 emit2 ("pop %s", _pairs[id].name);
3666 setupPair (PAIR_IY, aop, 0);
3669 wassertl (0, "Internal error - hit default case");
3672 aop->type = AOP_PAIRPTR;
3673 aop->aopu.aop_pairId = id;
3674 _G.pairs[id].offset = 0;
3675 _G.pairs[id].last_type = aop->type;
3679 setupToPreserveCarry (iCode * ic)
3681 asmop *left = AOP (IC_LEFT (ic));
3682 asmop *right = AOP (IC_RIGHT (ic));
3683 asmop *result = AOP (IC_RESULT (ic));
3685 wassert (left && right);
3689 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3691 shiftIntoPair (0, right);
3692 /* check result again, in case right == result */
3693 if (couldDestroyCarry (result))
3695 if (!isPairInUse (PAIR_DE, ic))
3696 shiftIntoPair (1, result);
3698 shiftIntoPair (2, result);
3701 else if (couldDestroyCarry (right))
3703 if (getPairId (result) == PAIR_HL)
3704 _G.preserveCarry = TRUE;
3706 shiftIntoPair (0, right);
3708 else if (couldDestroyCarry (result))
3710 shiftIntoPair (0, result);
3719 /*-----------------------------------------------------------------*/
3720 /* genPlus - generates code for addition */
3721 /*-----------------------------------------------------------------*/
3723 genPlus (iCode * ic)
3725 int size, offset = 0;
3727 /* special cases :- */
3729 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3730 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3731 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3733 /* Swap the left and right operands if:
3735 if literal, literal on the right or
3736 if left requires ACC or right is already
3739 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3740 (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3741 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3743 operand *t = IC_RIGHT (ic);
3744 IC_RIGHT (ic) = IC_LEFT (ic);
3748 /* if both left & right are in bit
3750 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3751 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3754 wassertl (0, "Tried to add two bits");
3757 /* if left in bit space & right literal */
3758 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3759 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3761 /* Can happen I guess */
3762 wassertl (0, "Tried to add a bit to a literal");
3765 /* if I can do an increment instead
3766 of add then GOOD for ME */
3767 if (genPlusIncr (ic) == TRUE)
3770 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3772 size = getDataSize (IC_RESULT (ic));
3774 /* Special case when left and right are constant */
3775 if (isPair (AOP (IC_RESULT (ic))))
3778 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3779 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3781 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3787 sprintf (buffer, "#(%s + %s)", left, right);
3788 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3793 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3795 /* Fetch into HL then do the add */
3796 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3797 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3799 spillPair (PAIR_HL);
3801 if (left == PAIR_HL && right != PAIR_INVALID)
3803 emit2 ("add hl,%s", _pairs[right].name);
3806 else if (right == PAIR_HL && left != PAIR_INVALID)
3808 emit2 ("add hl,%s", _pairs[left].name);
3811 else if (right != PAIR_INVALID && right != PAIR_HL)
3813 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3814 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3817 else if (left != PAIR_INVALID && left != PAIR_HL)
3819 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3820 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3829 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3831 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3832 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3834 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3839 ld hl,sp+n trashes C so we can't afford to do it during an
3840 add with stack based variables. Worst case is:
3853 So you can't afford to load up hl if either left, right, or result
3854 is on the stack (*sigh*) The alt is:
3862 Combinations in here are:
3863 * If left or right are in bc then the loss is small - trap later
3864 * If the result is in bc then the loss is also small
3868 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3869 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3870 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3872 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3873 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3874 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3875 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3877 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3879 /* Swap left and right */
3880 operand *t = IC_RIGHT (ic);
3881 IC_RIGHT (ic) = IC_LEFT (ic);
3884 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3886 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3887 emit2 ("add hl,bc");
3891 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3892 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3893 emit2 ("add hl,de");
3895 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3901 /* Be paranoid on the GB with 4 byte variables due to how C
3902 can be trashed by lda hl,n(sp).
3904 _gbz80_emitAddSubLong (ic, TRUE);
3909 setupToPreserveCarry (ic);
3913 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3915 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3918 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3921 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3925 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3928 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3931 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3933 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3937 _G.preserveCarry = FALSE;
3938 freeAsmop (IC_LEFT (ic), NULL, ic);
3939 freeAsmop (IC_RIGHT (ic), NULL, ic);
3940 freeAsmop (IC_RESULT (ic), NULL, ic);
3943 /*-----------------------------------------------------------------*/
3944 /* genMinusDec :- does subtraction with deccrement if possible */
3945 /*-----------------------------------------------------------------*/
3947 genMinusDec (iCode * ic)
3949 unsigned int icount;
3950 unsigned int size = getDataSize (IC_RESULT (ic));
3952 /* will try to generate an increment */
3953 /* if the right side is not a literal we cannot */
3954 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3957 /* if the literal value of the right hand side
3958 is greater than 4 then it is not worth it */
3959 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3962 size = getDataSize (IC_RESULT (ic));
3964 /* if decrement 16 bits in register */
3965 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3966 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3969 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3973 /* If result is a pair */
3974 if (isPair (AOP (IC_RESULT (ic))))
3976 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3978 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3982 /* if increment 16 bits in register */
3983 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3987 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3990 emit2 ("dec %s", _getTempPairName());
3993 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3999 /* if the sizes are greater than 1 then we cannot */
4000 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4001 AOP_SIZE (IC_LEFT (ic)) > 1)
4004 /* we can if the aops of the left & result match or if they are in
4005 registers and the registers are the same */
4006 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4009 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
4016 /*-----------------------------------------------------------------*/
4017 /* genMinus - generates code for subtraction */
4018 /*-----------------------------------------------------------------*/
4020 genMinus (iCode * ic)
4022 int size, offset = 0;
4023 unsigned long lit = 0L;
4025 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4026 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4027 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4029 /* special cases :- */
4030 /* if both left & right are in bit space */
4031 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4032 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4034 wassertl (0, "Tried to subtract two bits");
4038 /* if I can do an decrement instead of subtract then GOOD for ME */
4039 if (genMinusDec (ic) == TRUE)
4042 size = getDataSize (IC_RESULT (ic));
4044 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4049 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4053 /* Same logic as genPlus */
4056 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
4057 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
4058 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
4060 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
4061 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
4062 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
4063 AOP_SIZE (IC_RIGHT (ic)) <= 2))
4065 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
4066 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
4068 if (left == PAIR_INVALID && right == PAIR_INVALID)
4073 else if (right == PAIR_INVALID)
4075 else if (left == PAIR_INVALID)
4078 fetchPair (left, AOP (IC_LEFT (ic)));
4079 /* Order is important. Right may be HL */
4080 fetchPair (right, AOP (IC_RIGHT (ic)));
4082 emit2 ("ld a,%s", _pairs[left].l);
4083 emit2 ("sub a,%s", _pairs[right].l);
4085 emit2 ("ld a,%s", _pairs[left].h);
4086 emit2 ("sbc a,%s", _pairs[right].h);
4088 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4090 aopPut (AOP (IC_RESULT (ic)), "a", 1);
4092 aopPut (AOP (IC_RESULT (ic)), "e", 0);
4098 /* Be paranoid on the GB with 4 byte variables due to how C
4099 can be trashed by lda hl,n(sp).
4101 _gbz80_emitAddSubLong (ic, FALSE);
4106 setupToPreserveCarry (ic);
4108 /* if literal, add a,#-lit, else normal subb */
4111 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4112 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4116 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4119 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4123 /* first add without previous c */
4125 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4127 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4129 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4132 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4133 AOP_SIZE (IC_LEFT (ic)) == 3 &&
4134 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4136 wassertl (0, "Tried to subtract on a long pointer");
4140 _G.preserveCarry = FALSE;
4141 freeAsmop (IC_LEFT (ic), NULL, ic);
4142 freeAsmop (IC_RIGHT (ic), NULL, ic);
4143 freeAsmop (IC_RESULT (ic), NULL, ic);
4146 /*-----------------------------------------------------------------*/
4147 /* genMult - generates code for multiplication */
4148 /*-----------------------------------------------------------------*/
4150 genMult (iCode * ic)
4154 /* If true then the final operation should be a subtract */
4155 bool active = FALSE;
4158 /* Shouldn't occur - all done through function calls */
4159 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4160 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4161 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4163 byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
4165 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4166 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4167 AOP_SIZE (IC_RESULT (ic)) > 2)
4169 wassertl (0, "Multiplication is handled through support function calls");
4172 /* Swap left and right such that right is a literal */
4173 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4175 operand *t = IC_RIGHT (ic);
4176 IC_RIGHT (ic) = IC_LEFT (ic);
4180 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4182 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4183 // wassertl (val > 0, "Multiply must be positive");
4184 wassertl (val != 1, "Can't multiply by 1");
4186 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4188 _G.stack.pushedDE = TRUE;
4191 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4193 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4204 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4209 /* Fully unroled version of mul.s. Not the most efficient.
4211 for (count = 0; count < 16; count++)
4213 if (count != 0 && active)
4215 emit2 ("add hl,hl");
4219 if (active == FALSE)
4227 emit2 ("add hl,de");
4236 if (IS_Z80 && _G.stack.pushedDE)
4239 _G.stack.pushedDE = FALSE;
4243 aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4245 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4247 freeAsmop (IC_LEFT (ic), NULL, ic);
4248 freeAsmop (IC_RIGHT (ic), NULL, ic);
4249 freeAsmop (IC_RESULT (ic), NULL, ic);
4252 /*-----------------------------------------------------------------*/
4253 /* genDiv - generates code for division */
4254 /*-----------------------------------------------------------------*/
4258 /* Shouldn't occur - all done through function calls */
4259 wassertl (0, "Division is handled through support function calls");
4262 /*-----------------------------------------------------------------*/
4263 /* genMod - generates code for division */
4264 /*-----------------------------------------------------------------*/
4268 /* Shouldn't occur - all done through function calls */
4272 /*-----------------------------------------------------------------*/
4273 /* genIfxJump :- will create a jump depending on the ifx */
4274 /*-----------------------------------------------------------------*/
4276 genIfxJump (iCode * ic, char *jval)
4281 /* if true label then we jump if condition
4285 jlbl = IC_TRUE (ic);
4286 if (!strcmp (jval, "a"))
4290 else if (!strcmp (jval, "c"))
4294 else if (!strcmp (jval, "nc"))
4298 else if (!strcmp (jval, "m"))
4302 else if (!strcmp (jval, "p"))
4308 /* The buffer contains the bit on A that we should test */
4314 /* false label is present */
4315 jlbl = IC_FALSE (ic);
4316 if (!strcmp (jval, "a"))
4320 else if (!strcmp (jval, "c"))
4324 else if (!strcmp (jval, "nc"))
4328 else if (!strcmp (jval, "m"))
4332 else if (!strcmp (jval, "p"))
4338 /* The buffer contains the bit on A that we should test */
4342 /* Z80 can do a conditional long jump */
4343 if (!strcmp (jval, "a"))
4347 else if (!strcmp (jval, "c"))
4350 else if (!strcmp (jval, "nc"))
4353 else if (!strcmp (jval, "m"))
4356 else if (!strcmp (jval, "p"))
4361 emit2 ("bit %s,a", jval);
4363 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4365 /* mark the icode as generated */
4371 _getPairIdName (PAIR_ID id)
4373 return _pairs[id].name;
4378 /* if unsigned char cmp with lit, just compare */
4380 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4382 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4385 emit2 ("xor a,!immedbyte", 0x80);
4386 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4389 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4391 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4393 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4394 // Pull left into DE and right into HL
4395 aopGet (AOP(left), LSB, FALSE);
4398 aopGet (AOP(right), LSB, FALSE);
4402 if (size == 0 && sign)
4404 // Highest byte when signed needs the bits flipped
4407 emit2 ("ld a,(de)");
4408 emit2 ("xor !immedbyte", 0x80);
4410 emit2 ("ld a,(hl)");
4411 emit2 ("xor !immedbyte", 0x80);
4415 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4419 emit2 ("ld a,(de)");
4420 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4430 spillPair (PAIR_HL);
4432 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4434 setupPair (PAIR_HL, AOP (left), 0);
4435 aopGet (AOP(right), LSB, FALSE);
4439 if (size == 0 && sign)
4441 // Highest byte when signed needs the bits flipped
4444 emit2 ("ld a,(hl)");
4445 emit2 ("xor !immedbyte", 0x80);
4447 emit2 ("ld a,%d(iy)", offset);
4448 emit2 ("xor !immedbyte", 0x80);
4452 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4456 emit2 ("ld a,(hl)");
4457 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4466 spillPair (PAIR_HL);
4467 spillPair (PAIR_IY);
4471 if (AOP_TYPE (right) == AOP_LIT)
4473 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4474 /* optimize if(x < 0) or if(x >= 0) */
4479 /* No sign so it's always false */
4484 /* Just load in the top most bit */
4485 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4486 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4488 genIfxJump (ifx, "7");
4500 /* First setup h and l contaning the top most bytes XORed */
4501 bool fDidXor = FALSE;
4502 if (AOP_TYPE (left) == AOP_LIT)
4504 unsigned long lit = (unsigned long)
4505 floatFromVal (AOP (left)->aopu.aop_lit);
4506 emit2 ("ld %s,!immedbyte", _fTmp[0],
4507 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4511 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4512 emit2 ("xor a,!immedbyte", 0x80);
4513 emit2 ("ld %s,a", _fTmp[0]);
4516 if (AOP_TYPE (right) == AOP_LIT)
4518 unsigned long lit = (unsigned long)
4519 floatFromVal (AOP (right)->aopu.aop_lit);
4520 emit2 ("ld %s,!immedbyte", _fTmp[1],
4521 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4525 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4526 emit2 ("xor a,!immedbyte", 0x80);
4527 emit2 ("ld %s,a", _fTmp[1]);
4533 /* Do a long subtract */
4536 _moveA (aopGet (AOP (left), offset, FALSE));
4538 if (sign && size == 0)
4540 emit2 ("ld a,%s", _fTmp[0]);
4541 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4545 /* Subtract through, propagating the carry */
4546 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4554 /** Generic compare for > or <
4557 genCmp (operand * left, operand * right,
4558 operand * result, iCode * ifx, int sign)
4560 int size, offset = 0;
4561 unsigned long lit = 0L;
4562 bool swap_sense = FALSE;
4564 /* if left & right are bit variables */
4565 if (AOP_TYPE (left) == AOP_CRY &&
4566 AOP_TYPE (right) == AOP_CRY)
4568 /* Cant happen on the Z80 */
4569 wassertl (0, "Tried to compare two bits");
4573 /* Do a long subtract of right from left. */
4574 size = max (AOP_SIZE (left), AOP_SIZE (right));
4576 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4578 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4579 // Pull left into DE and right into HL
4580 aopGet (AOP(left), LSB, FALSE);
4583 aopGet (AOP(right), LSB, FALSE);
4587 emit2 ("ld a,(de)");
4588 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4597 spillPair (PAIR_HL);
4601 if (AOP_TYPE (right) == AOP_LIT)
4603 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4604 /* optimize if(x < 0) or if(x >= 0) */
4609 /* No sign so it's always false */
4614 /* Just load in the top most bit */
4615 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4616 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4618 genIfxJump (ifx, "7");
4629 genIfxJump (ifx, swap_sense ? "c" : "nc");
4640 _moveA (aopGet (AOP (left), offset, FALSE));
4641 /* Subtract through, propagating the carry */
4642 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4648 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4652 /* Shift the sign bit up into carry */
4655 outBitCLong (result, swap_sense);
4659 /* if the result is used in the next
4660 ifx conditional branch then generate
4661 code a little differently */
4669 genIfxJump (ifx, swap_sense ? "nc" : "c");
4673 genIfxJump (ifx, swap_sense ? "p" : "m");
4678 genIfxJump (ifx, swap_sense ? "nc" : "c");
4685 /* Shift the sign bit up into carry */
4688 outBitCLong (result, swap_sense);
4690 /* leave the result in acc */
4694 /*-----------------------------------------------------------------*/
4695 /* genCmpGt :- greater than comparison */
4696 /*-----------------------------------------------------------------*/
4698 genCmpGt (iCode * ic, iCode * ifx)
4700 operand *left, *right, *result;
4701 sym_link *letype, *retype;
4704 left = IC_LEFT (ic);
4705 right = IC_RIGHT (ic);
4706 result = IC_RESULT (ic);
4708 letype = getSpec (operandType (left));
4709 retype = getSpec (operandType (right));
4710 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4711 /* assign the amsops */
4712 aopOp (left, ic, FALSE, FALSE);
4713 aopOp (right, ic, FALSE, FALSE);
4714 aopOp (result, ic, TRUE, FALSE);
4716 genCmp (right, left, result, ifx, sign);
4718 freeAsmop (left, NULL, ic);
4719 freeAsmop (right, NULL, ic);
4720 freeAsmop (result, NULL, ic);
4723 /*-----------------------------------------------------------------*/
4724 /* genCmpLt - less than comparisons */
4725 /*-----------------------------------------------------------------*/
4727 genCmpLt (iCode * ic, iCode * ifx)
4729 operand *left, *right, *result;
4730 sym_link *letype, *retype;
4733 left = IC_LEFT (ic);
4734 right = IC_RIGHT (ic);
4735 result = IC_RESULT (ic);
4737 letype = getSpec (operandType (left));
4738 retype = getSpec (operandType (right));
4739 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4741 /* assign the amsops */
4742 aopOp (left, ic, FALSE, FALSE);
4743 aopOp (right, ic, FALSE, FALSE);
4744 aopOp (result, ic, TRUE, FALSE);
4746 genCmp (left, right, result, ifx, sign);
4748 freeAsmop (left, NULL, ic);
4749 freeAsmop (right, NULL, ic);
4750 freeAsmop (result, NULL, ic);
4753 /*-----------------------------------------------------------------*/
4754 /* gencjneshort - compare and jump if not equal */
4755 /*-----------------------------------------------------------------*/
4757 gencjneshort (operand * left, operand * right, symbol * lbl)
4759 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4761 unsigned long lit = 0L;
4763 /* Swap the left and right if it makes the computation easier */
4764 if (AOP_TYPE (left) == AOP_LIT)
4771 if (AOP_TYPE (right) == AOP_LIT)
4773 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4776 /* if the right side is a literal then anything goes */
4777 if (AOP_TYPE (right) == AOP_LIT &&
4778 AOP_TYPE (left) != AOP_DIR)
4782 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4787 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4794 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4800 _moveA (aopGet (AOP (left), offset, FALSE));
4801 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
4804 emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
4805 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4810 /* if the right side is in a register or in direct space or
4811 if the left is a pointer register & right is not */
4812 else if (AOP_TYPE (right) == AOP_REG ||
4813 AOP_TYPE (right) == AOP_DIR ||
4814 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4818 _moveA (aopGet (AOP (left), offset, FALSE));
4819 if (/*AOP_TYPE (left) == AOP_DIR &&*/ AOP_TYPE (right) == AOP_LIT &&
4820 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4823 /* MB: pending what? doesn't this need "or a,a"? */
4824 /* and I don't think AOP_TYPE(left) has anything to do with this */
4826 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4830 emit2 ("sub %s", aopGet (AOP (right), offset, FALSE));
4831 emit2 ("jp NZ,!tlabel", lbl->key + 100);
4838 /* right is a pointer reg need both a & b */
4839 /* PENDING: is this required? */
4842 _moveA (aopGet (AOP (right), offset, FALSE));
4843 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4844 emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
4850 /*-----------------------------------------------------------------*/
4851 /* gencjne - compare and jump if not equal */
4852 /*-----------------------------------------------------------------*/
4854 gencjne (operand * left, operand * right, symbol * lbl)
4856 symbol *tlbl = newiTempLabel (NULL);
4858 gencjneshort (left, right, lbl);
4861 emit2 ("ld a,!one");
4862 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4863 emitLabel (lbl->key + 100);
4865 emitLabel (tlbl->key + 100);
4868 /*-----------------------------------------------------------------*/
4869 /* genCmpEq - generates code for equal to */
4870 /*-----------------------------------------------------------------*/
4872 genCmpEq (iCode * ic, iCode * ifx)
4874 operand *left, *right, *result;
4876 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4877 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4878 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4880 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4882 /* Swap operands if it makes the operation easier. ie if:
4883 1. Left is a literal.
4885 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4887 operand *t = IC_RIGHT (ic);
4888 IC_RIGHT (ic) = IC_LEFT (ic);
4892 if (ifx && !AOP_SIZE (result))
4895 /* if they are both bit variables */
4896 if (AOP_TYPE (left) == AOP_CRY &&
4897 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4899 wassertl (0, "Tried to compare two bits");
4903 tlbl = newiTempLabel (NULL);
4904 gencjneshort (left, right, tlbl);
4907 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4908 emitLabel (tlbl->key + 100);
4912 /* PENDING: do this better */
4913 symbol *lbl = newiTempLabel (NULL);
4914 emit2 ("!shortjp !tlabel", lbl->key + 100);
4915 emitLabel (tlbl->key + 100);
4916 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4917 emitLabel (lbl->key + 100);
4920 /* mark the icode as generated */
4925 /* if they are both bit variables */
4926 if (AOP_TYPE (left) == AOP_CRY &&
4927 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4929 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4935 gencjne (left, right, newiTempLabel (NULL));
4936 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4943 genIfxJump (ifx, "a");
4946 /* if the result is used in an arithmetic operation
4947 then put the result in place */
4948 if (AOP_TYPE (result) != AOP_CRY)
4953 /* leave the result in acc */
4957 freeAsmop (left, NULL, ic);
4958 freeAsmop (right, NULL, ic);
4959 freeAsmop (result, NULL, ic);
4962 /*-----------------------------------------------------------------*/
4963 /* ifxForOp - returns the icode containing the ifx for operand */
4964 /*-----------------------------------------------------------------*/
4966 ifxForOp (operand * op, iCode * ic)
4968 /* if true symbol then needs to be assigned */
4969 if (IS_TRUE_SYMOP (op))
4972 /* if this has register type condition and
4973 the next instruction is ifx with the same operand
4974 and live to of the operand is upto the ifx only then */
4976 ic->next->op == IFX &&
4977 IC_COND (ic->next)->key == op->key &&
4978 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4984 /*-----------------------------------------------------------------*/
4985 /* genAndOp - for && operation */
4986 /*-----------------------------------------------------------------*/
4988 genAndOp (iCode * ic)
4990 operand *left, *right, *result;
4993 /* note here that && operations that are in an if statement are
4994 taken away by backPatchLabels only those used in arthmetic
4995 operations remain */
4996 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4997 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4998 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5000 /* if both are bit variables */
5001 if (AOP_TYPE (left) == AOP_CRY &&
5002 AOP_TYPE (right) == AOP_CRY)
5004 wassertl (0, "Tried to and two bits");
5008 tlbl = newiTempLabel (NULL);
5010 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
5012 emitLabel (tlbl->key + 100);
5016 freeAsmop (left, NULL, ic);
5017 freeAsmop (right, NULL, ic);
5018 freeAsmop (result, NULL, ic);
5021 /*-----------------------------------------------------------------*/
5022 /* genOrOp - for || operation */
5023 /*-----------------------------------------------------------------*/
5025 genOrOp (iCode * ic)
5027 operand *left, *right, *result;
5030 /* note here that || operations that are in an
5031 if statement are taken away by backPatchLabels
5032 only those used in arthmetic operations remain */
5033 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
5034 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
5035 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
5037 /* if both are bit variables */
5038 if (AOP_TYPE (left) == AOP_CRY &&
5039 AOP_TYPE (right) == AOP_CRY)
5041 wassertl (0, "Tried to OR two bits");
5045 tlbl = newiTempLabel (NULL);
5047 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5049 emitLabel (tlbl->key + 100);
5053 freeAsmop (left, NULL, ic);
5054 freeAsmop (right, NULL, ic);
5055 freeAsmop (result, NULL, ic);
5058 /*-----------------------------------------------------------------*/
5059 /* isLiteralBit - test if lit == 2^n */
5060 /*-----------------------------------------------------------------*/
5062 isLiteralBit (unsigned long lit)
5064 unsigned long pw[32] =
5065 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5066 0x100L, 0x200L, 0x400L, 0x800L,
5067 0x1000L, 0x2000L, 0x4000L, 0x8000L,
5068 0x10000L, 0x20000L, 0x40000L, 0x80000L,
5069 0x100000L, 0x200000L, 0x400000L, 0x800000L,
5070 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5071 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5074 for (idx = 0; idx < 32; idx++)
5080 /*-----------------------------------------------------------------*/
5081 /* jmpTrueOrFalse - */
5082 /*-----------------------------------------------------------------*/
5084 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5086 // ugly but optimized by peephole
5089 symbol *nlbl = newiTempLabel (NULL);
5090 emit2 ("jp !tlabel", nlbl->key + 100);
5091 emitLabel (tlbl->key + 100);
5092 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5093 emitLabel (nlbl->key + 100);
5097 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5098 emitLabel (tlbl->key + 100);
5103 /*-----------------------------------------------------------------*/
5104 /* genAnd - code for and */
5105 /*-----------------------------------------------------------------*/
5107 genAnd (iCode * ic, iCode * ifx)
5109 operand *left, *right, *result;
5110 int size, offset = 0;
5111 unsigned long lit = 0L;
5114 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5115 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5116 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5118 /* if left is a literal & right is not then exchange them */
5119 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5120 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5122 operand *tmp = right;
5127 /* if result = right then exchange them */
5128 if (sameRegs (AOP (result), AOP (right)))
5130 operand *tmp = right;
5135 /* if right is bit then exchange them */
5136 if (AOP_TYPE (right) == AOP_CRY &&
5137 AOP_TYPE (left) != AOP_CRY)
5139 operand *tmp = right;
5143 if (AOP_TYPE (right) == AOP_LIT)
5144 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5146 size = AOP_SIZE (result);
5148 if (AOP_TYPE (left) == AOP_CRY)
5150 wassertl (0, "Tried to perform an AND with a bit as an operand");
5154 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5155 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5156 if ((AOP_TYPE (right) == AOP_LIT) &&
5157 (AOP_TYPE (result) == AOP_CRY) &&
5158 (AOP_TYPE (left) != AOP_CRY))
5160 symbol *tlbl = newiTempLabel (NULL);
5161 int sizel = AOP_SIZE (left);
5164 /* PENDING: Test case for this. */
5169 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5171 _moveA (aopGet (AOP (left), offset, FALSE));
5172 if (bytelit != 0x0FFL)
5174 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5181 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5185 // bit = left & literal
5189 emit2 ("!tlabeldef", tlbl->key + 100);
5190 _G.lines.current->isLabel = 1;
5192 // if(left & literal)
5197 jmpTrueOrFalse (ifx, tlbl);
5205 /* if left is same as result */
5206 if (sameRegs (AOP (result), AOP (left)))
5208 for (; size--; offset++)
5210 if (AOP_TYPE (right) == AOP_LIT)
5212 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5217 aopPut (AOP (result), "!zero", offset);
5220 _moveA (aopGet (AOP (left), offset, FALSE));
5222 aopGet (AOP (right), offset, FALSE));
5223 aopPut (AOP (left), "a", offset);
5230 if (AOP_TYPE (left) == AOP_ACC)
5232 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5236 _moveA (aopGet (AOP (left), offset, FALSE));
5238 aopGet (AOP (right), offset, FALSE));
5239 aopPut (AOP (left), "a", offset);
5246 // left & result in different registers
5247 if (AOP_TYPE (result) == AOP_CRY)
5249 wassertl (0, "Tried to AND where the result is in carry");
5253 for (; (size--); offset++)
5256 // result = left & right
5257 if (AOP_TYPE (right) == AOP_LIT)
5259 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5261 aopPut (AOP (result),
5262 aopGet (AOP (left), offset, FALSE),
5266 else if (bytelit == 0)
5268 aopPut (AOP (result), "!zero", offset);
5272 // faster than result <- left, anl result,right
5273 // and better if result is SFR
5274 if (AOP_TYPE (left) == AOP_ACC)
5275 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5278 _moveA (aopGet (AOP (left), offset, FALSE));
5280 aopGet (AOP (right), offset, FALSE));
5282 aopPut (AOP (result), "a", offset);
5289 freeAsmop (left, NULL, ic);
5290 freeAsmop (right, NULL, ic);
5291 freeAsmop (result, NULL, ic);
5294 /*-----------------------------------------------------------------*/
5295 /* genOr - code for or */
5296 /*-----------------------------------------------------------------*/
5298 genOr (iCode * ic, iCode * ifx)
5300 operand *left, *right, *result;
5301 int size, offset = 0;
5302 unsigned long lit = 0L;
5305 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5306 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5307 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5309 /* if left is a literal & right is not then exchange them */
5310 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5311 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5313 operand *tmp = right;
5318 /* if result = right then exchange them */
5319 if (sameRegs (AOP (result), AOP (right)))
5321 operand *tmp = right;
5326 /* if right is bit then exchange them */
5327 if (AOP_TYPE (right) == AOP_CRY &&
5328 AOP_TYPE (left) != AOP_CRY)
5330 operand *tmp = right;
5334 if (AOP_TYPE (right) == AOP_LIT)
5335 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5337 size = AOP_SIZE (result);
5339 if (AOP_TYPE (left) == AOP_CRY)
5341 wassertl (0, "Tried to OR where left is a bit");
5345 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5346 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5347 if ((AOP_TYPE (right) == AOP_LIT) &&
5348 (AOP_TYPE (result) == AOP_CRY) &&
5349 (AOP_TYPE (left) != AOP_CRY))
5351 symbol *tlbl = newiTempLabel (NULL);
5352 int sizel = AOP_SIZE (left);
5356 wassertl (0, "Result is assigned to a bit");
5358 /* PENDING: Modeled after the AND code which is inefficient. */
5361 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5363 _moveA (aopGet (AOP (left), offset, FALSE));
5364 /* OR with any literal is the same as OR with itself. */
5366 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5372 jmpTrueOrFalse (ifx, tlbl);
5377 /* if left is same as result */
5378 if (sameRegs (AOP (result), AOP (left)))
5380 for (; size--; offset++)
5382 if (AOP_TYPE (right) == AOP_LIT)
5384 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5388 _moveA (aopGet (AOP (left), offset, FALSE));
5390 aopGet (AOP (right), offset, FALSE));
5391 aopPut (AOP (result), "a", offset);
5396 if (AOP_TYPE (left) == AOP_ACC)
5397 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5400 _moveA (aopGet (AOP (left), offset, FALSE));
5402 aopGet (AOP (right), offset, FALSE));
5403 aopPut (AOP (result), "a", offset);
5410 // left & result in different registers
5411 if (AOP_TYPE (result) == AOP_CRY)
5413 wassertl (0, "Result of OR is in a bit");
5416 for (; (size--); offset++)
5419 // result = left & right
5420 if (AOP_TYPE (right) == AOP_LIT)
5422 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5424 aopPut (AOP (result),
5425 aopGet (AOP (left), offset, FALSE),
5430 // faster than result <- left, anl result,right
5431 // and better if result is SFR
5432 if (AOP_TYPE (left) == AOP_ACC)
5433 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5436 _moveA (aopGet (AOP (left), offset, FALSE));
5438 aopGet (AOP (right), offset, FALSE));
5440 aopPut (AOP (result), "a", offset);
5441 /* PENDING: something weird is going on here. Add exception. */
5442 if (AOP_TYPE (result) == AOP_ACC)
5448 freeAsmop (left, NULL, ic);
5449 freeAsmop (right, NULL, ic);
5450 freeAsmop (result, NULL, ic);
5453 /*-----------------------------------------------------------------*/
5454 /* genXor - code for xclusive or */
5455 /*-----------------------------------------------------------------*/
5457 genXor (iCode * ic, iCode * ifx)
5459 operand *left, *right, *result;
5460 int size, offset = 0;
5461 unsigned long lit = 0L;
5463 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5464 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5465 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5467 /* if left is a literal & right is not then exchange them */
5468 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5469 (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5471 operand *tmp = right;
5476 /* if result = right then exchange them */
5477 if (sameRegs (AOP (result), AOP (right)))
5479 operand *tmp = right;
5484 /* if right is bit then exchange them */
5485 if (AOP_TYPE (right) == AOP_CRY &&
5486 AOP_TYPE (left) != AOP_CRY)
5488 operand *tmp = right;
5492 if (AOP_TYPE (right) == AOP_LIT)
5493 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5495 size = AOP_SIZE (result);
5497 if (AOP_TYPE (left) == AOP_CRY)
5499 wassertl (0, "Tried to XOR a bit");
5503 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5504 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5505 if ((AOP_TYPE (right) == AOP_LIT) &&
5506 (AOP_TYPE (result) == AOP_CRY) &&
5507 (AOP_TYPE (left) != AOP_CRY))
5509 symbol *tlbl = newiTempLabel (NULL);
5510 int sizel = AOP_SIZE (left);
5514 /* PENDING: Test case for this. */
5515 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5519 _moveA (aopGet (AOP (left), offset, FALSE));
5520 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5521 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5526 jmpTrueOrFalse (ifx, tlbl);
5530 wassertl (0, "Result of XOR was destined for a bit");
5535 /* if left is same as result */
5536 if (sameRegs (AOP (result), AOP (left)))
5538 for (; size--; offset++)
5540 if (AOP_TYPE (right) == AOP_LIT)
5542 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5546 _moveA (aopGet (AOP (left), offset, FALSE));
5548 aopGet (AOP (right), offset, FALSE));
5549 aopPut (AOP (result), "a", offset);
5554 if (AOP_TYPE (left) == AOP_ACC)
5556 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5560 _moveA (aopGet (AOP (left), offset, FALSE));
5562 aopGet (AOP (right), offset, FALSE));
5563 aopPut (AOP (result), "a", offset);
5570 // left & result in different registers
5571 if (AOP_TYPE (result) == AOP_CRY)
5573 wassertl (0, "Result of XOR is in a bit");
5576 for (; (size--); offset++)
5579 // result = left & right
5580 if (AOP_TYPE (right) == AOP_LIT)
5582 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5584 aopPut (AOP (result),
5585 aopGet (AOP (left), offset, FALSE),
5590 // faster than result <- left, anl result,right
5591 // and better if result is SFR
5592 if (AOP_TYPE (left) == AOP_ACC)
5594 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5598 _moveA (aopGet (AOP (left), offset, FALSE));
5600 aopGet (AOP (right), offset, FALSE));
5602 aopPut (AOP (result), "a", offset);
5607 freeAsmop (left, NULL, ic);
5608 freeAsmop (right, NULL, ic);
5609 freeAsmop (result, NULL, ic);
5612 /*-----------------------------------------------------------------*/
5613 /* genInline - write the inline code out */
5614 /*-----------------------------------------------------------------*/
5616 genInline (iCode * ic)
5618 char *buffer, *bp, *bp1;
5620 _G.lines.isInline += (!options.asmpeep);
5622 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5623 strcpy (buffer, IC_INLINE (ic));
5625 /* emit each line as a code */
5650 _G.lines.isInline -= (!options.asmpeep);
5654 /*-----------------------------------------------------------------*/
5655 /* genRRC - rotate right with carry */
5656 /*-----------------------------------------------------------------*/
5663 /*-----------------------------------------------------------------*/
5664 /* genRLC - generate code for rotate left with carry */
5665 /*-----------------------------------------------------------------*/
5672 /*-----------------------------------------------------------------*/
5673 /* genGetHbit - generates code get highest order bit */
5674 /*-----------------------------------------------------------------*/
5676 genGetHbit (iCode * ic)
5678 operand *left, *result;
5679 left = IC_LEFT (ic);
5680 result = IC_RESULT (ic);
5682 aopOp (left, ic, FALSE, FALSE);
5683 aopOp (result, ic, FALSE, FALSE);
5685 /* get the highest order byte into a */
5686 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5688 if (AOP_TYPE (result) == AOP_CRY)
5696 emit2 ("and a,!one");
5701 freeAsmop (left, NULL, ic);
5702 freeAsmop (result, NULL, ic);
5706 emitRsh2 (asmop *aop, int size, int is_signed)
5712 const char *l = aopGet (aop, size, FALSE);
5715 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5725 /*-----------------------------------------------------------------*/
5726 /* shiftR2Left2Result - shift right two bytes from left to result */
5727 /*-----------------------------------------------------------------*/
5729 shiftR2Left2Result (operand * left, int offl,
5730 operand * result, int offr,
5731 int shCount, int is_signed)
5734 symbol *tlbl, *tlbl1;
5736 movLeft2Result (left, offl, result, offr, 0);
5737 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5742 /* if (AOP(result)->type == AOP_REG) { */
5744 tlbl = newiTempLabel (NULL);
5745 tlbl1 = newiTempLabel (NULL);
5747 /* Left is already in result - so now do the shift */
5752 emitRsh2 (AOP (result), size, is_signed);
5757 emit2 ("ld a,!immedbyte+1", shCount);
5758 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5759 emitLabel (tlbl->key + 100);
5761 emitRsh2 (AOP (result), size, is_signed);
5763 emitLabel (tlbl1->key + 100);
5765 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5769 /*-----------------------------------------------------------------*/
5770 /* shiftL2Left2Result - shift left two bytes from left to result */
5771 /*-----------------------------------------------------------------*/
5773 shiftL2Left2Result (operand * left, int offl,
5774 operand * result, int offr, int shCount)
5776 if (sameRegs (AOP (result), AOP (left)) &&
5777 ((offl + MSB16) == offr))
5783 /* Copy left into result */
5784 movLeft2Result (left, offl, result, offr, 0);
5785 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5791 if (getPairId (AOP (result)) == PAIR_HL)
5795 emit2 ("add hl,hl");
5802 symbol *tlbl, *tlbl1;
5805 tlbl = newiTempLabel (NULL);
5806 tlbl1 = newiTempLabel (NULL);
5808 if (AOP (result)->type == AOP_REG)
5812 for (offset = 0; offset < size; offset++)
5814 l = aopGet (AOP (result), offset, FALSE);
5818 emit2 ("sla %s", l);
5829 /* Left is already in result - so now do the shift */
5832 emit2 ("ld a,!immedbyte+1", shCount);
5833 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5834 emitLabel (tlbl->key + 100);
5839 l = aopGet (AOP (result), offset, FALSE);
5843 emit2 ("sla %s", l);
5854 emitLabel (tlbl1->key + 100);
5856 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
5862 /*-----------------------------------------------------------------*/
5863 /* AccRol - rotate left accumulator by known count */
5864 /*-----------------------------------------------------------------*/
5866 AccRol (int shCount)
5868 shCount &= 0x0007; // shCount : 0..7
5945 /*-----------------------------------------------------------------*/
5946 /* AccLsh - left shift accumulator by known count */
5947 /*-----------------------------------------------------------------*/
5949 AccLsh (int shCount)
5951 static const unsigned char SLMask[] =
5953 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5962 else if (shCount == 2)
5969 /* rotate left accumulator */
5971 /* and kill the lower order bits */
5972 emit2 ("and a,!immedbyte", SLMask[shCount]);
5977 /*-----------------------------------------------------------------*/
5978 /* shiftL1Left2Result - shift left one byte from left to result */
5979 /*-----------------------------------------------------------------*/
5981 shiftL1Left2Result (operand * left, int offl,
5982 operand * result, int offr, int shCount)
5985 l = aopGet (AOP (left), offl, FALSE);
5987 /* shift left accumulator */
5989 aopPut (AOP (result), "a", offr);
5993 /*-----------------------------------------------------------------*/
5994 /* genlshTwo - left shift two bytes by known amount */
5995 /*-----------------------------------------------------------------*/
5997 genlshTwo (operand * result, operand * left, int shCount)
5999 int size = AOP_SIZE (result);
6001 wassert (size == 2);
6003 /* if shCount >= 8 */
6011 movLeft2Result (left, LSB, result, MSB16, 0);
6012 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
6013 aopPut (AOP (result), "!zero", LSB);
6017 movLeft2Result (left, LSB, result, MSB16, 0);
6018 aopPut (AOP (result), "!zero", 0);
6023 aopPut (AOP (result), "!zero", LSB);
6026 /* 0 <= shCount <= 7 */
6035 shiftL2Left2Result (left, LSB, result, LSB, shCount);
6040 /*-----------------------------------------------------------------*/
6041 /* genlshOne - left shift a one byte quantity by known count */
6042 /*-----------------------------------------------------------------*/
6044 genlshOne (operand * result, operand * left, int shCount)
6046 shiftL1Left2Result (left, LSB, result, LSB, shCount);
6049 /*-----------------------------------------------------------------*/
6050 /* genLeftShiftLiteral - left shifting by known count */
6051 /*-----------------------------------------------------------------*/
6053 genLeftShiftLiteral (operand * left,
6058 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6061 freeAsmop (right, NULL, ic);
6063 aopOp (left, ic, FALSE, FALSE);
6064 aopOp (result, ic, FALSE, FALSE);
6066 size = getSize (operandType (result));
6068 /* I suppose that the left size >= result size */
6070 if (shCount >= (size * 8))
6074 aopPut (AOP (result), "!zero", size);
6082 genlshOne (result, left, shCount);
6085 genlshTwo (result, left, shCount);
6088 wassertl (0, "Shifting of longs is currently unsupported");
6094 freeAsmop (left, NULL, ic);
6095 freeAsmop (result, NULL, ic);
6098 /*-----------------------------------------------------------------*/
6099 /* genLeftShift - generates code for left shifting */
6100 /*-----------------------------------------------------------------*/
6102 genLeftShift (iCode * ic)
6106 symbol *tlbl, *tlbl1;
6107 operand *left, *right, *result;
6109 right = IC_RIGHT (ic);
6110 left = IC_LEFT (ic);
6111 result = IC_RESULT (ic);
6113 aopOp (right, ic, FALSE, FALSE);
6115 /* if the shift count is known then do it
6116 as efficiently as possible */
6117 if (AOP_TYPE (right) == AOP_LIT)
6119 genLeftShiftLiteral (left, right, result, ic);
6123 /* shift count is unknown then we have to form a loop get the loop
6124 count in B : Note: we take only the lower order byte since
6125 shifting more that 32 bits make no sense anyway, ( the largest
6126 size of an object can be only 32 bits ) */
6127 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6129 freeAsmop (right, NULL, ic);
6130 aopOp (left, ic, FALSE, FALSE);
6131 aopOp (result, ic, FALSE, FALSE);
6133 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6136 /* now move the left to the result if they are not the
6139 if (!sameRegs (AOP (left), AOP (result)))
6142 size = AOP_SIZE (result);
6146 l = aopGet (AOP (left), offset, FALSE);
6147 aopPut (AOP (result), l, offset);
6152 tlbl = newiTempLabel (NULL);
6153 size = AOP_SIZE (result);
6155 tlbl1 = newiTempLabel (NULL);
6157 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6160 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6161 emitLabel (tlbl->key + 100);
6162 l = aopGet (AOP (result), offset, FALSE);
6166 l = aopGet (AOP (result), offset, FALSE);
6170 emit2 ("sla %s", l);
6178 emitLabel (tlbl1->key + 100);
6180 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6182 freeAsmop (left, NULL, ic);
6183 freeAsmop (result, NULL, ic);
6186 /*-----------------------------------------------------------------*/
6187 /* genrshOne - left shift two bytes by known amount != 0 */
6188 /*-----------------------------------------------------------------*/
6190 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6193 int size = AOP_SIZE (result);
6196 wassert (size == 1);
6197 wassert (shCount < 8);
6199 l = aopGet (AOP (left), 0, FALSE);
6201 if (AOP (result)->type == AOP_REG)
6203 aopPut (AOP (result), l, 0);
6204 l = aopGet (AOP (result), 0, FALSE);
6207 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6215 emit2 ("%s a", is_signed ? "sra" : "srl");
6217 aopPut (AOP (result), "a", 0);
6221 /*-----------------------------------------------------------------*/
6222 /* AccRsh - right shift accumulator by known count */
6223 /*-----------------------------------------------------------------*/
6225 AccRsh (int shCount)
6227 static const unsigned char SRMask[] =
6229 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6234 /* rotate right accumulator */
6235 AccRol (8 - shCount);
6236 /* and kill the higher order bits */
6237 emit2 ("and a,!immedbyte", SRMask[shCount]);
6241 /*-----------------------------------------------------------------*/
6242 /* shiftR1Left2Result - shift right one byte from left to result */
6243 /*-----------------------------------------------------------------*/
6245 shiftR1Left2Result (operand * left, int offl,
6246 operand * result, int offr,
6247 int shCount, int sign)
6249 _moveA (aopGet (AOP (left), offl, FALSE));
6254 emit2 ("%s a", sign ? "sra" : "srl");
6261 aopPut (AOP (result), "a", offr);
6264 /*-----------------------------------------------------------------*/
6265 /* genrshTwo - right shift two bytes by known amount */
6266 /*-----------------------------------------------------------------*/
6268 genrshTwo (operand * result, operand * left,
6269 int shCount, int sign)
6271 /* if shCount >= 8 */
6277 shiftR1Left2Result (left, MSB16, result, LSB,
6282 movLeft2Result (left, MSB16, result, LSB, sign);
6286 /* Sign extend the result */
6287 _moveA(aopGet (AOP (result), 0, FALSE));
6291 aopPut (AOP (result), ACC_NAME, MSB16);
6295 aopPut (AOP (result), "!zero", 1);
6298 /* 0 <= shCount <= 7 */
6301 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6305 /*-----------------------------------------------------------------*/
6306 /* genRightShiftLiteral - left shifting by known count */
6307 /*-----------------------------------------------------------------*/
6309 genRightShiftLiteral (operand * left,
6315 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6318 freeAsmop (right, NULL, ic);
6320 aopOp (left, ic, FALSE, FALSE);
6321 aopOp (result, ic, FALSE, FALSE);
6323 size = getSize (operandType (result));
6325 /* I suppose that the left size >= result size */
6327 if (shCount >= (size * 8)) {
6329 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6330 _moveA(aopGet (AOP (left), 0, FALSE));
6338 aopPut (AOP (result), s, size);
6345 genrshOne (result, left, shCount, sign);
6348 genrshTwo (result, left, shCount, sign);
6351 wassertl (0, "Asked to shift right a long which should be a function call");
6354 wassertl (0, "Entered default case in right shift delegate");
6357 freeAsmop (left, NULL, ic);
6358 freeAsmop (result, NULL, ic);
6361 /*-----------------------------------------------------------------*/
6362 /* genRightShift - generate code for right shifting */
6363 /*-----------------------------------------------------------------*/
6365 genRightShift (iCode * ic)
6367 operand *right, *left, *result;
6369 int size, offset, first = 1;
6373 symbol *tlbl, *tlbl1;
6375 /* if signed then we do it the hard way preserve the
6376 sign bit moving it inwards */
6377 retype = getSpec (operandType (IC_RESULT (ic)));
6379 is_signed = !SPEC_USIGN (retype);
6381 /* signed & unsigned types are treated the same : i.e. the
6382 signed is NOT propagated inwards : quoting from the
6383 ANSI - standard : "for E1 >> E2, is equivalent to division
6384 by 2**E2 if unsigned or if it has a non-negative value,
6385 otherwise the result is implementation defined ", MY definition
6386 is that the sign does not get propagated */
6388 right = IC_RIGHT (ic);
6389 left = IC_LEFT (ic);
6390 result = IC_RESULT (ic);
6392 aopOp (right, ic, FALSE, FALSE);
6394 /* if the shift count is known then do it
6395 as efficiently as possible */
6396 if (AOP_TYPE (right) == AOP_LIT)
6398 genRightShiftLiteral (left, right, result, ic, is_signed);
6402 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6404 freeAsmop (right, NULL, ic);
6406 aopOp (left, ic, FALSE, FALSE);
6407 aopOp (result, ic, FALSE, FALSE);
6409 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6412 /* now move the left to the result if they are not the
6414 if (!sameRegs (AOP (left), AOP (result)))
6417 size = AOP_SIZE (result);
6421 l = aopGet (AOP (left), offset, FALSE);
6422 aopPut (AOP (result), l, offset);
6427 tlbl = newiTempLabel (NULL);
6428 tlbl1 = newiTempLabel (NULL);
6429 size = AOP_SIZE (result);
6432 if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6435 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6436 emitLabel (tlbl->key + 100);
6439 l = aopGet (AOP (result), offset--, FALSE);
6442 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6450 emitLabel (tlbl1->key + 100);
6452 emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
6454 freeAsmop (left, NULL, ic);
6455 freeAsmop (result, NULL, ic);
6459 /*-----------------------------------------------------------------*/
6460 /* genUnpackBits - generates code for unpacking bits */
6461 /*-----------------------------------------------------------------*/
6463 genUnpackBits (operand * result, int pair)
6465 int offset = 0; /* result byte offset */
6466 int rsize; /* result size */
6467 int rlen = 0; /* remaining bitfield length */
6468 sym_link *etype; /* bitfield type information */
6469 int blen; /* bitfield length */
6470 int bstr; /* bitfield starting bit within byte */
6472 emitDebug ("; genUnpackBits");
6474 etype = getSpec (operandType (result));
6475 rsize = getSize (operandType (result));
6476 blen = SPEC_BLEN (etype);
6477 bstr = SPEC_BSTR (etype);
6479 /* If the bitfield length is less than a byte */
6482 emit2 ("ld a,!*pair", _pairs[pair].name);
6484 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6485 if (!SPEC_USIGN (etype))
6487 /* signed bitfield */
6488 symbol *tlbl = newiTempLabel (NULL);
6490 emit2 ("bit %d,a", blen - 1);
6491 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6492 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6493 emitLabel (tlbl->key + 100);
6495 aopPut (AOP (result), "a", offset++);
6499 /* TODO: what if pair == PAIR_DE ? */
6500 if (getPairId (AOP (result)) == PAIR_HL)
6502 wassertl (rsize == 2, "HL must be of size 2");
6503 emit2 ("ld a,!*hl");
6505 emit2 ("ld h,!*hl");
6508 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6509 if (!SPEC_USIGN (etype))
6511 /* signed bitfield */
6512 symbol *tlbl = newiTempLabel (NULL);
6514 emit2 ("bit %d,a", blen - 1);
6515 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6516 emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
6517 emitLabel (tlbl->key + 100);
6520 spillPair (PAIR_HL);
6524 /* Bit field did not fit in a byte. Copy all
6525 but the partial byte at the end. */
6526 for (rlen=blen;rlen>=8;rlen-=8)
6528 emit2 ("ld a,!*pair", _pairs[pair].name);
6529 aopPut (AOP (result), "a", offset++);
6532 emit2 ("inc %s", _pairs[pair].name);
6533 _G.pairs[pair].offset++;
6537 /* Handle the partial byte at the end */
6540 emit2 ("ld a,!*pair", _pairs[pair].name);
6541 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6542 if (!SPEC_USIGN (etype))
6544 /* signed bitfield */
6545 symbol *tlbl = newiTempLabel (NULL);
6547 emit2 ("bit %d,a", rlen - 1);
6548 emit2 ("jp Z,!tlabel", tlbl->key + 100);
6549 emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
6550 emitLabel (tlbl->key + 100);
6552 aopPut (AOP (result), "a", offset++);
6560 if (SPEC_USIGN (etype))
6564 /* signed bitfield: sign extension with 0x00 or 0xff */
6572 aopPut (AOP (result), source, offset++);
6576 /*-----------------------------------------------------------------*/
6577 /* genGenPointerGet - get value from generic pointer space */
6578 /*-----------------------------------------------------------------*/
6580 genGenPointerGet (operand * left,
6581 operand * result, iCode * ic)
6584 sym_link *retype = getSpec (operandType (result));
6590 aopOp (left, ic, FALSE, FALSE);
6591 aopOp (result, ic, FALSE, FALSE);
6593 size = AOP_SIZE (result);
6595 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6598 if (isPtrPair (AOP (left)))
6600 tsprintf (buffer, sizeof(buffer),
6601 "!*pair", getPairName (AOP (left)));
6602 aopPut (AOP (result), buffer, 0);
6606 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6607 aopPut (AOP (result), "a", 0);
6609 freeAsmop (left, NULL, ic);
6613 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6620 tsprintf (at, sizeof(at), "!*iyx", offset);
6621 aopPut (AOP (result), at, offset);
6625 freeAsmop (left, NULL, ic);
6629 /* For now we always load into IY */
6630 /* if this is remateriazable */
6631 fetchPair (pair, AOP (left));
6633 /* if bit then unpack */
6634 if (IS_BITVAR (retype))
6636 genUnpackBits (result, pair);
6637 freeAsmop (left, NULL, ic);
6641 else if (getPairId (AOP (result)) == PAIR_HL)
6643 wassertl (size == 2, "HL must be of size 2");
6644 emit2 ("ld a,!*hl");
6646 emit2 ("ld h,!*hl");
6648 spillPair (PAIR_HL);
6650 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6652 size = AOP_SIZE (result);
6657 /* PENDING: make this better */
6658 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6660 aopPut (AOP (result), "!*hl", offset++);
6664 emit2 ("ld a,!*pair", _pairs[pair].name);
6665 aopPut (AOP (result), "a", offset++);
6669 emit2 ("inc %s", _pairs[pair].name);
6670 _G.pairs[pair].offset++;
6673 /* Fixup HL back down */
6674 for (size = AOP_SIZE (result)-1; size; size--)
6676 emit2 ("dec %s", _pairs[pair].name);
6681 size = AOP_SIZE (result);
6686 /* PENDING: make this better */
6688 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6690 aopPut (AOP (result), "!*hl", offset++);
6694 emit2 ("ld a,!*pair", _pairs[pair].name);
6695 aopPut (AOP (result), "a", offset++);
6699 emit2 ("inc %s", _pairs[pair].name);
6700 _G.pairs[pair].offset++;
6705 freeAsmop (left, NULL, ic);
6708 freeAsmop (result, NULL, ic);
6711 /*-----------------------------------------------------------------*/
6712 /* genPointerGet - generate code for pointer get */
6713 /*-----------------------------------------------------------------*/
6715 genPointerGet (iCode * ic)
6717 operand *left, *result;
6718 sym_link *type, *etype;
6720 left = IC_LEFT (ic);
6721 result = IC_RESULT (ic);
6723 /* depending on the type of pointer we need to
6724 move it to the correct pointer register */
6725 type = operandType (left);
6726 etype = getSpec (type);
6728 genGenPointerGet (left, result, ic);
6732 isRegOrLit (asmop * aop)
6734 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6740 /*-----------------------------------------------------------------*/
6741 /* genPackBits - generates code for packed bit storage */
6742 /*-----------------------------------------------------------------*/
6744 genPackBits (sym_link * etype,
6749 int offset = 0; /* source byte offset */
6750 int rlen = 0; /* remaining bitfield length */
6751 int blen; /* bitfield length */
6752 int bstr; /* bitfield starting bit within byte */
6753 int litval; /* source literal value (if AOP_LIT) */
6754 unsigned char mask; /* bitmask within current byte */
6755 int extraPair; /* a tempory register */
6756 bool needPopExtra=0; /* need to restore original value of temp reg */
6758 emitDebug ("; genPackBits","");
6760 blen = SPEC_BLEN (etype);
6761 bstr = SPEC_BSTR (etype);
6763 /* If the bitfield length is less than a byte */
6766 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6767 (unsigned char) (0xFF >> (8 - bstr)));
6769 if (AOP_TYPE (right) == AOP_LIT)
6771 /* Case with a bitfield length <8 and literal source
6773 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6775 litval &= (~mask) & 0xff;
6776 emit2 ("ld a,!*pair", _pairs[pair].name);
6777 if ((mask|litval)!=0xff)
6778 emit2 ("and a,!immedbyte", mask);
6780 emit2 ("or a,!immedbyte", litval);
6781 emit2 ("ld !*pair,a", _pairs[pair].name);
6786 /* Case with a bitfield length <8 and arbitrary source
6788 _moveA (aopGet (AOP (right), 0, FALSE));
6789 /* shift and mask source value */
6791 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6793 extraPair = getFreePairId(ic);
6794 if (extraPair == PAIR_INVALID)
6796 extraPair = PAIR_BC;
6797 if (getPairId (AOP (right)) != PAIR_BC
6798 || !isLastUse (ic, right))
6804 emit2 ("ld %s,a", _pairs[extraPair].l);
6805 emit2 ("ld a,!*pair", _pairs[pair].name);
6807 emit2 ("and a,!immedbyte", mask);
6808 emit2 ("or a,%s", _pairs[extraPair].l);
6809 emit2 ("ld !*pair,a", _pairs[pair].name);
6816 /* Bit length is greater than 7 bits. In this case, copy */
6817 /* all except the partial byte at the end */
6818 for (rlen=blen;rlen>=8;rlen-=8)
6820 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6821 emit2 ("ld !*pair,a", _pairs[pair].name);
6824 emit2 ("inc %s", _pairs[pair].name);
6825 _G.pairs[pair].offset++;
6829 /* If there was a partial byte at the end */
6832 mask = (((unsigned char) -1 << rlen) & 0xff);
6834 if (AOP_TYPE (right) == AOP_LIT)
6836 /* Case with partial byte and literal source
6838 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6839 litval >>= (blen-rlen);
6840 litval &= (~mask) & 0xff;
6841 emit2 ("ld a,!*pair", _pairs[pair].name);
6842 if ((mask|litval)!=0xff)
6843 emit2 ("and a,!immedbyte", mask);
6845 emit2 ("or a,!immedbyte", litval);
6849 /* Case with partial byte and arbitrary source
6851 _moveA (aopGet (AOP (right), offset++, FALSE));
6852 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6854 extraPair = getFreePairId(ic);
6855 if (extraPair == PAIR_INVALID)
6857 extraPair = getPairId (AOP (right));
6858 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6859 extraPair = PAIR_BC;
6861 if (getPairId (AOP (right)) != PAIR_BC
6862 || !isLastUse (ic, right))
6868 emit2 ("ld %s,a", _pairs[extraPair].l);
6869 emit2 ("ld a,!*pair", _pairs[pair].name);
6871 emit2 ("and a,!immedbyte", mask);
6872 emit2 ("or a,%s", _pairs[extraPair].l);
6877 emit2 ("ld !*pair,a", _pairs[pair].name);
6882 /*-----------------------------------------------------------------*/
6883 /* genGenPointerSet - stores the value into a pointer location */
6884 /*-----------------------------------------------------------------*/
6886 genGenPointerSet (operand * right,
6887 operand * result, iCode * ic)
6890 sym_link *retype = getSpec (operandType (right));
6891 sym_link *letype = getSpec (operandType (result));
6892 PAIR_ID pairId = PAIR_HL;
6895 aopOp (result, ic, FALSE, FALSE);
6896 aopOp (right, ic, FALSE, FALSE);
6901 size = AOP_SIZE (right);
6903 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6904 emitDebug("; isBitvar = %d", isBitvar);
6906 /* Handle the exceptions first */
6907 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6910 const char *l = aopGet (AOP (right), 0, FALSE);
6911 const char *pair = getPairName (AOP (result));
6912 if (canAssignToPtr (l) && isPtr (pair))
6914 emit2 ("ld !*pair,%s", pair, l);
6919 emit2 ("ld !*pair,a", pair);
6924 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6927 const char *l = aopGet (AOP (right), 0, FALSE);
6932 if (canAssignToPtr (l))
6934 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6938 _moveA (aopGet (AOP (right), offset, FALSE));
6939 emit2 ("ld !*iyx,a", offset);
6945 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6952 const char *l = aopGet (AOP (right), offset, FALSE);
6953 if (isRegOrLit (AOP (right)) && !IS_GB)
6955 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6960 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6964 emit2 ("inc %s", _pairs[PAIR_HL].name);
6965 _G.pairs[PAIR_HL].offset++;
6970 /* Fixup HL back down */
6971 for (size = AOP_SIZE (right)-1; size; size--)
6973 emit2 ("dec %s", _pairs[PAIR_HL].name);
6978 /* if the operand is already in dptr
6979 then we do nothing else we move the value to dptr */
6980 if (AOP_TYPE (result) != AOP_STR)
6982 fetchPair (pairId, AOP (result));
6984 /* so hl now contains the address */
6985 freeAsmop (result, NULL, ic);
6987 /* if bit then unpack */
6990 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
7000 const char *l = aopGet (AOP (right), offset, FALSE);
7001 if (isRegOrLit (AOP (right)) && !IS_GB)
7003 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
7008 emit2 ("ld !*pair,a", _pairs[pairId].name);
7012 emit2 ("inc %s", _pairs[pairId].name);
7013 _G.pairs[pairId].offset++;
7019 freeAsmop (right, NULL, ic);
7022 /*-----------------------------------------------------------------*/
7023 /* genPointerSet - stores the value into a pointer location */
7024 /*-----------------------------------------------------------------*/
7026 genPointerSet (iCode * ic)
7028 operand *right, *result;
7029 sym_link *type, *etype;
7031 right = IC_RIGHT (ic);
7032 result = IC_RESULT (ic);
7034 /* depending on the type of pointer we need to
7035 move it to the correct pointer register */
7036 type = operandType (result);
7037 etype = getSpec (type);
7039 genGenPointerSet (right, result, ic);
7042 /*-----------------------------------------------------------------*/
7043 /* genIfx - generate code for Ifx statement */
7044 /*-----------------------------------------------------------------*/
7046 genIfx (iCode * ic, iCode * popIc)
7048 operand *cond = IC_COND (ic);
7051 aopOp (cond, ic, FALSE, TRUE);
7053 /* get the value into acc */
7054 if (AOP_TYPE (cond) != AOP_CRY)
7058 /* the result is now in the accumulator */
7059 freeAsmop (cond, NULL, ic);
7061 /* if there was something to be popped then do it */
7065 /* if the condition is a bit variable */
7066 if (isbit && IS_ITEMP (cond) &&
7068 genIfxJump (ic, SPIL_LOC (cond)->rname);
7069 else if (isbit && !IS_ITEMP (cond))
7070 genIfxJump (ic, OP_SYMBOL (cond)->rname);
7072 genIfxJump (ic, "a");
7077 /*-----------------------------------------------------------------*/
7078 /* genAddrOf - generates code for address of */
7079 /*-----------------------------------------------------------------*/
7081 genAddrOf (iCode * ic)
7083 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7085 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7087 /* if the operand is on the stack then we
7088 need to get the stack offset of this
7095 if (sym->stack <= 0)
7097 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
7101 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7103 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7107 emit2 ("ld de,!hashedstr", sym->rname);
7108 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
7116 /* if it has an offset then we need to compute it */
7118 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
7120 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
7121 emit2 ("add hl,sp");
7125 emit2 ("ld hl,!hashedstr", sym->rname);
7127 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7129 freeAsmop (IC_RESULT (ic), NULL, ic);
7132 /*-----------------------------------------------------------------*/
7133 /* genAssign - generate code for assignment */
7134 /*-----------------------------------------------------------------*/
7136 genAssign (iCode * ic)
7138 operand *result, *right;
7140 unsigned long lit = 0L;
7142 result = IC_RESULT (ic);
7143 right = IC_RIGHT (ic);
7145 /* Dont bother assigning if they are the same */
7146 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7148 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7152 aopOp (right, ic, FALSE, FALSE);
7153 aopOp (result, ic, TRUE, FALSE);
7155 /* if they are the same registers */
7156 if (sameRegs (AOP (right), AOP (result)))
7158 emitDebug ("; (registers are the same)");
7162 /* if the result is a bit */
7163 if (AOP_TYPE (result) == AOP_CRY)
7165 wassertl (0, "Tried to assign to a bit");
7169 size = AOP_SIZE (result);
7172 if (AOP_TYPE (right) == AOP_LIT)
7174 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7177 if (isPair (AOP (result)))
7179 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7181 else if ((size > 1) &&
7182 (AOP_TYPE (result) != AOP_REG) &&
7183 (AOP_TYPE (right) == AOP_LIT) &&
7184 !IS_FLOAT (operandType (right)) &&
7187 bool fXored = FALSE;
7189 /* Work from the top down.
7190 Done this way so that we can use the cached copy of 0
7191 in A for a fast clear */
7194 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7196 if (!fXored && size > 1)
7203 aopPut (AOP (result), "a", offset);
7207 aopPut (AOP (result), "!zero", offset);
7211 aopPut (AOP (result),
7212 aopGet (AOP (right), offset, FALSE),
7217 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7219 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7220 aopPut (AOP (result), "l", LSB);
7221 aopPut (AOP (result), "h", MSB16);
7223 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7225 /* Special case. Load into a and d, then load out. */
7226 _moveA (aopGet (AOP (right), 0, FALSE));
7227 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7228 aopPut (AOP (result), "a", 0);
7229 aopPut (AOP (result), "e", 1);
7231 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7233 /* Special case - simple memcpy */
7234 aopGet (AOP (right), LSB, FALSE);
7237 aopGet (AOP (result), LSB, FALSE);
7241 emit2 ("ld a,(de)");
7242 /* Peephole will optimise this. */
7243 emit2 ("ld (hl),a");
7251 spillPair (PAIR_HL);
7257 /* PENDING: do this check better */
7258 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7260 _moveA (aopGet (AOP (right), offset, FALSE));
7261 aopPut (AOP (result), "a", offset);
7264 aopPut (AOP (result),
7265 aopGet (AOP (right), offset, FALSE),
7272 freeAsmop (right, NULL, ic);
7273 freeAsmop (result, NULL, ic);
7276 /*-----------------------------------------------------------------*/
7277 /* genJumpTab - genrates code for jump table */
7278 /*-----------------------------------------------------------------*/
7280 genJumpTab (iCode * ic)
7285 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7286 /* get the condition into accumulator */
7287 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7290 emit2 ("ld e,%s", l);
7291 emit2 ("ld d,!zero");
7292 jtab = newiTempLabel (NULL);
7294 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7295 emit2 ("add hl,de");
7296 emit2 ("add hl,de");
7297 emit2 ("add hl,de");
7298 freeAsmop (IC_JTCOND (ic), NULL, ic);
7302 emitLabel (jtab->key + 100);
7303 /* now generate the jump labels */
7304 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7305 jtab = setNextItem (IC_JTLABELS (ic)))
7306 emit2 ("jp !tlabel", jtab->key + 100);
7309 /*-----------------------------------------------------------------*/
7310 /* genCast - gen code for casting */
7311 /*-----------------------------------------------------------------*/
7313 genCast (iCode * ic)
7315 operand *result = IC_RESULT (ic);
7316 sym_link *rtype = operandType (IC_RIGHT (ic));
7317 operand *right = IC_RIGHT (ic);
7320 /* if they are equivalent then do nothing */
7321 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7324 aopOp (right, ic, FALSE, FALSE);
7325 aopOp (result, ic, FALSE, FALSE);
7327 /* if the result is a bit */
7328 if (AOP_TYPE (result) == AOP_CRY)
7330 wassertl (0, "Tried to cast to a bit");
7333 /* if they are the same size : or less */
7334 if (AOP_SIZE (result) <= AOP_SIZE (right))
7337 /* if they are in the same place */
7338 if (sameRegs (AOP (right), AOP (result)))
7341 /* if they in different places then copy */
7342 size = AOP_SIZE (result);
7346 aopPut (AOP (result),
7347 aopGet (AOP (right), offset, FALSE),
7354 /* So we now know that the size of destination is greater
7355 than the size of the source */
7356 /* we move to result for the size of source */
7357 size = AOP_SIZE (right);
7361 aopPut (AOP (result),
7362 aopGet (AOP (right), offset, FALSE),
7367 /* now depending on the sign of the destination */
7368 size = AOP_SIZE (result) - AOP_SIZE (right);
7369 /* Unsigned or not an integral type - right fill with zeros */
7370 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7373 aopPut (AOP (result), "!zero", offset++);
7377 /* we need to extend the sign :{ */
7378 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7384 aopPut (AOP (result), "a", offset++);
7388 freeAsmop (right, NULL, ic);
7389 freeAsmop (result, NULL, ic);
7392 /*-----------------------------------------------------------------*/
7393 /* genReceive - generate code for a receive iCode */
7394 /*-----------------------------------------------------------------*/
7396 genReceive (iCode * ic)
7398 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7399 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7400 IS_TRUE_SYMOP (IC_RESULT (ic))))
7410 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7411 size = AOP_SIZE(IC_RESULT(ic));
7413 for (i = 0; i < size; i++) {
7414 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7418 freeAsmop (IC_RESULT (ic), NULL, ic);
7421 /*-----------------------------------------------------------------*/
7422 /* genDummyRead - generate code for dummy read of volatiles */
7423 /*-----------------------------------------------------------------*/
7425 genDummyRead (iCode * ic)
7431 if (op && IS_SYMOP (op))
7433 aopOp (op, ic, FALSE, FALSE);
7436 size = AOP_SIZE (op);
7441 _moveA (aopGet (AOP (op), offset, FALSE));
7445 freeAsmop (op, NULL, ic);
7449 if (op && IS_SYMOP (op))
7451 aopOp (op, ic, FALSE, FALSE);
7454 size = AOP_SIZE (op);
7459 _moveA (aopGet (AOP (op), offset, FALSE));
7463 freeAsmop (op, NULL, ic);
7467 /*-----------------------------------------------------------------*/
7468 /* genCritical - generate code for start of a critical sequence */
7469 /*-----------------------------------------------------------------*/
7471 genCritical (iCode *ic)
7473 symbol *tlbl = newiTempLabel (NULL);
7479 else if (IC_RESULT (ic))
7481 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7482 aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
7483 //get interrupt enable flag IFF2 into P/O
7487 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
7488 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7489 aopPut (AOP (IC_RESULT (ic)), "!one", 0);
7490 emit2 ("!tlabeldef", (tlbl->key + 100));
7491 _G.lines.current->isLabel = 1;
7492 freeAsmop (IC_RESULT (ic), NULL, ic);
7496 //get interrupt enable flag IFF2 into P/O
7505 /*-----------------------------------------------------------------*/
7506 /* genEndCritical - generate code for end of a critical sequence */
7507 /*-----------------------------------------------------------------*/
7509 genEndCritical (iCode *ic)
7511 symbol *tlbl = newiTempLabel (NULL);
7517 else if (IC_RIGHT (ic))
7519 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
7520 _toBoolean (IC_RIGHT (ic));
7521 //don't enable interrupts if they were off before
7522 emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
7524 emitLabel (tlbl->key + 100);
7525 freeAsmop (IC_RIGHT (ic), NULL, ic);
7531 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7532 //don't enable interrupts as they were off before
7533 emit2 ("jp PO,!tlabel", tlbl->key + 100);
7535 emit2 ("!tlabeldef", (tlbl->key + 100));
7536 _G.lines.current->isLabel = 1;
7542 /** Maximum number of bytes to emit per line. */
7546 /** Context for the byte output chunker. */
7549 unsigned char buffer[DBEMIT_MAX_RUN];
7554 /** Flushes a byte chunker by writing out all in the buffer and
7558 _dbFlush(DBEMITCTX *self)
7565 sprintf(line, ".db 0x%02X", self->buffer[0]);
7567 for (i = 1; i < self->pos; i++)
7569 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7576 /** Write out another byte, buffering until a decent line is
7580 _dbEmit(DBEMITCTX *self, int c)
7582 if (self->pos == DBEMIT_MAX_RUN)
7586 self->buffer[self->pos++] = c;
7589 /** Context for a simple run length encoder. */
7593 unsigned char buffer[128];
7595 /** runLen may be equivalent to pos. */
7601 RLE_CHANGE_COST = 4,
7605 /** Flush the buffer of a run length encoder by writing out the run or
7606 data that it currently contains.
7609 _rleCommit(RLECTX *self)
7615 memset(&db, 0, sizeof(db));
7617 emit2(".db %u", self->pos);
7619 for (i = 0; i < self->pos; i++)
7621 _dbEmit(&db, self->buffer[i]);
7630 Can get either a run or a block of random stuff.
7631 Only want to change state if a good run comes in or a run ends.
7632 Detecting run end is easy.
7635 Say initial state is in run, len zero, last zero. Then if you get a
7636 few zeros then something else then a short run will be output.
7637 Seems OK. While in run mode, keep counting. While in random mode,
7638 keep a count of the run. If run hits margin, output all up to run,
7639 restart, enter run mode.
7642 /** Add another byte into the run length encoder, flushing as
7643 required. The run length encoder uses the Amiga IFF style, where
7644 a block is prefixed by its run length. A positive length means
7645 the next n bytes pass straight through. A negative length means
7646 that the next byte is repeated -n times. A zero terminates the
7650 _rleAppend(RLECTX *self, unsigned c)
7654 if (c != self->last)
7656 /* The run has stopped. See if it is worthwhile writing it out
7657 as a run. Note that the random data comes in as runs of
7660 if (self->runLen > RLE_CHANGE_COST)
7662 /* Yes, worthwhile. */
7663 /* Commit whatever was in the buffer. */
7665 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7669 /* Not worthwhile. Append to the end of the random list. */
7670 for (i = 0; i < self->runLen; i++)
7672 if (self->pos >= RLE_MAX_BLOCK)
7677 self->buffer[self->pos++] = self->last;
7685 if (self->runLen >= RLE_MAX_BLOCK)
7687 /* Commit whatever was in the buffer. */
7690 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7698 _rleFlush(RLECTX *self)
7700 _rleAppend(self, -1);
7707 /** genArrayInit - Special code for initialising an array with constant
7711 genArrayInit (iCode * ic)
7715 int elementSize = 0, eIndex, i;
7716 unsigned val, lastVal;
7720 memset(&rle, 0, sizeof(rle));
7722 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7724 _saveRegsForCall(ic, 0);
7726 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7727 emit2 ("call __initrleblock");
7729 type = operandType(IC_LEFT(ic));
7731 if (type && type->next)
7733 if (IS_SPEC(type->next) || IS_PTR(type->next))
7735 elementSize = getSize(type->next);
7737 else if (IS_ARRAY(type->next) && type->next->next)
7739 elementSize = getSize(type->next->next);
7743 printTypeChainRaw (type, NULL);
7744 wassertl (0, "Can't determine element size in genArrayInit.");
7749 wassertl (0, "Can't determine element size in genArrayInit.");
7752 wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7754 iLoop = IC_ARRAYILIST(ic);
7755 lastVal = (unsigned)-1;
7757 /* Feed all the bytes into the run length encoder which will handle
7759 This works well for mixed char data, and for random int and long
7766 for (i = 0; i < ix; i++)
7768 for (eIndex = 0; eIndex < elementSize; eIndex++)
7770 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7771 _rleAppend(&rle, val);
7775 iLoop = iLoop->next;
7779 /* Mark the end of the run. */
7782 _restoreRegsAfterCall();
7786 freeAsmop (IC_LEFT(ic), NULL, ic);
7790 _swap (PAIR_ID one, PAIR_ID two)
7792 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7798 emit2 ("ld a,%s", _pairs[one].l);
7799 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7800 emit2 ("ld %s,a", _pairs[two].l);
7801 emit2 ("ld a,%s", _pairs[one].h);
7802 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7803 emit2 ("ld %s,a", _pairs[two].h);
7807 /* The problem is that we may have all three pairs used and they may
7808 be needed in a different order.
7813 hl = hl => unity, fine
7817 hl = hl hl = hl, swap de <=> bc
7825 hl = bc de = de, swap bc <=> hl
7833 hl = de bc = bc, swap hl <=> de
7838 * Any pair = pair are done last
7839 * Any pair = iTemp are done last
7840 * Any swaps can be done any time
7848 So how do we detect the cases?
7849 How about a 3x3 matrix?
7853 x x x x (Fourth for iTemp/other)
7855 First determin which mode to use by counting the number of unity and
7858 Two - Assign the pair first, then the rest
7859 One - Swap the two, then the rest
7863 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7865 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7867 PAIR_BC, PAIR_HL, PAIR_DE
7869 int i, j, nunity = 0;
7870 memset (ids, PAIR_INVALID, sizeof (ids));
7873 wassert (nparams == 3);
7875 /* First save everything that needs to be saved. */
7876 _saveRegsForCall (ic, 0);
7878 /* Loading HL first means that DE is always fine. */
7879 for (i = 0; i < nparams; i++)
7881 aopOp (pparams[i], ic, FALSE, FALSE);
7882 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7885 /* Count the number of unity or iTemp assigns. */
7886 for (i = 0; i < 3; i++)
7888 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7896 /* Any order, fall through. */
7898 else if (nunity == 2)
7900 /* One is assigned. Pull it out and assign. */
7901 for (i = 0; i < 3; i++)
7903 for (j = 0; j < NUM_PAIRS; j++)
7905 if (ids[dest[i]][j] == TRUE)
7907 /* Found it. See if it's the right one. */
7908 if (j == PAIR_INVALID || j == dest[i])
7914 fetchPair(dest[i], AOP (pparams[i]));
7921 else if (nunity == 1)
7923 /* Find the pairs to swap. */
7924 for (i = 0; i < 3; i++)
7926 for (j = 0; j < NUM_PAIRS; j++)
7928 if (ids[dest[i]][j] == TRUE)
7930 if (j == PAIR_INVALID || j == dest[i])
7945 int next = getPairId (AOP (pparams[0]));
7946 emit2 ("push %s", _pairs[next].name);
7948 if (next == dest[1])
7950 fetchPair (dest[1], AOP (pparams[1]));
7951 fetchPair (dest[2], AOP (pparams[2]));
7955 fetchPair (dest[2], AOP (pparams[2]));
7956 fetchPair (dest[1], AOP (pparams[1]));
7958 emit2 ("pop %s", _pairs[dest[0]].name);
7961 /* Finally pull out all of the iTemps */
7962 for (i = 0; i < 3; i++)
7964 if (ids[dest[i]][PAIR_INVALID] == 1)
7966 fetchPair (dest[i], AOP (pparams[i]));
7972 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7978 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7982 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7984 setupForBuiltin3 (ic, nParams, pparams);
7986 label = newiTempLabel(NULL);
7988 emitLabel (label->key);
7989 emit2 ("ld a,(hl)");
7992 emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
7994 freeAsmop (from, NULL, ic->next);
7995 freeAsmop (to, NULL, ic);
7999 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
8001 operand *from, *to, *count;
8004 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
8009 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
8011 setupForBuiltin3 (ic, nParams, pparams);
8015 freeAsmop (count, NULL, ic->next->next);
8016 freeAsmop (from, NULL, ic);
8018 _restoreRegsAfterCall();
8020 /* if we need assign a result value */
8021 if ((IS_ITEMP (IC_RESULT (ic)) &&
8022 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
8023 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
8024 IS_TRUE_SYMOP (IC_RESULT (ic)))
8026 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
8027 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
8028 freeAsmop (IC_RESULT (ic), NULL, ic);
8031 freeAsmop (to, NULL, ic->next);
8034 /*-----------------------------------------------------------------*/
8035 /* genBuiltIn - calls the appropriate function to generating code */
8036 /* for a built in function */
8037 /*-----------------------------------------------------------------*/
8038 static void genBuiltIn (iCode *ic)
8040 operand *bi_parms[MAX_BUILTIN_ARGS];
8045 /* get all the arguments for a built in function */
8046 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
8048 /* which function is it */
8049 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
8051 if (strcmp(bif->name,"__builtin_strcpy")==0)
8053 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
8055 else if (strcmp(bif->name,"__builtin_memcpy")==0)
8057 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
8061 wassertl (0, "Unknown builtin function encountered");
8065 /*-----------------------------------------------------------------*/
8066 /* genZ80Code - generate code for Z80 based controllers */
8067 /*-----------------------------------------------------------------*/
8069 genZ80Code (iCode * lic)
8077 _fReturn = _gbz80_return;
8078 _fTmp = _gbz80_return;
8082 _fReturn = _z80_return;
8083 _fTmp = _z80_return;
8086 _G.lines.head = _G.lines.current = NULL;
8088 /* if debug information required */
8089 if (options.debug && currFunc)
8091 debugFile->writeFunction (currFunc, lic);
8094 for (ic = lic; ic; ic = ic->next)
8096 _G.current_iCode = ic;
8098 if (ic->lineno && cln != ic->lineno)
8102 debugFile->writeCLine (ic);
8104 if (!options.noCcodeInAsm)
8106 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
8107 printCLine(ic->filename, ic->lineno));
8111 if (options.iCodeInAsm)
8113 char *iLine = printILine(ic);
8114 emit2 (";ic:%d: %s", ic->key, iLine);
8117 /* if the result is marked as
8118 spilt and rematerializable or code for
8119 this has already been generated then
8121 if (resultRemat (ic) || ic->generated)
8124 /* depending on the operation */
8128 emitDebug ("; genNot");
8133 emitDebug ("; genCpl");
8138 emitDebug ("; genUminus");
8143 emitDebug ("; genIpush");
8148 /* IPOP happens only when trying to restore a
8149 spilt live range, if there is an ifx statement
8150 following this pop then the if statement might
8151 be using some of the registers being popped which
8152 would destroy the contents of the register so
8153 we need to check for this condition and handle it */
8155 ic->next->op == IFX &&
8156 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
8158 emitDebug ("; genIfx");
8159 genIfx (ic->next, ic);
8163 emitDebug ("; genIpop");
8169 emitDebug ("; genCall");
8174 emitDebug ("; genPcall");
8179 emitDebug ("; genFunction");
8184 emitDebug ("; genEndFunction");
8185 genEndFunction (ic);
8189 emitDebug ("; genRet");
8194 emitDebug ("; genLabel");
8199 emitDebug ("; genGoto");
8204 emitDebug ("; genPlus");
8209 emitDebug ("; genMinus");
8214 emitDebug ("; genMult");
8219 emitDebug ("; genDiv");
8224 emitDebug ("; genMod");
8229 emitDebug ("; genCmpGt");
8230 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8234 emitDebug ("; genCmpLt");
8235 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8242 /* note these two are xlated by algebraic equivalence
8243 during parsing SDCC.y */
8244 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8245 "got '>=' or '<=' shouldn't have come here");
8249 emitDebug ("; genCmpEq");
8250 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8254 emitDebug ("; genAndOp");
8259 emitDebug ("; genOrOp");
8264 emitDebug ("; genXor");
8265 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8269 emitDebug ("; genOr");
8270 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8274 emitDebug ("; genAnd");
8275 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8279 emitDebug ("; genInline");
8284 emitDebug ("; genRRC");
8289 emitDebug ("; genRLC");
8294 emitDebug ("; genGetHBIT");
8299 emitDebug ("; genLeftShift");
8304 emitDebug ("; genRightShift");
8308 case GET_VALUE_AT_ADDRESS:
8309 emitDebug ("; genPointerGet");
8315 if (POINTER_SET (ic))
8317 emitDebug ("; genAssign (pointer)");
8322 emitDebug ("; genAssign");
8328 emitDebug ("; genIfx");
8333 emitDebug ("; genAddrOf");
8338 emitDebug ("; genJumpTab");
8343 emitDebug ("; genCast");
8348 emitDebug ("; genReceive");
8353 if (ic->builtinSEND)
8355 emitDebug ("; genBuiltIn");
8360 emitDebug ("; addSet");
8361 addSet (&_G.sendSet, ic);
8366 emitDebug ("; genArrayInit");
8370 case DUMMY_READ_VOLATILE:
8371 emitDebug ("; genDummyRead");
8376 emitDebug ("; genCritical");
8381 emitDebug ("; genEndCritical");
8382 genEndCritical (ic);
8391 /* now we are ready to call the
8392 peep hole optimizer */
8393 if (!options.nopeep)
8394 peepHole (&_G.lines.head);
8396 /* This is unfortunate */
8397 /* now do the actual printing */
8399 struct dbuf_s *buf = codeOutBuf;
8400 if (isInHome () && codeOutBuf == &code->oBuf)
8401 codeOutBuf = &home->oBuf;
8402 printLine (_G.lines.head, codeOutBuf);
8403 if (_G.flushStatics)
8406 _G.flushStatics = 0;
8411 freeTrace(&_G.lines.trace);
8412 freeTrace(&_G.trace.aops);
8418 _isPairUsed (iCode * ic, PAIR_ID pairId)
8424 if (bitVectBitValue (ic->rMask, D_IDX))
8426 if (bitVectBitValue (ic->rMask, E_IDX))
8436 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8439 value *val = aop->aopu.aop_lit;
8441 wassert (aop->type == AOP_LIT);
8442 wassert (!IS_FLOAT (val->type));
8444 v = (unsigned long) floatFromVal (val);
8452 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8453 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));