* src/mcs51/gen.c (genCmp): fixed bug #975903
[fw/sdcc] / src / z80 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - Z80 specific code generator.
3      
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)
8
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
12   later version.
13
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.
18
19
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.
23
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!
27
28 -------------------------------------------------------------------------*/
29
30 /*
31   Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
32                                        ticks dhry  size
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
46   5/3/00                                17741 185 17B6
47   With reg params for mul and div       16234 202 162D
48
49   1. Starting again at 3 Aug 01         34965  93 219C
50    No asm strings
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
61
62   10 and below are with asm strings off.
63
64   10 Mucho optimisations                13562 201 1FCC
65
66   Apparent advantage of turning on regparams:
67   1.  Cost of push
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
73             10+11+(7+6+7+6)*nargs
74   3.  Cost of fixing stack
75           - pop hl*nargs
76             10*nargs
77   
78   So cost is (10+11+7+6+7+10)*nargs+10+11 
79       = 51*nargs+21
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.
83 */
84
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <ctype.h>
89
90 #if defined(__BORLANDC__) || defined(_MSC_VER)
91 #define STRCASECMP stricmp
92 #else
93 #define STRCASECMP strcasecmp
94 #endif
95
96 #include "z80.h"
97 #include "SDCCglobl.h"
98 #include "SDCCpeeph.h"
99 #include "gen.h"
100 #include "SDCCglue.h"
101 #include "newalloc.h"
102
103 /* This is the down and dirty file with all kinds of kludgy & hacky
104    stuff. This is what it is all about CODE GENERATION for a specific MCU.
105    Some of the routines may be reusable, will have to see */
106
107 /* Z80 calling convention description.
108    Parameters are passed right to left.  As the stack grows downwards,
109    the parameters are arranged in left to right in memory.
110    Parameters may be passed in the HL and DE registers with one
111    parameter per pair.
112    PENDING: What if the parameter is a long?
113    Everything is caller saves. i.e. the caller must save any registers
114    that it wants to preserve over the call.
115    GB: The return value is returned in DEHL.  DE is normally used as a
116    working register pair.  Caller saves allows it to be used for a
117    return value.
118    va args functions do not use register parameters.  All arguments
119    are passed on the stack.
120    IX is used as an index register to the top of the local variable
121    area.  ix-0 is the top most local variable.
122 */
123
124 enum 
125 {
126   /* Set to enable debugging trace statements in the output assembly code. */
127   DISABLE_DEBUG = 0
128 };
129
130 static char *_z80_return[] =
131 {"l", "h", "e", "d"};
132 static char *_gbz80_return[] =
133 {"e", "d", "l", "h"};
134 static char *_fReceive[] =
135   { "c", "b", "e", "d" };
136
137 static char **_fReturn;
138 static char **_fTmp;
139
140 extern FILE *codeOutFile;
141
142 enum
143   {
144     INT8MIN = -128,
145     INT8MAX = 127
146   };
147
148 /** Enum covering all the possible register pairs.
149  */
150 typedef enum
151   {
152     PAIR_INVALID,
153     PAIR_AF,
154     PAIR_BC,
155     PAIR_DE,
156     PAIR_HL,
157     PAIR_IY,
158     PAIR_IX,
159     NUM_PAIRS
160   } PAIR_ID;
161
162 static struct
163 {
164   const char *name;
165   const char *l;
166   const char *h;
167 } _pairs[NUM_PAIRS] = {
168   {    "??1", "?2", "?3" },
169   {    "af", "f", "a" },
170   {    "bc", "c", "b" },
171   {    "de", "e", "d" },
172   {    "hl", "l", "h" },
173   {    "iy", "iyl", "iyh" },
174   {    "ix", "ixl", "ixh" }
175 };
176
177 // PENDING
178 #define ACC_NAME        _pairs[PAIR_AF].h
179
180 enum 
181   {
182     LSB,
183     MSB16,
184     MSB24,
185     MSB32
186   };
187
188 /** Code generator persistent data.
189  */
190 static struct 
191 {
192   /** Used to optimised setting up of a pair by remebering what it
193       contains and adjusting instead of reloading where possible.
194   */
195   struct 
196   {
197     AOP_TYPE last_type;
198     const char *base;
199     int offset;
200   } pairs[NUM_PAIRS];
201   struct 
202   {
203     int last;
204     int pushed;
205     int param_offset;
206     int offset;
207     int pushedBC;
208     int pushedDE;
209   } stack;
210
211   struct
212   {
213     int pushedBC;
214     int pushedDE;
215   } calleeSaves;
216
217   bool omitFramePtr;
218   int frameId;
219   int receiveOffset;
220   bool flushStatics;
221   bool in_home;
222   const char *lastFunctionName;
223   iCode *current_iCode;
224   bool preserveCarry;
225   
226   set *sendSet;
227
228   struct
229   {
230     /** TRUE if the registers have already been saved. */
231     bool saved;
232   } saves;
233
234   struct 
235   {
236     lineNode *head;
237     lineNode *current;
238     int isInline;
239     int isDebug;
240     allocTrace trace;
241   } lines;
242
243   struct
244   {
245     allocTrace aops;
246   } trace;
247 } _G;
248
249 static const char *aopGet (asmop * aop, int offset, bool bit16);
250
251 static const char *aopNames[] = {
252   "AOP_INVALID",
253   "AOP_LIT",
254   "AOP_REG",
255   "AOP_DIR",
256   "AOP_SFR",
257   "AOP_STK",
258   "AOP_IMMD",
259   "AOP_STR",
260   "AOP_CRY",
261   "AOP_IY",
262   "AOP_HL",
263   "AOP_ACC",
264   "AOP_HLREG",
265   "AOP_SIMPLELIT",
266   "AOP_EXSTK",
267   "AOP_PAIRPT",
268   "AOP_DUMMY"
269 };
270
271 static bool
272 isLastUse (iCode *ic, operand *op)
273 {
274   bitVect *uses = bitVectCopy (OP_USES (op));
275
276   while (!bitVectIsZero (uses))
277     {
278       if (bitVectFirstBit (uses) == ic->key)
279         {
280           if (bitVectnBitsOn (uses) == 1)
281             {
282               return TRUE;
283             }
284           else
285             {
286               return FALSE;
287             }
288         }
289       bitVectUnSetBit (uses, bitVectFirstBit (uses));
290     }
291
292   return FALSE;
293 }
294
295 static PAIR_ID
296 _getTempPairId(void)
297 {
298   if (IS_GB)
299     {
300       return PAIR_DE;
301     }
302   else
303     {
304       return PAIR_HL;
305     }
306 }
307
308 static const char *
309 _getTempPairName(void)
310 {
311   return _pairs[_getTempPairId()].name;
312 }
313
314 static bool
315 isPairInUse (PAIR_ID id, iCode *ic)
316 {
317   if (id == PAIR_DE)
318     {
319       return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
320     }
321   else if (id == PAIR_BC)
322     {
323       return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
324     }
325   else
326     {
327       wassertl (0, "Only implemented for DE and BC");
328       return TRUE;
329     }
330 }
331
332 static bool
333 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
334 {
335   bitVect *rInUse;
336   
337   rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
338   
339   if (id == PAIR_DE)
340     {
341       return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
342     }
343   else
344     {
345       wassertl (0, "Only implemented for DE");
346       return TRUE;
347     }
348 }
349
350 static PAIR_ID
351 getFreePairId (iCode *ic)
352 {
353   if (!isPairInUse (PAIR_BC, ic))
354     {
355       return PAIR_BC;
356     }
357   else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
358     {
359       return PAIR_DE;
360     }
361   else
362     {
363       return PAIR_INVALID;
364     }
365 }         
366
367 static void
368 _tidyUp (char *buf)
369 {
370   /* Clean up the line so that it is 'prettier' */
371   if (strchr (buf, ':'))
372     {
373       /* Is a label - cant do anything */
374       return;
375     }
376   /* Change the first (and probably only) ' ' to a tab so
377      everything lines up.
378   */
379   while (*buf)
380     {
381       if (*buf == ' ')
382         {
383           *buf = '\t';
384           break;
385         }
386       buf++;
387     }
388 }
389
390 static lineNode *
391 _newLineNode (char *line)
392 {
393   lineNode *pl;
394
395   pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
396   pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
397
398   return pl;
399 }
400
401 static void
402 _vemit2 (const char *szFormat, va_list ap)
403 {
404   char buffer[INITIAL_INLINEASM];
405
406   tvsprintf (buffer, sizeof(buffer), szFormat, ap);
407
408   _tidyUp (buffer);
409   _G.lines.current = (_G.lines.current ?
410               connectLine (_G.lines.current, _newLineNode (buffer)) :
411               (_G.lines.head = _newLineNode (buffer)));
412
413   _G.lines.current->isInline = _G.lines.isInline;
414   _G.lines.current->isDebug = _G.lines.isDebug;
415   _G.lines.current->ic = _G.current_iCode;
416 }
417
418 static void
419 emit2 (const char *szFormat,...)
420 {
421   va_list ap;
422
423   va_start (ap, szFormat);
424
425   _vemit2 (szFormat, ap);
426
427   va_end (ap);
428 }
429
430 static void
431 emitDebug (const char *szFormat,...)
432 {
433   if (!DISABLE_DEBUG)
434     {
435       va_list ap;
436
437       va_start (ap, szFormat);
438
439       _vemit2 (szFormat, ap);
440
441       va_end (ap);
442     }
443 }
444
445 /*-----------------------------------------------------------------*/
446 /* z80_emitDebuggerSymbol - associate the current code location    */
447 /*   with a debugger symbol                                        */
448 /*-----------------------------------------------------------------*/
449 void
450 z80_emitDebuggerSymbol (char * debugSym)
451 {
452   _G.lines.isDebug = 1;
453   emit2 ("%s !equ .", debugSym);
454   emit2 ("!global", debugSym);
455   _G.lines.isDebug = 0;
456 }
457
458 /*-----------------------------------------------------------------*/
459 /* emit2 - writes the code into a file : for now it is simple    */
460 /*-----------------------------------------------------------------*/
461 void
462 _emit2 (const char *inst, const char *fmt,...)
463 {
464   va_list ap;
465   char lb[INITIAL_INLINEASM];
466   char *lbp = lb;
467
468   va_start (ap, fmt);
469
470   if (*inst != '\0')
471     {
472       sprintf (lb, "%s\t", inst);
473       vsprintf (lb + (strlen (lb)), fmt, ap);
474     }
475   else
476     vsprintf (lb, fmt, ap);
477
478   while (isspace (*lbp))
479     lbp++;
480
481   if (lbp && *lbp)
482     {
483       _G.lines.current = (_G.lines.current ?
484                   connectLine (_G.lines.current, _newLineNode (lb)) :
485                   (_G.lines.head = _newLineNode (lb)));
486     }
487   _G.lines.current->isInline = _G.lines.isInline;
488   _G.lines.current->ic = _G.current_iCode;
489   va_end (ap);
490 }
491
492 static void
493 _emitMove(const char *to, const char *from)
494 {
495   if (STRCASECMP(to, from) != 0) 
496     {
497       emit2("ld %s,%s", to, from);
498     }
499   else 
500     {
501       // Optimise it out.
502       // Could leave this to the peephole, but sometimes the peephole is inhibited.
503     }
504 }
505
506 void
507 aopDump(const char *plabel, asmop *aop)
508 {
509   int i;
510   char regbuf[9];
511   char *rbp = regbuf;
512   
513   emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
514   switch (aop->type)
515     {
516     case AOP_EXSTK:
517     case AOP_STK:
518       emitDebug(";  aop_stk %d", aop->aopu.aop_stk);
519       break;
520     case AOP_REG:
521       for (i=aop->size-1;i>=0;i--)
522         *rbp++ = *(aop->aopu.aop_reg[i]->name);
523       *rbp = '\0';
524       emitDebug(";  reg = %s", regbuf);
525       break;
526     case AOP_PAIRPTR:
527       emitDebug(";  pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
528         
529     default:
530       /* No information. */
531       break;
532     }
533 }
534
535 static void
536 _moveA(const char *moveFrom)
537 {
538     // Let the peephole optimiser take care of redundent loads
539     _emitMove(ACC_NAME, moveFrom);
540 }
541
542 static void
543 _clearCarry(void)
544 {
545     emit2("xor a,a");
546 }
547
548 const char *
549 getPairName (asmop * aop)
550 {
551   if (aop->type == AOP_REG)
552     {
553       switch (aop->aopu.aop_reg[0]->rIdx)
554         {
555         case C_IDX:
556           return "bc";
557           break;
558         case E_IDX:
559           return "de";
560           break;
561         case L_IDX:
562           return "hl";
563           break;
564         }
565     }
566   else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
567     {
568       int i;
569       for (i = 0; i < NUM_PAIRS; i++)
570         {
571           if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
572             {
573               return _pairs[i].name;
574             }
575         }
576     }
577   wassertl (0, "Tried to get the pair name of something that isn't a pair");
578   return NULL;
579 }
580
581 static PAIR_ID
582 getPairId (asmop * aop)
583 {
584   if (aop->size == 2)
585     {
586       if (aop->type == AOP_REG)
587         {
588           if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
589             {
590               return PAIR_BC;
591             }
592           if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
593             {
594               return PAIR_DE;
595             }
596           if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
597             {
598               return PAIR_HL;
599             }
600         }
601       else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
602         {
603           int i;
604           for (i = 0; i < NUM_PAIRS; i++)
605             {
606               if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
607                 {
608                   return i;
609                 }
610             }
611         }
612     }
613   return PAIR_INVALID;
614 }
615
616 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
617 bool
618 isPair (asmop * aop)
619 {
620   return (getPairId (aop) != PAIR_INVALID);
621 }
622
623 /** Returns TRUE if the registers used in aop cannot be split into high
624     and low halves */
625 bool
626 isUnsplitable (asmop * aop)
627 {
628   switch (getPairId (aop))
629     {
630     case PAIR_IX:
631     case PAIR_IY:
632       return TRUE;
633     default:
634       return FALSE;
635     }
636   return FALSE;
637 }
638
639 bool
640 isPtrPair (asmop * aop)
641 {
642   PAIR_ID pairId = getPairId (aop);
643   switch (pairId)
644     {
645     case PAIR_HL:
646     case PAIR_IY:
647     case PAIR_IX:
648       return TRUE;
649     default:
650       return FALSE;
651     }
652 }
653
654 static void
655 spillPair (PAIR_ID pairId)
656 {
657   _G.pairs[pairId].last_type = AOP_INVALID;
658   _G.pairs[pairId].base = NULL;
659 }
660
661 /* Given a register name, spill the pair (if any) the register is part of */
662 static void
663 spillPairReg (const char *regname)
664 {      
665   if (strlen(regname)==1)
666     {
667       switch (*regname)
668         {
669         case 'h':
670         case 'l':
671           spillPair(PAIR_HL);
672           break;
673         case 'd':
674         case 'e':
675           spillPair(PAIR_DE);
676           break;
677         case 'b':
678         case 'c':
679           spillPair(PAIR_BC);
680           break;
681         }
682     }
683 }
684
685 /** Push a register pair onto the stack */
686 void
687 genPairPush (asmop * aop)
688 {
689   emit2 ("push %s", getPairName (aop));
690 }
691
692 static void
693 _push (PAIR_ID pairId)
694 {
695   emit2 ("push %s", _pairs[pairId].name);
696   _G.stack.pushed += 2;
697 }
698
699 static void
700 _pop (PAIR_ID pairId)
701 {
702   emit2 ("pop %s", _pairs[pairId].name);
703   _G.stack.pushed -= 2;
704   spillPair (pairId);
705 }
706
707 void
708 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
709 {
710   switch (dstPair)
711     {
712     case PAIR_IX:
713     case PAIR_IY:
714     case PAIR_AF:
715       _push(srcPair);
716       _pop(dstPair);
717       break;
718     case PAIR_BC:
719     case PAIR_DE:
720     case PAIR_HL:
721       if (srcPair == PAIR_IX || srcPair == PAIR_IY)
722         {
723           _push(srcPair);
724           _pop(dstPair);
725         }
726       else
727         {
728           emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
729           emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
730         }
731      default:
732        wassertl (0, "Tried to move a nonphysical pair");
733     }
734   _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
735   _G.pairs[dstPair].base = _G.pairs[srcPair].base;
736   _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
737 }
738
739
740 /*-----------------------------------------------------------------*/
741 /* newAsmop - creates a new asmOp                                  */
742 /*-----------------------------------------------------------------*/
743 static asmop *
744 newAsmop (short type)
745 {
746   asmop *aop;
747
748   aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
749   aop->type = type;
750   return aop;
751 }
752
753 /*-----------------------------------------------------------------*/
754 /* aopForSym - for a true symbol                                   */
755 /*-----------------------------------------------------------------*/
756 static asmop *
757 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
758 {
759   asmop *aop;
760   memmap *space;
761
762   wassert (ic);
763   wassert (sym);
764   wassert (sym->etype);
765
766   space = SPEC_OCLS (sym->etype);
767
768   /* if already has one */
769   if (sym->aop)
770     {
771       return sym->aop;
772     }
773
774   /* Assign depending on the storage class */
775   if (sym->onStack || sym->iaccess)
776     {
777       /* The pointer that is used depends on how big the offset is.
778          Normally everything is AOP_STK, but for offsets of < -128 or
779          > 127 on the Z80 an extended stack pointer is used.
780       */
781       if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
782         {
783           emitDebug ("; AOP_EXSTK for %s", sym->rname);
784           sym->aop = aop = newAsmop (AOP_EXSTK);
785         }
786       else
787         {
788           emitDebug ("; AOP_STK for %s", sym->rname);
789           sym->aop = aop = newAsmop (AOP_STK);
790         }
791
792       aop->size = getSize (sym->type);
793       aop->aopu.aop_stk = sym->stack;
794       return aop;
795     }
796
797   /* special case for a function */
798   if (IS_FUNC (sym->type))
799     {
800       sym->aop = aop = newAsmop (AOP_IMMD);
801       aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
802       aop->size = 2;
803       return aop;
804     }
805
806   if( IN_REGSP( space ))
807   { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
808     if (IS_GB)
809     {
810       /* if it is in direct space */
811       if( !requires_a )
812       {
813         sym->aop = aop = newAsmop (AOP_SFR);
814         aop->aopu.aop_dir = sym->rname;
815         aop->size = getSize (sym->type);
816           emitDebug ("; AOP_SFR for %s", sym->rname);
817         return aop;
818       }
819     }
820     else
821     { /*.p.t.20030716 adding SFR support to the Z80 port */
822       aop = newAsmop (AOP_SFR);
823       sym->aop          = aop;
824       aop->aopu.aop_dir = sym->rname;
825       aop->size         = getSize( sym->type );
826       aop->paged        = FUNC_REGBANK(sym->type);
827       aop->bcInUse      = isPairInUse( PAIR_BC, ic );
828       aop->deInUse      = isPairInUse( PAIR_DE, ic );
829       emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
830
831       return( aop );
832     }
833   }
834
835   /* only remaining is far space */
836   /* in which case DPTR gets the address */
837   if (IS_GB)
838     {
839       emitDebug ("; AOP_HL for %s", sym->rname);
840       sym->aop = aop = newAsmop (AOP_HL);
841     }
842   else
843     {
844       sym->aop = aop = newAsmop (AOP_IY);
845     }
846   aop->size = getSize (sym->type);
847   aop->aopu.aop_dir = sym->rname;
848
849   /* if it is in code space */
850   if (IN_CODESPACE (space))
851     aop->code = 1;
852
853   return aop;
854 }
855
856 /*-----------------------------------------------------------------*/
857 /* aopForRemat - rematerialzes an object                           */
858 /*-----------------------------------------------------------------*/
859 static asmop *
860 aopForRemat (symbol * sym)
861 {
862   char *s = buffer;
863   iCode *ic = sym->rematiCode;
864   asmop *aop = newAsmop (AOP_IMMD);
865
866   while (1)
867     {
868       /* if plus or minus print the right hand side */
869       if (ic->op == '+' || ic->op == '-')
870         {
871           /* PENDING: for re-target */
872           sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
873                    ic->op);
874           s += strlen (s);
875           ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
876           continue;
877         }
878       /* we reached the end */
879       sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
880       break;
881     }
882
883   aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
884   return aop;
885 }
886
887 /*-----------------------------------------------------------------*/
888 /* regsInCommon - two operands have some registers in common       */
889 /*-----------------------------------------------------------------*/
890 bool
891 regsInCommon (operand * op1, operand * op2)
892 {
893   symbol *sym1, *sym2;
894   int i;
895
896   /* if they have registers in common */
897   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
898     return FALSE;
899
900   sym1 = OP_SYMBOL (op1);
901   sym2 = OP_SYMBOL (op2);
902
903   if (sym1->nRegs == 0 || sym2->nRegs == 0)
904     return FALSE;
905
906   for (i = 0; i < sym1->nRegs; i++)
907     {
908       int j;
909       if (!sym1->regs[i])
910         continue;
911
912       for (j = 0; j < sym2->nRegs; j++)
913         {
914           if (!sym2->regs[j])
915             continue;
916
917           if (sym2->regs[j] == sym1->regs[i])
918             return TRUE;
919         }
920     }
921
922   return FALSE;
923 }
924
925 /*-----------------------------------------------------------------*/
926 /* operandsEqu - equivalent                                        */
927 /*-----------------------------------------------------------------*/
928 bool
929 operandsEqu (operand * op1, operand * op2)
930 {
931   symbol *sym1, *sym2;
932
933   /* if they not symbols */
934   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
935     return FALSE;
936
937   sym1 = OP_SYMBOL (op1);
938   sym2 = OP_SYMBOL (op2);
939
940   /* if both are itemps & one is spilt
941      and the other is not then false */
942   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
943       sym1->isspilt != sym2->isspilt)
944     return FALSE;
945
946   /* if they are the same */
947   if (sym1 == sym2)
948     return 1;
949
950   if (sym1->rname[0] && sym2->rname[0]
951       && strcmp (sym1->rname, sym2->rname) == 0)
952     return 2;
953
954   /* if left is a tmp & right is not */
955   if (IS_ITEMP (op1) &&
956       !IS_ITEMP (op2) &&
957       sym1->isspilt &&
958       (sym1->usl.spillLoc == sym2))
959     return 3;
960
961   if (IS_ITEMP (op2) &&
962       !IS_ITEMP (op1) &&
963       sym2->isspilt &&
964       sym1->level > 0 &&
965       (sym2->usl.spillLoc == sym1))
966     return 4;
967
968   return FALSE;
969 }
970
971 /*-----------------------------------------------------------------*/
972 /* sameRegs - two asmops have the same registers                   */
973 /*-----------------------------------------------------------------*/
974 bool
975 sameRegs (asmop * aop1, asmop * aop2)
976 {
977   int i;
978
979   if (aop1->type == AOP_SFR ||
980       aop2->type == AOP_SFR)
981     return FALSE;
982
983   if (aop1 == aop2)
984     return TRUE;
985
986   if (aop1->type != AOP_REG ||
987       aop2->type != AOP_REG)
988     return FALSE;
989
990   if (aop1->size != aop2->size)
991     return FALSE;
992
993   for (i = 0; i < aop1->size; i++)
994     if (aop1->aopu.aop_reg[i] !=
995         aop2->aopu.aop_reg[i])
996       return FALSE;
997
998   return TRUE;
999 }
1000
1001 /*-----------------------------------------------------------------*/
1002 /* aopOp - allocates an asmop for an operand  :                    */
1003 /*-----------------------------------------------------------------*/
1004 static void
1005 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
1006 {
1007   asmop *aop;
1008   symbol *sym;
1009   int i;
1010
1011   if (!op)
1012     return;
1013
1014   /* if this a literal */
1015   if (IS_OP_LITERAL (op))
1016     {
1017       op->aop = aop = newAsmop (AOP_LIT);
1018       aop->aopu.aop_lit = op->operand.valOperand;
1019       aop->size = getSize (operandType (op));
1020       return;
1021     }
1022
1023   /* if already has a asmop then continue */
1024   if (op->aop)
1025     {
1026       if (op->aop->type == AOP_SFR)
1027         {
1028           op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1029           op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1030         }
1031       return;
1032     }
1033
1034   /* if the underlying symbol has a aop */
1035   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1036     {
1037       op->aop = OP_SYMBOL (op)->aop;
1038       if (op->aop->type == AOP_SFR)
1039         {
1040           op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1041           op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1042         }
1043       return;
1044     }
1045
1046   /* if this is a true symbol */
1047   if (IS_TRUE_SYMOP (op))
1048     {
1049       op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1050       return;
1051     }
1052
1053   /* this is a temporary : this has
1054      only four choices :
1055      a) register
1056      b) spillocation
1057      c) rematerialize
1058      d) conditional
1059      e) can be a return use only */
1060
1061   sym = OP_SYMBOL (op);
1062
1063   /* if the type is a conditional */
1064   if (sym->regType == REG_CND)
1065     {
1066       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1067       aop->size = 0;
1068       return;
1069     }
1070
1071   /* if it is spilt then two situations
1072      a) is rematerialize
1073      b) has a spill location */
1074   if (sym->isspilt || sym->nRegs == 0)
1075     {
1076       /* rematerialize it NOW */
1077       if (sym->remat)
1078         {
1079           sym->aop = op->aop = aop =
1080             aopForRemat (sym);
1081           aop->size = getSize (sym->type);
1082           return;
1083         }
1084
1085       if (sym->ruonly)
1086         {
1087           int i;
1088           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1089           aop->size = getSize (sym->type);
1090           for (i = 0; i < 4; i++)
1091             aop->aopu.aop_str[i] = _fReturn[i];
1092           return;
1093         }
1094
1095       if (sym->accuse)
1096         {
1097           if (sym->accuse == ACCUSE_A)
1098             {
1099               aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1100               aop->size = getSize (sym->type);
1101               wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1102
1103               aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1104             }
1105           else if (sym->accuse == ACCUSE_SCRATCH)
1106             {
1107               aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1108               aop->size = getSize (sym->type);
1109               wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1110               aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1111               aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1112             }
1113           else if (sym->accuse == ACCUSE_IY)
1114             {
1115               aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1116               aop->size = getSize (sym->type);
1117               wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1118               aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1119               aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1120             }
1121           else 
1122               {
1123                   wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1124               }
1125           return;
1126         }
1127
1128       if (sym->usl.spillLoc)
1129         {
1130           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1131             {
1132               /* force a new aop if sizes differ */
1133               sym->usl.spillLoc->aop = NULL;
1134             }
1135           sym->aop = op->aop = aop =
1136                      aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1137           aop->size = getSize (sym->type);
1138           return;
1139         }
1140       
1141       /* else must be a dummy iTemp */
1142       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1143       aop->size = getSize (sym->type);
1144       return;
1145     }
1146
1147   /* must be in a register */
1148   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1149   aop->size = sym->nRegs;
1150   for (i = 0; i < sym->nRegs; i++)
1151     aop->aopu.aop_reg[i] = sym->regs[i];
1152 }
1153
1154 /*-----------------------------------------------------------------*/
1155 /* freeAsmop - free up the asmop given to an operand               */
1156 /*----------------------------------------------------------------*/
1157 static void
1158 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1159 {
1160   asmop *aop;
1161
1162   if (!op)
1163     aop = aaop;
1164   else
1165     aop = op->aop;
1166
1167   if (!aop)
1168     return;
1169
1170   if (aop->freed)
1171     goto dealloc;
1172
1173   aop->freed = 1;
1174
1175   if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1176     {
1177       _pop (aop->aopu.aop_pairId);
1178     }
1179
1180   if (getPairId (aop) == PAIR_HL)
1181     {
1182       spillPair (PAIR_HL);
1183     }
1184
1185 dealloc:
1186   /* all other cases just dealloc */
1187   if (op)
1188     {
1189       op->aop = NULL;
1190       if (IS_SYMOP (op))
1191         {
1192           OP_SYMBOL (op)->aop = NULL;
1193           /* if the symbol has a spill */
1194           if (SPIL_LOC (op))
1195             SPIL_LOC (op)->aop = NULL;
1196         }
1197     }
1198
1199 }
1200
1201 bool
1202 isLitWord (asmop * aop)
1203 {
1204   /*    if (aop->size != 2)
1205      return FALSE; */
1206   switch (aop->type)
1207     {
1208     case AOP_IMMD:
1209     case AOP_LIT:
1210       return TRUE;
1211     default:
1212       return FALSE;
1213     }
1214 }
1215
1216 char *
1217 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1218 {
1219   /* depending on type */
1220   switch (aop->type)
1221     {
1222     case AOP_HL:
1223     case AOP_IY:
1224     case AOP_IMMD:
1225       /* PENDING: for re-target */
1226       if (with_hash)
1227         {
1228           tsprintf (buffer, sizeof(buffer), 
1229                     "!hashedstr + %d", aop->aopu.aop_immd, offset);
1230         }
1231       else if (offset == 0)
1232         {
1233           tsprintf (buffer, sizeof(buffer),
1234                     "%s", aop->aopu.aop_immd);
1235         }
1236       else
1237         {
1238           tsprintf (buffer, sizeof(buffer), 
1239                     "%s + %d", aop->aopu.aop_immd, offset);
1240         }
1241       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1242
1243     case AOP_LIT:
1244       {
1245         value *val = aop->aopu.aop_lit;
1246         /* if it is a float then it gets tricky */
1247         /* otherwise it is fairly simple */
1248         if (!IS_FLOAT (val->type))
1249           {
1250             unsigned long v = (unsigned long) floatFromVal (val);
1251
1252             if (offset == 2)
1253               {
1254                 v >>= 16;
1255               }
1256             else if (offset == 0)
1257               {
1258                 // OK
1259               }
1260             else 
1261               {
1262                 wassertl(0, "Encountered an invalid offset while fetching a literal");
1263               }
1264
1265             if (with_hash)
1266               tsprintf (buffer, sizeof(buffer), "!immedword", v);
1267             else
1268               tsprintf (buffer, sizeof(buffer), "!constword", v);
1269
1270             return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1271           }
1272         else
1273           {
1274             union {
1275               float f;
1276               unsigned char c[4];
1277             }
1278             fl;
1279             unsigned int i;
1280
1281             /* it is type float */
1282             fl.f = (float) floatFromVal (val);
1283
1284 #ifdef WORDS_BIGENDIAN
1285             i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1286 #else
1287             i = fl.c[offset] | (fl.c[offset+1]<<8);
1288 #endif
1289             if (with_hash)
1290               tsprintf (buffer, sizeof(buffer), "!immedword", i);
1291             else
1292               tsprintf (buffer, sizeof(buffer), "!constword", i);
1293
1294             return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1295           }
1296       }
1297     default:
1298       return NULL;
1299     }
1300 }
1301
1302 char *
1303 aopGetWord (asmop * aop, int offset)
1304 {
1305   return aopGetLitWordLong (aop, offset, TRUE);
1306 }
1307
1308 bool
1309 isPtr (const char *s)
1310 {
1311   if (!strcmp (s, "hl"))
1312     return TRUE;
1313   if (!strcmp (s, "ix"))
1314     return TRUE;
1315   if (!strcmp (s, "iy"))
1316     return TRUE;
1317   return FALSE;
1318 }
1319
1320 static void
1321 adjustPair (const char *pair, int *pold, int new)
1322 {
1323   wassert (pair);
1324
1325   while (*pold < new)
1326     {
1327       emit2 ("inc %s", pair);
1328       (*pold)++;
1329     }
1330   while (*pold > new)
1331     {
1332       emit2 ("dec %s", pair);
1333       (*pold)--;
1334     }
1335 }
1336
1337 static void
1338 spillCached (void)
1339 {
1340   spillPair (PAIR_HL);
1341   spillPair (PAIR_IY);
1342 }
1343
1344 static bool
1345 requiresHL (asmop * aop)
1346 {
1347   switch (aop->type)
1348     {
1349     case AOP_IY:
1350     case AOP_HL:
1351     case AOP_STK:
1352     case AOP_EXSTK:
1353     case AOP_HLREG:
1354       return TRUE;
1355     default:
1356       return FALSE;
1357     }
1358 }
1359
1360 static void
1361 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1362 {
1363   const char *l, *base;
1364   const char *pair = _pairs[pairId].name;
1365   l = aopGetLitWordLong (left, offset, FALSE);
1366   base = aopGetLitWordLong (left, 0, FALSE);
1367   wassert (l && pair && base);
1368
1369   if (isPtr (pair))
1370     {
1371       if (pairId == PAIR_HL || pairId == PAIR_IY)
1372         {
1373           if (_G.pairs[pairId].last_type == left->type)
1374             {
1375               if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1376                 {
1377                   if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1378                     {
1379                       adjustPair (pair, &_G.pairs[pairId].offset, offset);
1380                       return;
1381                     }
1382                   if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1383                     {
1384                       return;
1385                     }
1386                 }
1387             }
1388         }
1389       _G.pairs[pairId].last_type = left->type;
1390       _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1391       _G.pairs[pairId].offset = offset;
1392     }
1393   /* Both a lit on the right and a true symbol on the left */
1394   emit2 ("ld %s,!hashedstr", pair, l);
1395 }
1396
1397 static PAIR_ID
1398 makeFreePairId (iCode *ic, bool *pisUsed)
1399 {
1400   *pisUsed = FALSE;
1401
1402   if (ic != NULL)
1403     {
1404       if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1405         {
1406           return PAIR_BC;
1407         }
1408       else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1409         {
1410           return PAIR_DE;
1411         }
1412       else
1413         {
1414           *pisUsed = TRUE;
1415           return PAIR_HL;
1416         }
1417     }
1418   else
1419     {
1420       *pisUsed = TRUE;
1421       return PAIR_HL;
1422     }
1423 }
1424
1425 static void
1426 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1427 {
1428     /* if this is remateriazable */
1429     if (isLitWord (aop)) {
1430         fetchLitPair (pairId, aop, offset);
1431     }
1432     else 
1433       {
1434         if (getPairId (aop) == pairId)
1435           {
1436             /* Do nothing */
1437           }
1438         /* we need to get it byte by byte */
1439         else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1440             aopGet (aop, offset, FALSE);
1441             switch (aop->size - offset) {
1442             case 1:
1443                 emit2 ("ld l,!*hl");
1444                 emit2 ("ld h,!immedbyte", 0);
1445                             break;
1446             case 2:
1447               // PENDING: Requires that you are only fetching two bytes.
1448             case 4:
1449                 emit2 ("!ldahli");
1450                 emit2 ("ld h,!*hl");
1451                 emit2 ("ld l,a");
1452                 break;
1453             default:
1454               wassertl (0, "Attempted to fetch too much data into HL");
1455               break;
1456             }
1457         }
1458         else if (IS_Z80 && aop->type == AOP_IY) {
1459             /* Instead of fetching relative to IY, just grab directly
1460                from the address IY refers to */
1461             char *l = aopGetLitWordLong (aop, offset, FALSE);
1462             wassert (l);
1463             emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1464
1465             if (aop->size < 2) {
1466                 emit2("ld %s,!zero", _pairs[pairId].h);
1467             }
1468         }
1469         else if (pairId == PAIR_IY)
1470           {
1471             if (isPair (aop))
1472               {
1473                 emit2 ("push %s", _pairs[getPairId(aop)].name);
1474                 emit2 ("pop iy");
1475               }
1476             else
1477               {
1478                 bool isUsed;
1479                 PAIR_ID id = makeFreePairId (ic, &isUsed);
1480                 if (isUsed)
1481                   _push (id);
1482                 /* Can't load into parts, so load into HL then exchange. */
1483                 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1484                 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1485                 emit2 ("push %s", _pairs[id].name);
1486                 emit2 ("pop iy");
1487                 if (isUsed)
1488                   _pop (id);
1489               }
1490           }
1491         else if (isUnsplitable(aop))
1492           {
1493             emit2("push %s", _pairs[getPairId(aop)].name);
1494             emit2("pop %s", _pairs[pairId].name);
1495           }
1496         else 
1497           {
1498             emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1499             emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1500           }
1501         /* PENDING: check? */
1502         if (pairId == PAIR_HL)
1503             spillPair (PAIR_HL);
1504     }
1505 }
1506
1507 static void
1508 fetchPair (PAIR_ID pairId, asmop * aop)
1509 {
1510   fetchPairLong (pairId, aop, NULL, 0);
1511 }
1512
1513 static void
1514 fetchHL (asmop * aop)
1515 {
1516   fetchPair (PAIR_HL, aop);
1517 }
1518
1519 static void
1520 setupPairFromSP (PAIR_ID id, int offset)
1521 {
1522   wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1523
1524   if (_G.preserveCarry)
1525     {
1526       _push (PAIR_AF);
1527       offset += 2;
1528     }
1529   
1530   if (offset < INT8MIN || offset > INT8MAX)
1531     {
1532       emit2 ("ld hl,!immedword", offset);
1533       emit2 ("add hl,sp");
1534     }
1535   else
1536     {
1537           emit2 ("!ldahlsp", offset);
1538     }
1539
1540   if (_G.preserveCarry)
1541     {
1542       _pop (PAIR_AF);
1543       offset -= 2;
1544     }
1545 }
1546
1547 static void
1548 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1549 {
1550   switch (aop->type)
1551     {
1552     case AOP_IY:
1553       wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1554       fetchLitPair (pairId, aop, 0);
1555       break;
1556
1557     case AOP_HL:
1558       wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1559       
1560       fetchLitPair (pairId, aop, offset);
1561       _G.pairs[pairId].offset = offset;
1562       break;
1563
1564     case AOP_EXSTK:
1565       wassertl (IS_Z80, "Only the Z80 has an extended stack");
1566       wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1567
1568       {
1569         int offset = aop->aopu.aop_stk + _G.stack.offset;
1570
1571         if (_G.pairs[pairId].last_type == aop->type &&
1572             _G.pairs[pairId].offset == offset)
1573           {
1574             /* Already setup */
1575           }
1576         else
1577           {
1578             /* PENDING: Do this better. */
1579             if (_G.preserveCarry)
1580               _push (PAIR_AF);
1581             sprintf (buffer, "%d", offset + _G.stack.pushed);
1582             emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1583             emit2 ("add %s,sp", _pairs[pairId].name);
1584             _G.pairs[pairId].last_type = aop->type;
1585             _G.pairs[pairId].offset = offset;
1586             if (_G.preserveCarry)
1587               _pop (PAIR_AF);
1588           }
1589       }
1590       break;
1591
1592     case AOP_STK:
1593       {
1594         /* Doesnt include _G.stack.pushed */
1595         int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1596
1597         if (aop->aopu.aop_stk > 0)
1598           {
1599             abso += _G.stack.param_offset;
1600           }
1601         assert (pairId == PAIR_HL);
1602         /* In some cases we can still inc or dec hl */
1603         if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1604           {
1605             adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1606           }
1607         else
1608           {
1609             setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1610           }
1611         _G.pairs[pairId].offset = abso;
1612         break;
1613       }
1614
1615     case AOP_PAIRPTR:
1616       if (pairId != aop->aopu.aop_pairId)
1617         genMovePairPair(aop->aopu.aop_pairId, pairId);
1618       adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1619       break;
1620       
1621     default:
1622       wassert (0);
1623     }
1624   _G.pairs[pairId].last_type = aop->type;
1625 }
1626
1627 static void
1628 emitLabel (int key)
1629 {
1630   emit2 ("!tlabeldef", key);
1631   spillCached ();
1632 }
1633
1634 /*-----------------------------------------------------------------*/
1635 /* aopGet - for fetching value of the aop                          */
1636 /*-----------------------------------------------------------------*/
1637 static const char *
1638 aopGet (asmop * aop, int offset, bool bit16)
1639 {
1640   // char *s = buffer;
1641
1642   /* offset is greater than size then zero */
1643   /* PENDING: this seems a bit screwed in some pointer cases. */
1644   if (offset > (aop->size - 1) &&
1645       aop->type != AOP_LIT) 
1646     {
1647       tsprintf (buffer, sizeof(buffer), "!zero");
1648       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1649     }
1650
1651   /* depending on type */
1652   switch (aop->type)
1653     {
1654     case AOP_DUMMY:
1655       tsprintf (buffer, sizeof(buffer), "!zero");
1656       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1657     
1658     case AOP_IMMD:
1659       /* PENDING: re-target */
1660       if (bit16)
1661         tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1662       else
1663         switch (offset)
1664           {
1665           case 2:
1666             tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1667             break;
1668           case 1:
1669             tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1670             break;
1671           case 0:
1672             tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1673             break;
1674           default:
1675             wassertl (0, "Fetching from beyond the limits of an immediate value.");
1676           }
1677
1678       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1679
1680     case AOP_DIR:
1681       wassert (IS_GB);
1682       emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1683       SNPRINTF (buffer, sizeof(buffer), "a");
1684
1685       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1686
1687     case AOP_SFR:
1688       if( IS_GB )
1689       {
1690         // wassert (IS_GB);
1691         emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1692         SNPRINTF (buffer, sizeof(buffer), "a");
1693
1694         return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1695       }
1696       else
1697       { /*.p.t.20030716 handling for i/o port read access for Z80 */
1698         if( aop->paged )
1699         { /* banked mode */
1700           /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1701           emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1702           emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1703         }
1704         else if( z80_opts.port_mode == 180 )
1705         { /* z180 in0/out0 mode */
1706           emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1707         }
1708         else
1709         { /* 8 bit mode */
1710           emit2( "in a,(%s)", aop->aopu.aop_dir );
1711         }
1712         
1713         SNPRINTF (buffer, sizeof(buffer), "a");
1714
1715         return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1716       }
1717
1718     case AOP_REG:
1719       return aop->aopu.aop_reg[offset]->name;
1720
1721     case AOP_HL:
1722       wassert (IS_GB);
1723       setupPair (PAIR_HL, aop, offset);
1724       tsprintf (buffer, sizeof(buffer), "!*hl");
1725
1726       return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1727
1728     case AOP_IY:
1729       wassert (IS_Z80);
1730       setupPair (PAIR_IY, aop, offset);
1731       tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1732
1733       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1734
1735     case AOP_EXSTK:
1736       wassert (IS_Z80);
1737       setupPair (PAIR_IY, aop, offset);
1738       tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1739
1740       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1741
1742     case AOP_STK:
1743       if (IS_GB)
1744         {
1745           setupPair (PAIR_HL, aop, offset);
1746           tsprintf (buffer, sizeof(buffer), "!*hl");
1747         }
1748       else
1749         {
1750           if (aop->aopu.aop_stk >= 0)
1751             offset += _G.stack.param_offset;
1752           tsprintf (buffer, sizeof(buffer),
1753                     "!*ixx", aop->aopu.aop_stk + offset);
1754         }
1755
1756       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1757
1758     case AOP_CRY:
1759       wassertl (0, "Tried to fetch from a bit variable");
1760
1761     case AOP_ACC:
1762       if (!offset)
1763         {
1764           return "a";
1765         }
1766       else
1767         {
1768           tsprintf(buffer, sizeof(buffer), "!zero");
1769           return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1770         }
1771
1772     case AOP_HLREG:
1773       wassert (offset < 2);
1774       return aop->aopu.aop_str[offset];
1775
1776     case AOP_LIT:
1777       return aopLiteral (aop->aopu.aop_lit, offset);
1778
1779     case AOP_SIMPLELIT:
1780       {
1781         unsigned long v = aop->aopu.aop_simplelit;
1782         
1783         v >>= (offset * 8);
1784         tsprintf (buffer, sizeof(buffer), 
1785                   "!immedbyte", (unsigned int) v & 0xff);
1786         
1787         return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1788       }
1789     case AOP_STR:
1790       aop->coff = offset;
1791       return aop->aopu.aop_str[offset];
1792
1793     case AOP_PAIRPTR:
1794       setupPair (aop->aopu.aop_pairId, aop, offset);
1795       if (aop->aopu.aop_pairId==PAIR_IX)
1796         SNPRINTF (buffer, sizeof(buffer), 
1797                   "!*ixx", 0);
1798       else if (aop->aopu.aop_pairId==PAIR_IY)
1799         SNPRINTF (buffer, sizeof(buffer), 
1800                   "!*iyx", 0);
1801       else
1802         SNPRINTF (buffer, sizeof(buffer), 
1803                   "(%s)", _pairs[aop->aopu.aop_pairId].name);
1804
1805       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1806
1807     default:
1808       break;
1809     }
1810   wassertl (0, "aopget got unsupported aop->type");
1811   exit (0);
1812 }
1813
1814 bool
1815 isRegString (const char *s)
1816 {
1817   if (!strcmp (s, "b") ||
1818       !strcmp (s, "c") ||
1819       !strcmp (s, "d") ||
1820       !strcmp (s, "e") ||
1821       !strcmp (s, "a") ||
1822       !strcmp (s, "h") ||
1823       !strcmp (s, "l"))
1824     return TRUE;
1825   return FALSE;
1826 }
1827
1828 bool
1829 isConstant (const char *s)
1830 {
1831   /* This is a bit of a hack... */
1832   return (*s == '#' || *s == '$');
1833 }
1834
1835 bool
1836 canAssignToPtr (const char *s)
1837 {
1838   if (isRegString (s))
1839     return TRUE;
1840   if (isConstant (s))
1841     return TRUE;
1842   return FALSE;
1843 }
1844
1845 /*-----------------------------------------------------------------*/
1846 /* aopPut - puts a string for a aop                                */
1847 /*-----------------------------------------------------------------*/
1848 static void
1849 aopPut (asmop * aop, const char *s, int offset)
1850 {
1851   char buffer2[256];
1852
1853   if (aop->size && offset > (aop->size - 1))
1854     {
1855       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1856               "aopPut got offset > aop->size");
1857       exit (0);
1858     }
1859
1860   // PENDING
1861   tsprintf(buffer2, sizeof(buffer2), s);
1862   s = buffer2;
1863
1864   /* will assign value to value */
1865   /* depending on where it is ofcourse */
1866   switch (aop->type)
1867     {
1868     case AOP_DUMMY:
1869       _moveA (s);  /* in case s is volatile */
1870       break;
1871       
1872     case AOP_DIR:
1873       /* Direct.  Hmmm. */
1874       wassert (IS_GB);
1875       if (strcmp (s, "a"))
1876         emit2 ("ld a,%s", s);
1877       emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1878       break;
1879
1880     case AOP_SFR:
1881       if( IS_GB )
1882       {
1883         //  wassert (IS_GB);
1884         if (strcmp (s, "a"))
1885           emit2 ("ld a,%s", s);
1886         emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1887       }
1888       else
1889       { /*.p.t.20030716 handling for i/o port read access for Z80 */
1890         if( aop->paged )
1891         { /* banked mode */
1892           if( aop->bcInUse )  emit2( "push bc" );
1893
1894           emit2( "ld bc,#%s", aop->aopu.aop_dir );
1895
1896           if(( s[0] == '#'    ) /* immediate number */
1897            ||( s[0] == '('    ) /* indirect register (ix or iy ??)*/
1898            ||( isdigit( s[0] )))/* indirect register with offset (ix or iy ??)*/
1899           {
1900             emit2( "ld a,%s", s );
1901             emit2( "out (c),a"  );
1902           }
1903           else
1904           {
1905             emit2( "out (c),%s", s );
1906           }
1907         
1908           if( aop->bcInUse )
1909             emit2( "pop bc"    );
1910           else
1911             spillPair (PAIR_BC);
1912         }
1913         else if( z80_opts.port_mode == 180 )
1914         { /* z180 in0/out0 mode */
1915           emit2( "ld a,%s", s );
1916           emit2( "out0 (%s),a", aop->aopu.aop_dir );
1917         }
1918         else
1919         { /* 8 bit mode */
1920           emit2( "ld a,%s", s );
1921           emit2( "out (%s),a", aop->aopu.aop_dir );
1922         }
1923       }
1924       break;
1925
1926     case AOP_REG:
1927       if (!strcmp (s, "!*hl"))
1928         emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1929       else
1930         emit2 ("ld %s,%s",
1931                aop->aopu.aop_reg[offset]->name, s);
1932       spillPairReg(aop->aopu.aop_reg[offset]->name);
1933       break;
1934
1935     case AOP_IY:
1936       wassert (!IS_GB);
1937       if (!canAssignToPtr (s))
1938         {
1939           emit2 ("ld a,%s", s);
1940           setupPair (PAIR_IY, aop, offset);
1941           emit2 ("ld !*iyx,a", offset);
1942         }
1943       else
1944         {
1945           setupPair (PAIR_IY, aop, offset);
1946           emit2 ("ld !*iyx,%s", offset, s);
1947         }
1948       break;
1949
1950     case AOP_HL:
1951       wassert (IS_GB);
1952       /* PENDING: for re-target */
1953       if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1954         {
1955           emit2 ("ld a,!*hl");
1956           s = "a";
1957         }
1958       setupPair (PAIR_HL, aop, offset);
1959
1960       emit2 ("ld !*hl,%s", s);
1961       break;
1962
1963     case AOP_EXSTK:
1964       wassert (!IS_GB);
1965       if (!canAssignToPtr (s))
1966         {
1967           emit2 ("ld a,%s", s);
1968           setupPair (PAIR_IY, aop, offset);
1969           emit2 ("ld !*iyx,a", offset);
1970         }
1971       else
1972         {
1973           setupPair (PAIR_IY, aop, offset);
1974           emit2 ("ld !*iyx,%s", offset, s);
1975         }
1976       break;
1977
1978     case AOP_STK:
1979       if (IS_GB)
1980         {
1981           /* PENDING: re-target */
1982           if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1983             {
1984               emit2 ("ld a,!*hl");
1985               s = "a";
1986             }
1987           setupPair (PAIR_HL, aop, offset);
1988           if (!canAssignToPtr (s))
1989             {
1990               emit2 ("ld a,%s", s);
1991               emit2 ("ld !*hl,a");
1992             }
1993           else
1994             emit2 ("ld !*hl,%s", s);
1995         }
1996       else
1997         {
1998           if (aop->aopu.aop_stk >= 0)
1999             offset += _G.stack.param_offset;
2000           if (!canAssignToPtr (s))
2001             {
2002               emit2 ("ld a,%s", s);
2003               emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
2004             }
2005           else
2006             {
2007               emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2008             }
2009         }
2010       break;
2011
2012     case AOP_CRY:
2013       /* if bit variable */
2014       if (!aop->aopu.aop_dir)
2015         {
2016           emit2 ("ld a,!zero");
2017           emit2 ("rla");
2018         }
2019       else
2020         {
2021           /* In bit space but not in C - cant happen */
2022           wassertl (0, "Tried to write into a bit variable");
2023         }
2024       break;
2025
2026     case AOP_STR:
2027       aop->coff = offset;
2028       if (strcmp (aop->aopu.aop_str[offset], s))
2029         {
2030           emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2031         }
2032       spillPairReg(aop->aopu.aop_str[offset]);
2033       break;
2034
2035     case AOP_ACC:
2036       aop->coff = offset;
2037       if (!offset && (strcmp (s, "acc") == 0))
2038         break;
2039       if (offset > 0)
2040         {
2041           wassertl (0, "Tried to access past the end of A");
2042         }
2043       else
2044         {
2045           if (strcmp (aop->aopu.aop_str[offset], s))
2046             {
2047               emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2048               spillPairReg(aop->aopu.aop_str[offset]);
2049             }
2050         }
2051       break;
2052
2053     case AOP_HLREG:
2054       wassert (offset < 2);
2055       emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2056       spillPairReg(aop->aopu.aop_str[offset]);
2057       break;
2058
2059     case AOP_PAIRPTR:
2060       setupPair (aop->aopu.aop_pairId, aop, offset);
2061       if (aop->aopu.aop_pairId==PAIR_IX)
2062         emit2 ("ld !*ixx,%s", 0, s);
2063       else if (aop->aopu.aop_pairId==PAIR_IY)
2064         emit2 ("ld !*ixy,%s", 0, s);
2065       else
2066         emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2067       break;
2068
2069     default:
2070       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2071               "aopPut got unsupported aop->type");
2072       exit (0);
2073     }
2074 }
2075
2076 #define AOP(op) op->aop
2077 #define AOP_TYPE(op) AOP(op)->type
2078 #define AOP_SIZE(op) AOP(op)->size
2079 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2080
2081 static void
2082 commitPair (asmop * aop, PAIR_ID id)
2083 {
2084   /* PENDING: Verify this. */
2085   if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2086     {
2087       emit2 ("ld a,l");
2088       emit2 ("ld d,h");
2089       aopPut (aop, "a", 0);
2090       aopPut (aop, "d", 1);
2091     }
2092   else
2093     {
2094       /* Special cases */
2095       if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2096         {
2097           char *l = aopGetLitWordLong (aop, 0, FALSE);
2098           wassert (l);
2099
2100           emit2 ("ld (%s),%s", l, _pairs[id].name);
2101         }
2102       else
2103         {
2104           aopPut (aop, _pairs[id].l, 0);
2105           aopPut (aop, _pairs[id].h, 1);
2106         }
2107     }
2108 }
2109
2110 /*-----------------------------------------------------------------*/
2111 /* getDataSize - get the operand data size                         */
2112 /*-----------------------------------------------------------------*/
2113 int
2114 getDataSize (operand * op)
2115 {
2116   int size;
2117   size = AOP_SIZE (op);
2118   if (size == 3)
2119     {
2120       /* pointer */
2121       wassertl (0, "Somehow got a three byte data pointer");
2122     }
2123   return size;
2124 }
2125
2126 /*-----------------------------------------------------------------*/
2127 /* movLeft2Result - move byte from left to result                  */
2128 /*-----------------------------------------------------------------*/
2129 static void
2130 movLeft2Result (operand * left, int offl,
2131                 operand * result, int offr, int sign)
2132 {
2133   const char *l;
2134
2135   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2136     {
2137       l = aopGet (AOP (left), offl, FALSE);
2138
2139       if (!sign)
2140         {
2141           aopPut (AOP (result), l, offr);
2142         }
2143       else
2144         {
2145           if (getDataSize (left) == offl + 1)
2146             {
2147               emit2 ("ld a,%s", l);
2148               aopPut (AOP (result), "a", offr);
2149             }
2150         }
2151     }
2152 }
2153
2154 static void
2155 movLeft2ResultLong (operand * left, int offl,
2156                 operand * result, int offr, int sign,
2157                 int size)
2158 {
2159   if (size == 1)
2160     {
2161       movLeft2Result (left, offl, result, offr, sign);
2162     }
2163   else
2164     {
2165       wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2166       wassertl (size == 2, "Only implemented for two bytes or one");
2167
2168       if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2169         {
2170           emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2171           emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2172           emit2 ("ld l,a");
2173           spillPair (PAIR_HL);
2174         }
2175       else if ( getPairId ( AOP (result)) == PAIR_IY)
2176         {
2177           PAIR_ID id = getPairId (AOP (left));
2178           if (id != PAIR_INVALID) 
2179             {
2180               emit2("push %s", _pairs[id].name);
2181               emit2("pop iy");
2182             }
2183           else
2184             {
2185               /* PENDING */
2186               emitDebug("Error");
2187             }
2188         }
2189       else
2190         {
2191           movLeft2Result (left, offl, result, offr, sign);
2192           movLeft2Result (left, offl+1, result, offr+1, sign);
2193         }
2194     }
2195 }
2196
2197 /** Put Acc into a register set
2198  */
2199 void
2200 outAcc (operand * result)
2201 {
2202   int size, offset;
2203   size = getDataSize (result);
2204   if (size)
2205     {
2206       aopPut (AOP (result), "a", 0);
2207       size--;
2208       offset = 1;
2209       /* unsigned or positive */
2210       while (size--)
2211         {
2212           aopPut (AOP (result), "!zero", offset++);
2213         }
2214     }
2215 }
2216
2217 /** Take the value in carry and put it into a register
2218  */
2219 void
2220 outBitCLong (operand * result, bool swap_sense)
2221 {
2222   /* if the result is bit */
2223   if (AOP_TYPE (result) == AOP_CRY)
2224     {
2225       wassertl (0, "Tried to write carry to a bit");
2226     }
2227   else
2228     {
2229       emit2 ("ld a,!zero");
2230       emit2 ("rla");
2231       if (swap_sense)
2232         emit2 ("xor a,!immedbyte", 1);
2233       outAcc (result);
2234     }
2235 }
2236
2237 void
2238 outBitC (operand * result)
2239 {
2240   outBitCLong (result, FALSE);
2241 }
2242
2243 /*-----------------------------------------------------------------*/
2244 /* toBoolean - emit code for orl a,operator(sizeop)                */
2245 /*-----------------------------------------------------------------*/
2246 void
2247 _toBoolean (operand * oper)
2248 {
2249   int size = AOP_SIZE (oper);
2250   int offset = 0;
2251   if (size > 1)
2252     {
2253       emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2254       size--;
2255       while (size--)
2256         emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2257     }
2258   else
2259     {
2260       if (AOP (oper)->type != AOP_ACC)
2261         {
2262           _clearCarry();
2263           emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2264         }
2265     }
2266 }
2267
2268
2269 /*-----------------------------------------------------------------*/
2270 /* genNot - generate code for ! operation                          */
2271 /*-----------------------------------------------------------------*/
2272 static void
2273 genNot (iCode * ic)
2274 {
2275
2276   /* assign asmOps to operand & result */
2277   aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2278   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2279
2280   /* if in bit space then a special case */
2281   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2282     {
2283       wassertl (0, "Tried to negate a bit");
2284     }
2285
2286   _toBoolean (IC_LEFT (ic));
2287
2288   /* Not of A:
2289      If A == 0, !A = 1
2290      else A = 0
2291      So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2292   emit2 ("sub a,!one");
2293   outBitC (IC_RESULT (ic));
2294
2295   /* release the aops */
2296   freeAsmop (IC_LEFT (ic), NULL, ic);
2297   freeAsmop (IC_RESULT (ic), NULL, ic);
2298 }
2299
2300 /*-----------------------------------------------------------------*/
2301 /* genCpl - generate code for complement                           */
2302 /*-----------------------------------------------------------------*/
2303 static void
2304 genCpl (iCode * ic)
2305 {
2306   int offset = 0;
2307   int size;
2308
2309
2310   /* assign asmOps to operand & result */
2311   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2312   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2313
2314   /* if both are in bit space then
2315      a special case */
2316   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2317       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2318     {
2319       wassertl (0, "Left and the result are in bit space");
2320     }
2321
2322   size = AOP_SIZE (IC_RESULT (ic));
2323   while (size--)
2324     {
2325       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2326       _moveA (l);
2327       emit2("cpl");
2328       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2329     }
2330
2331   /* release the aops */
2332   freeAsmop (IC_LEFT (ic), NULL, ic);
2333   freeAsmop (IC_RESULT (ic), NULL, ic);
2334 }
2335
2336 static void
2337 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2338 {
2339   /* Logic:
2340        ld de,right.lw
2341        setup hl to left
2342        de = hl - de
2343        push flags
2344        store de into result
2345        pop flags
2346        ld de,right.hw
2347        setup hl
2348        de = hl -de
2349        store de into result
2350   */
2351   const char *first = isAdd ? "add" : "sub";
2352   const char *later = isAdd ? "adc" : "sbc";
2353
2354   wassertl (IS_GB, "Code is only relevent to the gbz80");
2355   wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2356
2357   fetchPair (PAIR_DE, left);
2358
2359   emit2 ("ld a,e");
2360   emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2361   emit2 ("ld e,a");
2362   emit2 ("ld a,d");
2363   emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2364
2365   _push (PAIR_AF);
2366   aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2367   aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2368
2369   fetchPairLong (PAIR_DE, left, NULL, MSB24);
2370   aopGet (right, MSB24, FALSE);
2371
2372   _pop (PAIR_AF);
2373   emit2 ("ld a,e");
2374   emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2375   emit2 ("ld e,a");
2376   emit2 ("ld a,d");
2377   emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2378
2379   aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2380   aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2381 }
2382
2383 static void
2384 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2385 {
2386   _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2387 }
2388
2389 /*-----------------------------------------------------------------*/
2390 /* genUminusFloat - unary minus for floating points                */
2391 /*-----------------------------------------------------------------*/
2392 static void
2393 genUminusFloat (operand * op, operand * result)
2394 {
2395   int size, offset = 0;
2396
2397   emitDebug("; genUminusFloat");
2398
2399   /* for this we just need to flip the
2400      first it then copy the rest in place */
2401   size = AOP_SIZE (op) - 1;
2402
2403   _moveA(aopGet (AOP (op), MSB32, FALSE));
2404
2405   emit2("xor a,!immedbyte", 0x80);
2406   aopPut (AOP (result), "a", MSB32);
2407
2408   while (size--)
2409     {
2410       aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2411       offset++;
2412     }
2413 }
2414
2415 /*-----------------------------------------------------------------*/
2416 /* genUminus - unary minus code generation                         */
2417 /*-----------------------------------------------------------------*/
2418 static void
2419 genUminus (iCode * ic)
2420 {
2421   int offset, size;
2422   sym_link *optype, *rtype;
2423
2424   /* assign asmops */
2425   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2426   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2427
2428   /* if both in bit space then special
2429      case */
2430   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2431       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2432     {
2433       wassertl (0, "Left and right are in bit space");
2434       goto release;
2435     }
2436
2437   optype = operandType (IC_LEFT (ic));
2438   rtype = operandType (IC_RESULT (ic));
2439
2440   /* if float then do float stuff */
2441   if (IS_FLOAT (optype))
2442     {
2443       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2444       goto release;
2445     }
2446
2447   /* otherwise subtract from zero */
2448   size = AOP_SIZE (IC_LEFT (ic));
2449
2450   if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2451     {
2452       /* Create a new asmop with value zero */
2453       asmop *azero = newAsmop (AOP_SIMPLELIT);
2454       azero->aopu.aop_simplelit = 0;
2455       azero->size = size;
2456       _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2457       goto release;
2458     }
2459
2460   offset = 0;
2461   _clearCarry();
2462   while (size--)
2463     {
2464       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2465       emit2 ("ld a,!zero");
2466       emit2 ("sbc a,%s", l);
2467       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2468     }
2469
2470   /* if any remaining bytes in the result */
2471   /* we just need to propagate the sign   */
2472   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2473     {
2474       emit2 ("rlc a");
2475       emit2 ("sbc a,a");
2476       while (size--)
2477         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2478     }
2479
2480 release:
2481   /* release the aops */
2482   freeAsmop (IC_LEFT (ic), NULL, ic);
2483   freeAsmop (IC_RESULT (ic), NULL, ic);
2484 }
2485
2486 /*-----------------------------------------------------------------*/
2487 /* assignResultValue -               */
2488 /*-----------------------------------------------------------------*/
2489 void
2490 assignResultValue (operand * oper)
2491 {
2492   int size = AOP_SIZE (oper);
2493   bool topInA = 0;
2494
2495   wassertl (size <= 4, "Got a result that is bigger than four bytes");
2496   topInA = requiresHL (AOP (oper));
2497
2498   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2499     {
2500       /* We do it the hard way here. */
2501       _push (PAIR_HL);
2502       aopPut (AOP (oper), _fReturn[0], 0);
2503       aopPut (AOP (oper), _fReturn[1], 1);
2504       _pop (PAIR_DE);
2505       aopPut (AOP (oper), _fReturn[0], 2);
2506       aopPut (AOP (oper), _fReturn[1], 3);
2507     }
2508   else
2509     {
2510       while (size--)
2511         {
2512           aopPut (AOP (oper), _fReturn[size], size);
2513         }
2514     }
2515 }
2516
2517 /** Simple restore that doesn't take into account what is used in the
2518     return.
2519 */
2520 static void
2521 _restoreRegsAfterCall(void)
2522 {
2523   if (_G.stack.pushedDE)
2524     {
2525       _pop ( PAIR_DE);
2526       _G.stack.pushedDE = FALSE;
2527     }
2528   if (_G.stack.pushedBC)
2529     {
2530       _pop ( PAIR_BC);
2531       _G.stack.pushedBC = FALSE;
2532     }
2533   _G.saves.saved = FALSE;
2534 }
2535
2536 static void
2537 _saveRegsForCall(iCode *ic, int sendSetSize)
2538 {
2539   /* Rules:
2540       o Stack parameters are pushed before this function enters
2541       o DE and BC may be used in this function.
2542       o HL and DE may be used to return the result.
2543       o HL and DE may be used to send variables.
2544       o DE and BC may be used to store the result value.
2545       o HL may be used in computing the sent value of DE
2546       o The iPushes for other parameters occur before any addSets
2547
2548      Logic: (to be run inside the first iPush or if none, before sending)
2549       o Compute if DE and/or BC are in use over the call
2550       o Compute if DE is used in the send set
2551       o Compute if DE and/or BC are used to hold the result value
2552       o If (DE is used, or in the send set) and is not used in the result, push.
2553       o If BC is used and is not in the result, push
2554       o 
2555       o If DE is used in the send set, fetch
2556       o If HL is used in the send set, fetch
2557       o Call
2558       o ...
2559   */
2560   if (_G.saves.saved == FALSE) {
2561     bool deInUse, bcInUse;
2562     bool deSending;
2563     bool bcInRet = FALSE, deInRet = FALSE;
2564     bitVect *rInUse;
2565
2566     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), 
2567                             z80_rUmaskForOp (IC_RESULT(ic)));
2568
2569     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2570     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2571
2572     deSending = (sendSetSize > 1);
2573
2574     emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2575
2576     if (bcInUse && bcInRet == FALSE) {
2577       _push(PAIR_BC);
2578       _G.stack.pushedBC = TRUE;
2579     }
2580     if (deInUse && deInRet == FALSE) {
2581       _push(PAIR_DE);
2582       _G.stack.pushedDE = TRUE;
2583     }
2584
2585     _G.saves.saved = TRUE;
2586   }
2587   else {
2588     /* Already saved. */
2589   }
2590 }
2591
2592 /*-----------------------------------------------------------------*/
2593 /* genIpush - genrate code for pushing this gets a little complex  */
2594 /*-----------------------------------------------------------------*/
2595 static void
2596 genIpush (iCode * ic)
2597 {
2598   int size, offset = 0;
2599   const char *l;
2600
2601   /* if this is not a parm push : ie. it is spill push
2602      and spill push is always done on the local stack */
2603   if (!ic->parmPush)
2604     {
2605       wassertl(0, "Encountered an unsupported spill push.");
2606       return;
2607     }
2608
2609   if (_G.saves.saved == FALSE) {
2610     /* Caller saves, and this is the first iPush. */
2611     /* Scan ahead until we find the function that we are pushing parameters to.
2612        Count the number of addSets on the way to figure out what registers
2613        are used in the send set.
2614     */
2615     int nAddSets = 0;
2616     iCode *walk = ic->next;
2617     
2618     while (walk) {
2619       if (walk->op == SEND) {
2620         nAddSets++;
2621       }
2622       else if (walk->op == CALL || walk->op == PCALL) {
2623         /* Found it. */
2624         break;
2625       }
2626       else {
2627         /* Keep looking. */
2628       }
2629       walk = walk->next;
2630     }
2631     _saveRegsForCall(walk, nAddSets);
2632   }
2633   else {
2634     /* Already saved by another iPush. */
2635   }
2636
2637   /* then do the push */
2638   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2639
2640   size = AOP_SIZE (IC_LEFT (ic));
2641
2642   if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2643     {
2644       _G.stack.pushed += 2;
2645       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2646     }
2647   else
2648     {
2649       if (size == 2)
2650         {
2651           fetchHL (AOP (IC_LEFT (ic)));
2652           emit2 ("push hl");
2653           spillPair (PAIR_HL);
2654           _G.stack.pushed += 2;
2655           goto release;
2656         }
2657       if (size == 4)
2658         {
2659           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2660           emit2 ("push hl");
2661           spillPair (PAIR_HL);
2662           _G.stack.pushed += 2;
2663           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2664           emit2 ("push hl");
2665           spillPair (PAIR_HL);
2666           _G.stack.pushed += 2;
2667           goto release;
2668         }
2669       offset = size;
2670       while (size--)
2671         {
2672           if (AOP (IC_LEFT (ic))->type == AOP_IY)
2673             {
2674               char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2675               wassert (l);
2676               emit2 ("ld a,(%s)", l);
2677             }
2678           else
2679             {
2680               l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2681               emit2 ("ld a,%s", l);
2682             }
2683           emit2 ("push af");
2684           emit2 ("inc sp");
2685           _G.stack.pushed++;
2686         }
2687     }
2688 release:
2689   freeAsmop (IC_LEFT (ic), NULL, ic);
2690 }
2691
2692 /*-----------------------------------------------------------------*/
2693 /* genIpop - recover the registers: can happen only for spilling   */
2694 /*-----------------------------------------------------------------*/
2695 static void
2696 genIpop (iCode * ic)
2697 {
2698   int size, offset;
2699
2700
2701   /* if the temp was not pushed then */
2702   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2703     return;
2704
2705   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2706   size = AOP_SIZE (IC_LEFT (ic));
2707   offset = (size - 1);
2708   if (isPair (AOP (IC_LEFT (ic))))
2709     {
2710       emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2711     }
2712   else
2713     {
2714       while (size--)
2715         {
2716           emit2 ("dec sp");
2717           emit2 ("pop hl");
2718           spillPair (PAIR_HL);
2719           aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2720         }
2721     }
2722
2723   freeAsmop (IC_LEFT (ic), NULL, ic);
2724 }
2725
2726 /* This is quite unfortunate */
2727 static void
2728 setArea (int inHome)
2729 {
2730   /*
2731     static int lastArea = 0;
2732
2733      if (_G.in_home != inHome) {
2734      if (inHome) {
2735      const char *sz = port->mem.code_name;
2736      port->mem.code_name = "HOME";
2737      emit2("!area", CODE_NAME);
2738      port->mem.code_name = sz;
2739      }
2740      else
2741      emit2("!area", CODE_NAME); */
2742   _G.in_home = inHome;
2743   //    }
2744 }
2745
2746 static bool
2747 isInHome (void)
2748 {
2749   return _G.in_home;
2750 }
2751
2752 static int
2753 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2754 {
2755   int ret = 0;
2756   asmop *aop;
2757   symbol *sym = OP_SYMBOL (op);
2758
2759   if (sym->isspilt || sym->nRegs == 0)
2760     return 0;
2761
2762   aopOp (op, ic, FALSE, FALSE);
2763
2764   aop = AOP (op);
2765   if (aop->type == AOP_REG)
2766     {
2767       int i;
2768       for (i = 0; i < aop->size; i++)
2769         {
2770           if (pairId == PAIR_DE)
2771             {
2772               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2773               if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2774                 ret++;
2775               if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2776                 ret++;
2777             }
2778           else if (pairId == PAIR_BC)
2779             {
2780               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2781               if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2782                 ret++;
2783               if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2784                 ret++;
2785             }
2786           else
2787             {
2788               wassert (0);
2789             }
2790         }
2791     }
2792
2793   freeAsmop (IC_LEFT (ic), NULL, ic);
2794   return ret;
2795 }
2796
2797 /** Emit the code for a call statement
2798  */
2799 static void
2800 emitCall (iCode * ic, bool ispcall)
2801 {
2802   bool bInRet, cInRet, dInRet, eInRet;
2803   sym_link *dtype = operandType (IC_LEFT (ic));
2804
2805   /* if caller saves & we have not saved then */
2806   if (!ic->regsSaved)
2807     {
2808       /* PENDING */
2809     }
2810
2811   _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2812
2813   /* if send set is not empty then assign */
2814   if (_G.sendSet)
2815     {
2816       iCode *sic;
2817       int send = 0;
2818       int nSend = elementsInSet(_G.sendSet);
2819       bool swapped = FALSE;
2820
2821       int _z80_sendOrder[] = {
2822         PAIR_BC, PAIR_DE
2823       };
2824
2825       if (nSend > 1) {
2826         /* Check if the parameters are swapped.  If so route through hl instead. */
2827         wassertl (nSend == 2, "Pedantic check.  Code only checks for the two send items case.");
2828
2829         sic = setFirstItem(_G.sendSet);
2830         sic = setNextItem(_G.sendSet);
2831
2832         if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2833           /* The second send value is loaded from one the one that holds the first
2834              send, i.e. it is overwritten. */
2835           /* Cache the first in HL, and load the second from HL instead. */
2836           emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2837           emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2838
2839           swapped = TRUE;
2840         }
2841       }
2842
2843       for (sic = setFirstItem (_G.sendSet); sic;
2844            sic = setNextItem (_G.sendSet))
2845         {
2846           int size;
2847           aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2848
2849           size = AOP_SIZE (IC_LEFT (sic));
2850           wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2851           wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2852
2853           // PENDING: Mild hack
2854           if (swapped == TRUE && send == 1) {
2855             if (size > 1) {
2856               emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2857             }
2858             else {
2859               emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2860             }
2861             emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2862           }
2863           else {
2864             fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2865           }
2866
2867           send++;
2868           freeAsmop (IC_LEFT (sic), NULL, sic);
2869         }
2870       _G.sendSet = NULL;
2871     }
2872
2873   if (ispcall)
2874     {
2875       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2876         {
2877           werror (W_INDIR_BANKED);
2878         }
2879       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2880
2881       if (isLitWord (AOP (IC_LEFT (ic))))
2882         {
2883           emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2884         }
2885       else
2886         {
2887           symbol *rlbl = newiTempLabel (NULL);
2888           spillPair (PAIR_HL);
2889           emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2890           emit2 ("push hl");
2891           _G.stack.pushed += 2;
2892
2893           fetchHL (AOP (IC_LEFT (ic)));
2894           emit2 ("jp !*hl");
2895           emit2 ("!tlabeldef", (rlbl->key + 100));
2896           _G.stack.pushed -= 2;
2897         }
2898       freeAsmop (IC_LEFT (ic), NULL, ic);
2899     }
2900   else
2901     {
2902       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2903       OP_SYMBOL (IC_LEFT (ic))->rname :
2904       OP_SYMBOL (IC_LEFT (ic))->name;
2905       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2906         {
2907           emit2 ("call banked_call");
2908           emit2 ("!dws", name);
2909           emit2 ("!dw !bankimmeds", name);
2910         }
2911       else
2912         {
2913           /* make the call */
2914           emit2 ("call %s", name);
2915         }
2916     }
2917   spillCached ();
2918
2919   /* Mark the regsiters as restored. */
2920   _G.saves.saved = FALSE;
2921
2922   /* if we need assign a result value */
2923   if ((IS_ITEMP (IC_RESULT (ic)) &&
2924        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2925         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2926       IS_TRUE_SYMOP (IC_RESULT (ic)))
2927     {
2928
2929       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2930
2931       assignResultValue (IC_RESULT (ic));
2932
2933       freeAsmop (IC_RESULT (ic), NULL, ic);
2934     }
2935
2936   /* adjust the stack for parameters if required */
2937   if (ic->parmBytes)
2938     {
2939       int i = ic->parmBytes;
2940
2941       _G.stack.pushed -= i;
2942       if (IS_GB)
2943         {
2944           emit2 ("!ldaspsp", i);
2945         }
2946       else
2947         {
2948           spillCached ();
2949           if (i > 8)
2950             {
2951               emit2 ("ld iy,!immedword", i);
2952               emit2 ("add iy,sp");
2953               emit2 ("ld sp,iy");
2954             }
2955           else
2956             {
2957               while (i > 1)
2958                 {
2959                   emit2 ("pop af");
2960                   i -= 2;
2961                 }
2962               if (i)
2963                 {
2964                   emit2 ("inc sp");
2965                 }
2966             }
2967         }
2968     }
2969
2970   spillCached ();
2971   if (IC_RESULT (ic))
2972     {
2973       bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2974       bInRet = bitVectBitValue(result, B_IDX);
2975       cInRet = bitVectBitValue(result, C_IDX);
2976       dInRet = bitVectBitValue(result, D_IDX);
2977       eInRet = bitVectBitValue(result, E_IDX);
2978     }
2979   else
2980     {
2981       bInRet = FALSE;
2982       cInRet = FALSE;
2983       dInRet = FALSE;
2984       eInRet = FALSE;
2985     }
2986
2987   if (_G.stack.pushedDE) 
2988     {
2989       if (dInRet && eInRet)
2990         {
2991           wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2992         }
2993       else if (dInRet)
2994         {
2995           /* Only restore E */
2996           emit2 ("ld a,d");
2997           _pop (PAIR_DE);
2998           emit2 ("ld d,a");
2999         }
3000       else if (eInRet)
3001         {
3002           /* Only restore D */
3003           _pop (PAIR_AF);
3004           emit2 ("ld d,a");
3005         }
3006       else
3007         {
3008           _pop (PAIR_DE);
3009         }
3010       _G.stack.pushedDE = FALSE;
3011     }
3012   
3013   if (_G.stack.pushedBC) 
3014     {
3015       if (bInRet && cInRet)
3016         {
3017           wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3018         }
3019       else if (bInRet)
3020         {
3021           /* Only restore C */
3022           emit2 ("ld a,b");
3023           _pop (PAIR_BC);
3024           emit2 ("ld b,a");
3025         }
3026       else if (cInRet)
3027         {
3028           /* Only restore B */
3029           _pop (PAIR_AF);
3030           emit2 ("ld b,a");
3031         }
3032       else
3033         {
3034           _pop (PAIR_BC);
3035         }
3036       _G.stack.pushedBC = FALSE;
3037     }
3038 }
3039
3040 /*-----------------------------------------------------------------*/
3041 /* genCall - generates a call statement                            */
3042 /*-----------------------------------------------------------------*/
3043 static void
3044 genCall (iCode * ic)
3045 {
3046   emitCall (ic, FALSE);
3047 }
3048
3049 /*-----------------------------------------------------------------*/
3050 /* genPcall - generates a call by pointer statement                */
3051 /*-----------------------------------------------------------------*/
3052 static void
3053 genPcall (iCode * ic)
3054 {
3055   emitCall (ic, TRUE);
3056 }
3057
3058 /*-----------------------------------------------------------------*/
3059 /* resultRemat - result  is rematerializable                       */
3060 /*-----------------------------------------------------------------*/
3061 static int
3062 resultRemat (iCode * ic)
3063 {
3064   if (SKIP_IC (ic) || ic->op == IFX)
3065     return 0;
3066
3067   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3068     {
3069       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3070       if (sym->remat && !POINTER_SET (ic))
3071         return 1;
3072     }
3073
3074   return 0;
3075 }
3076
3077 extern set *publics;
3078
3079 /*-----------------------------------------------------------------*/
3080 /* genFunction - generated code for function entry                 */
3081 /*-----------------------------------------------------------------*/
3082 static void
3083 genFunction (iCode * ic)
3084 {
3085   bool stackParm;
3086   
3087   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3088   sym_link *ftype;
3089
3090   bool bcInUse = FALSE;
3091   bool deInUse = FALSE;
3092
3093   setArea (IFFUNC_NONBANKED (sym->type));
3094
3095   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
3096      else.
3097   */
3098   _G.receiveOffset = 0;
3099
3100   /* Record the last function name for debugging. */
3101   _G.lastFunctionName = sym->rname;
3102   
3103   /* Create the function header */
3104   emit2 ("!functionheader", sym->name);
3105   sprintf (buffer, "%s_start", sym->rname);
3106   emit2 ("!labeldef", buffer);
3107   emit2 ("!functionlabeldef", sym->rname);
3108
3109   if (options.profile) 
3110     {
3111       emit2 ("!profileenter");
3112     }
3113
3114   ftype = operandType (IC_LEFT (ic));
3115
3116   /* if critical function then turn interrupts off */
3117   if (IFFUNC_ISCRITICAL (ftype))
3118     emit2 ("!di");
3119
3120   /* if this is an interrupt service routine then save all potentially used registers. */
3121   if (IFFUNC_ISISR (sym->type))
3122     {
3123       emit2 ("!pusha");
3124     }
3125
3126   /* PENDING: callee-save etc */
3127
3128   _G.stack.param_offset = 0;
3129
3130   if (z80_opts.calleeSavesBC)
3131     {
3132       bcInUse = TRUE;
3133     }
3134
3135   /* Detect which registers are used. */
3136   if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3137     {
3138       int i;
3139       for (i = 0; i < sym->regsUsed->size; i++)
3140         {
3141           if (bitVectBitValue (sym->regsUsed, i))
3142             {
3143               switch (i)
3144                 {
3145                 case C_IDX:
3146                 case B_IDX:
3147                   bcInUse = TRUE;
3148                   break;
3149                 case D_IDX:
3150                 case E_IDX:
3151                   if (IS_Z80) {
3152                     deInUse = TRUE;
3153                   }
3154                   else {
3155                     /* Other systems use DE as a temporary. */
3156                   }
3157                   break;
3158                 }
3159             }
3160         }
3161     }
3162
3163   if (bcInUse) 
3164     {
3165       emit2 ("push bc");
3166       _G.stack.param_offset += 2;
3167     }
3168
3169   _G.calleeSaves.pushedBC = bcInUse;
3170
3171   if (deInUse)
3172     {
3173       emit2 ("push de");
3174       _G.stack.param_offset += 2;
3175     }
3176
3177   _G.calleeSaves.pushedDE = deInUse;
3178
3179   /* adjust the stack for the function */
3180   _G.stack.last = sym->stack;
3181   
3182   stackParm = FALSE;
3183   for (sym = setFirstItem (istack->syms); sym;
3184        sym = setNextItem (istack->syms))
3185     {
3186       if (sym->_isparm && !IS_REGPARM (sym->etype))
3187         {
3188           stackParm = TRUE;
3189           break;
3190         }
3191     }
3192   sym = OP_SYMBOL (IC_LEFT (ic));
3193   
3194   _G.omitFramePtr = options.ommitFramePtr;
3195   if (IS_Z80 && !stackParm && !sym->stack)
3196     {
3197       /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3198       /* the above !sym->stack condition can be removed. -- EEP       */
3199       if (sym->stack)
3200         emit2 ("!ldaspsp", -sym->stack);
3201       _G.omitFramePtr = TRUE;
3202     }
3203   else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3204     emit2 ("!enterxl", sym->stack);
3205   else if (sym->stack)
3206     emit2 ("!enterx", sym->stack);
3207   else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3208     emit2 ("!enter");
3209
3210   _G.stack.offset = sym->stack;
3211 }
3212
3213 /*-----------------------------------------------------------------*/
3214 /* genEndFunction - generates epilogue for functions               */
3215 /*-----------------------------------------------------------------*/
3216 static void
3217 genEndFunction (iCode * ic)
3218 {
3219   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3220
3221   if (IFFUNC_ISISR (sym->type))
3222     {
3223       wassertl (0, "Tried to close an interrupt support function");
3224     }
3225   else
3226     {
3227       if (IFFUNC_ISCRITICAL (sym->type))
3228         emit2 ("!ei");
3229
3230       /* PENDING: calleeSave */
3231
3232       if (IS_Z80 && _G.omitFramePtr)
3233         {
3234           if (_G.stack.offset)
3235             emit2 ("!ldaspsp", _G.stack.offset);
3236         }
3237       else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3238         {
3239           emit2 ("!leavexl", _G.stack.offset);
3240         }
3241       else if (_G.stack.offset)
3242         {
3243           emit2 ("!leavex", _G.stack.offset);
3244         }
3245       else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3246         {
3247           emit2 ("!leave");
3248         }
3249
3250       if (_G.calleeSaves.pushedDE) 
3251         {
3252           emit2 ("pop de");
3253           _G.calleeSaves.pushedDE = FALSE;
3254         }
3255
3256       if (_G.calleeSaves.pushedBC) 
3257         {
3258           emit2 ("pop bc");
3259           _G.calleeSaves.pushedBC = FALSE;
3260         }
3261
3262       if (options.profile) 
3263         {
3264           emit2 ("!profileexit");
3265         }
3266
3267
3268       if (options.debug && currFunc)
3269         {
3270           debugFile->writeEndFunction (currFunc, ic, 1);
3271         }
3272       
3273       /* Both banked and non-banked just ret */
3274       emit2 ("ret");
3275
3276       sprintf (buffer, "%s_end", sym->rname);
3277       emit2 ("!labeldef", buffer);
3278     }
3279   _G.flushStatics = 1;
3280   _G.stack.pushed = 0;
3281   _G.stack.offset = 0;
3282 }
3283
3284 /*-----------------------------------------------------------------*/
3285 /* genRet - generate code for return statement                     */
3286 /*-----------------------------------------------------------------*/
3287 static void
3288 genRet (iCode * ic)
3289 {
3290     const char *l;
3291   /* Errk.  This is a hack until I can figure out how
3292      to cause dehl to spill on a call */
3293   int size, offset = 0;
3294
3295   /* if we have no return value then
3296      just generate the "ret" */
3297   if (!IC_LEFT (ic))
3298     goto jumpret;
3299
3300   /* we have something to return then
3301      move the return value into place */
3302   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3303   size = AOP_SIZE (IC_LEFT (ic));
3304
3305   aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3306
3307   #if 0  
3308   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3309     {
3310       if (IS_GB)
3311         {
3312           emit2 ("ld de,%s", l);
3313         }
3314       else
3315         {
3316           emit2 ("ld hl,%s", l);
3317         }
3318     }
3319   #endif
3320   if (size==2)
3321     {
3322       fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3323     }
3324   else
3325     {
3326       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3327         {
3328           fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3329           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3330         }
3331       else
3332         {
3333           while (size--)
3334             {
3335               l = aopGet (AOP (IC_LEFT (ic)), offset,
3336                           FALSE);
3337               if (strcmp (_fReturn[offset], l))
3338                 emit2 ("ld %s,%s", _fReturn[offset], l);
3339               offset++;
3340             }
3341         }
3342     }
3343   freeAsmop (IC_LEFT (ic), NULL, ic);
3344
3345 jumpret:
3346   /* generate a jump to the return label
3347      if the next is not the return statement */
3348   if (!(ic->next && ic->next->op == LABEL &&
3349         IC_LABEL (ic->next) == returnLabel))
3350
3351     emit2 ("jp !tlabel", returnLabel->key + 100);
3352 }
3353
3354 /*-----------------------------------------------------------------*/
3355 /* genLabel - generates a label                                    */
3356 /*-----------------------------------------------------------------*/
3357 static void
3358 genLabel (iCode * ic)
3359 {
3360   /* special case never generate */
3361   if (IC_LABEL (ic) == entryLabel)
3362     return;
3363
3364   emitLabel (IC_LABEL (ic)->key + 100);
3365 }
3366
3367 /*-----------------------------------------------------------------*/
3368 /* genGoto - generates a ljmp                                      */
3369 /*-----------------------------------------------------------------*/
3370 static void
3371 genGoto (iCode * ic)
3372 {
3373   emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3374 }
3375
3376 /*-----------------------------------------------------------------*/
3377 /* genPlusIncr :- does addition with increment if possible         */
3378 /*-----------------------------------------------------------------*/
3379 static bool
3380 genPlusIncr (iCode * ic)
3381 {
3382   unsigned int icount;
3383   unsigned int size = getDataSize (IC_RESULT (ic));
3384   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3385
3386   /* will try to generate an increment */
3387   /* if the right side is not a literal
3388      we cannot */
3389   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3390     return FALSE;
3391
3392   emitDebug ("; genPlusIncr");
3393
3394   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3395
3396   /* If result is a pair */
3397   if (resultId != PAIR_INVALID)
3398     {
3399       if (isLitWord (AOP (IC_LEFT (ic))))
3400         {
3401           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3402           return TRUE;
3403         }
3404       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3405         {
3406           if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3407             {
3408               PAIR_ID freep = getFreePairId (ic);
3409               if (freep != PAIR_INVALID)
3410                 {
3411                   fetchPair (freep, AOP (IC_RIGHT (ic)));
3412                   emit2 ("add hl,%s", _pairs[freep].name);
3413                   return TRUE;
3414                 }
3415             }
3416           else
3417             {
3418               fetchPair (resultId, AOP (IC_RIGHT (ic)));
3419               emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3420               return TRUE;
3421             }
3422         }
3423       if (icount > 5)
3424         return FALSE;
3425       /* Inc a pair */
3426       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3427         {
3428           if (icount > 2)
3429             return FALSE;
3430           movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3431         }
3432       while (icount--)
3433         {
3434           emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3435         }
3436       return TRUE;
3437     }
3438
3439   if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3440     {
3441       fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3442       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3443       return TRUE;
3444     }
3445
3446   /* if the literal value of the right hand side
3447      is greater than 4 then it is not worth it */
3448   if (icount > 4)
3449     return FALSE;
3450
3451   /* if increment 16 bits in register */
3452   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3453       size > 1 &&
3454       icount == 1
3455     )
3456     {
3457       int offset = 0;
3458       symbol *tlbl = NULL;
3459       tlbl = newiTempLabel (NULL);
3460       while (size--)
3461         {
3462           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3463           if (size)
3464             {
3465               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3466             }
3467         }
3468       emitLabel (tlbl->key + 100);
3469       return TRUE;
3470     }
3471
3472   /* if the sizes are greater than 1 then we cannot */
3473   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3474       AOP_SIZE (IC_LEFT (ic)) > 1)
3475     return FALSE;
3476
3477   /* If the result is in a register then we can load then increment.
3478    */
3479   if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3480     {
3481       aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3482       while (icount--)
3483         {
3484           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3485         }
3486       return TRUE;
3487     }
3488
3489   /* we can if the aops of the left & result match or
3490      if they are in registers and the registers are the
3491      same */
3492   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3493     {
3494       while (icount--)
3495         {
3496           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3497         }
3498       return TRUE;
3499     }
3500
3501   return FALSE;
3502 }
3503
3504 /*-----------------------------------------------------------------*/
3505 /* outBitAcc - output a bit in acc                                 */
3506 /*-----------------------------------------------------------------*/
3507 void
3508 outBitAcc (operand * result)
3509 {
3510   symbol *tlbl = newiTempLabel (NULL);
3511   /* if the result is a bit */
3512   if (AOP_TYPE (result) == AOP_CRY)
3513     {
3514       wassertl (0, "Tried to write A into a bit");
3515     }
3516   else
3517     {
3518       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3519       emit2 ("ld a,!one");
3520       emitLabel (tlbl->key + 100);
3521       outAcc (result);
3522     }
3523 }
3524
3525 bool
3526 couldDestroyCarry (asmop *aop)
3527 {
3528   if (aop)
3529     {
3530       if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3531         {
3532           return TRUE;
3533         }
3534     }
3535   return FALSE;
3536 }
3537
3538 static void
3539 shiftIntoPair (int idx, asmop *aop)
3540 {
3541   PAIR_ID id = PAIR_INVALID;
3542
3543   wassertl (IS_Z80, "Only implemented for the Z80");
3544   //  wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3545
3546   switch (idx) 
3547     {
3548     case 0:
3549       id = PAIR_HL;
3550       break;
3551     case 1:
3552       id = PAIR_DE;
3553       _push (PAIR_DE);
3554       break;
3555     default:
3556       wassertl (0, "Internal error - hit default case");
3557     }
3558
3559   emitDebug ("; Shift into pair idx %u", idx);
3560
3561   if (id == PAIR_HL)
3562     {
3563       setupPair (PAIR_HL, aop, 0);
3564     }
3565   else
3566     {
3567       setupPair (PAIR_IY, aop, 0);
3568       emit2 ("push iy");
3569       emit2 ("pop %s", _pairs[id].name);
3570     }
3571
3572   aop->type = AOP_PAIRPTR;
3573   aop->aopu.aop_pairId = id;
3574   _G.pairs[id].offset = 0;
3575   _G.pairs[id].last_type = aop->type;
3576 }
3577
3578 static void 
3579 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3580 {
3581   wassert (left && right);
3582
3583   if (IS_Z80)
3584     {
3585       if (couldDestroyCarry (right) && couldDestroyCarry (result))
3586         {
3587           shiftIntoPair (0, right);
3588           /* check result again, in case right == result */
3589           if (couldDestroyCarry (result))
3590             shiftIntoPair (1, result);
3591         }
3592       else if (couldDestroyCarry (right))
3593         {
3594           if (getPairId (result) == PAIR_HL)
3595             _G.preserveCarry = TRUE;
3596           else
3597             shiftIntoPair (0, right);
3598         }
3599       else if (couldDestroyCarry (result))
3600         {
3601           shiftIntoPair (0, result);
3602         }
3603       else
3604         {
3605           /* Fine */
3606         }
3607     }
3608 }
3609
3610 /*-----------------------------------------------------------------*/
3611 /* genPlus - generates code for addition                           */
3612 /*-----------------------------------------------------------------*/
3613 static void
3614 genPlus (iCode * ic)
3615 {
3616   int size, offset = 0;
3617
3618   /* special cases :- */
3619
3620   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3621   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3622   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3623
3624   /* Swap the left and right operands if:
3625
3626      if literal, literal on the right or
3627      if left requires ACC or right is already
3628      in ACC */
3629
3630   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3631       (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3632       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3633     {
3634       operand *t = IC_RIGHT (ic);
3635       IC_RIGHT (ic) = IC_LEFT (ic);
3636       IC_LEFT (ic) = t;
3637     }
3638
3639   /* if both left & right are in bit
3640      space */
3641   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3642       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3643     {
3644       /* Cant happen */
3645       wassertl (0, "Tried to add two bits");
3646     }
3647
3648   /* if left in bit space & right literal */
3649   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3650       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3651     {
3652       /* Can happen I guess */
3653       wassertl (0, "Tried to add a bit to a literal");
3654     }
3655
3656   /* if I can do an increment instead
3657      of add then GOOD for ME */
3658   if (genPlusIncr (ic) == TRUE)
3659     goto release;
3660
3661   emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3662
3663   size = getDataSize (IC_RESULT (ic));
3664
3665   /* Special case when left and right are constant */
3666   if (isPair (AOP (IC_RESULT (ic))))
3667     {
3668       char *left, *right;
3669       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3670       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3671
3672       if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3673           left && right)
3674         {
3675           /* It's a pair */
3676           /* PENDING: fix */
3677           char buffer[100];
3678           sprintf (buffer, "#(%s + %s)", left, right);
3679           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3680           goto release;
3681         }
3682     }
3683
3684   if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3685     {
3686       /* Fetch into HL then do the add */
3687       PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3688       PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3689
3690       spillPair (PAIR_HL);
3691       
3692       if (left == PAIR_HL && right != PAIR_INVALID)
3693         {
3694           emit2 ("add hl,%s", _pairs[right].name);
3695           goto release;
3696         }
3697       else if (right == PAIR_HL && left != PAIR_INVALID)
3698         {
3699           emit2 ("add hl,%s", _pairs[left].name);
3700           goto release;
3701         }
3702       else if (right != PAIR_INVALID && right != PAIR_HL)
3703         {
3704           fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3705           emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3706           goto release;
3707         }
3708       else if (left != PAIR_INVALID && left != PAIR_HL)
3709         { 
3710           fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3711           emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3712           goto release;
3713         }
3714       else
3715         {
3716           /* Can't do it */
3717         }
3718     }
3719
3720   if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3721     {
3722       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3723       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3724       spillCached();
3725       commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3726       goto release;
3727     }
3728
3729   /* Special case:
3730      ld hl,sp+n trashes C so we cant afford to do it during an
3731      add with stack based varibles.  Worst case is:
3732      ld  hl,sp+left
3733      ld  a,(hl)
3734      ld  hl,sp+right
3735      add (hl)
3736      ld  hl,sp+result
3737      ld  (hl),a
3738      ld  hl,sp+left+1
3739      ld  a,(hl)
3740      ld  hl,sp+right+1
3741      adc (hl)
3742      ld  hl,sp+result+1
3743      ld  (hl),a
3744      So you cant afford to load up hl if either left, right, or result
3745      is on the stack (*sigh*)  The alt is:
3746      ld  hl,sp+left
3747      ld  de,(hl)
3748      ld  hl,sp+right
3749      ld  hl,(hl)
3750      add hl,de
3751      ld  hl,sp+result
3752      ld  (hl),hl
3753      Combinations in here are:
3754      * If left or right are in bc then the loss is small - trap later
3755      * If the result is in bc then the loss is also small
3756    */
3757   if (IS_GB)
3758     {
3759       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3760           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3761           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3762         {
3763           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3764                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3765               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3766                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3767             {
3768               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3769                 {
3770                   /* Swap left and right */
3771                   operand *t = IC_RIGHT (ic);
3772                   IC_RIGHT (ic) = IC_LEFT (ic);
3773                   IC_LEFT (ic) = t;
3774                 }
3775               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3776                 {
3777                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3778                   emit2 ("add hl,bc");
3779                 }
3780               else
3781                 {
3782                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3783                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3784                   emit2 ("add hl,de");
3785                 }
3786               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3787               goto release;
3788             }
3789         }
3790       if (size == 4)
3791         {
3792           /* Be paranoid on the GB with 4 byte variables due to how C
3793              can be trashed by lda hl,n(sp).
3794           */
3795           _gbz80_emitAddSubLong (ic, TRUE);
3796           goto release;
3797         }
3798     }
3799   
3800   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3801
3802   while (size--)
3803     {
3804       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3805         {
3806           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3807           if (offset == 0)
3808             emit2 ("add a,%s",
3809                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3810           else
3811             emit2 ("adc a,%s",
3812                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3813         }
3814       else
3815         {
3816           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3817           if (offset == 0)
3818             emit2 ("add a,%s",
3819                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3820           else
3821             emit2 ("adc a,%s",
3822                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3823         }
3824       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3825     }
3826
3827 release:
3828   _G.preserveCarry = FALSE;
3829   freeAsmop (IC_LEFT (ic), NULL, ic);
3830   freeAsmop (IC_RIGHT (ic), NULL, ic);
3831   freeAsmop (IC_RESULT (ic), NULL, ic);
3832
3833 }
3834
3835 /*-----------------------------------------------------------------*/
3836 /* genMinusDec :- does subtraction with deccrement if possible     */
3837 /*-----------------------------------------------------------------*/
3838 static bool
3839 genMinusDec (iCode * ic)
3840 {
3841   unsigned int icount;
3842   unsigned int size = getDataSize (IC_RESULT (ic));
3843
3844   /* will try to generate an increment */
3845   /* if the right side is not a literal we cannot */
3846   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3847     return FALSE;
3848
3849   /* if the literal value of the right hand side
3850      is greater than 4 then it is not worth it */
3851   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3852     return FALSE;
3853
3854   size = getDataSize (IC_RESULT (ic));
3855
3856   /* if decrement 16 bits in register */
3857   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3858       (size > 1) && isPair (AOP (IC_RESULT (ic))))
3859     {
3860       while (icount--)
3861         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3862       return TRUE;
3863     }
3864
3865   /* If result is a pair */
3866   if (isPair (AOP (IC_RESULT (ic))))
3867     {
3868       movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3869       while (icount--)
3870         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3871       return TRUE;
3872     }
3873
3874   /* if increment 16 bits in register */
3875   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3876       (size == 2)
3877       )
3878     {
3879       fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3880
3881       while (icount--) {
3882         emit2 ("dec %s", _getTempPairName());
3883       }
3884
3885       commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3886
3887       return TRUE;
3888     }
3889
3890
3891   /* if the sizes are greater than 1 then we cannot */
3892   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3893       AOP_SIZE (IC_LEFT (ic)) > 1)
3894     return FALSE;
3895
3896   /* we can if the aops of the left & result match or if they are in
3897      registers and the registers are the same */
3898   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3899     {
3900       while (icount--)
3901         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3902       return TRUE;
3903     }
3904
3905   return FALSE;
3906 }
3907
3908 /*-----------------------------------------------------------------*/
3909 /* genMinus - generates code for subtraction                       */
3910 /*-----------------------------------------------------------------*/
3911 static void
3912 genMinus (iCode * ic)
3913 {
3914   int size, offset = 0;
3915   unsigned long lit = 0L;
3916
3917   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3918   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3919   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3920
3921   /* special cases :- */
3922   /* if both left & right are in bit space */
3923   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3924       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3925     {
3926       wassertl (0, "Tried to subtract two bits");
3927       goto release;
3928     }
3929
3930   /* if I can do an decrement instead of subtract then GOOD for ME */
3931   if (genMinusDec (ic) == TRUE)
3932     goto release;
3933
3934   size = getDataSize (IC_RESULT (ic));
3935
3936   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3937     {
3938     }
3939   else
3940     {
3941       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3942       lit = -(long) lit;
3943     }
3944
3945   /* Same logic as genPlus */
3946   if (IS_GB)
3947     {
3948       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3949           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3950           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3951         {
3952           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3953                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3954               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3955                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3956             {
3957               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3958               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3959
3960               if (left == PAIR_INVALID && right == PAIR_INVALID)
3961                 {
3962                   left = PAIR_DE;
3963                   right = PAIR_HL;
3964                 }
3965               else if (right == PAIR_INVALID)
3966                 right = PAIR_DE;
3967               else if (left == PAIR_INVALID)
3968                 left = PAIR_DE;
3969
3970               fetchPair (left, AOP (IC_LEFT (ic)));
3971               /* Order is important.  Right may be HL */
3972               fetchPair (right, AOP (IC_RIGHT (ic)));
3973
3974               emit2 ("ld a,%s", _pairs[left].l);
3975               emit2 ("sub a,%s", _pairs[right].l);
3976               emit2 ("ld e,a");
3977               emit2 ("ld a,%s", _pairs[left].h);
3978               emit2 ("sbc a,%s", _pairs[right].h);
3979
3980               if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3981                 {
3982                   aopPut (AOP (IC_RESULT (ic)), "a", 1);
3983                 }
3984               aopPut (AOP (IC_RESULT (ic)), "e", 0);
3985               goto release;
3986             }
3987         }
3988       if (size == 4)
3989         {
3990           /* Be paranoid on the GB with 4 byte variables due to how C
3991              can be trashed by lda hl,n(sp).
3992           */
3993           _gbz80_emitAddSubLong (ic, FALSE);
3994           goto release;
3995         }
3996     }
3997
3998   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3999
4000   /* if literal, add a,#-lit, else normal subb */
4001   while (size--)
4002     {
4003       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4004       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4005         {
4006           if (!offset)
4007             emit2 ("sub a,%s",
4008                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4009           else
4010             emit2 ("sbc a,%s",
4011                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4012         }
4013       else
4014         {
4015           /* first add without previous c */
4016           if (!offset)
4017             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4018           else
4019             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4020         }
4021       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4022     }
4023
4024   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4025       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4026       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4027     {
4028       wassertl (0, "Tried to subtract on a long pointer");
4029     }
4030
4031 release:
4032   _G.preserveCarry = FALSE;
4033   freeAsmop (IC_LEFT (ic), NULL, ic);
4034   freeAsmop (IC_RIGHT (ic), NULL, ic);
4035   freeAsmop (IC_RESULT (ic), NULL, ic);
4036 }
4037
4038 /*-----------------------------------------------------------------*/
4039 /* genMult - generates code for multiplication                     */
4040 /*-----------------------------------------------------------------*/
4041 static void
4042 genMult (iCode * ic)
4043 {
4044   int val;
4045   int count, i;
4046   /* If true then the final operation should be a subtract */
4047   bool active = FALSE;
4048   bool byteResult;
4049
4050   /* Shouldn't occur - all done through function calls */
4051   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4052   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4053   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4054   
4055   byteResult =  (AOP_SIZE (IC_RESULT (ic)) == 1);
4056
4057   if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4058       AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4059       AOP_SIZE (IC_RESULT (ic)) > 2)
4060     {
4061       wassertl (0, "Multiplication is handled through support function calls");
4062     }
4063
4064   /* Swap left and right such that right is a literal */
4065   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4066     {
4067       operand *t = IC_RIGHT (ic);
4068       IC_RIGHT (ic) = IC_LEFT (ic);
4069       IC_LEFT (ic) = t;
4070     }
4071
4072   wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4073
4074   val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4075   //  wassertl (val > 0, "Multiply must be positive");
4076   wassertl (val != 1, "Can't multiply by 1");
4077
4078   if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4079     _push (PAIR_DE);
4080     _G.stack.pushedDE = TRUE;
4081   }
4082
4083   if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4084     {
4085       emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4086       if (!byteResult)
4087         {
4088           emit2 ("ld a,e");
4089           emit2 ("rlc a");
4090           emit2 ("sbc a,a");
4091           emit2 ("ld d,a");
4092         }
4093     }
4094   else
4095     {
4096       fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4097     }
4098
4099   i = val;
4100
4101   /* Fully unroled version of mul.s.  Not the most efficient.
4102    */
4103   for (count = 0; count < 16; count++)
4104     {
4105       if (count != 0 && active)
4106         {
4107           emit2 ("add hl,hl");
4108         }
4109       if (i & 0x8000U)
4110         {
4111           if (active == FALSE)
4112             {
4113               emit2 ("ld l,e");
4114               if (!byteResult)
4115                 emit2 ("ld h,d");
4116             }
4117           else
4118             {
4119               emit2 ("add hl,de");
4120             }
4121           active = TRUE;
4122         }
4123       i <<= 1;
4124     }
4125
4126   spillCached();
4127
4128   if (IS_Z80 && _G.stack.pushedDE)
4129     {
4130       _pop (PAIR_DE);
4131       _G.stack.pushedDE = FALSE;
4132     }
4133
4134   if (byteResult)
4135     aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4136   else
4137     commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4138
4139   freeAsmop (IC_LEFT (ic), NULL, ic);
4140   freeAsmop (IC_RIGHT (ic), NULL, ic);
4141   freeAsmop (IC_RESULT (ic), NULL, ic);
4142 }
4143
4144 /*-----------------------------------------------------------------*/
4145 /* genDiv - generates code for division                            */
4146 /*-----------------------------------------------------------------*/
4147 static void
4148 genDiv (iCode * ic)
4149 {
4150   /* Shouldn't occur - all done through function calls */
4151   wassertl (0, "Division is handled through support function calls");
4152 }
4153
4154 /*-----------------------------------------------------------------*/
4155 /* genMod - generates code for division                            */
4156 /*-----------------------------------------------------------------*/
4157 static void
4158 genMod (iCode * ic)
4159 {
4160   /* Shouldn't occur - all done through function calls */
4161   wassert (0);
4162 }
4163
4164 /*-----------------------------------------------------------------*/
4165 /* genIfxJump :- will create a jump depending on the ifx           */
4166 /*-----------------------------------------------------------------*/
4167 static void
4168 genIfxJump (iCode * ic, char *jval)
4169 {
4170   symbol *jlbl;
4171   const char *inst;
4172
4173   /* if true label then we jump if condition
4174      supplied is true */
4175   if (IC_TRUE (ic))
4176     {
4177       jlbl = IC_TRUE (ic);
4178       if (!strcmp (jval, "a"))
4179         {
4180           inst = "nz";
4181         }
4182       else if (!strcmp (jval, "c"))
4183         {
4184           inst = "c";
4185         }
4186       else if (!strcmp (jval, "nc"))
4187         {
4188           inst = "nc";
4189         }
4190       else if (!strcmp (jval, "m"))
4191         {
4192           inst = "m";
4193         }
4194       else if (!strcmp (jval, "p"))
4195         {
4196           inst = "p";
4197         }
4198       else
4199         {
4200           /* The buffer contains the bit on A that we should test */
4201           inst = "nz";
4202         }
4203     }
4204   else
4205     {
4206       /* false label is present */
4207       jlbl = IC_FALSE (ic);
4208       if (!strcmp (jval, "a"))
4209         {
4210           inst = "z";
4211         }
4212       else if (!strcmp (jval, "c"))
4213         {
4214           inst = "nc";
4215         }
4216       else if (!strcmp (jval, "nc"))
4217         {
4218           inst = "c";
4219         }
4220       else if (!strcmp (jval, "m"))
4221         {
4222           inst = "p";
4223         }
4224       else if (!strcmp (jval, "p"))
4225         {
4226           inst = "m";
4227         }
4228       else
4229         {
4230           /* The buffer contains the bit on A that we should test */
4231           inst = "z";
4232         }
4233     }
4234   /* Z80 can do a conditional long jump */
4235   if (!strcmp (jval, "a"))
4236     {
4237       emit2 ("or a,a");
4238     }
4239   else if (!strcmp (jval, "c"))
4240     {
4241     }
4242   else if (!strcmp (jval, "nc"))
4243     {
4244     }
4245   else if (!strcmp (jval, "m"))
4246     {
4247     }
4248   else if (!strcmp (jval, "p"))
4249     {
4250     }
4251   else
4252     {
4253       emit2 ("bit %s,a", jval);
4254     }
4255   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4256
4257   /* mark the icode as generated */
4258   ic->generated = 1;
4259 }
4260
4261 #if DISABLED
4262 static const char *
4263 _getPairIdName (PAIR_ID id)
4264 {
4265   return _pairs[id].name;
4266 }
4267 #endif
4268
4269 #if OLD
4270       /* if unsigned char cmp with lit, just compare */
4271       if ((size == 1) &&
4272           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4273         {
4274           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4275           if (sign)
4276             {
4277               emit2 ("xor a,!immedbyte", 0x80);
4278               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4279             }
4280           else
4281             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4282         }
4283       else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4284         {
4285           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4286           // Pull left into DE and right into HL
4287           aopGet (AOP(left), LSB, FALSE);
4288           emit2 ("ld d,h");
4289           emit2 ("ld e,l");
4290           aopGet (AOP(right), LSB, FALSE);
4291
4292           while (size--)
4293             {
4294               if (size == 0 && sign)
4295                 {
4296                   // Highest byte when signed needs the bits flipped
4297                   // Save the flags
4298                   emit2 ("push af");
4299                   emit2 ("ld a,(de)");
4300                   emit2 ("xor !immedbyte", 0x80);
4301                   emit2 ("ld e,a");
4302                   emit2 ("ld a,(hl)");
4303                   emit2 ("xor !immedbyte", 0x80);
4304                   emit2 ("ld d,a");
4305                   emit2 ("pop af");
4306                   emit2 ("ld a,e");
4307                   emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4308                 }
4309               else
4310                 {
4311                   emit2 ("ld a,(de)");
4312                   emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4313                 }
4314               
4315               if (size != 0)
4316                 {
4317                   emit2 ("inc hl");
4318                   emit2 ("inc de");
4319                 }
4320               offset++;
4321             }
4322           spillPair (PAIR_HL);
4323         }
4324       else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4325         {
4326           setupPair (PAIR_HL, AOP (left), 0);
4327           aopGet (AOP(right), LSB, FALSE);
4328
4329           while (size--)
4330             {
4331               if (size == 0 && sign)
4332                 {
4333                   // Highest byte when signed needs the bits flipped
4334                   // Save the flags
4335                   emit2 ("push af");
4336                   emit2 ("ld a,(hl)");
4337                   emit2 ("xor !immedbyte", 0x80);
4338                   emit2 ("ld l,a");
4339                   emit2 ("ld a,%d(iy)", offset);
4340                   emit2 ("xor !immedbyte", 0x80);
4341                   emit2 ("ld h,a");
4342                   emit2 ("pop af");
4343                   emit2 ("ld a,l");
4344                   emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4345                 }
4346               else
4347                 {
4348                   emit2 ("ld a,(hl)");
4349                   emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4350                 }
4351               
4352               if (size != 0)
4353                 {
4354                   emit2 ("inc hl");
4355                 }
4356               offset++;
4357             }
4358           spillPair (PAIR_HL);
4359           spillPair (PAIR_IY);
4360         }
4361       else
4362         {
4363           if (AOP_TYPE (right) == AOP_LIT)
4364             {
4365               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4366               /* optimize if(x < 0) or if(x >= 0) */
4367               if (lit == 0L)
4368                 {
4369                   if (!sign)
4370                     {
4371                       /* No sign so it's always false */
4372                       _clearCarry();
4373                     }
4374                   else
4375                     {
4376                       /* Just load in the top most bit */
4377                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4378                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4379                         {
4380                           genIfxJump (ifx, "7");
4381                           return;
4382                         }
4383                       else
4384                         emit2 ("rlc a");
4385                     }
4386                   goto release;
4387                 }
4388             }
4389           
4390           if (sign)
4391             {
4392               /* First setup h and l contaning the top most bytes XORed */
4393               bool fDidXor = FALSE;
4394               if (AOP_TYPE (left) == AOP_LIT)
4395                 {
4396                   unsigned long lit = (unsigned long)
4397                   floatFromVal (AOP (left)->aopu.aop_lit);
4398                   emit2 ("ld %s,!immedbyte", _fTmp[0],
4399                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4400                 }
4401               else
4402                 {
4403                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4404                   emit2 ("xor a,!immedbyte", 0x80);
4405                   emit2 ("ld %s,a", _fTmp[0]);
4406                   fDidXor = TRUE;
4407                 }
4408               if (AOP_TYPE (right) == AOP_LIT)
4409                 {
4410                   unsigned long lit = (unsigned long)
4411                   floatFromVal (AOP (right)->aopu.aop_lit);
4412                   emit2 ("ld %s,!immedbyte", _fTmp[1],
4413                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4414                 }
4415               else
4416                 {
4417                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4418                   emit2 ("xor a,!immedbyte", 0x80);
4419                   emit2 ("ld %s,a", _fTmp[1]);
4420                   fDidXor = TRUE;
4421                 }
4422             }
4423           while (size--)
4424             {
4425               /* Do a long subtract */
4426               if (!sign || size)
4427                 {
4428                   _moveA (aopGet (AOP (left), offset, FALSE));
4429                 }
4430               if (sign && size == 0)
4431                 {
4432                   emit2 ("ld a,%s", _fTmp[0]);
4433                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4434                 }
4435               else
4436                 {
4437                   /* Subtract through, propagating the carry */
4438                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4439                   offset++;
4440                 }
4441             }
4442         }
4443     }
4444 #endif
4445
4446 /** Generic compare for > or <
4447  */
4448 static void
4449 genCmp (operand * left, operand * right,
4450         operand * result, iCode * ifx, int sign)
4451 {
4452   int size, offset = 0;
4453   unsigned long lit = 0L;
4454   bool swap_sense = FALSE;
4455
4456   /* if left & right are bit variables */
4457   if (AOP_TYPE (left) == AOP_CRY &&
4458       AOP_TYPE (right) == AOP_CRY)
4459     {
4460       /* Cant happen on the Z80 */
4461       wassertl (0, "Tried to compare two bits");
4462     }
4463   else
4464     {
4465       /* Do a long subtract of right from left. */
4466       size = max (AOP_SIZE (left), AOP_SIZE (right));
4467
4468       if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4469         {
4470           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4471           // Pull left into DE and right into HL
4472           aopGet (AOP(left), LSB, FALSE);
4473           emit2 ("ld d,h");
4474           emit2 ("ld e,l");
4475           aopGet (AOP(right), LSB, FALSE);
4476
4477           while (size--)
4478             {
4479               emit2 ("ld a,(de)");
4480               emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4481               
4482               if (size != 0)
4483                 {
4484                   emit2 ("inc hl");
4485                   emit2 ("inc de");
4486                 }
4487               offset++;
4488             }
4489           spillPair (PAIR_HL);
4490           goto release;
4491         }
4492
4493       if (AOP_TYPE (right) == AOP_LIT)
4494         {
4495           lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4496           /* optimize if(x < 0) or if(x >= 0) */
4497           if (lit == 0)
4498             {
4499               if (!sign)
4500                 {
4501                   /* No sign so it's always false */
4502                   _clearCarry();
4503                 }
4504               else
4505                 {
4506                   /* Just load in the top most bit */
4507                   _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4508                   if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4509                     {
4510                       genIfxJump (ifx, "7");
4511                       return;
4512                     }
4513                   else
4514                     {
4515                       if (!sign) 
4516                         {
4517                           emit2 ("rlc a");
4518                         }
4519                       if (ifx)
4520                         {
4521                           genIfxJump (ifx, swap_sense ? "c" : "nc");
4522                           return;
4523                         }
4524                     }
4525                 }
4526               goto release;
4527             }
4528         }
4529
4530       while (size--)
4531         {
4532           _moveA (aopGet (AOP (left), offset, FALSE));
4533           /* Subtract through, propagating the carry */
4534           emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4535           offset++;
4536         }
4537     }
4538
4539 release:
4540   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4541     {
4542       if (sign)
4543         {
4544           /* Shift the sign bit up into carry */
4545           emit2 ("rlca");
4546         }
4547       outBitCLong (result, swap_sense);
4548     }
4549   else
4550     {
4551       /* if the result is used in the next
4552          ifx conditional branch then generate
4553          code a little differently */
4554       if (ifx)
4555         {
4556           if (sign)
4557             {
4558               if (IS_GB)
4559                 {
4560                   emit2 ("rlca");
4561                   genIfxJump (ifx, swap_sense ? "nc" : "c");
4562                 }
4563               else
4564                 {
4565                   genIfxJump (ifx, swap_sense ? "p" : "m");
4566                 }
4567             }
4568           else
4569             {
4570               genIfxJump (ifx, swap_sense ? "nc" : "c");
4571             }
4572         }
4573       else
4574         {
4575           if (sign)
4576             {
4577               /* Shift the sign bit up into carry */
4578               emit2 ("rlca");
4579             }
4580           outBitCLong (result, swap_sense);
4581         }
4582       /* leave the result in acc */
4583     }
4584 }
4585
4586 /*-----------------------------------------------------------------*/
4587 /* genCmpGt :- greater than comparison                             */
4588 /*-----------------------------------------------------------------*/
4589 static void
4590 genCmpGt (iCode * ic, iCode * ifx)
4591 {
4592   operand *left, *right, *result;
4593   sym_link *letype, *retype;
4594   int sign;
4595
4596   left = IC_LEFT (ic);
4597   right = IC_RIGHT (ic);
4598   result = IC_RESULT (ic);
4599
4600   letype = getSpec (operandType (left));
4601   retype = getSpec (operandType (right));
4602   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4603   /* assign the amsops */
4604   aopOp (left, ic, FALSE, FALSE);
4605   aopOp (right, ic, FALSE, FALSE);
4606   aopOp (result, ic, TRUE, FALSE);
4607
4608   genCmp (right, left, result, ifx, sign);
4609
4610   freeAsmop (left, NULL, ic);
4611   freeAsmop (right, NULL, ic);
4612   freeAsmop (result, NULL, ic);
4613 }
4614
4615 /*-----------------------------------------------------------------*/
4616 /* genCmpLt - less than comparisons                                */
4617 /*-----------------------------------------------------------------*/
4618 static void
4619 genCmpLt (iCode * ic, iCode * ifx)
4620 {
4621   operand *left, *right, *result;
4622   sym_link *letype, *retype;
4623   int sign;
4624
4625   left = IC_LEFT (ic);
4626   right = IC_RIGHT (ic);
4627   result = IC_RESULT (ic);
4628
4629   letype = getSpec (operandType (left));
4630   retype = getSpec (operandType (right));
4631   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4632
4633   /* assign the amsops */
4634   aopOp (left, ic, FALSE, FALSE);
4635   aopOp (right, ic, FALSE, FALSE);
4636   aopOp (result, ic, TRUE, FALSE);
4637
4638   genCmp (left, right, result, ifx, sign);
4639
4640   freeAsmop (left, NULL, ic);
4641   freeAsmop (right, NULL, ic);
4642   freeAsmop (result, NULL, ic);
4643 }
4644
4645 /*-----------------------------------------------------------------*/
4646 /* gencjneshort - compare and jump if not equal                    */
4647 /*-----------------------------------------------------------------*/
4648 static void
4649 gencjneshort (operand * left, operand * right, symbol * lbl)
4650 {
4651   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4652   int offset = 0;
4653   unsigned long lit = 0L;
4654
4655   /* Swap the left and right if it makes the computation easier */
4656   if (AOP_TYPE (left) == AOP_LIT)
4657     {
4658       operand *t = right;
4659       right = left;
4660       left = t;
4661     }
4662
4663   if (AOP_TYPE (right) == AOP_LIT)
4664     {
4665       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4666     }
4667
4668   /* if the right side is a literal then anything goes */
4669   if (AOP_TYPE (right) == AOP_LIT &&
4670       AOP_TYPE (left) != AOP_DIR)
4671     {
4672       if (lit == 0)
4673         {
4674           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4675           if (size > 1)
4676             {
4677               while (--size)
4678                 {
4679                   emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4680                 }
4681             }
4682           else
4683             {
4684               emit2 ("or a,a");
4685             }
4686           emit2 ("jp nz,!tlabel", lbl->key + 100);
4687         }
4688       else
4689         {
4690           while (size--)
4691             {
4692               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4693               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4694                 emit2 ("or a,a");
4695               else
4696                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4697               emit2 ("jp nz,!tlabel", lbl->key + 100);
4698               offset++;
4699             }
4700         }
4701     }
4702   /* if the right side is in a register or in direct space or
4703      if the left is a pointer register & right is not */
4704   else if (AOP_TYPE (right) == AOP_REG ||
4705            AOP_TYPE (right) == AOP_DIR ||
4706            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4707     {
4708       while (size--)
4709         {
4710           _moveA (aopGet (AOP (left), offset, FALSE));
4711           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4712               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4713             /* PENDING */
4714             emit2 ("jp nz,!tlabel", lbl->key + 100);
4715           else
4716             {
4717               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4718               emit2 ("jp nz,!tlabel", lbl->key + 100);
4719             }
4720           offset++;
4721         }
4722     }
4723   else
4724     {
4725       /* right is a pointer reg need both a & b */
4726       /* PENDING: is this required? */
4727       while (size--)
4728         {
4729           _moveA (aopGet (AOP (right), offset, FALSE));
4730           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4731           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4732           offset++;
4733         }
4734     }
4735 }
4736
4737 /*-----------------------------------------------------------------*/
4738 /* gencjne - compare and jump if not equal                         */
4739 /*-----------------------------------------------------------------*/
4740 static void
4741 gencjne (operand * left, operand * right, symbol * lbl)
4742 {
4743   symbol *tlbl = newiTempLabel (NULL);
4744
4745   gencjneshort (left, right, lbl);
4746
4747   /* PENDING: ?? */
4748   emit2 ("ld a,!one");
4749   emit2 ("!shortjp !tlabel", tlbl->key + 100);
4750   emitLabel (lbl->key + 100);
4751   emit2 ("xor a,a");
4752   emitLabel (tlbl->key + 100);
4753 }
4754
4755 /*-----------------------------------------------------------------*/
4756 /* genCmpEq - generates code for equal to                          */
4757 /*-----------------------------------------------------------------*/
4758 static void
4759 genCmpEq (iCode * ic, iCode * ifx)
4760 {
4761   operand *left, *right, *result;
4762
4763   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4764   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4765   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4766
4767   emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4768
4769   /* Swap operands if it makes the operation easier. ie if:
4770      1.  Left is a literal.
4771    */
4772   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4773     {
4774       operand *t = IC_RIGHT (ic);
4775       IC_RIGHT (ic) = IC_LEFT (ic);
4776       IC_LEFT (ic) = t;
4777     }
4778
4779   if (ifx && !AOP_SIZE (result))
4780     {
4781       symbol *tlbl;
4782       /* if they are both bit variables */
4783       if (AOP_TYPE (left) == AOP_CRY &&
4784           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4785         {
4786           wassertl (0, "Tried to compare two bits");
4787         }
4788       else
4789         {
4790           tlbl = newiTempLabel (NULL);
4791           gencjneshort (left, right, tlbl);
4792           if (IC_TRUE (ifx))
4793             {
4794               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4795               emitLabel (tlbl->key + 100);
4796             }
4797           else
4798             {
4799               /* PENDING: do this better */
4800               symbol *lbl = newiTempLabel (NULL);
4801               emit2 ("!shortjp !tlabel", lbl->key + 100);
4802               emitLabel (tlbl->key + 100);
4803               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4804               emitLabel (lbl->key + 100);
4805             }
4806         }
4807       /* mark the icode as generated */
4808       ifx->generated = 1;
4809       goto release;
4810     }
4811
4812   /* if they are both bit variables */
4813   if (AOP_TYPE (left) == AOP_CRY &&
4814       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4815     {
4816       wassertl (0, "Tried to compare a bit to either a literal or another bit");
4817     }
4818   else
4819     {
4820       emitDebug(";4");
4821       
4822       gencjne (left, right, newiTempLabel (NULL));
4823       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4824         {
4825           wassert (0);
4826         }
4827       if (ifx)
4828         {
4829           emitDebug(";5");
4830           genIfxJump (ifx, "a");
4831           goto release;
4832         }
4833       /* if the result is used in an arithmetic operation
4834          then put the result in place */
4835       if (AOP_TYPE (result) != AOP_CRY)
4836         {
4837           emitDebug(";6");
4838           outAcc (result);
4839         }
4840       /* leave the result in acc */
4841     }
4842
4843 release:
4844   freeAsmop (left, NULL, ic);
4845   freeAsmop (right, NULL, ic);
4846   freeAsmop (result, NULL, ic);
4847 }
4848
4849 /*-----------------------------------------------------------------*/
4850 /* ifxForOp - returns the icode containing the ifx for operand     */
4851 /*-----------------------------------------------------------------*/
4852 static iCode *
4853 ifxForOp (operand * op, iCode * ic)
4854 {
4855   /* if true symbol then needs to be assigned */
4856   if (IS_TRUE_SYMOP (op))
4857     return NULL;
4858
4859   /* if this has register type condition and
4860      the next instruction is ifx with the same operand
4861      and live to of the operand is upto the ifx only then */
4862   if (ic->next &&
4863       ic->next->op == IFX &&
4864       IC_COND (ic->next)->key == op->key &&
4865       OP_SYMBOL (op)->liveTo <= ic->next->seq)
4866     return ic->next;
4867
4868   return NULL;
4869 }
4870
4871 /*-----------------------------------------------------------------*/
4872 /* genAndOp - for && operation                                     */
4873 /*-----------------------------------------------------------------*/
4874 static void
4875 genAndOp (iCode * ic)
4876 {
4877   operand *left, *right, *result;
4878   symbol *tlbl;
4879
4880   /* note here that && operations that are in an if statement are
4881      taken away by backPatchLabels only those used in arthmetic
4882      operations remain */
4883   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4884   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4885   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4886
4887   /* if both are bit variables */
4888   if (AOP_TYPE (left) == AOP_CRY &&
4889       AOP_TYPE (right) == AOP_CRY)
4890     {
4891       wassertl (0, "Tried to and two bits");
4892     }
4893   else
4894     {
4895       tlbl = newiTempLabel (NULL);
4896       _toBoolean (left);
4897       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4898       _toBoolean (right);
4899       emitLabel (tlbl->key + 100);
4900       outBitAcc (result);
4901     }
4902
4903   freeAsmop (left, NULL, ic);
4904   freeAsmop (right, NULL, ic);
4905   freeAsmop (result, NULL, ic);
4906 }
4907
4908 /*-----------------------------------------------------------------*/
4909 /* genOrOp - for || operation                                      */
4910 /*-----------------------------------------------------------------*/
4911 static void
4912 genOrOp (iCode * ic)
4913 {
4914   operand *left, *right, *result;
4915   symbol *tlbl;
4916
4917   /* note here that || operations that are in an
4918      if statement are taken away by backPatchLabels
4919      only those used in arthmetic operations remain */
4920   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4921   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4922   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4923
4924   /* if both are bit variables */
4925   if (AOP_TYPE (left) == AOP_CRY &&
4926       AOP_TYPE (right) == AOP_CRY)
4927     {
4928       wassertl (0, "Tried to OR two bits");
4929     }
4930   else
4931     {
4932       tlbl = newiTempLabel (NULL);
4933       _toBoolean (left);
4934       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4935       _toBoolean (right);
4936       emitLabel (tlbl->key + 100);
4937       outBitAcc (result);
4938     }
4939
4940   freeAsmop (left, NULL, ic);
4941   freeAsmop (right, NULL, ic);
4942   freeAsmop (result, NULL, ic);
4943 }
4944
4945 /*-----------------------------------------------------------------*/
4946 /* isLiteralBit - test if lit == 2^n                               */
4947 /*-----------------------------------------------------------------*/
4948 int
4949 isLiteralBit (unsigned long lit)
4950 {
4951   unsigned long pw[32] =
4952   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4953    0x100L, 0x200L, 0x400L, 0x800L,
4954    0x1000L, 0x2000L, 0x4000L, 0x8000L,
4955    0x10000L, 0x20000L, 0x40000L, 0x80000L,
4956    0x100000L, 0x200000L, 0x400000L, 0x800000L,
4957    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4958    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4959   int idx;
4960
4961   for (idx = 0; idx < 32; idx++)
4962     if (lit == pw[idx])
4963       return idx + 1;
4964   return 0;
4965 }
4966
4967 /*-----------------------------------------------------------------*/
4968 /* jmpTrueOrFalse -                                                */
4969 /*-----------------------------------------------------------------*/
4970 static void
4971 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4972 {
4973   // ugly but optimized by peephole
4974   if (IC_TRUE (ic))
4975     {
4976       symbol *nlbl = newiTempLabel (NULL);
4977       emit2 ("jp !tlabel", nlbl->key + 100);
4978       emitLabel (tlbl->key + 100);
4979       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4980       emitLabel (nlbl->key + 100);
4981     }
4982   else
4983     {
4984       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4985       emitLabel (tlbl->key + 100);
4986     }
4987   ic->generated = 1;
4988 }
4989
4990 /*-----------------------------------------------------------------*/
4991 /* genAnd  - code for and                                          */
4992 /*-----------------------------------------------------------------*/
4993 static void
4994 genAnd (iCode * ic, iCode * ifx)
4995 {
4996   operand *left, *right, *result;
4997   int size, offset = 0;
4998   unsigned long lit = 0L;
4999   int bytelit = 0;
5000
5001   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5002   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5003   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5004
5005   /* if left is a literal & right is not then exchange them */
5006   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5007       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5008     {
5009       operand *tmp = right;
5010       right = left;
5011       left = tmp;
5012     }
5013
5014   /* if result = right then exchange them */
5015   if (sameRegs (AOP (result), AOP (right)))
5016     {
5017       operand *tmp = right;
5018       right = left;
5019       left = tmp;
5020     }
5021
5022   /* if right is bit then exchange them */
5023   if (AOP_TYPE (right) == AOP_CRY &&
5024       AOP_TYPE (left) != AOP_CRY)
5025     {
5026       operand *tmp = right;
5027       right = left;
5028       left = tmp;
5029     }
5030   if (AOP_TYPE (right) == AOP_LIT)
5031     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5032
5033   size = AOP_SIZE (result);
5034
5035   if (AOP_TYPE (left) == AOP_CRY)
5036     {
5037       wassertl (0, "Tried to perform an AND with a bit as an operand");
5038       goto release;
5039     }
5040
5041   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5042   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5043   if ((AOP_TYPE (right) == AOP_LIT) &&
5044       (AOP_TYPE (result) == AOP_CRY) &&
5045       (AOP_TYPE (left) != AOP_CRY))
5046     {
5047       symbol *tlbl = newiTempLabel (NULL);
5048       int sizel = AOP_SIZE (left);
5049       if (size)
5050         {
5051           /* PENDING: Test case for this. */
5052           emit2 ("scf");
5053         }
5054       while (sizel--)
5055         {
5056           if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5057             {
5058               _moveA (aopGet (AOP (left), offset, FALSE));
5059               if (bytelit != 0x0FFL)
5060                 {
5061                   emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5062                 }
5063               else
5064                 {
5065                   /* For the flags */
5066                   emit2 ("or a,a");
5067                 }
5068               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5069             }
5070               offset++;
5071         }
5072       // bit = left & literal
5073       if (size)
5074         {
5075           emit2 ("clr c");
5076           emit2 ("!tlabeldef", tlbl->key + 100);
5077         }
5078       // if(left & literal)
5079       else
5080         {
5081           if (ifx)
5082             {
5083               jmpTrueOrFalse (ifx, tlbl);
5084             }
5085           goto release;
5086         }
5087       outBitC (result);
5088       goto release;
5089     }
5090
5091   /* if left is same as result */
5092   if (sameRegs (AOP (result), AOP (left)))
5093     {
5094       for (; size--; offset++)
5095         {
5096           if (AOP_TYPE (right) == AOP_LIT)
5097             {
5098               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5099                 continue;
5100               else
5101                 {
5102                   if (bytelit == 0)
5103                     aopPut (AOP (result), "!zero", offset);
5104                   else
5105                     {
5106                       _moveA (aopGet (AOP (left), offset, FALSE));
5107                       emit2 ("and a,%s",
5108                                 aopGet (AOP (right), offset, FALSE));
5109                       aopPut (AOP (left), "a", offset);
5110                     }
5111                 }
5112
5113             }
5114           else
5115             {
5116               if (AOP_TYPE (left) == AOP_ACC)
5117                 {
5118                   wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5119                 }
5120               else
5121                 {
5122                   _moveA (aopGet (AOP (left), offset, FALSE));
5123                   emit2 ("and a,%s",
5124                             aopGet (AOP (right), offset, FALSE));
5125                   aopPut (AOP (left), "a", offset);
5126                 }
5127             }
5128         }
5129     }
5130   else
5131     {
5132       // left & result in different registers
5133       if (AOP_TYPE (result) == AOP_CRY)
5134         {
5135           wassertl (0, "Tried to AND where the result is in carry");
5136         }
5137       else
5138         {
5139           for (; (size--); offset++)
5140             {
5141               // normal case
5142               // result = left & right
5143               if (AOP_TYPE (right) == AOP_LIT)
5144                 {
5145                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5146                     {
5147                       aopPut (AOP (result),
5148                               aopGet (AOP (left), offset, FALSE),
5149                               offset);
5150                       continue;
5151                     }
5152                   else if (bytelit == 0)
5153                     {
5154                       aopPut (AOP (result), "!zero", offset);
5155                       continue;
5156                     }
5157                 }
5158               // faster than result <- left, anl result,right
5159               // and better if result is SFR
5160               if (AOP_TYPE (left) == AOP_ACC)
5161                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5162               else
5163                 {
5164                   _moveA (aopGet (AOP (left), offset, FALSE));
5165                   emit2 ("and a,%s",
5166                             aopGet (AOP (right), offset, FALSE));
5167                 }
5168               aopPut (AOP (result), "a", offset);
5169             }
5170         }
5171
5172     }
5173
5174 release:
5175   freeAsmop (left, NULL, ic);
5176   freeAsmop (right, NULL, ic);
5177   freeAsmop (result, NULL, ic);
5178 }
5179
5180 /*-----------------------------------------------------------------*/
5181 /* genOr  - code for or                                            */
5182 /*-----------------------------------------------------------------*/
5183 static void
5184 genOr (iCode * ic, iCode * ifx)
5185 {
5186   operand *left, *right, *result;
5187   int size, offset = 0;
5188   unsigned long lit = 0L;
5189   int bytelit = 0;
5190
5191   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5192   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5193   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5194
5195   /* if left is a literal & right is not then exchange them */
5196   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5197       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5198     {
5199       operand *tmp = right;
5200       right = left;
5201       left = tmp;
5202     }
5203
5204   /* if result = right then exchange them */
5205   if (sameRegs (AOP (result), AOP (right)))
5206     {
5207       operand *tmp = right;
5208       right = left;
5209       left = tmp;
5210     }
5211
5212   /* if right is bit then exchange them */
5213   if (AOP_TYPE (right) == AOP_CRY &&
5214       AOP_TYPE (left) != AOP_CRY)
5215     {
5216       operand *tmp = right;
5217       right = left;
5218       left = tmp;
5219     }
5220   if (AOP_TYPE (right) == AOP_LIT)
5221     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5222
5223   size = AOP_SIZE (result);
5224
5225   if (AOP_TYPE (left) == AOP_CRY)
5226     {
5227       wassertl (0, "Tried to OR where left is a bit");
5228       goto release;
5229     }
5230
5231   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5232   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5233   if ((AOP_TYPE (right) == AOP_LIT) &&
5234       (AOP_TYPE (result) == AOP_CRY) &&
5235       (AOP_TYPE (left) != AOP_CRY))
5236     {
5237       symbol *tlbl = newiTempLabel (NULL);
5238       int sizel = AOP_SIZE (left);
5239
5240       if (size)
5241         {
5242           wassertl (0, "Result is assigned to a bit");
5243         }
5244       /* PENDING: Modeled after the AND code which is inefficent. */
5245       while (sizel--)
5246         {
5247           bytelit = (lit >> (offset * 8)) & 0x0FFL;
5248
5249           _moveA (aopGet (AOP (left), offset, FALSE));
5250           /* OR with any literal is the same as OR with itself. */
5251           emit2 ("or a,a");
5252           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5253
5254           offset++;
5255         }
5256       if (ifx)
5257         {
5258           jmpTrueOrFalse (ifx, tlbl);
5259         }
5260       goto release;
5261     }
5262
5263   /* if left is same as result */
5264   if (sameRegs (AOP (result), AOP (left)))
5265     {
5266       for (; size--; offset++)
5267         {
5268           if (AOP_TYPE (right) == AOP_LIT)
5269             {
5270               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5271                 continue;
5272               else
5273                 {
5274                   _moveA (aopGet (AOP (left), offset, FALSE));
5275                   emit2 ("or a,%s",
5276                             aopGet (AOP (right), offset, FALSE));
5277                   aopPut (AOP (result), "a", offset);
5278                 }
5279             }
5280           else
5281             {
5282               if (AOP_TYPE (left) == AOP_ACC)
5283                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5284               else
5285                 {
5286                   _moveA (aopGet (AOP (left), offset, FALSE));
5287                   emit2 ("or a,%s",
5288                             aopGet (AOP (right), offset, FALSE));
5289                   aopPut (AOP (result), "a", offset);
5290                 }
5291             }
5292         }
5293     }
5294   else
5295     {
5296       // left & result in different registers
5297       if (AOP_TYPE (result) == AOP_CRY)
5298         {
5299           wassertl (0, "Result of OR is in a bit");
5300         }
5301       else
5302         for (; (size--); offset++)
5303           {
5304             // normal case
5305             // result = left & right
5306             if (AOP_TYPE (right) == AOP_LIT)
5307               {
5308                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5309                   {
5310                     aopPut (AOP (result),
5311                             aopGet (AOP (left), offset, FALSE),
5312                             offset);
5313                     continue;
5314                   }
5315               }
5316             // faster than result <- left, anl result,right
5317             // and better if result is SFR
5318             if (AOP_TYPE (left) == AOP_ACC)
5319               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5320             else
5321               {
5322                 _moveA (aopGet (AOP (left), offset, FALSE));
5323                 emit2 ("or a,%s",
5324                           aopGet (AOP (right), offset, FALSE));
5325               }
5326             aopPut (AOP (result), "a", offset);
5327             /* PENDING: something weird is going on here.  Add exception. */
5328             if (AOP_TYPE (result) == AOP_ACC)
5329               break;
5330           }
5331     }
5332
5333 release:
5334   freeAsmop (left, NULL, ic);
5335   freeAsmop (right, NULL, ic);
5336   freeAsmop (result, NULL, ic);
5337 }
5338
5339 /*-----------------------------------------------------------------*/
5340 /* genXor - code for xclusive or                                   */
5341 /*-----------------------------------------------------------------*/
5342 static void
5343 genXor (iCode * ic, iCode * ifx)
5344 {
5345   operand *left, *right, *result;
5346   int size, offset = 0;
5347   unsigned long lit = 0L;
5348
5349   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5350   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5351   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5352
5353   /* if left is a literal & right is not then exchange them */
5354   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5355       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5356     {
5357       operand *tmp = right;
5358       right = left;
5359       left = tmp;
5360     }
5361
5362   /* if result = right then exchange them */
5363   if (sameRegs (AOP (result), AOP (right)))
5364     {
5365       operand *tmp = right;
5366       right = left;
5367       left = tmp;
5368     }
5369
5370   /* if right is bit then exchange them */
5371   if (AOP_TYPE (right) == AOP_CRY &&
5372       AOP_TYPE (left) != AOP_CRY)
5373     {
5374       operand *tmp = right;
5375       right = left;
5376       left = tmp;
5377     }
5378   if (AOP_TYPE (right) == AOP_LIT)
5379     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5380
5381   size = AOP_SIZE (result);
5382
5383   if (AOP_TYPE (left) == AOP_CRY)
5384     {
5385       wassertl (0, "Tried to XOR a bit");
5386       goto release;
5387     }
5388
5389   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5390   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5391   if ((AOP_TYPE (right) == AOP_LIT) &&
5392       (AOP_TYPE (result) == AOP_CRY) &&
5393       (AOP_TYPE (left) != AOP_CRY))
5394     {
5395       symbol *tlbl = newiTempLabel (NULL);
5396       int sizel = AOP_SIZE (left);
5397
5398       if (size)
5399         {
5400           /* PENDING: Test case for this. */
5401           wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5402         }
5403       while (sizel--)
5404         {
5405           _moveA (aopGet (AOP (left), offset, FALSE));
5406           emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5407           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5408           offset++;
5409         }
5410       if (ifx)
5411         {
5412           jmpTrueOrFalse (ifx, tlbl);
5413         }
5414       else
5415         {
5416           wassertl (0, "Result of XOR was destined for a bit");
5417         }
5418       goto release;
5419     }
5420
5421   /* if left is same as result */
5422   if (sameRegs (AOP (result), AOP (left)))
5423     {
5424       for (; size--; offset++)
5425         {
5426           if (AOP_TYPE (right) == AOP_LIT)
5427             {
5428               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5429                 continue;
5430               else
5431                 {
5432                   _moveA (aopGet (AOP (left), offset, FALSE));
5433                   emit2 ("xor a,%s",
5434                             aopGet (AOP (right), offset, FALSE));
5435                   aopPut (AOP (result), "a", offset);
5436                 }
5437             }
5438           else
5439             {
5440               if (AOP_TYPE (left) == AOP_ACC)
5441                 {
5442                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5443                 }
5444               else
5445                 {
5446                   _moveA (aopGet (AOP (left), offset, FALSE));
5447                   emit2 ("xor a,%s",
5448                             aopGet (AOP (right), offset, FALSE));
5449                   aopPut (AOP (result), "a", offset);
5450                 }
5451             }
5452         }
5453     }
5454   else
5455     {
5456       // left & result in different registers
5457       if (AOP_TYPE (result) == AOP_CRY)
5458         {
5459           wassertl (0, "Result of XOR is in a bit");
5460         }
5461       else
5462         for (; (size--); offset++)
5463           {
5464             // normal case
5465             // result = left & right
5466             if (AOP_TYPE (right) == AOP_LIT)
5467               {
5468                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5469                   {
5470                     aopPut (AOP (result),
5471                             aopGet (AOP (left), offset, FALSE),
5472                             offset);
5473                     continue;
5474                   }
5475               }
5476             // faster than result <- left, anl result,right
5477             // and better if result is SFR
5478             if (AOP_TYPE (left) == AOP_ACC) 
5479               {
5480                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5481               }
5482             else
5483               {
5484                 _moveA (aopGet (AOP (left), offset, FALSE));
5485                 emit2 ("xor a,%s",
5486                           aopGet (AOP (right), offset, FALSE));
5487               }
5488             aopPut (AOP (result), "a", offset);
5489           }
5490     }
5491
5492 release:
5493   freeAsmop (left, NULL, ic);
5494   freeAsmop (right, NULL, ic);
5495   freeAsmop (result, NULL, ic);
5496 }
5497
5498 /*-----------------------------------------------------------------*/
5499 /* genInline - write the inline code out                           */
5500 /*-----------------------------------------------------------------*/
5501 static void
5502 genInline (iCode * ic)
5503 {
5504   char *buffer, *bp, *bp1;
5505
5506   _G.lines.isInline += (!options.asmpeep);
5507
5508   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5509   strcpy (buffer, IC_INLINE (ic));
5510
5511   /* emit each line as a code */
5512   while (*bp)
5513     {
5514       if (*bp == '\n')
5515         {
5516           *bp++ = '\0';
5517           emit2 (bp1);
5518           bp1 = bp;
5519         }
5520       else
5521         {
5522           if (*bp == ':')
5523             {
5524               bp++;
5525               *bp = '\0';
5526               bp++;
5527               emit2 (bp1);
5528               bp1 = bp;
5529             }
5530           else
5531             bp++;
5532         }
5533     }
5534   if (bp1 != bp)
5535     emit2 (bp1);
5536   _G.lines.isInline -= (!options.asmpeep);
5537
5538 }
5539
5540 /*-----------------------------------------------------------------*/
5541 /* genRRC - rotate right with carry                                */
5542 /*-----------------------------------------------------------------*/
5543 static void
5544 genRRC (iCode * ic)
5545 {
5546   wassert (0);
5547 }
5548
5549 /*-----------------------------------------------------------------*/
5550 /* genRLC - generate code for rotate left with carry               */
5551 /*-----------------------------------------------------------------*/
5552 static void
5553 genRLC (iCode * ic)
5554 {
5555   wassert (0);
5556 }
5557
5558 /*-----------------------------------------------------------------*/
5559 /* genGetHbit - generates code get highest order bit               */
5560 /*-----------------------------------------------------------------*/
5561 static void
5562 genGetHbit (iCode * ic)
5563 {
5564   operand *left, *result;
5565   left = IC_LEFT (ic);
5566   result = IC_RESULT (ic);
5567
5568   aopOp (left, ic, FALSE, FALSE);
5569   aopOp (result, ic, FALSE, FALSE);
5570
5571   /* get the highest order byte into a */
5572   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5573
5574   if (AOP_TYPE (result) == AOP_CRY)
5575     {
5576       emit2 ("rl a");
5577       outBitC (result);
5578     }
5579   else
5580     {
5581       emit2 ("rlc a");
5582       emit2 ("and a,!one");
5583       outAcc (result);
5584     }
5585
5586
5587   freeAsmop (left, NULL, ic);
5588   freeAsmop (result, NULL, ic);
5589 }
5590
5591 static void
5592 emitRsh2 (asmop *aop, int size, int is_signed)
5593 {
5594   int offset = 0;
5595
5596   while (size--)
5597     {
5598       const char *l = aopGet (aop, size, FALSE);
5599       if (offset == 0)
5600         {
5601           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5602         }
5603       else
5604         {
5605           emit2 ("rr %s", l);
5606         }
5607       offset++;
5608     }
5609 }
5610
5611 /*-----------------------------------------------------------------*/
5612 /* shiftR2Left2Result - shift right two bytes from left to result  */
5613 /*-----------------------------------------------------------------*/
5614 static void
5615 shiftR2Left2Result (operand * left, int offl,
5616                     operand * result, int offr,
5617                     int shCount, int is_signed)
5618 {
5619   int size = 2;
5620   symbol *tlbl, *tlbl1;
5621
5622   movLeft2Result (left, offl, result, offr, 0);
5623   movLeft2Result (left, offl + 1, result, offr + 1, 0);
5624
5625   /*  if (AOP(result)->type == AOP_REG) { */
5626   
5627   tlbl = newiTempLabel (NULL);
5628   tlbl1 = newiTempLabel (NULL);
5629
5630   /* Left is already in result - so now do the shift */
5631   if (shCount <= 4)
5632     {
5633       while (shCount--)
5634         {
5635           emitRsh2 (AOP (result), size, is_signed);
5636         }
5637     }
5638   else
5639     {
5640       emit2 ("ld a,!immedbyte+1", shCount);
5641       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5642       emitLabel (tlbl->key + 100);
5643
5644       emitRsh2 (AOP (result), size, is_signed);
5645
5646       emitLabel (tlbl1->key + 100);
5647       emit2 ("dec a");
5648       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5649     }
5650 }
5651
5652 /*-----------------------------------------------------------------*/
5653 /* shiftL2Left2Result - shift left two bytes from left to result   */
5654 /*-----------------------------------------------------------------*/
5655 static void
5656 shiftL2Left2Result (operand * left, int offl,
5657                     operand * result, int offr, int shCount)
5658 {
5659   if (sameRegs (AOP (result), AOP (left)) &&
5660       ((offl + MSB16) == offr))
5661     {
5662       wassert (0);
5663     }
5664   else
5665     {
5666       /* Copy left into result */
5667       movLeft2Result (left, offl, result, offr, 0);
5668       movLeft2Result (left, offl + 1, result, offr + 1, 0);
5669     }
5670
5671   if (getPairId (AOP (result)) == PAIR_HL)
5672     {
5673       while (shCount--)
5674         {
5675           emit2 ("add hl,hl");
5676         }
5677     }
5678   else
5679     {
5680     int size = 2;
5681     int offset = 0;
5682     symbol *tlbl, *tlbl1;
5683     const char *l;
5684
5685     tlbl = newiTempLabel (NULL);
5686     tlbl1 = newiTempLabel (NULL);
5687
5688     if (AOP (result)->type == AOP_REG)
5689       {
5690         while (shCount--)
5691           {
5692             for (offset = 0; offset < size; offset++)
5693               {
5694                 l = aopGet (AOP (result), offset, FALSE);
5695             
5696                 if (offset == 0)
5697                   {
5698                     emit2 ("sla %s", l);
5699                   }
5700                 else
5701                   {
5702                     emit2 ("rl %s", l);
5703                   }
5704               }
5705           }
5706       }
5707     else
5708       {
5709         /* Left is already in result - so now do the shift */
5710         if (shCount > 1)
5711           {
5712             emit2 ("ld a,!immedbyte+1", shCount);
5713             emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5714             emitLabel (tlbl->key + 100);
5715           }
5716
5717         while (size--)
5718           {
5719             l = aopGet (AOP (result), offset, FALSE);
5720             
5721             if (offset == 0)
5722               {
5723                 emit2 ("sla %s", l);
5724               }
5725             else
5726               {
5727                 emit2 ("rl %s", l);
5728               }
5729             
5730             offset++;
5731           }
5732         if (shCount > 1)
5733           {
5734             emitLabel (tlbl1->key + 100);
5735             emit2 ("dec a");
5736             emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5737           }
5738       }
5739   }
5740 }
5741
5742 /*-----------------------------------------------------------------*/
5743 /* AccRol - rotate left accumulator by known count                 */
5744 /*-----------------------------------------------------------------*/
5745 static void
5746 AccRol (int shCount)
5747 {
5748   shCount &= 0x0007;            // shCount : 0..7
5749
5750 #if 0
5751   switch (shCount)
5752     {
5753     case 0:
5754       break;
5755     case 1:
5756       emit2 ("sla a");
5757       break;
5758     case 2:
5759       emit2 ("sla a");
5760       emit2 ("rl a");
5761       break;
5762     case 3:
5763       emit2 ("sla a");
5764       emit2 ("rl a");
5765       emit2 ("rl a");
5766       break;
5767     case 4:
5768       emit2 ("sla a");
5769       emit2 ("rl a");
5770       emit2 ("rl a");
5771       emit2 ("rl a");
5772       break;
5773     case 5:
5774       emit2 ("srl a");
5775       emit2 ("rr a");
5776       emit2 ("rr a");
5777       break;
5778     case 6:
5779       emit2 ("srl a");
5780       emit2 ("rr a");
5781       break;
5782     case 7:
5783       emit2 ("srl a");
5784       break;
5785     }
5786 #else
5787   switch (shCount)
5788     {
5789     case 0:
5790       break;
5791     case 1:
5792       emit2 ("rlca");
5793       break;
5794     case 2:
5795       emit2 ("rlca");
5796       emit2 ("rlca");
5797       break;
5798     case 3:
5799       emit2 ("rlca");
5800       emit2 ("rlca");
5801       emit2 ("rlca");
5802       break;
5803     case 4:
5804       emit2 ("rlca");
5805       emit2 ("rlca");
5806       emit2 ("rlca");
5807       emit2 ("rlca");
5808       break;
5809     case 5:
5810       emit2 ("rrca");
5811       emit2 ("rrca");
5812       emit2 ("rrca");
5813       break;
5814     case 6:
5815       emit2 ("rrca");
5816       emit2 ("rrca");
5817       break;
5818     case 7:
5819       emit2 ("rrca");
5820       break;
5821     }
5822 #endif
5823 }
5824
5825 /*-----------------------------------------------------------------*/
5826 /* AccLsh - left shift accumulator by known count                  */
5827 /*-----------------------------------------------------------------*/
5828 static void
5829 AccLsh (int shCount)
5830 {
5831   static const unsigned char SLMask[] =
5832     {
5833       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5834     };
5835
5836   if (shCount != 0)
5837     {
5838       if (shCount == 1)
5839         {
5840           emit2 ("add a,a");
5841         }
5842       else if (shCount == 2)
5843         {
5844           emit2 ("add a,a");
5845           emit2 ("add a,a");
5846         }
5847       else
5848         {
5849           /* rotate left accumulator */
5850           AccRol (shCount);
5851           /* and kill the lower order bits */
5852           emit2 ("and a,!immedbyte", SLMask[shCount]);
5853         }
5854     }
5855 }
5856
5857 /*-----------------------------------------------------------------*/
5858 /* shiftL1Left2Result - shift left one byte from left to result    */
5859 /*-----------------------------------------------------------------*/
5860 static void
5861 shiftL1Left2Result (operand * left, int offl,
5862                     operand * result, int offr, int shCount)
5863 {
5864   const char *l;
5865   l = aopGet (AOP (left), offl, FALSE);
5866   _moveA (l);
5867   /* shift left accumulator */
5868   AccLsh (shCount);
5869   aopPut (AOP (result), "a", offr);
5870 }
5871
5872
5873 /*-----------------------------------------------------------------*/
5874 /* genlshTwo - left shift two bytes by known amount != 0           */
5875 /*-----------------------------------------------------------------*/
5876 static void
5877 genlshTwo (operand * result, operand * left, int shCount)
5878 {
5879   int size = AOP_SIZE (result);
5880
5881   wassert (size == 2);
5882
5883   /* if shCount >= 8 */
5884   if (shCount >= 8)
5885     {
5886       shCount -= 8;
5887       if (size > 1)
5888         {
5889           if (shCount)
5890             {
5891               movLeft2Result (left, LSB, result, MSB16, 0);
5892               aopPut (AOP (result), "!zero", 0);
5893               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5894             }
5895           else
5896             {
5897               movLeft2Result (left, LSB, result, MSB16, 0);
5898               aopPut (AOP (result), "!zero", 0);
5899             }
5900         }
5901       else
5902         {
5903           aopPut (AOP (result), "!zero", LSB);
5904         }
5905     }
5906   /*  1 <= shCount <= 7 */
5907   else
5908     {
5909       if (size == 1)
5910         {
5911           wassert (0);
5912         }
5913       else
5914         {
5915           shiftL2Left2Result (left, LSB, result, LSB, shCount);
5916         }
5917     }
5918 }
5919
5920 /*-----------------------------------------------------------------*/
5921 /* genlshOne - left shift a one byte quantity by known count       */
5922 /*-----------------------------------------------------------------*/
5923 static void
5924 genlshOne (operand * result, operand * left, int shCount)
5925 {
5926   shiftL1Left2Result (left, LSB, result, LSB, shCount);
5927 }
5928
5929 /*-----------------------------------------------------------------*/
5930 /* genLeftShiftLiteral - left shifting by known count              */
5931 /*-----------------------------------------------------------------*/
5932 static void
5933 genLeftShiftLiteral (operand * left,
5934                      operand * right,
5935                      operand * result,
5936                      iCode * ic)
5937 {
5938   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5939   int size;
5940
5941   freeAsmop (right, NULL, ic);
5942
5943   aopOp (left, ic, FALSE, FALSE);
5944   aopOp (result, ic, FALSE, FALSE);
5945
5946   size = getSize (operandType (result));
5947
5948   /* I suppose that the left size >= result size */
5949   if (shCount == 0)
5950     {
5951       wassert (0);
5952     }
5953
5954   else if (shCount >= (size * 8)) 
5955     {
5956       while (size--)
5957         {
5958           aopPut (AOP (result), "!zero", size);
5959         }
5960     }
5961   else
5962     {
5963       switch (size)
5964         {
5965         case 1:
5966           genlshOne (result, left, shCount);
5967           break;
5968         case 2:
5969           genlshTwo (result, left, shCount);
5970           break;
5971         case 4:
5972           wassertl (0, "Shifting of longs is currently unsupported");
5973           break;
5974         default:
5975           wassert (0);
5976         }
5977     }
5978   freeAsmop (left, NULL, ic);
5979   freeAsmop (result, NULL, ic);
5980 }
5981
5982 /*-----------------------------------------------------------------*/
5983 /* genLeftShift - generates code for left shifting                 */
5984 /*-----------------------------------------------------------------*/
5985 static void
5986 genLeftShift (iCode * ic)
5987 {
5988   int size, offset;
5989   const char *l;
5990   symbol *tlbl, *tlbl1;
5991   operand *left, *right, *result;
5992
5993   right = IC_RIGHT (ic);
5994   left = IC_LEFT (ic);
5995   result = IC_RESULT (ic);
5996
5997   aopOp (right, ic, FALSE, FALSE);
5998
5999   /* if the shift count is known then do it
6000      as efficiently as possible */
6001   if (AOP_TYPE (right) == AOP_LIT)
6002     {
6003       genLeftShiftLiteral (left, right, result, ic);
6004       return;
6005     }
6006
6007   /* shift count is unknown then we have to form a loop get the loop
6008      count in B : Note: we take only the lower order byte since
6009      shifting more that 32 bits make no sense anyway, ( the largest
6010      size of an object can be only 32 bits ) */
6011   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6012   emit2 ("inc a");
6013   freeAsmop (right, NULL, ic);
6014   aopOp (left, ic, FALSE, FALSE);
6015   aopOp (result, ic, FALSE, FALSE);
6016
6017   /* now move the left to the result if they are not the
6018      same */
6019
6020   if (!sameRegs (AOP (left), AOP (result)))
6021     {
6022
6023       size = AOP_SIZE (result);
6024       offset = 0;
6025       while (size--)
6026         {
6027           l = aopGet (AOP (left), offset, FALSE);
6028           aopPut (AOP (result), l, offset);
6029           offset++;
6030         }
6031     }
6032
6033   tlbl = newiTempLabel (NULL);
6034   size = AOP_SIZE (result);
6035   offset = 0;
6036   tlbl1 = newiTempLabel (NULL);
6037
6038   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6039   emitLabel (tlbl->key + 100);
6040   l = aopGet (AOP (result), offset, FALSE);
6041
6042   while (size--)
6043     {
6044       l = aopGet (AOP (result), offset, FALSE);
6045
6046       if (offset == 0)
6047         {
6048           emit2 ("sla %s", l);
6049         }
6050       else
6051         {
6052           emit2 ("rl %s", l);
6053         }
6054       offset++;
6055     }
6056   emitLabel (tlbl1->key + 100);
6057   emit2 ("dec a");
6058   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6059
6060   freeAsmop (left, NULL, ic);
6061   freeAsmop (result, NULL, ic);
6062 }
6063
6064 /*-----------------------------------------------------------------*/
6065 /* genrshOne - left shift two bytes by known amount != 0           */
6066 /*-----------------------------------------------------------------*/
6067 static void
6068 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6069 {
6070   /* Errk */
6071   int size = AOP_SIZE (result);
6072   const char *l;
6073
6074   wassert (size == 1);
6075   wassert (shCount < 8);
6076
6077   l = aopGet (AOP (left), 0, FALSE);
6078
6079   if (AOP (result)->type == AOP_REG)
6080     {
6081       aopPut (AOP (result), l, 0);
6082       l = aopGet (AOP (result), 0, FALSE);
6083       while (shCount--)
6084         {
6085           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6086         }
6087     }
6088   else
6089     {
6090       _moveA (l);
6091       while (shCount--)
6092         {
6093           emit2 ("%s a", is_signed ? "sra" : "srl");
6094         }
6095       aopPut (AOP (result), "a", 0);
6096     }
6097 }
6098
6099 /*-----------------------------------------------------------------*/
6100 /* AccRsh - right shift accumulator by known count                 */
6101 /*-----------------------------------------------------------------*/
6102 static void
6103 AccRsh (int shCount)
6104 {
6105   static const unsigned char SRMask[] =
6106     {
6107       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6108     };
6109
6110   if (shCount != 0)
6111     {
6112       /* rotate right accumulator */
6113       AccRol (8 - shCount);
6114       /* and kill the higher order bits */
6115       emit2 ("and a,!immedbyte", SRMask[shCount]);
6116     }
6117 }
6118
6119 /*-----------------------------------------------------------------*/
6120 /* shiftR1Left2Result - shift right one byte from left to result   */
6121 /*-----------------------------------------------------------------*/
6122 static void
6123 shiftR1Left2Result (operand * left, int offl,
6124                     operand * result, int offr,
6125                     int shCount, int sign)
6126 {
6127   _moveA (aopGet (AOP (left), offl, FALSE));
6128   if (sign)
6129     {
6130       while (shCount--)
6131         {
6132           emit2 ("%s a", sign ? "sra" : "srl");
6133         }
6134     }
6135   else
6136     {
6137       AccRsh (shCount);
6138     }
6139   aopPut (AOP (result), "a", offr);
6140 }
6141
6142 /*-----------------------------------------------------------------*/
6143 /* genrshTwo - right shift two bytes by known amount != 0          */
6144 /*-----------------------------------------------------------------*/
6145 static void
6146 genrshTwo (operand * result, operand * left,
6147            int shCount, int sign)
6148 {
6149   /* if shCount >= 8 */
6150   if (shCount >= 8)
6151     {
6152       shCount -= 8;
6153       if (shCount)
6154         {
6155           shiftR1Left2Result (left, MSB16, result, LSB,
6156                               shCount, sign);
6157         }
6158       else
6159         {
6160           movLeft2Result (left, MSB16, result, LSB, sign);
6161         }
6162       if (sign)
6163         {
6164           /* Sign extend the result */
6165           _moveA(aopGet (AOP (result), 0, FALSE));
6166           emit2 ("rlc a");
6167           emit2 ("sbc a,a");
6168
6169           aopPut (AOP (result), ACC_NAME, MSB16);
6170         }
6171       else
6172         {
6173           aopPut (AOP (result), "!zero", 1);
6174         }
6175     }
6176   /*  1 <= shCount <= 7 */
6177   else
6178     {
6179       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6180     }
6181 }
6182
6183 /*-----------------------------------------------------------------*/
6184 /* genRightShiftLiteral - left shifting by known count              */
6185 /*-----------------------------------------------------------------*/
6186 static void
6187 genRightShiftLiteral (operand * left,
6188                       operand * right,
6189                       operand * result,
6190                       iCode * ic,
6191                       int sign)
6192 {
6193   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6194   int size;
6195
6196   freeAsmop (right, NULL, ic);
6197
6198   aopOp (left, ic, FALSE, FALSE);
6199   aopOp (result, ic, FALSE, FALSE);
6200
6201   size = getSize (operandType (result));
6202
6203   /* I suppose that the left size >= result size */
6204   if (shCount == 0)
6205     {
6206       wassert (0);
6207     }
6208
6209   else if (shCount >= (size * 8)) {
6210     const char *s;
6211     if (!SPEC_USIGN(getSpec(operandType(left)))) {
6212       _moveA(aopGet (AOP (left), 0, FALSE));
6213       emit2 ("rlc a");
6214       emit2 ("sbc a,a");
6215       s=ACC_NAME;
6216     } else {
6217       s="!zero";
6218     }
6219     while (size--)
6220       aopPut (AOP (result), s, size);
6221   }
6222   else
6223     {
6224       switch (size)
6225         {
6226         case 1:
6227           genrshOne (result, left, shCount, sign);
6228           break;
6229         case 2:
6230           genrshTwo (result, left, shCount, sign);
6231           break;
6232         case 4:
6233           wassertl (0, "Asked to shift right a long which should be a function call");
6234           break;
6235         default:
6236           wassertl (0, "Entered default case in right shift delegate");
6237         }
6238     }
6239   freeAsmop (left, NULL, ic);
6240   freeAsmop (result, NULL, ic);
6241 }
6242
6243 /*-----------------------------------------------------------------*/
6244 /* genRightShift - generate code for right shifting                */
6245 /*-----------------------------------------------------------------*/
6246 static void
6247 genRightShift (iCode * ic)
6248 {
6249   operand *right, *left, *result;
6250   sym_link *retype;
6251   int size, offset, first = 1;
6252   const char *l;
6253   bool is_signed;
6254
6255   symbol *tlbl, *tlbl1;
6256
6257   /* if signed then we do it the hard way preserve the
6258      sign bit moving it inwards */
6259   retype = getSpec (operandType (IC_RESULT (ic)));
6260
6261   is_signed = !SPEC_USIGN (retype);
6262
6263   /* signed & unsigned types are treated the same : i.e. the
6264      signed is NOT propagated inwards : quoting from the
6265      ANSI - standard : "for E1 >> E2, is equivalent to division
6266      by 2**E2 if unsigned or if it has a non-negative value,
6267      otherwise the result is implementation defined ", MY definition
6268      is that the sign does not get propagated */
6269
6270   right = IC_RIGHT (ic);
6271   left = IC_LEFT (ic);
6272   result = IC_RESULT (ic);
6273
6274   aopOp (right, ic, FALSE, FALSE);
6275
6276   /* if the shift count is known then do it
6277      as efficiently as possible */
6278   if (AOP_TYPE (right) == AOP_LIT)
6279     {
6280       genRightShiftLiteral (left, right, result, ic, is_signed);
6281       return;
6282     }
6283
6284   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6285   emit2 ("inc a");
6286   freeAsmop (right, NULL, ic);
6287
6288   aopOp (left, ic, FALSE, FALSE);
6289   aopOp (result, ic, FALSE, FALSE);
6290
6291   /* now move the left to the result if they are not the
6292      same */
6293   if (!sameRegs (AOP (left), AOP (result)))
6294     {
6295
6296       size = AOP_SIZE (result);
6297       offset = 0;
6298       while (size--)
6299         {
6300           l = aopGet (AOP (left), offset, FALSE);
6301           aopPut (AOP (result), l, offset);
6302           offset++;
6303         }
6304     }
6305
6306   tlbl = newiTempLabel (NULL);
6307   tlbl1 = newiTempLabel (NULL);
6308   size = AOP_SIZE (result);
6309   offset = size - 1;
6310
6311   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6312   emitLabel (tlbl->key + 100);
6313   while (size--)
6314     {
6315       l = aopGet (AOP (result), offset--, FALSE);
6316       if (first)
6317         {
6318           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6319           first = 0;
6320         }
6321       else
6322         {
6323           emit2 ("rr %s", l);
6324         }
6325     }
6326   emitLabel (tlbl1->key + 100);
6327   emit2 ("dec a");
6328   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6329
6330   freeAsmop (left, NULL, ic);
6331   freeAsmop (result, NULL, ic);
6332 }
6333
6334
6335 /*-----------------------------------------------------------------*/
6336 /* genUnpackBits - generates code for unpacking bits               */
6337 /*-----------------------------------------------------------------*/
6338 static void
6339 genUnpackBits (operand * result, int pair)
6340 {
6341   int offset = 0;       /* result byte offset */
6342   int rsize;            /* result size */
6343   int rlen = 0;         /* remaining bitfield length */
6344   sym_link *etype;      /* bitfield type information */
6345   int blen;             /* bitfield length */
6346   int bstr;             /* bitfield starting bit within byte */
6347
6348   emitDebug ("; genUnpackBits");
6349
6350   etype = getSpec (operandType (result));
6351   rsize = getSize (operandType (result));
6352   blen = SPEC_BLEN (etype);
6353   bstr = SPEC_BSTR (etype);
6354
6355   /* If the bitfield length is less than a byte */
6356   if (blen < 8)
6357     {
6358       emit2 ("ld a,!*pair", _pairs[pair].name);
6359       AccRsh (bstr);
6360       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6361       aopPut (AOP (result), "a", offset++);
6362       goto finish;
6363     }
6364
6365   /* TODO: what if pair == PAIR_DE ? */
6366   if (getPairId (AOP (result)) == PAIR_HL)
6367     {
6368       wassertl (rsize == 2, "HL must be of size 2");
6369       emit2 ("ld a,!*hl");
6370       emit2 ("inc hl");
6371       emit2 ("ld h,!*hl");
6372       emit2 ("ld l,a");
6373       emit2 ("ld a,h");
6374       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6375       emit2 ("ld h,a");
6376       spillPair (PAIR_HL);
6377       return;
6378     }
6379
6380   /* Bit field did not fit in a byte. Copy all
6381      but the partial byte at the end.  */
6382   for (rlen=blen;rlen>=8;rlen-=8)
6383     {
6384       emit2 ("ld a,!*pair", _pairs[pair].name);
6385       aopPut (AOP (result), "a", offset++);
6386       if (rlen>8)
6387         {
6388           emit2 ("inc %s", _pairs[pair].name);
6389           _G.pairs[pair].offset++;
6390         }
6391     }
6392
6393   /* Handle the partial byte at the end */
6394   if (rlen)
6395     {
6396       emit2 ("ld a,!*pair", _pairs[pair].name);
6397       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6398       aopPut (AOP (result), "a", offset++);
6399     }
6400
6401 finish:
6402   if (offset < rsize)
6403     {
6404       rsize -= offset;
6405       while (rsize--)
6406         aopPut (AOP (result), "!zero", offset++);
6407     }
6408 }
6409
6410 /*-----------------------------------------------------------------*/
6411 /* genGenPointerGet -  get value from generic pointer space        */
6412 /*-----------------------------------------------------------------*/
6413 static void
6414 genGenPointerGet (operand * left,
6415                   operand * result, iCode * ic)
6416 {
6417   int size, offset;
6418   sym_link *retype = getSpec (operandType (result));
6419   int pair = PAIR_HL;
6420
6421   if (IS_GB)
6422     pair = PAIR_DE;
6423
6424   aopOp (left, ic, FALSE, FALSE);
6425   aopOp (result, ic, FALSE, FALSE);
6426
6427   size = AOP_SIZE (result);
6428
6429   if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6430     {
6431       /* Just do it */
6432       if (isPtrPair (AOP (left)))
6433         {
6434           tsprintf (buffer, sizeof(buffer), 
6435                     "!*pair", getPairName (AOP (left)));
6436           aopPut (AOP (result), buffer, 0);
6437         }
6438       else
6439         {
6440           emit2 ("ld a,!*pair", getPairName (AOP (left)));
6441           aopPut (AOP (result), "a", 0);
6442         }
6443       freeAsmop (left, NULL, ic);
6444       goto release;
6445     }
6446
6447   if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6448     {
6449       /* Just do it */
6450       offset = 0;
6451       while (size--) 
6452         {
6453           char at[20];
6454           tsprintf (at, sizeof(at), "!*iyx", offset);
6455           aopPut (AOP (result), at, offset);
6456           offset++;
6457         }
6458  
6459       freeAsmop (left, NULL, ic);
6460       goto release;
6461     }
6462
6463   /* For now we always load into IY */
6464   /* if this is remateriazable */
6465   fetchPair (pair, AOP (left));
6466
6467   /* if bit then unpack */
6468   if (IS_BITVAR (retype))
6469     {
6470       genUnpackBits (result, pair);
6471       freeAsmop (left, NULL, ic);
6472       goto release;
6473       //wassert (0);
6474     }
6475   else if (getPairId (AOP (result)) == PAIR_HL)
6476     {
6477       wassertl (size == 2, "HL must be of size 2");
6478       emit2 ("ld a,!*hl");
6479       emit2 ("inc hl");
6480       emit2 ("ld h,!*hl");
6481       emit2 ("ld l,a");
6482       spillPair (PAIR_HL);
6483     }
6484   else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6485     {
6486       size = AOP_SIZE (result);
6487       offset = 0;
6488
6489       while (size--)
6490         {
6491           /* PENDING: make this better */
6492           if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6493             {
6494               aopPut (AOP (result), "!*hl", offset++);
6495             }
6496           else
6497             {
6498               emit2 ("ld a,!*pair", _pairs[pair].name);
6499               aopPut (AOP (result), "a", offset++);
6500             }
6501           if (size)
6502             {
6503               emit2 ("inc %s", _pairs[pair].name);
6504               _G.pairs[pair].offset++;
6505             }
6506         }
6507       /* Fixup HL back down */
6508       for (size = AOP_SIZE (result)-1; size; size--)
6509         {
6510           emit2 ("dec %s", _pairs[pair].name);
6511         }
6512     }
6513   else
6514     {
6515       size = AOP_SIZE (result);
6516       offset = 0;
6517
6518       while (size--)
6519         {
6520           /* PENDING: make this better */
6521           if (!IS_GB && 
6522               (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6523             {
6524               aopPut (AOP (result), "!*hl", offset++);
6525             }
6526           else
6527             {
6528               emit2 ("ld a,!*pair", _pairs[pair].name);
6529               aopPut (AOP (result), "a", offset++);
6530             }
6531           if (size)
6532             {
6533               emit2 ("inc %s", _pairs[pair].name);
6534               _G.pairs[pair].offset++;
6535             }
6536         }
6537     }
6538
6539   freeAsmop (left, NULL, ic);
6540
6541 release:
6542   freeAsmop (result, NULL, ic);
6543 }
6544
6545 /*-----------------------------------------------------------------*/
6546 /* genPointerGet - generate code for pointer get                   */
6547 /*-----------------------------------------------------------------*/
6548 static void
6549 genPointerGet (iCode * ic)
6550 {
6551   operand *left, *result;
6552   sym_link *type, *etype;
6553
6554   left = IC_LEFT (ic);
6555   result = IC_RESULT (ic);
6556
6557   /* depending on the type of pointer we need to
6558      move it to the correct pointer register */
6559   type = operandType (left);
6560   etype = getSpec (type);
6561
6562   genGenPointerGet (left, result, ic);
6563 }
6564
6565 bool
6566 isRegOrLit (asmop * aop)
6567 {
6568   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6569     return TRUE;
6570   return FALSE;
6571 }
6572
6573
6574 /*-----------------------------------------------------------------*/
6575 /* genPackBits - generates code for packed bit storage             */
6576 /*-----------------------------------------------------------------*/
6577 static void
6578 genPackBits (sym_link * etype,
6579              operand * right,
6580              int pair,
6581              iCode *ic)
6582 {
6583   int offset = 0;       /* source byte offset */
6584   int rlen = 0;         /* remaining bitfield length */
6585   int blen;             /* bitfield length */
6586   int bstr;             /* bitfield starting bit within byte */
6587   int litval;           /* source literal value (if AOP_LIT) */
6588   unsigned char mask;   /* bitmask within current byte */
6589   int extraPair;        /* a tempory register */
6590   bool needPopExtra=0;  /* need to restore original value of temp reg */
6591
6592   emitDebug (";     genPackBits","");
6593
6594   blen = SPEC_BLEN (etype);
6595   bstr = SPEC_BSTR (etype);
6596
6597   /* If the bitfield length is less than a byte */
6598   if (blen < 8)
6599     {
6600       mask = ((unsigned char) (0xFF << (blen + bstr)) |
6601               (unsigned char) (0xFF >> (8 - bstr)));
6602
6603       if (AOP_TYPE (right) == AOP_LIT)
6604         {
6605           /* Case with a bitfield length <8 and literal source
6606           */
6607           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6608           litval <<= bstr;
6609           litval &= (~mask) & 0xff;
6610           emit2 ("ld a,!*pair", _pairs[pair].name);
6611           if ((mask|litval)!=0xff)
6612             emit2 ("and a,!immedbyte", mask);
6613           if (litval)
6614             emit2 ("or a,!immedbyte", litval);
6615           emit2 ("ld !*pair,a", _pairs[pair].name);
6616           return;
6617         }
6618       else
6619         {
6620           /* Case with a bitfield length <8 and arbitrary source
6621           */
6622           _moveA (aopGet (AOP (right), 0, FALSE));
6623           /* shift and mask source value */
6624           AccLsh (bstr);
6625           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6626
6627           extraPair = getFreePairId(ic);
6628           if (extraPair == PAIR_INVALID)
6629             {
6630               extraPair = PAIR_BC;
6631               if (getPairId (AOP (right)) != PAIR_BC
6632                   || !isLastUse (ic, right))
6633                 {
6634                   _push (extraPair);
6635                   needPopExtra = 1;
6636                 }
6637             }
6638           emit2 ("ld %s,a", _pairs[extraPair].l);
6639           emit2 ("ld a,!*pair", _pairs[pair].name);
6640
6641           emit2 ("and a,!immedbyte", mask);
6642           emit2 ("or a,%s", _pairs[extraPair].l);
6643           emit2 ("ld !*pair,a", _pairs[pair].name);
6644           if (needPopExtra)
6645             _pop (extraPair);
6646           return;
6647         }
6648     }
6649
6650   /* Bit length is greater than 7 bits. In this case, copy  */
6651   /* all except the partial byte at the end                 */
6652   for (rlen=blen;rlen>=8;rlen-=8)
6653     {
6654       emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6655       emit2 ("ld !*pair,a", _pairs[pair].name);
6656       if (rlen>8)
6657         {
6658           emit2 ("inc %s", _pairs[pair].name);
6659           _G.pairs[pair].offset++;
6660         }
6661     }
6662
6663   /* If there was a partial byte at the end */
6664   if (rlen)
6665     {
6666       mask = (((unsigned char) -1 << rlen) & 0xff);
6667       
6668       if (AOP_TYPE (right) == AOP_LIT)
6669         {
6670           /* Case with partial byte and literal source
6671           */
6672           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6673           litval >>= (blen-rlen);
6674           litval &= (~mask) & 0xff;
6675           emit2 ("ld a,!*pair", _pairs[pair].name);
6676           if ((mask|litval)!=0xff)
6677             emit2 ("and a,!immedbyte", mask);
6678           if (litval)
6679             emit2 ("or a,!immedbyte", litval);
6680         }
6681       else
6682         {
6683           /* Case with partial byte and arbitrary source
6684           */
6685           _moveA (aopGet (AOP (right), offset++, FALSE));
6686           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6687
6688           extraPair = getFreePairId(ic);
6689           if (extraPair == PAIR_INVALID)
6690             {
6691               extraPair = getPairId (AOP (right));
6692               if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6693                 extraPair = PAIR_BC;
6694
6695               if (getPairId (AOP (right)) != PAIR_BC
6696                   || !isLastUse (ic, right))
6697                 {
6698                   _push (extraPair);
6699                   needPopExtra = 1;
6700                 }
6701             }
6702           emit2 ("ld %s,a", _pairs[extraPair].l);
6703           emit2 ("ld a,!*pair", _pairs[pair].name);
6704
6705           emit2 ("and a,!immedbyte", mask);
6706           emit2 ("or a,%s", _pairs[extraPair].l);
6707           if (needPopExtra)
6708             _pop (extraPair);
6709
6710         }
6711       emit2 ("ld !*pair,a", _pairs[pair].name);
6712     }
6713 }
6714
6715
6716 /*-----------------------------------------------------------------*/
6717 /* genGenPointerSet - stores the value into a pointer location        */
6718 /*-----------------------------------------------------------------*/
6719 static void
6720 genGenPointerSet (operand * right,
6721                   operand * result, iCode * ic)
6722 {
6723   int size, offset;
6724   sym_link *retype = getSpec (operandType (right));
6725   sym_link *letype = getSpec (operandType (result));
6726   PAIR_ID pairId = PAIR_HL;
6727   bool isBitvar;
6728   
6729   aopOp (result, ic, FALSE, FALSE);
6730   aopOp (right, ic, FALSE, FALSE);
6731
6732   if (IS_GB)
6733     pairId = PAIR_DE;
6734
6735   size = AOP_SIZE (right);
6736
6737   isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6738   emitDebug("; isBitvar = %d", isBitvar);
6739
6740   /* Handle the exceptions first */
6741   if (isPair (AOP (result)) && size == 1 && !isBitvar)
6742     {
6743       /* Just do it */
6744       const char *l = aopGet (AOP (right), 0, FALSE);
6745       const char *pair = getPairName (AOP (result));
6746       if (canAssignToPtr (l) && isPtr (pair))
6747         {
6748           emit2 ("ld !*pair,%s", pair, l);
6749         }
6750       else
6751         {
6752           _moveA (l);
6753           emit2 ("ld !*pair,a", pair);
6754         }
6755       goto release;
6756     }
6757   
6758   if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6759     {
6760       /* Just do it */
6761       const char *l = aopGet (AOP (right), 0, FALSE);
6762
6763       offset = 0;
6764       while (size--) 
6765         {
6766           if (canAssignToPtr (l))
6767             {
6768               emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6769             }
6770           else
6771             {
6772               _moveA (aopGet (AOP (right), offset, FALSE));
6773               emit2 ("ld !*iyx,a", offset);
6774             }
6775           offset++;
6776         }
6777       goto release;
6778     }
6779   else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6780            && !isBitvar)
6781     {
6782       offset = 0;
6783
6784       while (size--)
6785         {
6786           const char *l = aopGet (AOP (right), offset, FALSE);
6787           if (isRegOrLit (AOP (right)) && !IS_GB)
6788             {
6789               emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6790             }
6791           else
6792             {
6793               _moveA (l);
6794               emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6795             }
6796           if (size)
6797             {
6798               emit2 ("inc %s", _pairs[PAIR_HL].name);
6799               _G.pairs[PAIR_HL].offset++;
6800             }
6801           offset++;
6802         }
6803
6804       /* Fixup HL back down */
6805       for (size = AOP_SIZE (right)-1; size; size--)
6806         {
6807           emit2 ("dec %s", _pairs[PAIR_HL].name);
6808         }
6809       goto release;
6810     }
6811
6812   /* if the operand is already in dptr
6813      then we do nothing else we move the value to dptr */
6814   if (AOP_TYPE (result) != AOP_STR)
6815     {
6816       fetchPair (pairId, AOP (result));
6817     }
6818   /* so hl now contains the address */
6819   freeAsmop (result, NULL, ic);
6820
6821   /* if bit then unpack */
6822   if (isBitvar)
6823     {
6824       genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6825       goto release;
6826       //wassert (0);
6827     }
6828   else
6829     {
6830       offset = 0;
6831
6832       while (size--)
6833         {
6834           const char *l = aopGet (AOP (right), offset, FALSE);
6835           if (isRegOrLit (AOP (right)) && !IS_GB)
6836             {
6837               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6838             }
6839           else
6840             {
6841               _moveA (l);
6842               emit2 ("ld !*pair,a", _pairs[pairId].name);
6843             }
6844           if (size)
6845             {
6846               emit2 ("inc %s", _pairs[pairId].name);
6847               _G.pairs[pairId].offset++;
6848             }
6849           offset++;
6850         }
6851     }
6852 release:
6853   freeAsmop (right, NULL, ic);
6854 }
6855
6856 /*-----------------------------------------------------------------*/
6857 /* genPointerSet - stores the value into a pointer location        */
6858 /*-----------------------------------------------------------------*/
6859 static void
6860 genPointerSet (iCode * ic)
6861 {
6862   operand *right, *result;
6863   sym_link *type, *etype;
6864
6865   right = IC_RIGHT (ic);
6866   result = IC_RESULT (ic);
6867
6868   /* depending on the type of pointer we need to
6869      move it to the correct pointer register */
6870   type = operandType (result);
6871   etype = getSpec (type);
6872
6873   genGenPointerSet (right, result, ic);
6874 }
6875
6876 /*-----------------------------------------------------------------*/
6877 /* genIfx - generate code for Ifx statement                        */
6878 /*-----------------------------------------------------------------*/
6879 static void
6880 genIfx (iCode * ic, iCode * popIc)
6881 {
6882   operand *cond = IC_COND (ic);
6883   int isbit = 0;
6884
6885   aopOp (cond, ic, FALSE, TRUE);
6886
6887   /* get the value into acc */
6888   if (AOP_TYPE (cond) != AOP_CRY)
6889     _toBoolean (cond);
6890   else
6891     isbit = 1;
6892   /* the result is now in the accumulator */
6893   freeAsmop (cond, NULL, ic);
6894
6895   /* if there was something to be popped then do it */
6896   if (popIc)
6897     genIpop (popIc);
6898
6899   /* if the condition is  a bit variable */
6900   if (isbit && IS_ITEMP (cond) &&
6901       SPIL_LOC (cond))
6902     genIfxJump (ic, SPIL_LOC (cond)->rname);
6903   else if (isbit && !IS_ITEMP (cond))
6904     genIfxJump (ic, OP_SYMBOL (cond)->rname);
6905   else
6906     genIfxJump (ic, "a");
6907
6908   ic->generated = 1;
6909 }
6910
6911 /*-----------------------------------------------------------------*/
6912 /* genAddrOf - generates code for address of                       */
6913 /*-----------------------------------------------------------------*/
6914 static void
6915 genAddrOf (iCode * ic)
6916 {
6917   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6918
6919   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6920
6921   /* if the operand is on the stack then we
6922      need to get the stack offset of this
6923      variable */
6924   if (IS_GB)
6925     {
6926       if (sym->onStack)
6927         {
6928           spillCached ();
6929           if (sym->stack <= 0)
6930             {
6931               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6932             }
6933           else
6934             {
6935               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6936             }
6937           commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6938         }
6939       else
6940         {
6941           emit2 ("ld de,!hashedstr", sym->rname);
6942           commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6943         }
6944     }
6945   else
6946     {
6947       spillCached ();
6948       if (sym->onStack)
6949         {
6950           /* if it has an offset  then we need to compute it */
6951           if (sym->stack > 0)
6952             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6953           else
6954             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6955           emit2 ("add hl,sp");
6956         }
6957       else
6958         {
6959           emit2 ("ld hl,!hashedstr", sym->rname);
6960         }
6961       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6962     }
6963   freeAsmop (IC_RESULT (ic), NULL, ic);
6964 }
6965
6966 /*-----------------------------------------------------------------*/
6967 /* genAssign - generate code for assignment                        */
6968 /*-----------------------------------------------------------------*/
6969 static void
6970 genAssign (iCode * ic)
6971 {
6972   operand *result, *right;
6973   int size, offset;
6974   unsigned long lit = 0L;
6975
6976   result = IC_RESULT (ic);
6977   right = IC_RIGHT (ic);
6978
6979   /* Dont bother assigning if they are the same */
6980   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6981     {
6982       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6983       return;
6984     }
6985
6986   aopOp (right, ic, FALSE, FALSE);
6987   aopOp (result, ic, TRUE, FALSE);
6988
6989   /* if they are the same registers */
6990   if (sameRegs (AOP (right), AOP (result)))
6991     {
6992       emitDebug ("; (registers are the same)");
6993       goto release;
6994     }
6995
6996   /* if the result is a bit */
6997   if (AOP_TYPE (result) == AOP_CRY)
6998     {
6999       wassertl (0, "Tried to assign to a bit");
7000     }
7001
7002   /* general case */
7003   size = AOP_SIZE (result);
7004   offset = 0;
7005
7006   if (AOP_TYPE (right) == AOP_LIT)
7007     {
7008       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7009     }
7010
7011   if (isPair (AOP (result)))
7012     {
7013       fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7014     }
7015   else if ((size > 1) &&
7016            (AOP_TYPE (result) != AOP_REG) &&
7017            (AOP_TYPE (right) == AOP_LIT) &&
7018            !IS_FLOAT (operandType (right)) &&
7019            (lit < 256L))
7020     {
7021       bool fXored = FALSE;
7022       offset = 0;
7023       /* Work from the top down.
7024          Done this way so that we can use the cached copy of 0
7025          in A for a fast clear */
7026       while (size--)
7027         {
7028           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7029             {
7030               if (!fXored && size > 1)
7031                 {
7032                   emit2 ("xor a,a");
7033                   fXored = TRUE;
7034                 }
7035               if (fXored)
7036                 {
7037                   aopPut (AOP (result), "a", offset);
7038                 }
7039               else
7040                 {
7041                   aopPut (AOP (result), "!zero", offset);
7042                 }
7043             }
7044           else
7045             aopPut (AOP (result),
7046                     aopGet (AOP (right), offset, FALSE),
7047                     offset);
7048           offset++;
7049         }
7050     }
7051   else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7052     {
7053       emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7054       aopPut (AOP (result), "l", LSB);
7055       aopPut (AOP (result), "h", MSB16);
7056     }
7057   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7058     {
7059       /* Special case.  Load into a and d, then load out. */
7060       _moveA (aopGet (AOP (right), 0, FALSE));
7061       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7062       aopPut (AOP (result), "a", 0);
7063       aopPut (AOP (result), "e", 1);
7064     }
7065   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7066     {
7067       /* Special case - simple memcpy */
7068       aopGet (AOP (right), LSB, FALSE);
7069       emit2 ("ld d,h");
7070       emit2 ("ld e,l");
7071       aopGet (AOP (result), LSB, FALSE);
7072
7073       while (size--)
7074         {
7075           emit2 ("ld a,(de)");
7076           /* Peephole will optimise this. */
7077           emit2 ("ld (hl),a");
7078
7079           if (size != 0)
7080             {
7081               emit2 ("inc hl");
7082               emit2 ("inc de");
7083             }
7084         }
7085       spillPair (PAIR_HL);
7086     }
7087   else
7088     {
7089       while (size--)
7090         {
7091           /* PENDING: do this check better */
7092           if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7093             {
7094               _moveA (aopGet (AOP (right), offset, FALSE));
7095               aopPut (AOP (result), "a", offset);
7096             }
7097           else
7098             aopPut (AOP (result),
7099                     aopGet (AOP (right), offset, FALSE),
7100                     offset);
7101           offset++;
7102         }
7103     }
7104
7105 release:
7106   freeAsmop (right, NULL, ic);
7107   freeAsmop (result, NULL, ic);
7108 }
7109
7110 /*-----------------------------------------------------------------*/
7111 /* genJumpTab - genrates code for jump table                       */
7112 /*-----------------------------------------------------------------*/
7113 static void
7114 genJumpTab (iCode * ic)
7115 {
7116   symbol *jtab;
7117   const char *l;
7118
7119   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7120   /* get the condition into accumulator */
7121   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7122   if (!IS_GB)
7123     emit2 ("push de");
7124   emit2 ("ld e,%s", l);
7125   emit2 ("ld d,!zero");
7126   jtab = newiTempLabel (NULL);
7127   spillCached ();
7128   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7129   emit2 ("add hl,de");
7130   emit2 ("add hl,de");
7131   emit2 ("add hl,de");
7132   freeAsmop (IC_JTCOND (ic), NULL, ic);
7133   if (!IS_GB)
7134     emit2 ("pop de");
7135   emit2 ("jp !*hl");
7136   emitLabel (jtab->key + 100);
7137   /* now generate the jump labels */
7138   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7139        jtab = setNextItem (IC_JTLABELS (ic)))
7140     emit2 ("jp !tlabel", jtab->key + 100);
7141 }
7142
7143 /*-----------------------------------------------------------------*/
7144 /* genCast - gen code for casting                                  */
7145 /*-----------------------------------------------------------------*/
7146 static void
7147 genCast (iCode * ic)
7148 {
7149   operand *result = IC_RESULT (ic);
7150   sym_link *rtype = operandType (IC_RIGHT (ic));
7151   operand *right = IC_RIGHT (ic);
7152   int size, offset;
7153
7154   /* if they are equivalent then do nothing */
7155   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7156     return;
7157
7158   aopOp (right, ic, FALSE, FALSE);
7159   aopOp (result, ic, FALSE, FALSE);
7160
7161   /* if the result is a bit */
7162   if (AOP_TYPE (result) == AOP_CRY)
7163     {
7164       wassertl (0, "Tried to cast to a bit");
7165     }
7166
7167   /* if they are the same size : or less */
7168   if (AOP_SIZE (result) <= AOP_SIZE (right))
7169     {
7170
7171       /* if they are in the same place */
7172       if (sameRegs (AOP (right), AOP (result)))
7173         goto release;
7174
7175       /* if they in different places then copy */
7176       size = AOP_SIZE (result);
7177       offset = 0;
7178       while (size--)
7179         {
7180           aopPut (AOP (result),
7181                   aopGet (AOP (right), offset, FALSE),
7182                   offset);
7183           offset++;
7184         }
7185       goto release;
7186     }
7187
7188   /* So we now know that the size of destination is greater
7189      than the size of the source */
7190   /* we move to result for the size of source */
7191   size = AOP_SIZE (right);
7192   offset = 0;
7193   while (size--)
7194     {
7195       aopPut (AOP (result),
7196               aopGet (AOP (right), offset, FALSE),
7197               offset);
7198       offset++;
7199     }
7200
7201   /* now depending on the sign of the destination */
7202   size = AOP_SIZE (result) - AOP_SIZE (right);
7203   /* Unsigned or not an integral type - right fill with zeros */
7204   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7205     {
7206       while (size--)
7207         aopPut (AOP (result), "!zero", offset++);
7208     }
7209   else
7210     {
7211       /* we need to extend the sign :{ */
7212         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7213                         FALSE);
7214       _moveA (l);
7215       emit2 ("rla ");
7216       emit2 ("sbc a,a");
7217       while (size--)
7218         aopPut (AOP (result), "a", offset++);
7219     }
7220
7221 release:
7222   freeAsmop (right, NULL, ic);
7223   freeAsmop (result, NULL, ic);
7224 }
7225
7226 /*-----------------------------------------------------------------*/
7227 /* genReceive - generate code for a receive iCode                  */
7228 /*-----------------------------------------------------------------*/
7229 static void
7230 genReceive (iCode * ic)
7231 {
7232   if (isOperandInFarSpace (IC_RESULT (ic)) &&
7233       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7234        IS_TRUE_SYMOP (IC_RESULT (ic))))
7235     {
7236       wassert (0);
7237     }
7238   else
7239     {
7240         // PENDING: HACK
7241         int size;
7242         int i;
7243
7244         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7245         size = AOP_SIZE(IC_RESULT(ic));
7246
7247         for (i = 0; i < size; i++) {
7248             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7249         }
7250     }
7251
7252   freeAsmop (IC_RESULT (ic), NULL, ic);
7253 }
7254
7255 /*-----------------------------------------------------------------*/
7256 /* genDummyRead - generate code for dummy read of volatiles        */
7257 /*-----------------------------------------------------------------*/
7258 static void
7259 genDummyRead (iCode * ic)
7260 {
7261   operand *op;
7262   int size, offset;
7263
7264   op = IC_RIGHT (ic);
7265   if (op && IS_SYMOP (op))
7266     {
7267       aopOp (op, ic, FALSE, FALSE);
7268   
7269       /* general case */
7270       size = AOP_SIZE (op);
7271       offset = 0;
7272
7273       while (size--)
7274         {
7275           _moveA (aopGet (AOP (op), offset, FALSE));
7276           offset++;
7277         }
7278
7279       freeAsmop (op, NULL, ic);
7280     }
7281   
7282   op = IC_LEFT (ic);
7283   if (op && IS_SYMOP (op))
7284     {
7285       aopOp (op, ic, FALSE, FALSE);
7286   
7287       /* general case */
7288       size = AOP_SIZE (op);
7289       offset = 0;
7290
7291       while (size--)
7292         {
7293           _moveA (aopGet (AOP (op), offset, FALSE));
7294           offset++;
7295         }
7296
7297       freeAsmop (op, NULL, ic);
7298     }
7299 }
7300
7301 enum
7302   {
7303     /** Maximum number of bytes to emit per line. */
7304     DBEMIT_MAX_RUN = 8
7305   };
7306
7307 /** Context for the byte output chunker. */
7308 typedef struct
7309 {
7310   unsigned char buffer[DBEMIT_MAX_RUN];
7311   int pos;
7312 } DBEMITCTX;
7313
7314
7315 /** Flushes a byte chunker by writing out all in the buffer and
7316     reseting. 
7317 */
7318 static void
7319 _dbFlush(DBEMITCTX *self)
7320 {
7321   char line[256];
7322
7323   if (self->pos > 0)
7324     {
7325       int i;
7326       sprintf(line, ".db 0x%02X", self->buffer[0]);
7327
7328       for (i = 1; i < self->pos; i++)
7329         {
7330           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7331         }
7332       emit2(line);
7333     }
7334   self->pos = 0;
7335 }
7336
7337 /** Write out another byte, buffering until a decent line is
7338     generated.
7339 */
7340 static void
7341 _dbEmit(DBEMITCTX *self, int c)
7342 {
7343   if (self->pos == DBEMIT_MAX_RUN)
7344     {
7345       _dbFlush(self);
7346     }
7347   self->buffer[self->pos++] = c;
7348 }
7349
7350 /** Context for a simple run length encoder. */
7351 typedef struct
7352 {
7353   unsigned last;
7354   unsigned char buffer[128];
7355   int pos;
7356   /** runLen may be equivalent to pos. */
7357   int runLen;
7358 } RLECTX;
7359
7360 enum
7361   {
7362     RLE_CHANGE_COST = 4,
7363     RLE_MAX_BLOCK = 127
7364   };
7365
7366 /** Flush the buffer of a run length encoder by writing out the run or
7367     data that it currently contains.
7368 */
7369 static void
7370 _rleCommit(RLECTX *self)
7371 {
7372   int i;
7373   if (self->pos != 0)
7374     {
7375       DBEMITCTX db;
7376       memset(&db, 0, sizeof(db));
7377           
7378       emit2(".db %u", self->pos);
7379       
7380       for (i = 0; i < self->pos; i++)
7381         {
7382           _dbEmit(&db, self->buffer[i]);
7383         }
7384       _dbFlush(&db);
7385     }
7386   /* Reset */
7387   self->pos = 0;
7388 }
7389
7390 /* Encoder design:
7391    Can get either a run or a block of random stuff.
7392    Only want to change state if a good run comes in or a run ends.
7393    Detecting run end is easy.
7394    Initial state?
7395
7396    Say initial state is in run, len zero, last zero.  Then if you get a
7397    few zeros then something else then a short run will be output.
7398    Seems OK.  While in run mode, keep counting.  While in random mode,
7399    keep a count of the run.  If run hits margin, output all up to run,
7400    restart, enter run mode.
7401 */
7402
7403 /** Add another byte into the run length encoder, flushing as
7404     required.  The run length encoder uses the Amiga IFF style, where
7405     a block is prefixed by its run length.  A positive length means
7406     the next n bytes pass straight through.  A negative length means
7407     that the next byte is repeated -n times.  A zero terminates the
7408     chunks.
7409 */
7410 static void
7411 _rleAppend(RLECTX *self, int c)
7412 {
7413   int i;
7414
7415   if (c != self->last)
7416     {
7417       /* The run has stopped.  See if it is worthwhile writing it out
7418          as a run.  Note that the random data comes in as runs of
7419          length one.
7420       */
7421       if (self->runLen > RLE_CHANGE_COST)
7422         {
7423           /* Yes, worthwhile. */
7424           /* Commit whatever was in the buffer. */
7425           _rleCommit(self);
7426           emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7427         }
7428       else
7429         {
7430           /* Not worthwhile.  Append to the end of the random list. */
7431           for (i = 0; i < self->runLen; i++)
7432             {
7433               if (self->pos >= RLE_MAX_BLOCK)
7434                 {
7435                   /* Commit. */
7436                   _rleCommit(self);
7437                 }
7438               self->buffer[self->pos++] = self->last;
7439             }
7440         }
7441       self->runLen = 1;
7442       self->last = c;
7443     }
7444   else
7445     {
7446       if (self->runLen >= RLE_MAX_BLOCK)
7447         {
7448           /* Commit whatever was in the buffer. */
7449           _rleCommit(self);
7450
7451           emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7452           self->runLen = 0;
7453         }
7454       self->runLen++;
7455     }
7456 }
7457
7458 static void
7459 _rleFlush(RLECTX *self)
7460 {
7461   _rleAppend(self, -1);
7462   _rleCommit(self);
7463   self->pos = 0;
7464   self->last = 0;
7465   self->runLen = 0;
7466 }
7467
7468 /** genArrayInit - Special code for initialising an array with constant
7469    data.
7470 */
7471 static void
7472 genArrayInit (iCode * ic)
7473 {
7474   literalList *iLoop;
7475   int         ix;
7476   int         elementSize = 0, eIndex, i;
7477   unsigned    val, lastVal;
7478   sym_link    *type;
7479   RLECTX      rle;
7480
7481   memset(&rle, 0, sizeof(rle));
7482
7483   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7484
7485   _saveRegsForCall(ic, 0);
7486
7487   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7488   emit2 ("call __initrleblock");
7489     
7490   type = operandType(IC_LEFT(ic));
7491     
7492   if (type && type->next)
7493     {
7494       if (IS_SPEC(type->next) || IS_PTR(type->next))
7495         {
7496           elementSize = getSize(type->next);
7497         }
7498       else if (IS_ARRAY(type->next) && type->next->next)
7499         {
7500           elementSize = getSize(type->next->next);
7501         }
7502       else
7503         {
7504           printTypeChainRaw (type, NULL);
7505           wassertl (0, "Can't determine element size in genArrayInit.");
7506         }
7507     }
7508   else
7509     {
7510       wassertl (0, "Can't determine element size in genArrayInit.");
7511     }
7512
7513   wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7514
7515   iLoop = IC_ARRAYILIST(ic);
7516   lastVal = (unsigned)-1;
7517
7518   /* Feed all the bytes into the run length encoder which will handle
7519      the actual output.
7520      This works well for mixed char data, and for random int and long
7521      data.
7522   */
7523   while (iLoop)
7524     {
7525       ix = iLoop->count;
7526
7527       for (i = 0; i < ix; i++)
7528         {
7529           for (eIndex = 0; eIndex < elementSize; eIndex++)
7530             {
7531               val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7532               _rleAppend(&rle, val);
7533             }
7534         }
7535         
7536       iLoop = iLoop->next;
7537     }
7538
7539   _rleFlush(&rle);
7540   /* Mark the end of the run. */
7541   emit2(".db 0");
7542
7543   _restoreRegsAfterCall();
7544
7545   spillCached ();
7546
7547   freeAsmop (IC_LEFT(ic), NULL, ic);
7548 }
7549
7550 static void
7551 _swap (PAIR_ID one, PAIR_ID two)
7552 {
7553   if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7554     {
7555       emit2 ("ex de,hl");
7556     }
7557   else
7558     {
7559       emit2 ("ld a,%s", _pairs[one].l);
7560       emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7561       emit2 ("ld %s,a", _pairs[two].l);
7562       emit2 ("ld a,%s", _pairs[one].h);
7563       emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7564       emit2 ("ld %s,a", _pairs[two].h);
7565     }
7566 }
7567
7568 /* The problem is that we may have all three pairs used and they may
7569    be needed in a different order.
7570
7571    Note: Have ex de,hl
7572
7573    Combinations:
7574      hl = hl            => unity, fine
7575      bc = bc
7576      de = de
7577
7578      hl = hl            hl = hl, swap de <=> bc
7579      bc = de
7580      de = bc
7581
7582      hl = bc            Worst case
7583      bc = de
7584      de = hl
7585      
7586      hl = bc            de = de, swap bc <=> hl
7587      bc = hl
7588      de = de
7589
7590      hl = de            Worst case
7591      bc = hl
7592      de = bc
7593
7594      hl = de            bc = bc, swap hl <=> de
7595      bc = bc
7596      de = hl
7597
7598    Break it down into:
7599     * Any pair = pair are done last
7600     * Any pair = iTemp are done last
7601     * Any swaps can be done any time
7602
7603    A worst case:
7604     push p1
7605     p1 = p2
7606     p2 = p3
7607     pop  p3
7608
7609    So how do we detect the cases?
7610    How about a 3x3 matrix?
7611         source
7612    dest x x x x
7613         x x x x
7614         x x x x (Fourth for iTemp/other)
7615
7616    First determin which mode to use by counting the number of unity and
7617    iTemp assigns.
7618      Three - any order
7619      Two - Assign the pair first, then the rest
7620      One - Swap the two, then the rest
7621      Zero - Worst case.
7622 */
7623 static void
7624 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7625 {
7626   PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7627   PAIR_ID dest[3] = {
7628     PAIR_BC, PAIR_HL, PAIR_DE
7629   };
7630   int i, j, nunity = 0;
7631   memset (ids, PAIR_INVALID, sizeof (ids));
7632
7633   /* Sanity checks */
7634   wassert (nparams == 3);
7635
7636   /* First save everything that needs to be saved. */
7637   _saveRegsForCall (ic, 0);
7638
7639   /* Loading HL first means that DE is always fine. */
7640   for (i = 0; i < nparams; i++)
7641     {
7642       aopOp (pparams[i], ic, FALSE, FALSE);
7643       ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7644     }
7645
7646   /* Count the number of unity or iTemp assigns. */
7647   for (i = 0; i < 3; i++) 
7648     {
7649       if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7650         {
7651           nunity++;
7652         }
7653     }
7654
7655   if (nunity == 3)
7656     {
7657       /* Any order, fall through. */
7658     }
7659   else if (nunity == 2)
7660     {
7661       /* One is assigned.  Pull it out and assign. */
7662       for (i = 0; i < 3; i++)
7663         {
7664           for (j = 0; j < NUM_PAIRS; j++)
7665             {
7666               if (ids[dest[i]][j] == TRUE)
7667                 {
7668                   /* Found it.  See if it's the right one. */
7669                   if (j == PAIR_INVALID || j == dest[i])
7670                     {
7671                       /* Keep looking. */
7672                     }
7673                   else
7674                     {
7675                       fetchPair(dest[i], AOP (pparams[i]));
7676                       goto done;
7677                     }
7678                 }
7679             }
7680         }
7681     }
7682   else if (nunity == 1)
7683     {
7684       /* Find the pairs to swap. */
7685       for (i = 0; i < 3; i++)
7686         {
7687           for (j = 0; j < NUM_PAIRS; j++)
7688             {
7689               if (ids[dest[i]][j] == TRUE)
7690                 {
7691                   if (j == PAIR_INVALID || j == dest[i])
7692                     {
7693                       /* Keep looking. */
7694                     }
7695                   else
7696                     {
7697                       _swap (j, dest[i]);
7698                       goto done;
7699                     }
7700                 }
7701             }
7702         }
7703     }
7704   else
7705     {
7706       int next = getPairId (AOP (pparams[0]));
7707       emit2 ("push %s", _pairs[next].name);
7708
7709       if (next == dest[1])
7710         {
7711           fetchPair (dest[1], AOP (pparams[1]));
7712           fetchPair (dest[2], AOP (pparams[2]));
7713         }
7714       else
7715         {
7716           fetchPair (dest[2], AOP (pparams[2]));
7717           fetchPair (dest[1], AOP (pparams[1]));
7718         }
7719       emit2 ("pop %s", _pairs[dest[0]].name);
7720     }
7721  done:
7722   /* Finally pull out all of the iTemps */
7723   for (i = 0; i < 3; i++)
7724     {
7725       if (ids[dest[i]][PAIR_INVALID] == 1)
7726         {
7727           fetchPair (dest[i], AOP (pparams[i]));
7728         }
7729     }
7730 }
7731
7732 static void
7733 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7734 {
7735   operand *from, *to;
7736   symbol *label;
7737   bool deInUse;
7738
7739   wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7740   to = pparams[0];
7741   from = pparams[1];
7742
7743   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7744
7745   setupForBuiltin3 (ic, nParams, pparams);
7746
7747   label = newiTempLabel(NULL);
7748
7749   emitLabel (label->key);
7750   emit2 ("ld a,(hl)");
7751   emit2 ("ldi");
7752   emit2 ("or a");
7753   emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7754
7755   freeAsmop (from, NULL, ic->next);
7756   freeAsmop (to, NULL, ic);
7757 }
7758
7759 static void
7760 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7761 {
7762   operand *from, *to, *count;
7763   bool deInUse;
7764
7765   wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7766   to = pparams[2];
7767   from = pparams[1];
7768   count = pparams[0];
7769
7770   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7771
7772   setupForBuiltin3 (ic, nParams, pparams);
7773
7774   emit2 ("ldir");
7775
7776   freeAsmop (count, NULL, ic->next->next);
7777   freeAsmop (from, NULL, ic);
7778
7779   _restoreRegsAfterCall();
7780
7781   /* if we need assign a result value */
7782   if ((IS_ITEMP (IC_RESULT (ic)) &&
7783        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7784         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7785       IS_TRUE_SYMOP (IC_RESULT (ic)))
7786     {
7787       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7788       movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7789       freeAsmop (IC_RESULT (ic), NULL, ic);
7790     }
7791
7792   freeAsmop (to, NULL, ic->next);
7793 }
7794
7795 /*-----------------------------------------------------------------*/
7796 /* genBuiltIn - calls the appropriate function to  generating code */
7797 /* for a built in function                                         */
7798 /*-----------------------------------------------------------------*/
7799 static void genBuiltIn (iCode *ic)
7800 {
7801     operand *bi_parms[MAX_BUILTIN_ARGS];
7802     int nbi_parms;
7803     iCode *bi_iCode;
7804     symbol *bif;
7805
7806     /* get all the arguments for a built in function */
7807     bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7808
7809     /* which function is it */
7810     bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7811
7812     if (strcmp(bif->name,"__builtin_strcpy")==0) 
7813       {
7814         genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7815       } 
7816     else if (strcmp(bif->name,"__builtin_memcpy")==0) 
7817       {
7818         genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7819       } 
7820     else 
7821       {
7822         wassertl (0, "Unknown builtin function encountered");
7823       }
7824 }
7825
7826 /*-----------------------------------------------------------------*/
7827 /* genZ80Code - generate code for Z80 based controllers            */
7828 /*-----------------------------------------------------------------*/
7829 void
7830 genZ80Code (iCode * lic)
7831 {
7832   iCode *ic;
7833   int cln = 0;
7834
7835   /* Hack */
7836   if (IS_GB)
7837     {
7838       _fReturn = _gbz80_return;
7839       _fTmp = _gbz80_return;
7840     }
7841   else
7842     {
7843       _fReturn = _z80_return;
7844       _fTmp = _z80_return;
7845     }
7846
7847   _G.lines.head = _G.lines.current = NULL;
7848   
7849   /* if debug information required */
7850   if (options.debug && currFunc)
7851     {
7852       debugFile->writeFunction (currFunc, lic);
7853     }
7854
7855   for (ic = lic; ic; ic = ic->next)
7856     {
7857       _G.current_iCode = ic;
7858
7859       if (ic->lineno && cln != ic->lineno)
7860         {
7861           if (options.debug)
7862             {
7863               debugFile->writeCLine (ic);
7864             }
7865           if (!options.noCcodeInAsm) {
7866             emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7867                    printCLine(ic->filename, ic->lineno));
7868           }
7869           cln = ic->lineno;
7870         }
7871       if (options.iCodeInAsm) {
7872         emit2 (";ic:%d: %s", ic->key, printILine(ic));
7873       }
7874       /* if the result is marked as
7875          spilt and rematerializable or code for
7876          this has already been generated then
7877          do nothing */
7878       if (resultRemat (ic) || ic->generated)
7879         continue;
7880
7881       /* depending on the operation */
7882       switch (ic->op)
7883         {
7884         case '!':
7885           emitDebug ("; genNot");
7886           genNot (ic);
7887           break;
7888
7889         case '~':
7890           emitDebug ("; genCpl");
7891           genCpl (ic);
7892           break;
7893
7894         case UNARYMINUS:
7895           emitDebug ("; genUminus");
7896           genUminus (ic);
7897           break;
7898
7899         case IPUSH:
7900           emitDebug ("; genIpush");
7901           genIpush (ic);
7902           break;
7903
7904         case IPOP:
7905           /* IPOP happens only when trying to restore a
7906              spilt live range, if there is an ifx statement
7907              following this pop then the if statement might
7908              be using some of the registers being popped which
7909              would destory the contents of the register so
7910              we need to check for this condition and handle it */
7911           if (ic->next &&
7912               ic->next->op == IFX &&
7913               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7914             {
7915               emitDebug ("; genIfx");
7916               genIfx (ic->next, ic);
7917             }
7918           else
7919             {
7920               emitDebug ("; genIpop");
7921               genIpop (ic);
7922             }
7923           break;
7924
7925         case CALL:
7926           emitDebug ("; genCall");
7927           genCall (ic);
7928           break;
7929
7930         case PCALL:
7931           emitDebug ("; genPcall");
7932           genPcall (ic);
7933           break;
7934
7935         case FUNCTION:
7936           emitDebug ("; genFunction");
7937           genFunction (ic);
7938           break;
7939
7940         case ENDFUNCTION:
7941           emitDebug ("; genEndFunction");
7942           genEndFunction (ic);
7943           break;
7944
7945         case RETURN:
7946           emitDebug ("; genRet");
7947           genRet (ic);
7948           break;
7949
7950         case LABEL:
7951           emitDebug ("; genLabel");
7952           genLabel (ic);
7953           break;
7954
7955         case GOTO:
7956           emitDebug ("; genGoto");
7957           genGoto (ic);
7958           break;
7959
7960         case '+':
7961           emitDebug ("; genPlus");
7962           genPlus (ic);
7963           break;
7964
7965         case '-':
7966           emitDebug ("; genMinus");
7967           genMinus (ic);
7968           break;
7969
7970         case '*':
7971           emitDebug ("; genMult");
7972           genMult (ic);
7973           break;
7974
7975         case '/':
7976           emitDebug ("; genDiv");
7977           genDiv (ic);
7978           break;
7979
7980         case '%':
7981           emitDebug ("; genMod");
7982           genMod (ic);
7983           break;
7984
7985         case '>':
7986           emitDebug ("; genCmpGt");
7987           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7988           break;
7989
7990         case '<':
7991           emitDebug ("; genCmpLt");
7992           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7993           break;
7994
7995         case LE_OP:
7996         case GE_OP:
7997         case NE_OP:
7998
7999           /* note these two are xlated by algebraic equivalence
8000              during parsing SDCC.y */
8001           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8002                   "got '>=' or '<=' shouldn't have come here");
8003           break;
8004
8005         case EQ_OP:
8006           emitDebug ("; genCmpEq");
8007           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8008           break;
8009
8010         case AND_OP:
8011           emitDebug ("; genAndOp");
8012           genAndOp (ic);
8013           break;
8014
8015         case OR_OP:
8016           emitDebug ("; genOrOp");
8017           genOrOp (ic);
8018           break;
8019
8020         case '^':
8021           emitDebug ("; genXor");
8022           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8023           break;
8024
8025         case '|':
8026           emitDebug ("; genOr");
8027           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8028           break;
8029
8030         case BITWISEAND:
8031           emitDebug ("; genAnd");
8032           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8033           break;
8034
8035         case INLINEASM:
8036           emitDebug ("; genInline");
8037           genInline (ic);
8038           break;
8039
8040         case RRC:
8041           emitDebug ("; genRRC");
8042           genRRC (ic);
8043           break;
8044
8045         case RLC:
8046           emitDebug ("; genRLC");
8047           genRLC (ic);
8048           break;
8049
8050         case GETHBIT:
8051           emitDebug ("; genGetHBIT");
8052           genGetHbit (ic);
8053           break;
8054
8055         case LEFT_OP:
8056           emitDebug ("; genLeftShift");
8057           genLeftShift (ic);
8058           break;
8059
8060         case RIGHT_OP:
8061           emitDebug ("; genRightShift");
8062           genRightShift (ic);
8063           break;
8064
8065         case GET_VALUE_AT_ADDRESS:
8066           emitDebug ("; genPointerGet");
8067           genPointerGet (ic);
8068           break;
8069
8070         case '=':
8071
8072           if (POINTER_SET (ic))
8073             {
8074               emitDebug ("; genAssign (pointer)");
8075               genPointerSet (ic);
8076             }
8077           else
8078             {
8079               emitDebug ("; genAssign");
8080               genAssign (ic);
8081             }
8082           break;
8083
8084         case IFX:
8085           emitDebug ("; genIfx");
8086           genIfx (ic, NULL);
8087           break;
8088
8089         case ADDRESS_OF:
8090           emitDebug ("; genAddrOf");
8091           genAddrOf (ic);
8092           break;
8093
8094         case JUMPTABLE:
8095           emitDebug ("; genJumpTab");
8096           genJumpTab (ic);
8097           break;
8098
8099         case CAST:
8100           emitDebug ("; genCast");
8101           genCast (ic);
8102           break;
8103
8104         case RECEIVE:
8105           emitDebug ("; genReceive");
8106           genReceive (ic);
8107           break;
8108
8109         case SEND:
8110           if (ic->builtinSEND)
8111             {
8112               emitDebug ("; genBuiltIn");
8113               genBuiltIn(ic);
8114             }
8115           else
8116             {
8117               emitDebug ("; addSet");
8118               addSet (&_G.sendSet, ic);
8119             }
8120           break;
8121
8122         case ARRAYINIT:
8123           emitDebug ("; genArrayInit");
8124           genArrayInit(ic);
8125           break;
8126
8127         case DUMMY_READ_VOLATILE:
8128           emitDebug ("; genDummyRead");
8129           genDummyRead (ic);
8130           break;
8131
8132         default:
8133           ic = ic;
8134         }
8135     }
8136
8137
8138   /* now we are ready to call the
8139      peep hole optimizer */
8140   if (!options.nopeep)
8141     peepHole (&_G.lines.head);
8142
8143   /* This is unfortunate */
8144   /* now do the actual printing */
8145   {
8146     FILE *fp = codeOutFile;
8147     if (isInHome () && codeOutFile == code->oFile)
8148       codeOutFile = home->oFile;
8149     printLine (_G.lines.head, codeOutFile);
8150     if (_G.flushStatics)
8151       {
8152         flushStatics ();
8153         _G.flushStatics = 0;
8154       }
8155     codeOutFile = fp;
8156   }
8157
8158   freeTrace(&_G.lines.trace);
8159   freeTrace(&_G.trace.aops);
8160 }
8161
8162 /*
8163   Attic
8164 static int
8165 _isPairUsed (iCode * ic, PAIR_ID pairId)
8166 {
8167   int ret = 0;
8168   switch (pairId)
8169     {
8170     case PAIR_DE:
8171       if (bitVectBitValue (ic->rMask, D_IDX))
8172         ret++;
8173       if (bitVectBitValue (ic->rMask, E_IDX))
8174         ret++;
8175       break;
8176     default:
8177       wassert (0);
8178     }
8179   return ret;
8180 }
8181
8182 static char *
8183 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8184 {
8185   unsigned long v;
8186   value *val = aop->aopu.aop_lit;
8187
8188   wassert (aop->type == AOP_LIT);
8189   wassert (!IS_FLOAT (val->type));
8190
8191   v = (unsigned long) floatFromVal (val);
8192
8193   if (xor)
8194     v ^= 0x8000;
8195   if (negate)
8196     v = 0-v;
8197   v &= 0xFFFF;
8198
8199   tsprintf (buffer, sizeof(buffer), "!immedword", v);
8200   return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
8201 }
8202
8203
8204 */