* src/z80/gen.c (genFunction, genEndFunction): avoided generating
[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 bit 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   if (!IS_STATIC(sym->etype))
3106     {
3107       sprintf (buffer, "%s_start", sym->rname);
3108       emit2 ("!labeldef", buffer);
3109     }
3110   emit2 ("!functionlabeldef", sym->rname);
3111
3112   if (options.profile) 
3113     {
3114       emit2 ("!profileenter");
3115     }
3116
3117   ftype = operandType (IC_LEFT (ic));
3118
3119   /* if this is an interrupt service routine then save all potentially used registers. */
3120   if (IFFUNC_ISISR (sym->type))
3121     {
3122       if (!FUNC_ISNAKED( sym->type ))
3123         {
3124           emit2 ("!pusha");
3125         }
3126     }
3127   else
3128     {
3129       /* if critical function then turn interrupts off */
3130       if (IFFUNC_ISCRITICAL (sym->type))
3131         {
3132           emit2 ("!di");
3133         }
3134     }
3135
3136   /* PENDING: callee-save etc */
3137
3138   _G.stack.param_offset = 0;
3139
3140   if (z80_opts.calleeSavesBC)
3141     {
3142       bcInUse = TRUE;
3143     }
3144
3145   /* Detect which registers are used. */
3146   if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3147     {
3148       int i;
3149       for (i = 0; i < sym->regsUsed->size; i++)
3150         {
3151           if (bitVectBitValue (sym->regsUsed, i))
3152             {
3153               switch (i)
3154                 {
3155                 case C_IDX:
3156                 case B_IDX:
3157                   bcInUse = TRUE;
3158                   break;
3159                 case D_IDX:
3160                 case E_IDX:
3161                   if (IS_Z80) {
3162                     deInUse = TRUE;
3163                   }
3164                   else {
3165                     /* Other systems use DE as a temporary. */
3166                   }
3167                   break;
3168                 }
3169             }
3170         }
3171     }
3172
3173   if (bcInUse) 
3174     {
3175       emit2 ("push bc");
3176       _G.stack.param_offset += 2;
3177     }
3178
3179   _G.calleeSaves.pushedBC = bcInUse;
3180
3181   if (deInUse)
3182     {
3183       emit2 ("push de");
3184       _G.stack.param_offset += 2;
3185     }
3186
3187   _G.calleeSaves.pushedDE = deInUse;
3188
3189   /* adjust the stack for the function */
3190   _G.stack.last = sym->stack;
3191   
3192   stackParm = FALSE;
3193   for (sym = setFirstItem (istack->syms); sym;
3194        sym = setNextItem (istack->syms))
3195     {
3196       if (sym->_isparm && !IS_REGPARM (sym->etype))
3197         {
3198           stackParm = TRUE;
3199           break;
3200         }
3201     }
3202   sym = OP_SYMBOL (IC_LEFT (ic));
3203   
3204   _G.omitFramePtr = options.ommitFramePtr;
3205   if (IS_Z80 && !stackParm && !sym->stack)
3206     {
3207       /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3208       /* the above !sym->stack condition can be removed. -- EEP       */
3209       if (sym->stack)
3210         emit2 ("!ldaspsp", -sym->stack);
3211       _G.omitFramePtr = TRUE;
3212     }
3213   else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3214     emit2 ("!enterxl", sym->stack);
3215   else if (sym->stack)
3216     emit2 ("!enterx", sym->stack);
3217   else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3218     emit2 ("!enter");
3219
3220   _G.stack.offset = sym->stack;
3221 }
3222
3223 /*-----------------------------------------------------------------*/
3224 /* genEndFunction - generates epilogue for functions               */
3225 /*-----------------------------------------------------------------*/
3226 static void
3227 genEndFunction (iCode * ic)
3228 {
3229   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3230
3231
3232   /* PENDING: calleeSave */
3233   if (IS_Z80 && _G.omitFramePtr)
3234     {
3235       if (_G.stack.offset)
3236         emit2 ("!ldaspsp", _G.stack.offset);
3237     }
3238   else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3239     {
3240       emit2 ("!leavexl", _G.stack.offset);
3241     }
3242   else if (_G.stack.offset)
3243     {
3244       emit2 ("!leavex", _G.stack.offset);
3245     }
3246   else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3247     {
3248       emit2 ("!leave");
3249     }
3250       
3251   if (_G.calleeSaves.pushedDE) 
3252     {
3253       emit2 ("pop de");
3254       _G.calleeSaves.pushedDE = FALSE;
3255     }
3256
3257   if (_G.calleeSaves.pushedBC) 
3258     {
3259       emit2 ("pop bc");
3260       _G.calleeSaves.pushedBC = FALSE;
3261     }
3262
3263   if (options.profile) 
3264     {
3265       emit2 ("!profileexit");
3266     }
3267
3268   /* if this is an interrupt service routine then restore all potentially used registers. */
3269   if (IFFUNC_ISISR (sym->type))
3270     {
3271       if (!FUNC_ISNAKED( sym->type ))
3272         {
3273           emit2 ("!popa");
3274         }
3275     }
3276   else
3277     {
3278       /* if critical function then turn interrupts back on */
3279       if (IFFUNC_ISCRITICAL (sym->type))
3280         emit2 ("!ei");
3281     }
3282
3283   if (options.debug && currFunc)
3284     {
3285       debugFile->writeEndFunction (currFunc, ic, 1);
3286     }
3287       
3288   if (IFFUNC_ISISR (sym->type))
3289     {
3290       /* "critical interrupt" is used to imply NMI handler */
3291       if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type))
3292         emit2 ("retn");
3293       else
3294         emit2 ("reti");
3295     }
3296   else
3297     {
3298       /* Both banked and non-banked just ret */
3299       emit2 ("ret");
3300     }
3301       
3302   if (!IS_STATIC(sym->etype))
3303     {
3304       sprintf (buffer, "%s_end", sym->rname);
3305       emit2 ("!labeldef", buffer);
3306     }
3307   
3308   _G.flushStatics = 1;
3309   _G.stack.pushed = 0;
3310   _G.stack.offset = 0;
3311 }
3312
3313 /*-----------------------------------------------------------------*/
3314 /* genRet - generate code for return statement                     */
3315 /*-----------------------------------------------------------------*/
3316 static void
3317 genRet (iCode * ic)
3318 {
3319     const char *l;
3320   /* Errk.  This is a hack until I can figure out how
3321      to cause dehl to spill on a call */
3322   int size, offset = 0;
3323
3324   /* if we have no return value then
3325      just generate the "ret" */
3326   if (!IC_LEFT (ic))
3327     goto jumpret;
3328
3329   /* we have something to return then
3330      move the return value into place */
3331   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3332   size = AOP_SIZE (IC_LEFT (ic));
3333
3334   aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3335
3336   #if 0  
3337   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3338     {
3339       if (IS_GB)
3340         {
3341           emit2 ("ld de,%s", l);
3342         }
3343       else
3344         {
3345           emit2 ("ld hl,%s", l);
3346         }
3347     }
3348   #endif
3349   if (size==2)
3350     {
3351       fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3352     }
3353   else
3354     {
3355       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3356         {
3357           fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3358           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3359         }
3360       else
3361         {
3362           while (size--)
3363             {
3364               l = aopGet (AOP (IC_LEFT (ic)), offset,
3365                           FALSE);
3366               if (strcmp (_fReturn[offset], l))
3367                 emit2 ("ld %s,%s", _fReturn[offset], l);
3368               offset++;
3369             }
3370         }
3371     }
3372   freeAsmop (IC_LEFT (ic), NULL, ic);
3373
3374 jumpret:
3375   /* generate a jump to the return label
3376      if the next is not the return statement */
3377   if (!(ic->next && ic->next->op == LABEL &&
3378         IC_LABEL (ic->next) == returnLabel))
3379
3380     emit2 ("jp !tlabel", returnLabel->key + 100);
3381 }
3382
3383 /*-----------------------------------------------------------------*/
3384 /* genLabel - generates a label                                    */
3385 /*-----------------------------------------------------------------*/
3386 static void
3387 genLabel (iCode * ic)
3388 {
3389   /* special case never generate */
3390   if (IC_LABEL (ic) == entryLabel)
3391     return;
3392
3393   emitLabel (IC_LABEL (ic)->key + 100);
3394 }
3395
3396 /*-----------------------------------------------------------------*/
3397 /* genGoto - generates a ljmp                                      */
3398 /*-----------------------------------------------------------------*/
3399 static void
3400 genGoto (iCode * ic)
3401 {
3402   emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3403 }
3404
3405 /*-----------------------------------------------------------------*/
3406 /* genPlusIncr :- does addition with increment if possible         */
3407 /*-----------------------------------------------------------------*/
3408 static bool
3409 genPlusIncr (iCode * ic)
3410 {
3411   unsigned int icount;
3412   unsigned int size = getDataSize (IC_RESULT (ic));
3413   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3414
3415   /* will try to generate an increment */
3416   /* if the right side is not a literal
3417      we cannot */
3418   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3419     return FALSE;
3420
3421   emitDebug ("; genPlusIncr");
3422
3423   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3424
3425   /* If result is a pair */
3426   if (resultId != PAIR_INVALID)
3427     {
3428       if (isLitWord (AOP (IC_LEFT (ic))))
3429         {
3430           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3431           return TRUE;
3432         }
3433       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3434         {
3435           if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3436             {
3437               PAIR_ID freep = getFreePairId (ic);
3438               if (freep != PAIR_INVALID)
3439                 {
3440                   fetchPair (freep, AOP (IC_RIGHT (ic)));
3441                   emit2 ("add hl,%s", _pairs[freep].name);
3442                   return TRUE;
3443                 }
3444             }
3445           else
3446             {
3447               fetchPair (resultId, AOP (IC_RIGHT (ic)));
3448               emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3449               return TRUE;
3450             }
3451         }
3452       if (icount > 5)
3453         return FALSE;
3454       /* Inc a pair */
3455       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3456         {
3457           if (icount > 2)
3458             return FALSE;
3459           movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3460         }
3461       while (icount--)
3462         {
3463           emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3464         }
3465       return TRUE;
3466     }
3467
3468   if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3469     {
3470       fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3471       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3472       return TRUE;
3473     }
3474
3475   /* if the literal value of the right hand side
3476      is greater than 4 then it is not worth it */
3477   if (icount > 4)
3478     return FALSE;
3479
3480   /* if increment 16 bits in register */
3481   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3482       size > 1 &&
3483       icount == 1
3484     )
3485     {
3486       int offset = 0;
3487       symbol *tlbl = NULL;
3488       tlbl = newiTempLabel (NULL);
3489       while (size--)
3490         {
3491           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3492           if (size)
3493             {
3494               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3495             }
3496         }
3497       emitLabel (tlbl->key + 100);
3498       return TRUE;
3499     }
3500
3501   /* if the sizes are greater than 1 then we cannot */
3502   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3503       AOP_SIZE (IC_LEFT (ic)) > 1)
3504     return FALSE;
3505
3506   /* If the result is in a register then we can load then increment.
3507    */
3508   if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3509     {
3510       aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3511       while (icount--)
3512         {
3513           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3514         }
3515       return TRUE;
3516     }
3517
3518   /* we can if the aops of the left & result match or
3519      if they are in registers and the registers are the
3520      same */
3521   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3522     {
3523       while (icount--)
3524         {
3525           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3526         }
3527       return TRUE;
3528     }
3529
3530   return FALSE;
3531 }
3532
3533 /*-----------------------------------------------------------------*/
3534 /* outBitAcc - output a bit in acc                                 */
3535 /*-----------------------------------------------------------------*/
3536 void
3537 outBitAcc (operand * result)
3538 {
3539   symbol *tlbl = newiTempLabel (NULL);
3540   /* if the result is a bit */
3541   if (AOP_TYPE (result) == AOP_CRY)
3542     {
3543       wassertl (0, "Tried to write A into a bit");
3544     }
3545   else
3546     {
3547       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3548       emit2 ("ld a,!one");
3549       emitLabel (tlbl->key + 100);
3550       outAcc (result);
3551     }
3552 }
3553
3554 bool
3555 couldDestroyCarry (asmop *aop)
3556 {
3557   if (aop)
3558     {
3559       if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3560         {
3561           return TRUE;
3562         }
3563     }
3564   return FALSE;
3565 }
3566
3567 static void
3568 shiftIntoPair (int idx, asmop *aop)
3569 {
3570   PAIR_ID id = PAIR_INVALID;
3571
3572   wassertl (IS_Z80, "Only implemented for the Z80");
3573   //  wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3574
3575   switch (idx) 
3576     {
3577     case 0:
3578       id = PAIR_HL;
3579       break;
3580     case 1:
3581       id = PAIR_DE;
3582       _push (PAIR_DE);
3583       break;
3584     default:
3585       wassertl (0, "Internal error - hit default case");
3586     }
3587
3588   emitDebug ("; Shift into pair idx %u", idx);
3589
3590   if (id == PAIR_HL)
3591     {
3592       setupPair (PAIR_HL, aop, 0);
3593     }
3594   else
3595     {
3596       setupPair (PAIR_IY, aop, 0);
3597       emit2 ("push iy");
3598       emit2 ("pop %s", _pairs[id].name);
3599     }
3600
3601   aop->type = AOP_PAIRPTR;
3602   aop->aopu.aop_pairId = id;
3603   _G.pairs[id].offset = 0;
3604   _G.pairs[id].last_type = aop->type;
3605 }
3606
3607 static void 
3608 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3609 {
3610   wassert (left && right);
3611
3612   if (IS_Z80)
3613     {
3614       if (couldDestroyCarry (right) && couldDestroyCarry (result))
3615         {
3616           shiftIntoPair (0, right);
3617           /* check result again, in case right == result */
3618           if (couldDestroyCarry (result))
3619             shiftIntoPair (1, result);
3620         }
3621       else if (couldDestroyCarry (right))
3622         {
3623           if (getPairId (result) == PAIR_HL)
3624             _G.preserveCarry = TRUE;
3625           else
3626             shiftIntoPair (0, right);
3627         }
3628       else if (couldDestroyCarry (result))
3629         {
3630           shiftIntoPair (0, result);
3631         }
3632       else
3633         {
3634           /* Fine */
3635         }
3636     }
3637 }
3638
3639 /*-----------------------------------------------------------------*/
3640 /* genPlus - generates code for addition                           */
3641 /*-----------------------------------------------------------------*/
3642 static void
3643 genPlus (iCode * ic)
3644 {
3645   int size, offset = 0;
3646
3647   /* special cases :- */
3648
3649   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3650   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3651   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3652
3653   /* Swap the left and right operands if:
3654
3655      if literal, literal on the right or
3656      if left requires ACC or right is already
3657      in ACC */
3658
3659   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3660       (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3661       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3662     {
3663       operand *t = IC_RIGHT (ic);
3664       IC_RIGHT (ic) = IC_LEFT (ic);
3665       IC_LEFT (ic) = t;
3666     }
3667
3668   /* if both left & right are in bit
3669      space */
3670   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3671       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3672     {
3673       /* Cant happen */
3674       wassertl (0, "Tried to add two bits");
3675     }
3676
3677   /* if left in bit space & right literal */
3678   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3679       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3680     {
3681       /* Can happen I guess */
3682       wassertl (0, "Tried to add a bit to a literal");
3683     }
3684
3685   /* if I can do an increment instead
3686      of add then GOOD for ME */
3687   if (genPlusIncr (ic) == TRUE)
3688     goto release;
3689
3690   emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3691
3692   size = getDataSize (IC_RESULT (ic));
3693
3694   /* Special case when left and right are constant */
3695   if (isPair (AOP (IC_RESULT (ic))))
3696     {
3697       char *left, *right;
3698       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3699       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3700
3701       if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3702           left && right)
3703         {
3704           /* It's a pair */
3705           /* PENDING: fix */
3706           char buffer[100];
3707           sprintf (buffer, "#(%s + %s)", left, right);
3708           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3709           goto release;
3710         }
3711     }
3712
3713   if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3714     {
3715       /* Fetch into HL then do the add */
3716       PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3717       PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3718
3719       spillPair (PAIR_HL);
3720       
3721       if (left == PAIR_HL && right != PAIR_INVALID)
3722         {
3723           emit2 ("add hl,%s", _pairs[right].name);
3724           goto release;
3725         }
3726       else if (right == PAIR_HL && left != PAIR_INVALID)
3727         {
3728           emit2 ("add hl,%s", _pairs[left].name);
3729           goto release;
3730         }
3731       else if (right != PAIR_INVALID && right != PAIR_HL)
3732         {
3733           fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3734           emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3735           goto release;
3736         }
3737       else if (left != PAIR_INVALID && left != PAIR_HL)
3738         { 
3739           fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3740           emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3741           goto release;
3742         }
3743       else
3744         {
3745           /* Can't do it */
3746         }
3747     }
3748
3749   if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3750     {
3751       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3752       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3753       spillCached();
3754       commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3755       goto release;
3756     }
3757
3758   /* Special case:
3759      ld hl,sp+n trashes C so we cant afford to do it during an
3760      add with stack based varibles.  Worst case is:
3761      ld  hl,sp+left
3762      ld  a,(hl)
3763      ld  hl,sp+right
3764      add (hl)
3765      ld  hl,sp+result
3766      ld  (hl),a
3767      ld  hl,sp+left+1
3768      ld  a,(hl)
3769      ld  hl,sp+right+1
3770      adc (hl)
3771      ld  hl,sp+result+1
3772      ld  (hl),a
3773      So you cant afford to load up hl if either left, right, or result
3774      is on the stack (*sigh*)  The alt is:
3775      ld  hl,sp+left
3776      ld  de,(hl)
3777      ld  hl,sp+right
3778      ld  hl,(hl)
3779      add hl,de
3780      ld  hl,sp+result
3781      ld  (hl),hl
3782      Combinations in here are:
3783      * If left or right are in bc then the loss is small - trap later
3784      * If the result is in bc then the loss is also small
3785    */
3786   if (IS_GB)
3787     {
3788       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3789           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3790           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3791         {
3792           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3793                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3794               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3795                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3796             {
3797               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3798                 {
3799                   /* Swap left and right */
3800                   operand *t = IC_RIGHT (ic);
3801                   IC_RIGHT (ic) = IC_LEFT (ic);
3802                   IC_LEFT (ic) = t;
3803                 }
3804               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3805                 {
3806                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3807                   emit2 ("add hl,bc");
3808                 }
3809               else
3810                 {
3811                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3812                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3813                   emit2 ("add hl,de");
3814                 }
3815               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3816               goto release;
3817             }
3818         }
3819       if (size == 4)
3820         {
3821           /* Be paranoid on the GB with 4 byte variables due to how C
3822              can be trashed by lda hl,n(sp).
3823           */
3824           _gbz80_emitAddSubLong (ic, TRUE);
3825           goto release;
3826         }
3827     }
3828   
3829   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3830
3831   while (size--)
3832     {
3833       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3834         {
3835           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3836           if (offset == 0)
3837             emit2 ("add a,%s",
3838                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3839           else
3840             emit2 ("adc a,%s",
3841                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3842         }
3843       else
3844         {
3845           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3846           if (offset == 0)
3847             emit2 ("add a,%s",
3848                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3849           else
3850             emit2 ("adc a,%s",
3851                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3852         }
3853       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3854     }
3855
3856 release:
3857   _G.preserveCarry = FALSE;
3858   freeAsmop (IC_LEFT (ic), NULL, ic);
3859   freeAsmop (IC_RIGHT (ic), NULL, ic);
3860   freeAsmop (IC_RESULT (ic), NULL, ic);
3861
3862 }
3863
3864 /*-----------------------------------------------------------------*/
3865 /* genMinusDec :- does subtraction with deccrement if possible     */
3866 /*-----------------------------------------------------------------*/
3867 static bool
3868 genMinusDec (iCode * ic)
3869 {
3870   unsigned int icount;
3871   unsigned int size = getDataSize (IC_RESULT (ic));
3872
3873   /* will try to generate an increment */
3874   /* if the right side is not a literal we cannot */
3875   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3876     return FALSE;
3877
3878   /* if the literal value of the right hand side
3879      is greater than 4 then it is not worth it */
3880   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3881     return FALSE;
3882
3883   size = getDataSize (IC_RESULT (ic));
3884
3885   /* if decrement 16 bits in register */
3886   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3887       (size > 1) && isPair (AOP (IC_RESULT (ic))))
3888     {
3889       while (icount--)
3890         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3891       return TRUE;
3892     }
3893
3894   /* If result is a pair */
3895   if (isPair (AOP (IC_RESULT (ic))))
3896     {
3897       movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3898       while (icount--)
3899         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3900       return TRUE;
3901     }
3902
3903   /* if increment 16 bits in register */
3904   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3905       (size == 2)
3906       )
3907     {
3908       fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3909
3910       while (icount--) {
3911         emit2 ("dec %s", _getTempPairName());
3912       }
3913
3914       commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3915
3916       return TRUE;
3917     }
3918
3919
3920   /* if the sizes are greater than 1 then we cannot */
3921   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3922       AOP_SIZE (IC_LEFT (ic)) > 1)
3923     return FALSE;
3924
3925   /* we can if the aops of the left & result match or if they are in
3926      registers and the registers are the same */
3927   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3928     {
3929       while (icount--)
3930         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3931       return TRUE;
3932     }
3933
3934   return FALSE;
3935 }
3936
3937 /*-----------------------------------------------------------------*/
3938 /* genMinus - generates code for subtraction                       */
3939 /*-----------------------------------------------------------------*/
3940 static void
3941 genMinus (iCode * ic)
3942 {
3943   int size, offset = 0;
3944   unsigned long lit = 0L;
3945
3946   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3947   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3948   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3949
3950   /* special cases :- */
3951   /* if both left & right are in bit space */
3952   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3953       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3954     {
3955       wassertl (0, "Tried to subtract two bits");
3956       goto release;
3957     }
3958
3959   /* if I can do an decrement instead of subtract then GOOD for ME */
3960   if (genMinusDec (ic) == TRUE)
3961     goto release;
3962
3963   size = getDataSize (IC_RESULT (ic));
3964
3965   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3966     {
3967     }
3968   else
3969     {
3970       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3971       lit = -(long) lit;
3972     }
3973
3974   /* Same logic as genPlus */
3975   if (IS_GB)
3976     {
3977       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3978           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3979           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3980         {
3981           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3982                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3983               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3984                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3985             {
3986               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3987               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3988
3989               if (left == PAIR_INVALID && right == PAIR_INVALID)
3990                 {
3991                   left = PAIR_DE;
3992                   right = PAIR_HL;
3993                 }
3994               else if (right == PAIR_INVALID)
3995                 right = PAIR_DE;
3996               else if (left == PAIR_INVALID)
3997                 left = PAIR_DE;
3998
3999               fetchPair (left, AOP (IC_LEFT (ic)));
4000               /* Order is important.  Right may be HL */
4001               fetchPair (right, AOP (IC_RIGHT (ic)));
4002
4003               emit2 ("ld a,%s", _pairs[left].l);
4004               emit2 ("sub a,%s", _pairs[right].l);
4005               emit2 ("ld e,a");
4006               emit2 ("ld a,%s", _pairs[left].h);
4007               emit2 ("sbc a,%s", _pairs[right].h);
4008
4009               if ( AOP_SIZE (IC_RESULT (ic)) > 1)
4010                 {
4011                   aopPut (AOP (IC_RESULT (ic)), "a", 1);
4012                 }
4013               aopPut (AOP (IC_RESULT (ic)), "e", 0);
4014               goto release;
4015             }
4016         }
4017       if (size == 4)
4018         {
4019           /* Be paranoid on the GB with 4 byte variables due to how C
4020              can be trashed by lda hl,n(sp).
4021           */
4022           _gbz80_emitAddSubLong (ic, FALSE);
4023           goto release;
4024         }
4025     }
4026
4027   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
4028
4029   /* if literal, add a,#-lit, else normal subb */
4030   while (size--)
4031     {
4032       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4033       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4034         {
4035           if (!offset)
4036             emit2 ("sub a,%s",
4037                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4038           else
4039             emit2 ("sbc a,%s",
4040                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4041         }
4042       else
4043         {
4044           /* first add without previous c */
4045           if (!offset)
4046             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4047           else
4048             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4049         }
4050       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4051     }
4052
4053   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4054       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4055       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4056     {
4057       wassertl (0, "Tried to subtract on a long pointer");
4058     }
4059
4060 release:
4061   _G.preserveCarry = FALSE;
4062   freeAsmop (IC_LEFT (ic), NULL, ic);
4063   freeAsmop (IC_RIGHT (ic), NULL, ic);
4064   freeAsmop (IC_RESULT (ic), NULL, ic);
4065 }
4066
4067 /*-----------------------------------------------------------------*/
4068 /* genMult - generates code for multiplication                     */
4069 /*-----------------------------------------------------------------*/
4070 static void
4071 genMult (iCode * ic)
4072 {
4073   int val;
4074   int count, i;
4075   /* If true then the final operation should be a subtract */
4076   bool active = FALSE;
4077   bool byteResult;
4078
4079   /* Shouldn't occur - all done through function calls */
4080   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4081   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4082   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4083   
4084   byteResult =  (AOP_SIZE (IC_RESULT (ic)) == 1);
4085
4086   if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4087       AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4088       AOP_SIZE (IC_RESULT (ic)) > 2)
4089     {
4090       wassertl (0, "Multiplication is handled through support function calls");
4091     }
4092
4093   /* Swap left and right such that right is a literal */
4094   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4095     {
4096       operand *t = IC_RIGHT (ic);
4097       IC_RIGHT (ic) = IC_LEFT (ic);
4098       IC_LEFT (ic) = t;
4099     }
4100
4101   wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4102
4103   val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4104   //  wassertl (val > 0, "Multiply must be positive");
4105   wassertl (val != 1, "Can't multiply by 1");
4106
4107   if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4108     _push (PAIR_DE);
4109     _G.stack.pushedDE = TRUE;
4110   }
4111
4112   if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4113     {
4114       emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4115       if (!byteResult)
4116         {
4117           emit2 ("ld a,e");
4118           emit2 ("rlc a");
4119           emit2 ("sbc a,a");
4120           emit2 ("ld d,a");
4121         }
4122     }
4123   else
4124     {
4125       fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4126     }
4127
4128   i = val;
4129
4130   /* Fully unroled version of mul.s.  Not the most efficient.
4131    */
4132   for (count = 0; count < 16; count++)
4133     {
4134       if (count != 0 && active)
4135         {
4136           emit2 ("add hl,hl");
4137         }
4138       if (i & 0x8000U)
4139         {
4140           if (active == FALSE)
4141             {
4142               emit2 ("ld l,e");
4143               if (!byteResult)
4144                 emit2 ("ld h,d");
4145             }
4146           else
4147             {
4148               emit2 ("add hl,de");
4149             }
4150           active = TRUE;
4151         }
4152       i <<= 1;
4153     }
4154
4155   spillCached();
4156
4157   if (IS_Z80 && _G.stack.pushedDE)
4158     {
4159       _pop (PAIR_DE);
4160       _G.stack.pushedDE = FALSE;
4161     }
4162
4163   if (byteResult)
4164     aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
4165   else
4166     commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4167
4168   freeAsmop (IC_LEFT (ic), NULL, ic);
4169   freeAsmop (IC_RIGHT (ic), NULL, ic);
4170   freeAsmop (IC_RESULT (ic), NULL, ic);
4171 }
4172
4173 /*-----------------------------------------------------------------*/
4174 /* genDiv - generates code for division                            */
4175 /*-----------------------------------------------------------------*/
4176 static void
4177 genDiv (iCode * ic)
4178 {
4179   /* Shouldn't occur - all done through function calls */
4180   wassertl (0, "Division is handled through support function calls");
4181 }
4182
4183 /*-----------------------------------------------------------------*/
4184 /* genMod - generates code for division                            */
4185 /*-----------------------------------------------------------------*/
4186 static void
4187 genMod (iCode * ic)
4188 {
4189   /* Shouldn't occur - all done through function calls */
4190   wassert (0);
4191 }
4192
4193 /*-----------------------------------------------------------------*/
4194 /* genIfxJump :- will create a jump depending on the ifx           */
4195 /*-----------------------------------------------------------------*/
4196 static void
4197 genIfxJump (iCode * ic, char *jval)
4198 {
4199   symbol *jlbl;
4200   const char *inst;
4201
4202   /* if true label then we jump if condition
4203      supplied is true */
4204   if (IC_TRUE (ic))
4205     {
4206       jlbl = IC_TRUE (ic);
4207       if (!strcmp (jval, "a"))
4208         {
4209           inst = "nz";
4210         }
4211       else if (!strcmp (jval, "c"))
4212         {
4213           inst = "c";
4214         }
4215       else if (!strcmp (jval, "nc"))
4216         {
4217           inst = "nc";
4218         }
4219       else if (!strcmp (jval, "m"))
4220         {
4221           inst = "m";
4222         }
4223       else if (!strcmp (jval, "p"))
4224         {
4225           inst = "p";
4226         }
4227       else
4228         {
4229           /* The buffer contains the bit on A that we should test */
4230           inst = "nz";
4231         }
4232     }
4233   else
4234     {
4235       /* false label is present */
4236       jlbl = IC_FALSE (ic);
4237       if (!strcmp (jval, "a"))
4238         {
4239           inst = "z";
4240         }
4241       else if (!strcmp (jval, "c"))
4242         {
4243           inst = "nc";
4244         }
4245       else if (!strcmp (jval, "nc"))
4246         {
4247           inst = "c";
4248         }
4249       else if (!strcmp (jval, "m"))
4250         {
4251           inst = "p";
4252         }
4253       else if (!strcmp (jval, "p"))
4254         {
4255           inst = "m";
4256         }
4257       else
4258         {
4259           /* The buffer contains the bit on A that we should test */
4260           inst = "z";
4261         }
4262     }
4263   /* Z80 can do a conditional long jump */
4264   if (!strcmp (jval, "a"))
4265     {
4266       emit2 ("or a,a");
4267     }
4268   else if (!strcmp (jval, "c"))
4269     {
4270     }
4271   else if (!strcmp (jval, "nc"))
4272     {
4273     }
4274   else if (!strcmp (jval, "m"))
4275     {
4276     }
4277   else if (!strcmp (jval, "p"))
4278     {
4279     }
4280   else
4281     {
4282       emit2 ("bit %s,a", jval);
4283     }
4284   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4285
4286   /* mark the icode as generated */
4287   ic->generated = 1;
4288 }
4289
4290 #if DISABLED
4291 static const char *
4292 _getPairIdName (PAIR_ID id)
4293 {
4294   return _pairs[id].name;
4295 }
4296 #endif
4297
4298 #if OLD
4299       /* if unsigned char cmp with lit, just compare */
4300       if ((size == 1) &&
4301           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4302         {
4303           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4304           if (sign)
4305             {
4306               emit2 ("xor a,!immedbyte", 0x80);
4307               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4308             }
4309           else
4310             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4311         }
4312       else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4313         {
4314           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4315           // Pull left into DE and right into HL
4316           aopGet (AOP(left), LSB, FALSE);
4317           emit2 ("ld d,h");
4318           emit2 ("ld e,l");
4319           aopGet (AOP(right), LSB, FALSE);
4320
4321           while (size--)
4322             {
4323               if (size == 0 && sign)
4324                 {
4325                   // Highest byte when signed needs the bits flipped
4326                   // Save the flags
4327                   emit2 ("push af");
4328                   emit2 ("ld a,(de)");
4329                   emit2 ("xor !immedbyte", 0x80);
4330                   emit2 ("ld e,a");
4331                   emit2 ("ld a,(hl)");
4332                   emit2 ("xor !immedbyte", 0x80);
4333                   emit2 ("ld d,a");
4334                   emit2 ("pop af");
4335                   emit2 ("ld a,e");
4336                   emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4337                 }
4338               else
4339                 {
4340                   emit2 ("ld a,(de)");
4341                   emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4342                 }
4343               
4344               if (size != 0)
4345                 {
4346                   emit2 ("inc hl");
4347                   emit2 ("inc de");
4348                 }
4349               offset++;
4350             }
4351           spillPair (PAIR_HL);
4352         }
4353       else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4354         {
4355           setupPair (PAIR_HL, AOP (left), 0);
4356           aopGet (AOP(right), LSB, FALSE);
4357
4358           while (size--)
4359             {
4360               if (size == 0 && sign)
4361                 {
4362                   // Highest byte when signed needs the bits flipped
4363                   // Save the flags
4364                   emit2 ("push af");
4365                   emit2 ("ld a,(hl)");
4366                   emit2 ("xor !immedbyte", 0x80);
4367                   emit2 ("ld l,a");
4368                   emit2 ("ld a,%d(iy)", offset);
4369                   emit2 ("xor !immedbyte", 0x80);
4370                   emit2 ("ld h,a");
4371                   emit2 ("pop af");
4372                   emit2 ("ld a,l");
4373                   emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4374                 }
4375               else
4376                 {
4377                   emit2 ("ld a,(hl)");
4378                   emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4379                 }
4380               
4381               if (size != 0)
4382                 {
4383                   emit2 ("inc hl");
4384                 }
4385               offset++;
4386             }
4387           spillPair (PAIR_HL);
4388           spillPair (PAIR_IY);
4389         }
4390       else
4391         {
4392           if (AOP_TYPE (right) == AOP_LIT)
4393             {
4394               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4395               /* optimize if(x < 0) or if(x >= 0) */
4396               if (lit == 0L)
4397                 {
4398                   if (!sign)
4399                     {
4400                       /* No sign so it's always false */
4401                       _clearCarry();
4402                     }
4403                   else
4404                     {
4405                       /* Just load in the top most bit */
4406                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4407                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4408                         {
4409                           genIfxJump (ifx, "7");
4410                           return;
4411                         }
4412                       else
4413                         emit2 ("rlc a");
4414                     }
4415                   goto release;
4416                 }
4417             }
4418           
4419           if (sign)
4420             {
4421               /* First setup h and l contaning the top most bytes XORed */
4422               bool fDidXor = FALSE;
4423               if (AOP_TYPE (left) == AOP_LIT)
4424                 {
4425                   unsigned long lit = (unsigned long)
4426                   floatFromVal (AOP (left)->aopu.aop_lit);
4427                   emit2 ("ld %s,!immedbyte", _fTmp[0],
4428                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4429                 }
4430               else
4431                 {
4432                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4433                   emit2 ("xor a,!immedbyte", 0x80);
4434                   emit2 ("ld %s,a", _fTmp[0]);
4435                   fDidXor = TRUE;
4436                 }
4437               if (AOP_TYPE (right) == AOP_LIT)
4438                 {
4439                   unsigned long lit = (unsigned long)
4440                   floatFromVal (AOP (right)->aopu.aop_lit);
4441                   emit2 ("ld %s,!immedbyte", _fTmp[1],
4442                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4443                 }
4444               else
4445                 {
4446                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4447                   emit2 ("xor a,!immedbyte", 0x80);
4448                   emit2 ("ld %s,a", _fTmp[1]);
4449                   fDidXor = TRUE;
4450                 }
4451             }
4452           while (size--)
4453             {
4454               /* Do a long subtract */
4455               if (!sign || size)
4456                 {
4457                   _moveA (aopGet (AOP (left), offset, FALSE));
4458                 }
4459               if (sign && size == 0)
4460                 {
4461                   emit2 ("ld a,%s", _fTmp[0]);
4462                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4463                 }
4464               else
4465                 {
4466                   /* Subtract through, propagating the carry */
4467                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4468                   offset++;
4469                 }
4470             }
4471         }
4472     }
4473 #endif
4474
4475 /** Generic compare for > or <
4476  */
4477 static void
4478 genCmp (operand * left, operand * right,
4479         operand * result, iCode * ifx, int sign)
4480 {
4481   int size, offset = 0;
4482   unsigned long lit = 0L;
4483   bool swap_sense = FALSE;
4484
4485   /* if left & right are bit variables */
4486   if (AOP_TYPE (left) == AOP_CRY &&
4487       AOP_TYPE (right) == AOP_CRY)
4488     {
4489       /* Cant happen on the Z80 */
4490       wassertl (0, "Tried to compare two bits");
4491     }
4492   else
4493     {
4494       /* Do a long subtract of right from left. */
4495       size = max (AOP_SIZE (left), AOP_SIZE (right));
4496
4497       if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4498         {
4499           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4500           // Pull left into DE and right into HL
4501           aopGet (AOP(left), LSB, FALSE);
4502           emit2 ("ld d,h");
4503           emit2 ("ld e,l");
4504           aopGet (AOP(right), LSB, FALSE);
4505
4506           while (size--)
4507             {
4508               emit2 ("ld a,(de)");
4509               emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4510               
4511               if (size != 0)
4512                 {
4513                   emit2 ("inc hl");
4514                   emit2 ("inc de");
4515                 }
4516               offset++;
4517             }
4518           spillPair (PAIR_HL);
4519           goto release;
4520         }
4521
4522       if (AOP_TYPE (right) == AOP_LIT)
4523         {
4524           lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4525           /* optimize if(x < 0) or if(x >= 0) */
4526           if (lit == 0)
4527             {
4528               if (!sign)
4529                 {
4530                   /* No sign so it's always false */
4531                   _clearCarry();
4532                 }
4533               else
4534                 {
4535                   /* Just load in the top most bit */
4536                   _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4537                   if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4538                     {
4539                       genIfxJump (ifx, "7");
4540                       return;
4541                     }
4542                   else
4543                     {
4544                       if (!sign) 
4545                         {
4546                           emit2 ("rlc a");
4547                         }
4548                       if (ifx)
4549                         {
4550                           genIfxJump (ifx, swap_sense ? "c" : "nc");
4551                           return;
4552                         }
4553                     }
4554                 }
4555               goto release;
4556             }
4557         }
4558
4559       while (size--)
4560         {
4561           _moveA (aopGet (AOP (left), offset, FALSE));
4562           /* Subtract through, propagating the carry */
4563           emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4564           offset++;
4565         }
4566     }
4567
4568 release:
4569   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4570     {
4571       if (sign)
4572         {
4573           /* Shift the sign bit up into carry */
4574           emit2 ("rlca");
4575         }
4576       outBitCLong (result, swap_sense);
4577     }
4578   else
4579     {
4580       /* if the result is used in the next
4581          ifx conditional branch then generate
4582          code a little differently */
4583       if (ifx)
4584         {
4585           if (sign)
4586             {
4587               if (IS_GB)
4588                 {
4589                   emit2 ("rlca");
4590                   genIfxJump (ifx, swap_sense ? "nc" : "c");
4591                 }
4592               else
4593                 {
4594                   genIfxJump (ifx, swap_sense ? "p" : "m");
4595                 }
4596             }
4597           else
4598             {
4599               genIfxJump (ifx, swap_sense ? "nc" : "c");
4600             }
4601         }
4602       else
4603         {
4604           if (sign)
4605             {
4606               /* Shift the sign bit up into carry */
4607               emit2 ("rlca");
4608             }
4609           outBitCLong (result, swap_sense);
4610         }
4611       /* leave the result in acc */
4612     }
4613 }
4614
4615 /*-----------------------------------------------------------------*/
4616 /* genCmpGt :- greater than comparison                             */
4617 /*-----------------------------------------------------------------*/
4618 static void
4619 genCmpGt (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   /* assign the amsops */
4633   aopOp (left, ic, FALSE, FALSE);
4634   aopOp (right, ic, FALSE, FALSE);
4635   aopOp (result, ic, TRUE, FALSE);
4636
4637   genCmp (right, left, result, ifx, sign);
4638
4639   freeAsmop (left, NULL, ic);
4640   freeAsmop (right, NULL, ic);
4641   freeAsmop (result, NULL, ic);
4642 }
4643
4644 /*-----------------------------------------------------------------*/
4645 /* genCmpLt - less than comparisons                                */
4646 /*-----------------------------------------------------------------*/
4647 static void
4648 genCmpLt (iCode * ic, iCode * ifx)
4649 {
4650   operand *left, *right, *result;
4651   sym_link *letype, *retype;
4652   int sign;
4653
4654   left = IC_LEFT (ic);
4655   right = IC_RIGHT (ic);
4656   result = IC_RESULT (ic);
4657
4658   letype = getSpec (operandType (left));
4659   retype = getSpec (operandType (right));
4660   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4661
4662   /* assign the amsops */
4663   aopOp (left, ic, FALSE, FALSE);
4664   aopOp (right, ic, FALSE, FALSE);
4665   aopOp (result, ic, TRUE, FALSE);
4666
4667   genCmp (left, right, result, ifx, sign);
4668
4669   freeAsmop (left, NULL, ic);
4670   freeAsmop (right, NULL, ic);
4671   freeAsmop (result, NULL, ic);
4672 }
4673
4674 /*-----------------------------------------------------------------*/
4675 /* gencjneshort - compare and jump if not equal                    */
4676 /*-----------------------------------------------------------------*/
4677 static void
4678 gencjneshort (operand * left, operand * right, symbol * lbl)
4679 {
4680   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4681   int offset = 0;
4682   unsigned long lit = 0L;
4683
4684   /* Swap the left and right if it makes the computation easier */
4685   if (AOP_TYPE (left) == AOP_LIT)
4686     {
4687       operand *t = right;
4688       right = left;
4689       left = t;
4690     }
4691
4692   if (AOP_TYPE (right) == AOP_LIT)
4693     {
4694       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4695     }
4696
4697   /* if the right side is a literal then anything goes */
4698   if (AOP_TYPE (right) == AOP_LIT &&
4699       AOP_TYPE (left) != AOP_DIR)
4700     {
4701       if (lit == 0)
4702         {
4703           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4704           if (size > 1)
4705             {
4706               while (--size)
4707                 {
4708                   emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4709                 }
4710             }
4711           else
4712             {
4713               emit2 ("or a,a");
4714             }
4715           emit2 ("jp nz,!tlabel", lbl->key + 100);
4716         }
4717       else
4718         {
4719           while (size--)
4720             {
4721               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4722               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4723                 emit2 ("or a,a");
4724               else
4725                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4726               emit2 ("jp nz,!tlabel", lbl->key + 100);
4727               offset++;
4728             }
4729         }
4730     }
4731   /* if the right side is in a register or in direct space or
4732      if the left is a pointer register & right is not */
4733   else if (AOP_TYPE (right) == AOP_REG ||
4734            AOP_TYPE (right) == AOP_DIR ||
4735            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4736     {
4737       while (size--)
4738         {
4739           _moveA (aopGet (AOP (left), offset, FALSE));
4740           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4741               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4742             /* PENDING */
4743             emit2 ("jp nz,!tlabel", lbl->key + 100);
4744           else
4745             {
4746               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4747               emit2 ("jp nz,!tlabel", lbl->key + 100);
4748             }
4749           offset++;
4750         }
4751     }
4752   else
4753     {
4754       /* right is a pointer reg need both a & b */
4755       /* PENDING: is this required? */
4756       while (size--)
4757         {
4758           _moveA (aopGet (AOP (right), offset, FALSE));
4759           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4760           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4761           offset++;
4762         }
4763     }
4764 }
4765
4766 /*-----------------------------------------------------------------*/
4767 /* gencjne - compare and jump if not equal                         */
4768 /*-----------------------------------------------------------------*/
4769 static void
4770 gencjne (operand * left, operand * right, symbol * lbl)
4771 {
4772   symbol *tlbl = newiTempLabel (NULL);
4773
4774   gencjneshort (left, right, lbl);
4775
4776   /* PENDING: ?? */
4777   emit2 ("ld a,!one");
4778   emit2 ("!shortjp !tlabel", tlbl->key + 100);
4779   emitLabel (lbl->key + 100);
4780   emit2 ("xor a,a");
4781   emitLabel (tlbl->key + 100);
4782 }
4783
4784 /*-----------------------------------------------------------------*/
4785 /* genCmpEq - generates code for equal to                          */
4786 /*-----------------------------------------------------------------*/
4787 static void
4788 genCmpEq (iCode * ic, iCode * ifx)
4789 {
4790   operand *left, *right, *result;
4791
4792   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4793   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4794   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4795
4796   emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4797
4798   /* Swap operands if it makes the operation easier. ie if:
4799      1.  Left is a literal.
4800    */
4801   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4802     {
4803       operand *t = IC_RIGHT (ic);
4804       IC_RIGHT (ic) = IC_LEFT (ic);
4805       IC_LEFT (ic) = t;
4806     }
4807
4808   if (ifx && !AOP_SIZE (result))
4809     {
4810       symbol *tlbl;
4811       /* if they are both bit variables */
4812       if (AOP_TYPE (left) == AOP_CRY &&
4813           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4814         {
4815           wassertl (0, "Tried to compare two bits");
4816         }
4817       else
4818         {
4819           tlbl = newiTempLabel (NULL);
4820           gencjneshort (left, right, tlbl);
4821           if (IC_TRUE (ifx))
4822             {
4823               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4824               emitLabel (tlbl->key + 100);
4825             }
4826           else
4827             {
4828               /* PENDING: do this better */
4829               symbol *lbl = newiTempLabel (NULL);
4830               emit2 ("!shortjp !tlabel", lbl->key + 100);
4831               emitLabel (tlbl->key + 100);
4832               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4833               emitLabel (lbl->key + 100);
4834             }
4835         }
4836       /* mark the icode as generated */
4837       ifx->generated = 1;
4838       goto release;
4839     }
4840
4841   /* if they are both bit variables */
4842   if (AOP_TYPE (left) == AOP_CRY &&
4843       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4844     {
4845       wassertl (0, "Tried to compare a bit to either a literal or another bit");
4846     }
4847   else
4848     {
4849       emitDebug(";4");
4850       
4851       gencjne (left, right, newiTempLabel (NULL));
4852       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4853         {
4854           wassert (0);
4855         }
4856       if (ifx)
4857         {
4858           emitDebug(";5");
4859           genIfxJump (ifx, "a");
4860           goto release;
4861         }
4862       /* if the result is used in an arithmetic operation
4863          then put the result in place */
4864       if (AOP_TYPE (result) != AOP_CRY)
4865         {
4866           emitDebug(";6");
4867           outAcc (result);
4868         }
4869       /* leave the result in acc */
4870     }
4871
4872 release:
4873   freeAsmop (left, NULL, ic);
4874   freeAsmop (right, NULL, ic);
4875   freeAsmop (result, NULL, ic);
4876 }
4877
4878 /*-----------------------------------------------------------------*/
4879 /* ifxForOp - returns the icode containing the ifx for operand     */
4880 /*-----------------------------------------------------------------*/
4881 static iCode *
4882 ifxForOp (operand * op, iCode * ic)
4883 {
4884   /* if true symbol then needs to be assigned */
4885   if (IS_TRUE_SYMOP (op))
4886     return NULL;
4887
4888   /* if this has register type condition and
4889      the next instruction is ifx with the same operand
4890      and live to of the operand is upto the ifx only then */
4891   if (ic->next &&
4892       ic->next->op == IFX &&
4893       IC_COND (ic->next)->key == op->key &&
4894       OP_SYMBOL (op)->liveTo <= ic->next->seq)
4895     return ic->next;
4896
4897   return NULL;
4898 }
4899
4900 /*-----------------------------------------------------------------*/
4901 /* genAndOp - for && operation                                     */
4902 /*-----------------------------------------------------------------*/
4903 static void
4904 genAndOp (iCode * ic)
4905 {
4906   operand *left, *right, *result;
4907   symbol *tlbl;
4908
4909   /* note here that && operations that are in an if statement are
4910      taken away by backPatchLabels only those used in arthmetic
4911      operations remain */
4912   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4913   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4914   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4915
4916   /* if both are bit variables */
4917   if (AOP_TYPE (left) == AOP_CRY &&
4918       AOP_TYPE (right) == AOP_CRY)
4919     {
4920       wassertl (0, "Tried to and two bits");
4921     }
4922   else
4923     {
4924       tlbl = newiTempLabel (NULL);
4925       _toBoolean (left);
4926       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4927       _toBoolean (right);
4928       emitLabel (tlbl->key + 100);
4929       outBitAcc (result);
4930     }
4931
4932   freeAsmop (left, NULL, ic);
4933   freeAsmop (right, NULL, ic);
4934   freeAsmop (result, NULL, ic);
4935 }
4936
4937 /*-----------------------------------------------------------------*/
4938 /* genOrOp - for || operation                                      */
4939 /*-----------------------------------------------------------------*/
4940 static void
4941 genOrOp (iCode * ic)
4942 {
4943   operand *left, *right, *result;
4944   symbol *tlbl;
4945
4946   /* note here that || operations that are in an
4947      if statement are taken away by backPatchLabels
4948      only those used in arthmetic operations remain */
4949   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4950   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4951   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4952
4953   /* if both are bit variables */
4954   if (AOP_TYPE (left) == AOP_CRY &&
4955       AOP_TYPE (right) == AOP_CRY)
4956     {
4957       wassertl (0, "Tried to OR two bits");
4958     }
4959   else
4960     {
4961       tlbl = newiTempLabel (NULL);
4962       _toBoolean (left);
4963       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4964       _toBoolean (right);
4965       emitLabel (tlbl->key + 100);
4966       outBitAcc (result);
4967     }
4968
4969   freeAsmop (left, NULL, ic);
4970   freeAsmop (right, NULL, ic);
4971   freeAsmop (result, NULL, ic);
4972 }
4973
4974 /*-----------------------------------------------------------------*/
4975 /* isLiteralBit - test if lit == 2^n                               */
4976 /*-----------------------------------------------------------------*/
4977 int
4978 isLiteralBit (unsigned long lit)
4979 {
4980   unsigned long pw[32] =
4981   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4982    0x100L, 0x200L, 0x400L, 0x800L,
4983    0x1000L, 0x2000L, 0x4000L, 0x8000L,
4984    0x10000L, 0x20000L, 0x40000L, 0x80000L,
4985    0x100000L, 0x200000L, 0x400000L, 0x800000L,
4986    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4987    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4988   int idx;
4989
4990   for (idx = 0; idx < 32; idx++)
4991     if (lit == pw[idx])
4992       return idx + 1;
4993   return 0;
4994 }
4995
4996 /*-----------------------------------------------------------------*/
4997 /* jmpTrueOrFalse -                                                */
4998 /*-----------------------------------------------------------------*/
4999 static void
5000 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
5001 {
5002   // ugly but optimized by peephole
5003   if (IC_TRUE (ic))
5004     {
5005       symbol *nlbl = newiTempLabel (NULL);
5006       emit2 ("jp !tlabel", nlbl->key + 100);
5007       emitLabel (tlbl->key + 100);
5008       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
5009       emitLabel (nlbl->key + 100);
5010     }
5011   else
5012     {
5013       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
5014       emitLabel (tlbl->key + 100);
5015     }
5016   ic->generated = 1;
5017 }
5018
5019 /*-----------------------------------------------------------------*/
5020 /* genAnd  - code for and                                          */
5021 /*-----------------------------------------------------------------*/
5022 static void
5023 genAnd (iCode * ic, iCode * ifx)
5024 {
5025   operand *left, *right, *result;
5026   int size, offset = 0;
5027   unsigned long lit = 0L;
5028   int bytelit = 0;
5029
5030   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5031   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5032   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5033
5034   /* if left is a literal & right is not then exchange them */
5035   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5036       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5037     {
5038       operand *tmp = right;
5039       right = left;
5040       left = tmp;
5041     }
5042
5043   /* if result = right then exchange them */
5044   if (sameRegs (AOP (result), AOP (right)))
5045     {
5046       operand *tmp = right;
5047       right = left;
5048       left = tmp;
5049     }
5050
5051   /* if right is bit then exchange them */
5052   if (AOP_TYPE (right) == AOP_CRY &&
5053       AOP_TYPE (left) != AOP_CRY)
5054     {
5055       operand *tmp = right;
5056       right = left;
5057       left = tmp;
5058     }
5059   if (AOP_TYPE (right) == AOP_LIT)
5060     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5061
5062   size = AOP_SIZE (result);
5063
5064   if (AOP_TYPE (left) == AOP_CRY)
5065     {
5066       wassertl (0, "Tried to perform an AND with a bit as an operand");
5067       goto release;
5068     }
5069
5070   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5071   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5072   if ((AOP_TYPE (right) == AOP_LIT) &&
5073       (AOP_TYPE (result) == AOP_CRY) &&
5074       (AOP_TYPE (left) != AOP_CRY))
5075     {
5076       symbol *tlbl = newiTempLabel (NULL);
5077       int sizel = AOP_SIZE (left);
5078       if (size)
5079         {
5080           /* PENDING: Test case for this. */
5081           emit2 ("scf");
5082         }
5083       while (sizel--)
5084         {
5085           if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5086             {
5087               _moveA (aopGet (AOP (left), offset, FALSE));
5088               if (bytelit != 0x0FFL)
5089                 {
5090                   emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5091                 }
5092               else
5093                 {
5094                   /* For the flags */
5095                   emit2 ("or a,a");
5096                 }
5097               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5098             }
5099               offset++;
5100         }
5101       // bit = left & literal
5102       if (size)
5103         {
5104           emit2 ("clr c");
5105           emit2 ("!tlabeldef", tlbl->key + 100);
5106         }
5107       // if(left & literal)
5108       else
5109         {
5110           if (ifx)
5111             {
5112               jmpTrueOrFalse (ifx, tlbl);
5113             }
5114           goto release;
5115         }
5116       outBitC (result);
5117       goto release;
5118     }
5119
5120   /* if left is same as result */
5121   if (sameRegs (AOP (result), AOP (left)))
5122     {
5123       for (; size--; offset++)
5124         {
5125           if (AOP_TYPE (right) == AOP_LIT)
5126             {
5127               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5128                 continue;
5129               else
5130                 {
5131                   if (bytelit == 0)
5132                     aopPut (AOP (result), "!zero", offset);
5133                   else
5134                     {
5135                       _moveA (aopGet (AOP (left), offset, FALSE));
5136                       emit2 ("and a,%s",
5137                                 aopGet (AOP (right), offset, FALSE));
5138                       aopPut (AOP (left), "a", offset);
5139                     }
5140                 }
5141
5142             }
5143           else
5144             {
5145               if (AOP_TYPE (left) == AOP_ACC)
5146                 {
5147                   wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5148                 }
5149               else
5150                 {
5151                   _moveA (aopGet (AOP (left), offset, FALSE));
5152                   emit2 ("and a,%s",
5153                             aopGet (AOP (right), offset, FALSE));
5154                   aopPut (AOP (left), "a", offset);
5155                 }
5156             }
5157         }
5158     }
5159   else
5160     {
5161       // left & result in different registers
5162       if (AOP_TYPE (result) == AOP_CRY)
5163         {
5164           wassertl (0, "Tried to AND where the result is in carry");
5165         }
5166       else
5167         {
5168           for (; (size--); offset++)
5169             {
5170               // normal case
5171               // result = left & right
5172               if (AOP_TYPE (right) == AOP_LIT)
5173                 {
5174                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5175                     {
5176                       aopPut (AOP (result),
5177                               aopGet (AOP (left), offset, FALSE),
5178                               offset);
5179                       continue;
5180                     }
5181                   else if (bytelit == 0)
5182                     {
5183                       aopPut (AOP (result), "!zero", offset);
5184                       continue;
5185                     }
5186                 }
5187               // faster than result <- left, anl result,right
5188               // and better if result is SFR
5189               if (AOP_TYPE (left) == AOP_ACC)
5190                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5191               else
5192                 {
5193                   _moveA (aopGet (AOP (left), offset, FALSE));
5194                   emit2 ("and a,%s",
5195                             aopGet (AOP (right), offset, FALSE));
5196                 }
5197               aopPut (AOP (result), "a", offset);
5198             }
5199         }
5200
5201     }
5202
5203 release:
5204   freeAsmop (left, NULL, ic);
5205   freeAsmop (right, NULL, ic);
5206   freeAsmop (result, NULL, ic);
5207 }
5208
5209 /*-----------------------------------------------------------------*/
5210 /* genOr  - code for or                                            */
5211 /*-----------------------------------------------------------------*/
5212 static void
5213 genOr (iCode * ic, iCode * ifx)
5214 {
5215   operand *left, *right, *result;
5216   int size, offset = 0;
5217   unsigned long lit = 0L;
5218   int bytelit = 0;
5219
5220   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5221   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5222   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5223
5224   /* if left is a literal & right is not then exchange them */
5225   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5226       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5227     {
5228       operand *tmp = right;
5229       right = left;
5230       left = tmp;
5231     }
5232
5233   /* if result = right then exchange them */
5234   if (sameRegs (AOP (result), AOP (right)))
5235     {
5236       operand *tmp = right;
5237       right = left;
5238       left = tmp;
5239     }
5240
5241   /* if right is bit then exchange them */
5242   if (AOP_TYPE (right) == AOP_CRY &&
5243       AOP_TYPE (left) != AOP_CRY)
5244     {
5245       operand *tmp = right;
5246       right = left;
5247       left = tmp;
5248     }
5249   if (AOP_TYPE (right) == AOP_LIT)
5250     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5251
5252   size = AOP_SIZE (result);
5253
5254   if (AOP_TYPE (left) == AOP_CRY)
5255     {
5256       wassertl (0, "Tried to OR where left is a bit");
5257       goto release;
5258     }
5259
5260   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5261   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5262   if ((AOP_TYPE (right) == AOP_LIT) &&
5263       (AOP_TYPE (result) == AOP_CRY) &&
5264       (AOP_TYPE (left) != AOP_CRY))
5265     {
5266       symbol *tlbl = newiTempLabel (NULL);
5267       int sizel = AOP_SIZE (left);
5268
5269       if (size)
5270         {
5271           wassertl (0, "Result is assigned to a bit");
5272         }
5273       /* PENDING: Modeled after the AND code which is inefficent. */
5274       while (sizel--)
5275         {
5276           bytelit = (lit >> (offset * 8)) & 0x0FFL;
5277
5278           _moveA (aopGet (AOP (left), offset, FALSE));
5279           /* OR with any literal is the same as OR with itself. */
5280           emit2 ("or a,a");
5281           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5282
5283           offset++;
5284         }
5285       if (ifx)
5286         {
5287           jmpTrueOrFalse (ifx, tlbl);
5288         }
5289       goto release;
5290     }
5291
5292   /* if left is same as result */
5293   if (sameRegs (AOP (result), AOP (left)))
5294     {
5295       for (; size--; offset++)
5296         {
5297           if (AOP_TYPE (right) == AOP_LIT)
5298             {
5299               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5300                 continue;
5301               else
5302                 {
5303                   _moveA (aopGet (AOP (left), offset, FALSE));
5304                   emit2 ("or a,%s",
5305                             aopGet (AOP (right), offset, FALSE));
5306                   aopPut (AOP (result), "a", offset);
5307                 }
5308             }
5309           else
5310             {
5311               if (AOP_TYPE (left) == AOP_ACC)
5312                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5313               else
5314                 {
5315                   _moveA (aopGet (AOP (left), offset, FALSE));
5316                   emit2 ("or a,%s",
5317                             aopGet (AOP (right), offset, FALSE));
5318                   aopPut (AOP (result), "a", offset);
5319                 }
5320             }
5321         }
5322     }
5323   else
5324     {
5325       // left & result in different registers
5326       if (AOP_TYPE (result) == AOP_CRY)
5327         {
5328           wassertl (0, "Result of OR is in a bit");
5329         }
5330       else
5331         for (; (size--); offset++)
5332           {
5333             // normal case
5334             // result = left & right
5335             if (AOP_TYPE (right) == AOP_LIT)
5336               {
5337                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5338                   {
5339                     aopPut (AOP (result),
5340                             aopGet (AOP (left), offset, FALSE),
5341                             offset);
5342                     continue;
5343                   }
5344               }
5345             // faster than result <- left, anl result,right
5346             // and better if result is SFR
5347             if (AOP_TYPE (left) == AOP_ACC)
5348               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5349             else
5350               {
5351                 _moveA (aopGet (AOP (left), offset, FALSE));
5352                 emit2 ("or a,%s",
5353                           aopGet (AOP (right), offset, FALSE));
5354               }
5355             aopPut (AOP (result), "a", offset);
5356             /* PENDING: something weird is going on here.  Add exception. */
5357             if (AOP_TYPE (result) == AOP_ACC)
5358               break;
5359           }
5360     }
5361
5362 release:
5363   freeAsmop (left, NULL, ic);
5364   freeAsmop (right, NULL, ic);
5365   freeAsmop (result, NULL, ic);
5366 }
5367
5368 /*-----------------------------------------------------------------*/
5369 /* genXor - code for xclusive or                                   */
5370 /*-----------------------------------------------------------------*/
5371 static void
5372 genXor (iCode * ic, iCode * ifx)
5373 {
5374   operand *left, *right, *result;
5375   int size, offset = 0;
5376   unsigned long lit = 0L;
5377
5378   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5379   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5380   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5381
5382   /* if left is a literal & right is not then exchange them */
5383   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5384       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5385     {
5386       operand *tmp = right;
5387       right = left;
5388       left = tmp;
5389     }
5390
5391   /* if result = right then exchange them */
5392   if (sameRegs (AOP (result), AOP (right)))
5393     {
5394       operand *tmp = right;
5395       right = left;
5396       left = tmp;
5397     }
5398
5399   /* if right is bit then exchange them */
5400   if (AOP_TYPE (right) == AOP_CRY &&
5401       AOP_TYPE (left) != AOP_CRY)
5402     {
5403       operand *tmp = right;
5404       right = left;
5405       left = tmp;
5406     }
5407   if (AOP_TYPE (right) == AOP_LIT)
5408     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5409
5410   size = AOP_SIZE (result);
5411
5412   if (AOP_TYPE (left) == AOP_CRY)
5413     {
5414       wassertl (0, "Tried to XOR a bit");
5415       goto release;
5416     }
5417
5418   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5419   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5420   if ((AOP_TYPE (right) == AOP_LIT) &&
5421       (AOP_TYPE (result) == AOP_CRY) &&
5422       (AOP_TYPE (left) != AOP_CRY))
5423     {
5424       symbol *tlbl = newiTempLabel (NULL);
5425       int sizel = AOP_SIZE (left);
5426
5427       if (size)
5428         {
5429           /* PENDING: Test case for this. */
5430           wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5431         }
5432       while (sizel--)
5433         {
5434           _moveA (aopGet (AOP (left), offset, FALSE));
5435           emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5436           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5437           offset++;
5438         }
5439       if (ifx)
5440         {
5441           jmpTrueOrFalse (ifx, tlbl);
5442         }
5443       else
5444         {
5445           wassertl (0, "Result of XOR was destined for a bit");
5446         }
5447       goto release;
5448     }
5449
5450   /* if left is same as result */
5451   if (sameRegs (AOP (result), AOP (left)))
5452     {
5453       for (; size--; offset++)
5454         {
5455           if (AOP_TYPE (right) == AOP_LIT)
5456             {
5457               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5458                 continue;
5459               else
5460                 {
5461                   _moveA (aopGet (AOP (left), offset, FALSE));
5462                   emit2 ("xor a,%s",
5463                             aopGet (AOP (right), offset, FALSE));
5464                   aopPut (AOP (result), "a", offset);
5465                 }
5466             }
5467           else
5468             {
5469               if (AOP_TYPE (left) == AOP_ACC)
5470                 {
5471                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5472                 }
5473               else
5474                 {
5475                   _moveA (aopGet (AOP (left), offset, FALSE));
5476                   emit2 ("xor a,%s",
5477                             aopGet (AOP (right), offset, FALSE));
5478                   aopPut (AOP (result), "a", offset);
5479                 }
5480             }
5481         }
5482     }
5483   else
5484     {
5485       // left & result in different registers
5486       if (AOP_TYPE (result) == AOP_CRY)
5487         {
5488           wassertl (0, "Result of XOR is in a bit");
5489         }
5490       else
5491         for (; (size--); offset++)
5492           {
5493             // normal case
5494             // result = left & right
5495             if (AOP_TYPE (right) == AOP_LIT)
5496               {
5497                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5498                   {
5499                     aopPut (AOP (result),
5500                             aopGet (AOP (left), offset, FALSE),
5501                             offset);
5502                     continue;
5503                   }
5504               }
5505             // faster than result <- left, anl result,right
5506             // and better if result is SFR
5507             if (AOP_TYPE (left) == AOP_ACC) 
5508               {
5509                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5510               }
5511             else
5512               {
5513                 _moveA (aopGet (AOP (left), offset, FALSE));
5514                 emit2 ("xor a,%s",
5515                           aopGet (AOP (right), offset, FALSE));
5516               }
5517             aopPut (AOP (result), "a", offset);
5518           }
5519     }
5520
5521 release:
5522   freeAsmop (left, NULL, ic);
5523   freeAsmop (right, NULL, ic);
5524   freeAsmop (result, NULL, ic);
5525 }
5526
5527 /*-----------------------------------------------------------------*/
5528 /* genInline - write the inline code out                           */
5529 /*-----------------------------------------------------------------*/
5530 static void
5531 genInline (iCode * ic)
5532 {
5533   char *buffer, *bp, *bp1;
5534
5535   _G.lines.isInline += (!options.asmpeep);
5536
5537   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5538   strcpy (buffer, IC_INLINE (ic));
5539
5540   /* emit each line as a code */
5541   while (*bp)
5542     {
5543       if (*bp == '\n')
5544         {
5545           *bp++ = '\0';
5546           emit2 (bp1);
5547           bp1 = bp;
5548         }
5549       else
5550         {
5551           if (*bp == ':')
5552             {
5553               bp++;
5554               *bp = '\0';
5555               bp++;
5556               emit2 (bp1);
5557               bp1 = bp;
5558             }
5559           else
5560             bp++;
5561         }
5562     }
5563   if (bp1 != bp)
5564     emit2 (bp1);
5565   _G.lines.isInline -= (!options.asmpeep);
5566
5567 }
5568
5569 /*-----------------------------------------------------------------*/
5570 /* genRRC - rotate right with carry                                */
5571 /*-----------------------------------------------------------------*/
5572 static void
5573 genRRC (iCode * ic)
5574 {
5575   wassert (0);
5576 }
5577
5578 /*-----------------------------------------------------------------*/
5579 /* genRLC - generate code for rotate left with carry               */
5580 /*-----------------------------------------------------------------*/
5581 static void
5582 genRLC (iCode * ic)
5583 {
5584   wassert (0);
5585 }
5586
5587 /*-----------------------------------------------------------------*/
5588 /* genGetHbit - generates code get highest order bit               */
5589 /*-----------------------------------------------------------------*/
5590 static void
5591 genGetHbit (iCode * ic)
5592 {
5593   operand *left, *result;
5594   left = IC_LEFT (ic);
5595   result = IC_RESULT (ic);
5596
5597   aopOp (left, ic, FALSE, FALSE);
5598   aopOp (result, ic, FALSE, FALSE);
5599
5600   /* get the highest order byte into a */
5601   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5602
5603   if (AOP_TYPE (result) == AOP_CRY)
5604     {
5605       emit2 ("rl a");
5606       outBitC (result);
5607     }
5608   else
5609     {
5610       emit2 ("rlc a");
5611       emit2 ("and a,!one");
5612       outAcc (result);
5613     }
5614
5615
5616   freeAsmop (left, NULL, ic);
5617   freeAsmop (result, NULL, ic);
5618 }
5619
5620 static void
5621 emitRsh2 (asmop *aop, int size, int is_signed)
5622 {
5623   int offset = 0;
5624
5625   while (size--)
5626     {
5627       const char *l = aopGet (aop, size, FALSE);
5628       if (offset == 0)
5629         {
5630           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5631         }
5632       else
5633         {
5634           emit2 ("rr %s", l);
5635         }
5636       offset++;
5637     }
5638 }
5639
5640 /*-----------------------------------------------------------------*/
5641 /* shiftR2Left2Result - shift right two bytes from left to result  */
5642 /*-----------------------------------------------------------------*/
5643 static void
5644 shiftR2Left2Result (operand * left, int offl,
5645                     operand * result, int offr,
5646                     int shCount, int is_signed)
5647 {
5648   int size = 2;
5649   symbol *tlbl, *tlbl1;
5650
5651   movLeft2Result (left, offl, result, offr, 0);
5652   movLeft2Result (left, offl + 1, result, offr + 1, 0);
5653
5654   /*  if (AOP(result)->type == AOP_REG) { */
5655   
5656   tlbl = newiTempLabel (NULL);
5657   tlbl1 = newiTempLabel (NULL);
5658
5659   /* Left is already in result - so now do the shift */
5660   if (shCount <= 4)
5661     {
5662       while (shCount--)
5663         {
5664           emitRsh2 (AOP (result), size, is_signed);
5665         }
5666     }
5667   else
5668     {
5669       emit2 ("ld a,!immedbyte+1", shCount);
5670       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5671       emitLabel (tlbl->key + 100);
5672
5673       emitRsh2 (AOP (result), size, is_signed);
5674
5675       emitLabel (tlbl1->key + 100);
5676       emit2 ("dec a");
5677       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5678     }
5679 }
5680
5681 /*-----------------------------------------------------------------*/
5682 /* shiftL2Left2Result - shift left two bytes from left to result   */
5683 /*-----------------------------------------------------------------*/
5684 static void
5685 shiftL2Left2Result (operand * left, int offl,
5686                     operand * result, int offr, int shCount)
5687 {
5688   if (sameRegs (AOP (result), AOP (left)) &&
5689       ((offl + MSB16) == offr))
5690     {
5691       wassert (0);
5692     }
5693   else
5694     {
5695       /* Copy left into result */
5696       movLeft2Result (left, offl, result, offr, 0);
5697       movLeft2Result (left, offl + 1, result, offr + 1, 0);
5698     }
5699
5700   if (getPairId (AOP (result)) == PAIR_HL)
5701     {
5702       while (shCount--)
5703         {
5704           emit2 ("add hl,hl");
5705         }
5706     }
5707   else
5708     {
5709     int size = 2;
5710     int offset = 0;
5711     symbol *tlbl, *tlbl1;
5712     const char *l;
5713
5714     tlbl = newiTempLabel (NULL);
5715     tlbl1 = newiTempLabel (NULL);
5716
5717     if (AOP (result)->type == AOP_REG)
5718       {
5719         while (shCount--)
5720           {
5721             for (offset = 0; offset < size; offset++)
5722               {
5723                 l = aopGet (AOP (result), offset, FALSE);
5724             
5725                 if (offset == 0)
5726                   {
5727                     emit2 ("sla %s", l);
5728                   }
5729                 else
5730                   {
5731                     emit2 ("rl %s", l);
5732                   }
5733               }
5734           }
5735       }
5736     else
5737       {
5738         /* Left is already in result - so now do the shift */
5739         if (shCount > 1)
5740           {
5741             emit2 ("ld a,!immedbyte+1", shCount);
5742             emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5743             emitLabel (tlbl->key + 100);
5744           }
5745
5746         while (size--)
5747           {
5748             l = aopGet (AOP (result), offset, FALSE);
5749             
5750             if (offset == 0)
5751               {
5752                 emit2 ("sla %s", l);
5753               }
5754             else
5755               {
5756                 emit2 ("rl %s", l);
5757               }
5758             
5759             offset++;
5760           }
5761         if (shCount > 1)
5762           {
5763             emitLabel (tlbl1->key + 100);
5764             emit2 ("dec a");
5765             emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5766           }
5767       }
5768   }
5769 }
5770
5771 /*-----------------------------------------------------------------*/
5772 /* AccRol - rotate left accumulator by known count                 */
5773 /*-----------------------------------------------------------------*/
5774 static void
5775 AccRol (int shCount)
5776 {
5777   shCount &= 0x0007;            // shCount : 0..7
5778
5779 #if 0
5780   switch (shCount)
5781     {
5782     case 0:
5783       break;
5784     case 1:
5785       emit2 ("sla a");
5786       break;
5787     case 2:
5788       emit2 ("sla a");
5789       emit2 ("rl a");
5790       break;
5791     case 3:
5792       emit2 ("sla a");
5793       emit2 ("rl a");
5794       emit2 ("rl a");
5795       break;
5796     case 4:
5797       emit2 ("sla a");
5798       emit2 ("rl a");
5799       emit2 ("rl a");
5800       emit2 ("rl a");
5801       break;
5802     case 5:
5803       emit2 ("srl a");
5804       emit2 ("rr a");
5805       emit2 ("rr a");
5806       break;
5807     case 6:
5808       emit2 ("srl a");
5809       emit2 ("rr a");
5810       break;
5811     case 7:
5812       emit2 ("srl a");
5813       break;
5814     }
5815 #else
5816   switch (shCount)
5817     {
5818     case 0:
5819       break;
5820     case 1:
5821       emit2 ("rlca");
5822       break;
5823     case 2:
5824       emit2 ("rlca");
5825       emit2 ("rlca");
5826       break;
5827     case 3:
5828       emit2 ("rlca");
5829       emit2 ("rlca");
5830       emit2 ("rlca");
5831       break;
5832     case 4:
5833       emit2 ("rlca");
5834       emit2 ("rlca");
5835       emit2 ("rlca");
5836       emit2 ("rlca");
5837       break;
5838     case 5:
5839       emit2 ("rrca");
5840       emit2 ("rrca");
5841       emit2 ("rrca");
5842       break;
5843     case 6:
5844       emit2 ("rrca");
5845       emit2 ("rrca");
5846       break;
5847     case 7:
5848       emit2 ("rrca");
5849       break;
5850     }
5851 #endif
5852 }
5853
5854 /*-----------------------------------------------------------------*/
5855 /* AccLsh - left shift accumulator by known count                  */
5856 /*-----------------------------------------------------------------*/
5857 static void
5858 AccLsh (int shCount)
5859 {
5860   static const unsigned char SLMask[] =
5861     {
5862       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5863     };
5864
5865   if (shCount != 0)
5866     {
5867       if (shCount == 1)
5868         {
5869           emit2 ("add a,a");
5870         }
5871       else if (shCount == 2)
5872         {
5873           emit2 ("add a,a");
5874           emit2 ("add a,a");
5875         }
5876       else
5877         {
5878           /* rotate left accumulator */
5879           AccRol (shCount);
5880           /* and kill the lower order bits */
5881           emit2 ("and a,!immedbyte", SLMask[shCount]);
5882         }
5883     }
5884 }
5885
5886 /*-----------------------------------------------------------------*/
5887 /* shiftL1Left2Result - shift left one byte from left to result    */
5888 /*-----------------------------------------------------------------*/
5889 static void
5890 shiftL1Left2Result (operand * left, int offl,
5891                     operand * result, int offr, int shCount)
5892 {
5893   const char *l;
5894   l = aopGet (AOP (left), offl, FALSE);
5895   _moveA (l);
5896   /* shift left accumulator */
5897   AccLsh (shCount);
5898   aopPut (AOP (result), "a", offr);
5899 }
5900
5901
5902 /*-----------------------------------------------------------------*/
5903 /* genlshTwo - left shift two bytes by known amount != 0           */
5904 /*-----------------------------------------------------------------*/
5905 static void
5906 genlshTwo (operand * result, operand * left, int shCount)
5907 {
5908   int size = AOP_SIZE (result);
5909
5910   wassert (size == 2);
5911
5912   /* if shCount >= 8 */
5913   if (shCount >= 8)
5914     {
5915       shCount -= 8;
5916       if (size > 1)
5917         {
5918           if (shCount)
5919             {
5920               movLeft2Result (left, LSB, result, MSB16, 0);
5921               aopPut (AOP (result), "!zero", 0);
5922               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5923             }
5924           else
5925             {
5926               movLeft2Result (left, LSB, result, MSB16, 0);
5927               aopPut (AOP (result), "!zero", 0);
5928             }
5929         }
5930       else
5931         {
5932           aopPut (AOP (result), "!zero", LSB);
5933         }
5934     }
5935   /*  1 <= shCount <= 7 */
5936   else
5937     {
5938       if (size == 1)
5939         {
5940           wassert (0);
5941         }
5942       else
5943         {
5944           shiftL2Left2Result (left, LSB, result, LSB, shCount);
5945         }
5946     }
5947 }
5948
5949 /*-----------------------------------------------------------------*/
5950 /* genlshOne - left shift a one byte quantity by known count       */
5951 /*-----------------------------------------------------------------*/
5952 static void
5953 genlshOne (operand * result, operand * left, int shCount)
5954 {
5955   shiftL1Left2Result (left, LSB, result, LSB, shCount);
5956 }
5957
5958 /*-----------------------------------------------------------------*/
5959 /* genLeftShiftLiteral - left shifting by known count              */
5960 /*-----------------------------------------------------------------*/
5961 static void
5962 genLeftShiftLiteral (operand * left,
5963                      operand * right,
5964                      operand * result,
5965                      iCode * ic)
5966 {
5967   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5968   int size;
5969
5970   freeAsmop (right, NULL, ic);
5971
5972   aopOp (left, ic, FALSE, FALSE);
5973   aopOp (result, ic, FALSE, FALSE);
5974
5975   size = getSize (operandType (result));
5976
5977   /* I suppose that the left size >= result size */
5978   if (shCount == 0)
5979     {
5980       wassert (0);
5981     }
5982
5983   else if (shCount >= (size * 8)) 
5984     {
5985       while (size--)
5986         {
5987           aopPut (AOP (result), "!zero", size);
5988         }
5989     }
5990   else
5991     {
5992       switch (size)
5993         {
5994         case 1:
5995           genlshOne (result, left, shCount);
5996           break;
5997         case 2:
5998           genlshTwo (result, left, shCount);
5999           break;
6000         case 4:
6001           wassertl (0, "Shifting of longs is currently unsupported");
6002           break;
6003         default:
6004           wassert (0);
6005         }
6006     }
6007   freeAsmop (left, NULL, ic);
6008   freeAsmop (result, NULL, ic);
6009 }
6010
6011 /*-----------------------------------------------------------------*/
6012 /* genLeftShift - generates code for left shifting                 */
6013 /*-----------------------------------------------------------------*/
6014 static void
6015 genLeftShift (iCode * ic)
6016 {
6017   int size, offset;
6018   const char *l;
6019   symbol *tlbl, *tlbl1;
6020   operand *left, *right, *result;
6021
6022   right = IC_RIGHT (ic);
6023   left = IC_LEFT (ic);
6024   result = IC_RESULT (ic);
6025
6026   aopOp (right, ic, FALSE, FALSE);
6027
6028   /* if the shift count is known then do it
6029      as efficiently as possible */
6030   if (AOP_TYPE (right) == AOP_LIT)
6031     {
6032       genLeftShiftLiteral (left, right, result, ic);
6033       return;
6034     }
6035
6036   /* shift count is unknown then we have to form a loop get the loop
6037      count in B : Note: we take only the lower order byte since
6038      shifting more that 32 bits make no sense anyway, ( the largest
6039      size of an object can be only 32 bits ) */
6040   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6041   emit2 ("inc a");
6042   freeAsmop (right, NULL, ic);
6043   aopOp (left, ic, FALSE, FALSE);
6044   aopOp (result, ic, FALSE, FALSE);
6045
6046   /* now move the left to the result if they are not the
6047      same */
6048
6049   if (!sameRegs (AOP (left), AOP (result)))
6050     {
6051
6052       size = AOP_SIZE (result);
6053       offset = 0;
6054       while (size--)
6055         {
6056           l = aopGet (AOP (left), offset, FALSE);
6057           aopPut (AOP (result), l, offset);
6058           offset++;
6059         }
6060     }
6061
6062   tlbl = newiTempLabel (NULL);
6063   size = AOP_SIZE (result);
6064   offset = 0;
6065   tlbl1 = newiTempLabel (NULL);
6066
6067   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6068   emitLabel (tlbl->key + 100);
6069   l = aopGet (AOP (result), offset, FALSE);
6070
6071   while (size--)
6072     {
6073       l = aopGet (AOP (result), offset, FALSE);
6074
6075       if (offset == 0)
6076         {
6077           emit2 ("sla %s", l);
6078         }
6079       else
6080         {
6081           emit2 ("rl %s", l);
6082         }
6083       offset++;
6084     }
6085   emitLabel (tlbl1->key + 100);
6086   emit2 ("dec a");
6087   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6088
6089   freeAsmop (left, NULL, ic);
6090   freeAsmop (result, NULL, ic);
6091 }
6092
6093 /*-----------------------------------------------------------------*/
6094 /* genrshOne - left shift two bytes by known amount != 0           */
6095 /*-----------------------------------------------------------------*/
6096 static void
6097 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6098 {
6099   /* Errk */
6100   int size = AOP_SIZE (result);
6101   const char *l;
6102
6103   wassert (size == 1);
6104   wassert (shCount < 8);
6105
6106   l = aopGet (AOP (left), 0, FALSE);
6107
6108   if (AOP (result)->type == AOP_REG)
6109     {
6110       aopPut (AOP (result), l, 0);
6111       l = aopGet (AOP (result), 0, FALSE);
6112       while (shCount--)
6113         {
6114           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6115         }
6116     }
6117   else
6118     {
6119       _moveA (l);
6120       while (shCount--)
6121         {
6122           emit2 ("%s a", is_signed ? "sra" : "srl");
6123         }
6124       aopPut (AOP (result), "a", 0);
6125     }
6126 }
6127
6128 /*-----------------------------------------------------------------*/
6129 /* AccRsh - right shift accumulator by known count                 */
6130 /*-----------------------------------------------------------------*/
6131 static void
6132 AccRsh (int shCount)
6133 {
6134   static const unsigned char SRMask[] =
6135     {
6136       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6137     };
6138
6139   if (shCount != 0)
6140     {
6141       /* rotate right accumulator */
6142       AccRol (8 - shCount);
6143       /* and kill the higher order bits */
6144       emit2 ("and a,!immedbyte", SRMask[shCount]);
6145     }
6146 }
6147
6148 /*-----------------------------------------------------------------*/
6149 /* shiftR1Left2Result - shift right one byte from left to result   */
6150 /*-----------------------------------------------------------------*/
6151 static void
6152 shiftR1Left2Result (operand * left, int offl,
6153                     operand * result, int offr,
6154                     int shCount, int sign)
6155 {
6156   _moveA (aopGet (AOP (left), offl, FALSE));
6157   if (sign)
6158     {
6159       while (shCount--)
6160         {
6161           emit2 ("%s a", sign ? "sra" : "srl");
6162         }
6163     }
6164   else
6165     {
6166       AccRsh (shCount);
6167     }
6168   aopPut (AOP (result), "a", offr);
6169 }
6170
6171 /*-----------------------------------------------------------------*/
6172 /* genrshTwo - right shift two bytes by known amount != 0          */
6173 /*-----------------------------------------------------------------*/
6174 static void
6175 genrshTwo (operand * result, operand * left,
6176            int shCount, int sign)
6177 {
6178   /* if shCount >= 8 */
6179   if (shCount >= 8)
6180     {
6181       shCount -= 8;
6182       if (shCount)
6183         {
6184           shiftR1Left2Result (left, MSB16, result, LSB,
6185                               shCount, sign);
6186         }
6187       else
6188         {
6189           movLeft2Result (left, MSB16, result, LSB, sign);
6190         }
6191       if (sign)
6192         {
6193           /* Sign extend the result */
6194           _moveA(aopGet (AOP (result), 0, FALSE));
6195           emit2 ("rlc a");
6196           emit2 ("sbc a,a");
6197
6198           aopPut (AOP (result), ACC_NAME, MSB16);
6199         }
6200       else
6201         {
6202           aopPut (AOP (result), "!zero", 1);
6203         }
6204     }
6205   /*  1 <= shCount <= 7 */
6206   else
6207     {
6208       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6209     }
6210 }
6211
6212 /*-----------------------------------------------------------------*/
6213 /* genRightShiftLiteral - left shifting by known count              */
6214 /*-----------------------------------------------------------------*/
6215 static void
6216 genRightShiftLiteral (operand * left,
6217                       operand * right,
6218                       operand * result,
6219                       iCode * ic,
6220                       int sign)
6221 {
6222   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6223   int size;
6224
6225   freeAsmop (right, NULL, ic);
6226
6227   aopOp (left, ic, FALSE, FALSE);
6228   aopOp (result, ic, FALSE, FALSE);
6229
6230   size = getSize (operandType (result));
6231
6232   /* I suppose that the left size >= result size */
6233   if (shCount == 0)
6234     {
6235       wassert (0);
6236     }
6237
6238   else if (shCount >= (size * 8)) {
6239     const char *s;
6240     if (!SPEC_USIGN(getSpec(operandType(left)))) {
6241       _moveA(aopGet (AOP (left), 0, FALSE));
6242       emit2 ("rlc a");
6243       emit2 ("sbc a,a");
6244       s=ACC_NAME;
6245     } else {
6246       s="!zero";
6247     }
6248     while (size--)
6249       aopPut (AOP (result), s, size);
6250   }
6251   else
6252     {
6253       switch (size)
6254         {
6255         case 1:
6256           genrshOne (result, left, shCount, sign);
6257           break;
6258         case 2:
6259           genrshTwo (result, left, shCount, sign);
6260           break;
6261         case 4:
6262           wassertl (0, "Asked to shift right a long which should be a function call");
6263           break;
6264         default:
6265           wassertl (0, "Entered default case in right shift delegate");
6266         }
6267     }
6268   freeAsmop (left, NULL, ic);
6269   freeAsmop (result, NULL, ic);
6270 }
6271
6272 /*-----------------------------------------------------------------*/
6273 /* genRightShift - generate code for right shifting                */
6274 /*-----------------------------------------------------------------*/
6275 static void
6276 genRightShift (iCode * ic)
6277 {
6278   operand *right, *left, *result;
6279   sym_link *retype;
6280   int size, offset, first = 1;
6281   const char *l;
6282   bool is_signed;
6283
6284   symbol *tlbl, *tlbl1;
6285
6286   /* if signed then we do it the hard way preserve the
6287      sign bit moving it inwards */
6288   retype = getSpec (operandType (IC_RESULT (ic)));
6289
6290   is_signed = !SPEC_USIGN (retype);
6291
6292   /* signed & unsigned types are treated the same : i.e. the
6293      signed is NOT propagated inwards : quoting from the
6294      ANSI - standard : "for E1 >> E2, is equivalent to division
6295      by 2**E2 if unsigned or if it has a non-negative value,
6296      otherwise the result is implementation defined ", MY definition
6297      is that the sign does not get propagated */
6298
6299   right = IC_RIGHT (ic);
6300   left = IC_LEFT (ic);
6301   result = IC_RESULT (ic);
6302
6303   aopOp (right, ic, FALSE, FALSE);
6304
6305   /* if the shift count is known then do it
6306      as efficiently as possible */
6307   if (AOP_TYPE (right) == AOP_LIT)
6308     {
6309       genRightShiftLiteral (left, right, result, ic, is_signed);
6310       return;
6311     }
6312
6313   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6314   emit2 ("inc a");
6315   freeAsmop (right, NULL, ic);
6316
6317   aopOp (left, ic, FALSE, FALSE);
6318   aopOp (result, ic, FALSE, FALSE);
6319
6320   /* now move the left to the result if they are not the
6321      same */
6322   if (!sameRegs (AOP (left), AOP (result)))
6323     {
6324
6325       size = AOP_SIZE (result);
6326       offset = 0;
6327       while (size--)
6328         {
6329           l = aopGet (AOP (left), offset, FALSE);
6330           aopPut (AOP (result), l, offset);
6331           offset++;
6332         }
6333     }
6334
6335   tlbl = newiTempLabel (NULL);
6336   tlbl1 = newiTempLabel (NULL);
6337   size = AOP_SIZE (result);
6338   offset = size - 1;
6339
6340   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6341   emitLabel (tlbl->key + 100);
6342   while (size--)
6343     {
6344       l = aopGet (AOP (result), offset--, FALSE);
6345       if (first)
6346         {
6347           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6348           first = 0;
6349         }
6350       else
6351         {
6352           emit2 ("rr %s", l);
6353         }
6354     }
6355   emitLabel (tlbl1->key + 100);
6356   emit2 ("dec a");
6357   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6358
6359   freeAsmop (left, NULL, ic);
6360   freeAsmop (result, NULL, ic);
6361 }
6362
6363
6364 /*-----------------------------------------------------------------*/
6365 /* genUnpackBits - generates code for unpacking bits               */
6366 /*-----------------------------------------------------------------*/
6367 static void
6368 genUnpackBits (operand * result, int pair)
6369 {
6370   int offset = 0;       /* result byte offset */
6371   int rsize;            /* result size */
6372   int rlen = 0;         /* remaining bitfield length */
6373   sym_link *etype;      /* bitfield type information */
6374   int blen;             /* bitfield length */
6375   int bstr;             /* bitfield starting bit within byte */
6376
6377   emitDebug ("; genUnpackBits");
6378
6379   etype = getSpec (operandType (result));
6380   rsize = getSize (operandType (result));
6381   blen = SPEC_BLEN (etype);
6382   bstr = SPEC_BSTR (etype);
6383
6384   /* If the bitfield length is less than a byte */
6385   if (blen < 8)
6386     {
6387       emit2 ("ld a,!*pair", _pairs[pair].name);
6388       AccRsh (bstr);
6389       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6390       aopPut (AOP (result), "a", offset++);
6391       goto finish;
6392     }
6393
6394   /* TODO: what if pair == PAIR_DE ? */
6395   if (getPairId (AOP (result)) == PAIR_HL)
6396     {
6397       wassertl (rsize == 2, "HL must be of size 2");
6398       emit2 ("ld a,!*hl");
6399       emit2 ("inc hl");
6400       emit2 ("ld h,!*hl");
6401       emit2 ("ld l,a");
6402       emit2 ("ld a,h");
6403       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6404       emit2 ("ld h,a");
6405       spillPair (PAIR_HL);
6406       return;
6407     }
6408
6409   /* Bit field did not fit in a byte. Copy all
6410      but the partial byte at the end.  */
6411   for (rlen=blen;rlen>=8;rlen-=8)
6412     {
6413       emit2 ("ld a,!*pair", _pairs[pair].name);
6414       aopPut (AOP (result), "a", offset++);
6415       if (rlen>8)
6416         {
6417           emit2 ("inc %s", _pairs[pair].name);
6418           _G.pairs[pair].offset++;
6419         }
6420     }
6421
6422   /* Handle the partial byte at the end */
6423   if (rlen)
6424     {
6425       emit2 ("ld a,!*pair", _pairs[pair].name);
6426       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6427       aopPut (AOP (result), "a", offset++);
6428     }
6429
6430 finish:
6431   if (offset < rsize)
6432     {
6433       rsize -= offset;
6434       while (rsize--)
6435         aopPut (AOP (result), "!zero", offset++);
6436     }
6437 }
6438
6439 /*-----------------------------------------------------------------*/
6440 /* genGenPointerGet -  get value from generic pointer space        */
6441 /*-----------------------------------------------------------------*/
6442 static void
6443 genGenPointerGet (operand * left,
6444                   operand * result, iCode * ic)
6445 {
6446   int size, offset;
6447   sym_link *retype = getSpec (operandType (result));
6448   int pair = PAIR_HL;
6449
6450   if (IS_GB)
6451     pair = PAIR_DE;
6452
6453   aopOp (left, ic, FALSE, FALSE);
6454   aopOp (result, ic, FALSE, FALSE);
6455
6456   size = AOP_SIZE (result);
6457
6458   if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6459     {
6460       /* Just do it */
6461       if (isPtrPair (AOP (left)))
6462         {
6463           tsprintf (buffer, sizeof(buffer), 
6464                     "!*pair", getPairName (AOP (left)));
6465           aopPut (AOP (result), buffer, 0);
6466         }
6467       else
6468         {
6469           emit2 ("ld a,!*pair", getPairName (AOP (left)));
6470           aopPut (AOP (result), "a", 0);
6471         }
6472       freeAsmop (left, NULL, ic);
6473       goto release;
6474     }
6475
6476   if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6477     {
6478       /* Just do it */
6479       offset = 0;
6480       while (size--) 
6481         {
6482           char at[20];
6483           tsprintf (at, sizeof(at), "!*iyx", offset);
6484           aopPut (AOP (result), at, offset);
6485           offset++;
6486         }
6487  
6488       freeAsmop (left, NULL, ic);
6489       goto release;
6490     }
6491
6492   /* For now we always load into IY */
6493   /* if this is remateriazable */
6494   fetchPair (pair, AOP (left));
6495
6496   /* if bit then unpack */
6497   if (IS_BITVAR (retype))
6498     {
6499       genUnpackBits (result, pair);
6500       freeAsmop (left, NULL, ic);
6501       goto release;
6502       //wassert (0);
6503     }
6504   else if (getPairId (AOP (result)) == PAIR_HL)
6505     {
6506       wassertl (size == 2, "HL must be of size 2");
6507       emit2 ("ld a,!*hl");
6508       emit2 ("inc hl");
6509       emit2 ("ld h,!*hl");
6510       emit2 ("ld l,a");
6511       spillPair (PAIR_HL);
6512     }
6513   else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6514     {
6515       size = AOP_SIZE (result);
6516       offset = 0;
6517
6518       while (size--)
6519         {
6520           /* PENDING: make this better */
6521           if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6522             {
6523               aopPut (AOP (result), "!*hl", offset++);
6524             }
6525           else
6526             {
6527               emit2 ("ld a,!*pair", _pairs[pair].name);
6528               aopPut (AOP (result), "a", offset++);
6529             }
6530           if (size)
6531             {
6532               emit2 ("inc %s", _pairs[pair].name);
6533               _G.pairs[pair].offset++;
6534             }
6535         }
6536       /* Fixup HL back down */
6537       for (size = AOP_SIZE (result)-1; size; size--)
6538         {
6539           emit2 ("dec %s", _pairs[pair].name);
6540         }
6541     }
6542   else
6543     {
6544       size = AOP_SIZE (result);
6545       offset = 0;
6546
6547       while (size--)
6548         {
6549           /* PENDING: make this better */
6550           if (!IS_GB && 
6551               (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6552             {
6553               aopPut (AOP (result), "!*hl", offset++);
6554             }
6555           else
6556             {
6557               emit2 ("ld a,!*pair", _pairs[pair].name);
6558               aopPut (AOP (result), "a", offset++);
6559             }
6560           if (size)
6561             {
6562               emit2 ("inc %s", _pairs[pair].name);
6563               _G.pairs[pair].offset++;
6564             }
6565         }
6566     }
6567
6568   freeAsmop (left, NULL, ic);
6569
6570 release:
6571   freeAsmop (result, NULL, ic);
6572 }
6573
6574 /*-----------------------------------------------------------------*/
6575 /* genPointerGet - generate code for pointer get                   */
6576 /*-----------------------------------------------------------------*/
6577 static void
6578 genPointerGet (iCode * ic)
6579 {
6580   operand *left, *result;
6581   sym_link *type, *etype;
6582
6583   left = IC_LEFT (ic);
6584   result = IC_RESULT (ic);
6585
6586   /* depending on the type of pointer we need to
6587      move it to the correct pointer register */
6588   type = operandType (left);
6589   etype = getSpec (type);
6590
6591   genGenPointerGet (left, result, ic);
6592 }
6593
6594 bool
6595 isRegOrLit (asmop * aop)
6596 {
6597   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6598     return TRUE;
6599   return FALSE;
6600 }
6601
6602
6603 /*-----------------------------------------------------------------*/
6604 /* genPackBits - generates code for packed bit storage             */
6605 /*-----------------------------------------------------------------*/
6606 static void
6607 genPackBits (sym_link * etype,
6608              operand * right,
6609              int pair,
6610              iCode *ic)
6611 {
6612   int offset = 0;       /* source byte offset */
6613   int rlen = 0;         /* remaining bitfield length */
6614   int blen;             /* bitfield length */
6615   int bstr;             /* bitfield starting bit within byte */
6616   int litval;           /* source literal value (if AOP_LIT) */
6617   unsigned char mask;   /* bitmask within current byte */
6618   int extraPair;        /* a tempory register */
6619   bool needPopExtra=0;  /* need to restore original value of temp reg */
6620
6621   emitDebug (";     genPackBits","");
6622
6623   blen = SPEC_BLEN (etype);
6624   bstr = SPEC_BSTR (etype);
6625
6626   /* If the bitfield length is less than a byte */
6627   if (blen < 8)
6628     {
6629       mask = ((unsigned char) (0xFF << (blen + bstr)) |
6630               (unsigned char) (0xFF >> (8 - bstr)));
6631
6632       if (AOP_TYPE (right) == AOP_LIT)
6633         {
6634           /* Case with a bitfield length <8 and literal source
6635           */
6636           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6637           litval <<= bstr;
6638           litval &= (~mask) & 0xff;
6639           emit2 ("ld a,!*pair", _pairs[pair].name);
6640           if ((mask|litval)!=0xff)
6641             emit2 ("and a,!immedbyte", mask);
6642           if (litval)
6643             emit2 ("or a,!immedbyte", litval);
6644           emit2 ("ld !*pair,a", _pairs[pair].name);
6645           return;
6646         }
6647       else
6648         {
6649           /* Case with a bitfield length <8 and arbitrary source
6650           */
6651           _moveA (aopGet (AOP (right), 0, FALSE));
6652           /* shift and mask source value */
6653           AccLsh (bstr);
6654           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6655
6656           extraPair = getFreePairId(ic);
6657           if (extraPair == PAIR_INVALID)
6658             {
6659               extraPair = PAIR_BC;
6660               if (getPairId (AOP (right)) != PAIR_BC
6661                   || !isLastUse (ic, right))
6662                 {
6663                   _push (extraPair);
6664                   needPopExtra = 1;
6665                 }
6666             }
6667           emit2 ("ld %s,a", _pairs[extraPair].l);
6668           emit2 ("ld a,!*pair", _pairs[pair].name);
6669
6670           emit2 ("and a,!immedbyte", mask);
6671           emit2 ("or a,%s", _pairs[extraPair].l);
6672           emit2 ("ld !*pair,a", _pairs[pair].name);
6673           if (needPopExtra)
6674             _pop (extraPair);
6675           return;
6676         }
6677     }
6678
6679   /* Bit length is greater than 7 bits. In this case, copy  */
6680   /* all except the partial byte at the end                 */
6681   for (rlen=blen;rlen>=8;rlen-=8)
6682     {
6683       emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6684       emit2 ("ld !*pair,a", _pairs[pair].name);
6685       if (rlen>8)
6686         {
6687           emit2 ("inc %s", _pairs[pair].name);
6688           _G.pairs[pair].offset++;
6689         }
6690     }
6691
6692   /* If there was a partial byte at the end */
6693   if (rlen)
6694     {
6695       mask = (((unsigned char) -1 << rlen) & 0xff);
6696       
6697       if (AOP_TYPE (right) == AOP_LIT)
6698         {
6699           /* Case with partial byte and literal source
6700           */
6701           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6702           litval >>= (blen-rlen);
6703           litval &= (~mask) & 0xff;
6704           emit2 ("ld a,!*pair", _pairs[pair].name);
6705           if ((mask|litval)!=0xff)
6706             emit2 ("and a,!immedbyte", mask);
6707           if (litval)
6708             emit2 ("or a,!immedbyte", litval);
6709         }
6710       else
6711         {
6712           /* Case with partial byte and arbitrary source
6713           */
6714           _moveA (aopGet (AOP (right), offset++, FALSE));
6715           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6716
6717           extraPair = getFreePairId(ic);
6718           if (extraPair == PAIR_INVALID)
6719             {
6720               extraPair = getPairId (AOP (right));
6721               if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6722                 extraPair = PAIR_BC;
6723
6724               if (getPairId (AOP (right)) != PAIR_BC
6725                   || !isLastUse (ic, right))
6726                 {
6727                   _push (extraPair);
6728                   needPopExtra = 1;
6729                 }
6730             }
6731           emit2 ("ld %s,a", _pairs[extraPair].l);
6732           emit2 ("ld a,!*pair", _pairs[pair].name);
6733
6734           emit2 ("and a,!immedbyte", mask);
6735           emit2 ("or a,%s", _pairs[extraPair].l);
6736           if (needPopExtra)
6737             _pop (extraPair);
6738
6739         }
6740       emit2 ("ld !*pair,a", _pairs[pair].name);
6741     }
6742 }
6743
6744
6745 /*-----------------------------------------------------------------*/
6746 /* genGenPointerSet - stores the value into a pointer location        */
6747 /*-----------------------------------------------------------------*/
6748 static void
6749 genGenPointerSet (operand * right,
6750                   operand * result, iCode * ic)
6751 {
6752   int size, offset;
6753   sym_link *retype = getSpec (operandType (right));
6754   sym_link *letype = getSpec (operandType (result));
6755   PAIR_ID pairId = PAIR_HL;
6756   bool isBitvar;
6757   
6758   aopOp (result, ic, FALSE, FALSE);
6759   aopOp (right, ic, FALSE, FALSE);
6760
6761   if (IS_GB)
6762     pairId = PAIR_DE;
6763
6764   size = AOP_SIZE (right);
6765
6766   isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6767   emitDebug("; isBitvar = %d", isBitvar);
6768
6769   /* Handle the exceptions first */
6770   if (isPair (AOP (result)) && size == 1 && !isBitvar)
6771     {
6772       /* Just do it */
6773       const char *l = aopGet (AOP (right), 0, FALSE);
6774       const char *pair = getPairName (AOP (result));
6775       if (canAssignToPtr (l) && isPtr (pair))
6776         {
6777           emit2 ("ld !*pair,%s", pair, l);
6778         }
6779       else
6780         {
6781           _moveA (l);
6782           emit2 ("ld !*pair,a", pair);
6783         }
6784       goto release;
6785     }
6786   
6787   if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6788     {
6789       /* Just do it */
6790       const char *l = aopGet (AOP (right), 0, FALSE);
6791
6792       offset = 0;
6793       while (size--) 
6794         {
6795           if (canAssignToPtr (l))
6796             {
6797               emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6798             }
6799           else
6800             {
6801               _moveA (aopGet (AOP (right), offset, FALSE));
6802               emit2 ("ld !*iyx,a", offset);
6803             }
6804           offset++;
6805         }
6806       goto release;
6807     }
6808   else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6809            && !isBitvar)
6810     {
6811       offset = 0;
6812
6813       while (size--)
6814         {
6815           const char *l = aopGet (AOP (right), offset, FALSE);
6816           if (isRegOrLit (AOP (right)) && !IS_GB)
6817             {
6818               emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6819             }
6820           else
6821             {
6822               _moveA (l);
6823               emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6824             }
6825           if (size)
6826             {
6827               emit2 ("inc %s", _pairs[PAIR_HL].name);
6828               _G.pairs[PAIR_HL].offset++;
6829             }
6830           offset++;
6831         }
6832
6833       /* Fixup HL back down */
6834       for (size = AOP_SIZE (right)-1; size; size--)
6835         {
6836           emit2 ("dec %s", _pairs[PAIR_HL].name);
6837         }
6838       goto release;
6839     }
6840
6841   /* if the operand is already in dptr
6842      then we do nothing else we move the value to dptr */
6843   if (AOP_TYPE (result) != AOP_STR)
6844     {
6845       fetchPair (pairId, AOP (result));
6846     }
6847   /* so hl now contains the address */
6848   freeAsmop (result, NULL, ic);
6849
6850   /* if bit then unpack */
6851   if (isBitvar)
6852     {
6853       genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6854       goto release;
6855       //wassert (0);
6856     }
6857   else
6858     {
6859       offset = 0;
6860
6861       while (size--)
6862         {
6863           const char *l = aopGet (AOP (right), offset, FALSE);
6864           if (isRegOrLit (AOP (right)) && !IS_GB)
6865             {
6866               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6867             }
6868           else
6869             {
6870               _moveA (l);
6871               emit2 ("ld !*pair,a", _pairs[pairId].name);
6872             }
6873           if (size)
6874             {
6875               emit2 ("inc %s", _pairs[pairId].name);
6876               _G.pairs[pairId].offset++;
6877             }
6878           offset++;
6879         }
6880     }
6881 release:
6882   freeAsmop (right, NULL, ic);
6883 }
6884
6885 /*-----------------------------------------------------------------*/
6886 /* genPointerSet - stores the value into a pointer location        */
6887 /*-----------------------------------------------------------------*/
6888 static void
6889 genPointerSet (iCode * ic)
6890 {
6891   operand *right, *result;
6892   sym_link *type, *etype;
6893
6894   right = IC_RIGHT (ic);
6895   result = IC_RESULT (ic);
6896
6897   /* depending on the type of pointer we need to
6898      move it to the correct pointer register */
6899   type = operandType (result);
6900   etype = getSpec (type);
6901
6902   genGenPointerSet (right, result, ic);
6903 }
6904
6905 /*-----------------------------------------------------------------*/
6906 /* genIfx - generate code for Ifx statement                        */
6907 /*-----------------------------------------------------------------*/
6908 static void
6909 genIfx (iCode * ic, iCode * popIc)
6910 {
6911   operand *cond = IC_COND (ic);
6912   int isbit = 0;
6913
6914   aopOp (cond, ic, FALSE, TRUE);
6915
6916   /* get the value into acc */
6917   if (AOP_TYPE (cond) != AOP_CRY)
6918     _toBoolean (cond);
6919   else
6920     isbit = 1;
6921   /* the result is now in the accumulator */
6922   freeAsmop (cond, NULL, ic);
6923
6924   /* if there was something to be popped then do it */
6925   if (popIc)
6926     genIpop (popIc);
6927
6928   /* if the condition is  a bit variable */
6929   if (isbit && IS_ITEMP (cond) &&
6930       SPIL_LOC (cond))
6931     genIfxJump (ic, SPIL_LOC (cond)->rname);
6932   else if (isbit && !IS_ITEMP (cond))
6933     genIfxJump (ic, OP_SYMBOL (cond)->rname);
6934   else
6935     genIfxJump (ic, "a");
6936
6937   ic->generated = 1;
6938 }
6939
6940 /*-----------------------------------------------------------------*/
6941 /* genAddrOf - generates code for address of                       */
6942 /*-----------------------------------------------------------------*/
6943 static void
6944 genAddrOf (iCode * ic)
6945 {
6946   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6947
6948   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6949
6950   /* if the operand is on the stack then we
6951      need to get the stack offset of this
6952      variable */
6953   if (IS_GB)
6954     {
6955       if (sym->onStack)
6956         {
6957           spillCached ();
6958           if (sym->stack <= 0)
6959             {
6960               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6961             }
6962           else
6963             {
6964               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6965             }
6966           commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6967         }
6968       else
6969         {
6970           emit2 ("ld de,!hashedstr", sym->rname);
6971           commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6972         }
6973     }
6974   else
6975     {
6976       spillCached ();
6977       if (sym->onStack)
6978         {
6979           /* if it has an offset  then we need to compute it */
6980           if (sym->stack > 0)
6981             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6982           else
6983             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6984           emit2 ("add hl,sp");
6985         }
6986       else
6987         {
6988           emit2 ("ld hl,!hashedstr", sym->rname);
6989         }
6990       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6991     }
6992   freeAsmop (IC_RESULT (ic), NULL, ic);
6993 }
6994
6995 /*-----------------------------------------------------------------*/
6996 /* genAssign - generate code for assignment                        */
6997 /*-----------------------------------------------------------------*/
6998 static void
6999 genAssign (iCode * ic)
7000 {
7001   operand *result, *right;
7002   int size, offset;
7003   unsigned long lit = 0L;
7004
7005   result = IC_RESULT (ic);
7006   right = IC_RIGHT (ic);
7007
7008   /* Dont bother assigning if they are the same */
7009   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7010     {
7011       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7012       return;
7013     }
7014
7015   aopOp (right, ic, FALSE, FALSE);
7016   aopOp (result, ic, TRUE, FALSE);
7017
7018   /* if they are the same registers */
7019   if (sameRegs (AOP (right), AOP (result)))
7020     {
7021       emitDebug ("; (registers are the same)");
7022       goto release;
7023     }
7024
7025   /* if the result is a bit */
7026   if (AOP_TYPE (result) == AOP_CRY)
7027     {
7028       wassertl (0, "Tried to assign to a bit");
7029     }
7030
7031   /* general case */
7032   size = AOP_SIZE (result);
7033   offset = 0;
7034
7035   if (AOP_TYPE (right) == AOP_LIT)
7036     {
7037       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7038     }
7039
7040   if (isPair (AOP (result)))
7041     {
7042       fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7043     }
7044   else if ((size > 1) &&
7045            (AOP_TYPE (result) != AOP_REG) &&
7046            (AOP_TYPE (right) == AOP_LIT) &&
7047            !IS_FLOAT (operandType (right)) &&
7048            (lit < 256L))
7049     {
7050       bool fXored = FALSE;
7051       offset = 0;
7052       /* Work from the top down.
7053          Done this way so that we can use the cached copy of 0
7054          in A for a fast clear */
7055       while (size--)
7056         {
7057           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7058             {
7059               if (!fXored && size > 1)
7060                 {
7061                   emit2 ("xor a,a");
7062                   fXored = TRUE;
7063                 }
7064               if (fXored)
7065                 {
7066                   aopPut (AOP (result), "a", offset);
7067                 }
7068               else
7069                 {
7070                   aopPut (AOP (result), "!zero", offset);
7071                 }
7072             }
7073           else
7074             aopPut (AOP (result),
7075                     aopGet (AOP (right), offset, FALSE),
7076                     offset);
7077           offset++;
7078         }
7079     }
7080   else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7081     {
7082       emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7083       aopPut (AOP (result), "l", LSB);
7084       aopPut (AOP (result), "h", MSB16);
7085     }
7086   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7087     {
7088       /* Special case.  Load into a and d, then load out. */
7089       _moveA (aopGet (AOP (right), 0, FALSE));
7090       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7091       aopPut (AOP (result), "a", 0);
7092       aopPut (AOP (result), "e", 1);
7093     }
7094   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7095     {
7096       /* Special case - simple memcpy */
7097       aopGet (AOP (right), LSB, FALSE);
7098       emit2 ("ld d,h");
7099       emit2 ("ld e,l");
7100       aopGet (AOP (result), LSB, FALSE);
7101
7102       while (size--)
7103         {
7104           emit2 ("ld a,(de)");
7105           /* Peephole will optimise this. */
7106           emit2 ("ld (hl),a");
7107
7108           if (size != 0)
7109             {
7110               emit2 ("inc hl");
7111               emit2 ("inc de");
7112             }
7113         }
7114       spillPair (PAIR_HL);
7115     }
7116   else
7117     {
7118       while (size--)
7119         {
7120           /* PENDING: do this check better */
7121           if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7122             {
7123               _moveA (aopGet (AOP (right), offset, FALSE));
7124               aopPut (AOP (result), "a", offset);
7125             }
7126           else
7127             aopPut (AOP (result),
7128                     aopGet (AOP (right), offset, FALSE),
7129                     offset);
7130           offset++;
7131         }
7132     }
7133
7134 release:
7135   freeAsmop (right, NULL, ic);
7136   freeAsmop (result, NULL, ic);
7137 }
7138
7139 /*-----------------------------------------------------------------*/
7140 /* genJumpTab - genrates code for jump table                       */
7141 /*-----------------------------------------------------------------*/
7142 static void
7143 genJumpTab (iCode * ic)
7144 {
7145   symbol *jtab;
7146   const char *l;
7147
7148   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7149   /* get the condition into accumulator */
7150   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7151   if (!IS_GB)
7152     emit2 ("push de");
7153   emit2 ("ld e,%s", l);
7154   emit2 ("ld d,!zero");
7155   jtab = newiTempLabel (NULL);
7156   spillCached ();
7157   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7158   emit2 ("add hl,de");
7159   emit2 ("add hl,de");
7160   emit2 ("add hl,de");
7161   freeAsmop (IC_JTCOND (ic), NULL, ic);
7162   if (!IS_GB)
7163     emit2 ("pop de");
7164   emit2 ("jp !*hl");
7165   emitLabel (jtab->key + 100);
7166   /* now generate the jump labels */
7167   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7168        jtab = setNextItem (IC_JTLABELS (ic)))
7169     emit2 ("jp !tlabel", jtab->key + 100);
7170 }
7171
7172 /*-----------------------------------------------------------------*/
7173 /* genCast - gen code for casting                                  */
7174 /*-----------------------------------------------------------------*/
7175 static void
7176 genCast (iCode * ic)
7177 {
7178   operand *result = IC_RESULT (ic);
7179   sym_link *rtype = operandType (IC_RIGHT (ic));
7180   operand *right = IC_RIGHT (ic);
7181   int size, offset;
7182
7183   /* if they are equivalent then do nothing */
7184   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7185     return;
7186
7187   aopOp (right, ic, FALSE, FALSE);
7188   aopOp (result, ic, FALSE, FALSE);
7189
7190   /* if the result is a bit */
7191   if (AOP_TYPE (result) == AOP_CRY)
7192     {
7193       wassertl (0, "Tried to cast to a bit");
7194     }
7195
7196   /* if they are the same size : or less */
7197   if (AOP_SIZE (result) <= AOP_SIZE (right))
7198     {
7199
7200       /* if they are in the same place */
7201       if (sameRegs (AOP (right), AOP (result)))
7202         goto release;
7203
7204       /* if they in different places then copy */
7205       size = AOP_SIZE (result);
7206       offset = 0;
7207       while (size--)
7208         {
7209           aopPut (AOP (result),
7210                   aopGet (AOP (right), offset, FALSE),
7211                   offset);
7212           offset++;
7213         }
7214       goto release;
7215     }
7216
7217   /* So we now know that the size of destination is greater
7218      than the size of the source */
7219   /* we move to result for the size of source */
7220   size = AOP_SIZE (right);
7221   offset = 0;
7222   while (size--)
7223     {
7224       aopPut (AOP (result),
7225               aopGet (AOP (right), offset, FALSE),
7226               offset);
7227       offset++;
7228     }
7229
7230   /* now depending on the sign of the destination */
7231   size = AOP_SIZE (result) - AOP_SIZE (right);
7232   /* Unsigned or not an integral type - right fill with zeros */
7233   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7234     {
7235       while (size--)
7236         aopPut (AOP (result), "!zero", offset++);
7237     }
7238   else
7239     {
7240       /* we need to extend the sign :{ */
7241         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7242                         FALSE);
7243       _moveA (l);
7244       emit2 ("rla ");
7245       emit2 ("sbc a,a");
7246       while (size--)
7247         aopPut (AOP (result), "a", offset++);
7248     }
7249
7250 release:
7251   freeAsmop (right, NULL, ic);
7252   freeAsmop (result, NULL, ic);
7253 }
7254
7255 /*-----------------------------------------------------------------*/
7256 /* genReceive - generate code for a receive iCode                  */
7257 /*-----------------------------------------------------------------*/
7258 static void
7259 genReceive (iCode * ic)
7260 {
7261   if (isOperandInFarSpace (IC_RESULT (ic)) &&
7262       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7263        IS_TRUE_SYMOP (IC_RESULT (ic))))
7264     {
7265       wassert (0);
7266     }
7267   else
7268     {
7269         // PENDING: HACK
7270         int size;
7271         int i;
7272
7273         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7274         size = AOP_SIZE(IC_RESULT(ic));
7275
7276         for (i = 0; i < size; i++) {
7277             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7278         }
7279     }
7280
7281   freeAsmop (IC_RESULT (ic), NULL, ic);
7282 }
7283
7284 /*-----------------------------------------------------------------*/
7285 /* genDummyRead - generate code for dummy read of volatiles        */
7286 /*-----------------------------------------------------------------*/
7287 static void
7288 genDummyRead (iCode * ic)
7289 {
7290   operand *op;
7291   int size, offset;
7292
7293   op = IC_RIGHT (ic);
7294   if (op && IS_SYMOP (op))
7295     {
7296       aopOp (op, ic, FALSE, FALSE);
7297   
7298       /* general case */
7299       size = AOP_SIZE (op);
7300       offset = 0;
7301
7302       while (size--)
7303         {
7304           _moveA (aopGet (AOP (op), offset, FALSE));
7305           offset++;
7306         }
7307
7308       freeAsmop (op, NULL, ic);
7309     }
7310   
7311   op = IC_LEFT (ic);
7312   if (op && IS_SYMOP (op))
7313     {
7314       aopOp (op, ic, FALSE, FALSE);
7315   
7316       /* general case */
7317       size = AOP_SIZE (op);
7318       offset = 0;
7319
7320       while (size--)
7321         {
7322           _moveA (aopGet (AOP (op), offset, FALSE));
7323           offset++;
7324         }
7325
7326       freeAsmop (op, NULL, ic);
7327     }
7328 }
7329
7330 enum
7331   {
7332     /** Maximum number of bytes to emit per line. */
7333     DBEMIT_MAX_RUN = 8
7334   };
7335
7336 /** Context for the byte output chunker. */
7337 typedef struct
7338 {
7339   unsigned char buffer[DBEMIT_MAX_RUN];
7340   int pos;
7341 } DBEMITCTX;
7342
7343
7344 /** Flushes a byte chunker by writing out all in the buffer and
7345     reseting. 
7346 */
7347 static void
7348 _dbFlush(DBEMITCTX *self)
7349 {
7350   char line[256];
7351
7352   if (self->pos > 0)
7353     {
7354       int i;
7355       sprintf(line, ".db 0x%02X", self->buffer[0]);
7356
7357       for (i = 1; i < self->pos; i++)
7358         {
7359           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7360         }
7361       emit2(line);
7362     }
7363   self->pos = 0;
7364 }
7365
7366 /** Write out another byte, buffering until a decent line is
7367     generated.
7368 */
7369 static void
7370 _dbEmit(DBEMITCTX *self, int c)
7371 {
7372   if (self->pos == DBEMIT_MAX_RUN)
7373     {
7374       _dbFlush(self);
7375     }
7376   self->buffer[self->pos++] = c;
7377 }
7378
7379 /** Context for a simple run length encoder. */
7380 typedef struct
7381 {
7382   unsigned last;
7383   unsigned char buffer[128];
7384   int pos;
7385   /** runLen may be equivalent to pos. */
7386   int runLen;
7387 } RLECTX;
7388
7389 enum
7390   {
7391     RLE_CHANGE_COST = 4,
7392     RLE_MAX_BLOCK = 127
7393   };
7394
7395 /** Flush the buffer of a run length encoder by writing out the run or
7396     data that it currently contains.
7397 */
7398 static void
7399 _rleCommit(RLECTX *self)
7400 {
7401   int i;
7402   if (self->pos != 0)
7403     {
7404       DBEMITCTX db;
7405       memset(&db, 0, sizeof(db));
7406           
7407       emit2(".db %u", self->pos);
7408       
7409       for (i = 0; i < self->pos; i++)
7410         {
7411           _dbEmit(&db, self->buffer[i]);
7412         }
7413       _dbFlush(&db);
7414     }
7415   /* Reset */
7416   self->pos = 0;
7417 }
7418
7419 /* Encoder design:
7420    Can get either a run or a block of random stuff.
7421    Only want to change state if a good run comes in or a run ends.
7422    Detecting run end is easy.
7423    Initial state?
7424
7425    Say initial state is in run, len zero, last zero.  Then if you get a
7426    few zeros then something else then a short run will be output.
7427    Seems OK.  While in run mode, keep counting.  While in random mode,
7428    keep a count of the run.  If run hits margin, output all up to run,
7429    restart, enter run mode.
7430 */
7431
7432 /** Add another byte into the run length encoder, flushing as
7433     required.  The run length encoder uses the Amiga IFF style, where
7434     a block is prefixed by its run length.  A positive length means
7435     the next n bytes pass straight through.  A negative length means
7436     that the next byte is repeated -n times.  A zero terminates the
7437     chunks.
7438 */
7439 static void
7440 _rleAppend(RLECTX *self, unsigned c)
7441 {
7442   int i;
7443
7444   if (c != self->last)
7445     {
7446       /* The run has stopped.  See if it is worthwhile writing it out
7447          as a run.  Note that the random data comes in as runs of
7448          length one.
7449       */
7450       if (self->runLen > RLE_CHANGE_COST)
7451         {
7452           /* Yes, worthwhile. */
7453           /* Commit whatever was in the buffer. */
7454           _rleCommit(self);
7455           emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7456         }
7457       else
7458         {
7459           /* Not worthwhile.  Append to the end of the random list. */
7460           for (i = 0; i < self->runLen; i++)
7461             {
7462               if (self->pos >= RLE_MAX_BLOCK)
7463                 {
7464                   /* Commit. */
7465                   _rleCommit(self);
7466                 }
7467               self->buffer[self->pos++] = self->last;
7468             }
7469         }
7470       self->runLen = 1;
7471       self->last = c;
7472     }
7473   else
7474     {
7475       if (self->runLen >= RLE_MAX_BLOCK)
7476         {
7477           /* Commit whatever was in the buffer. */
7478           _rleCommit(self);
7479
7480           emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7481           self->runLen = 0;
7482         }
7483       self->runLen++;
7484     }
7485 }
7486
7487 static void
7488 _rleFlush(RLECTX *self)
7489 {
7490   _rleAppend(self, -1);
7491   _rleCommit(self);
7492   self->pos = 0;
7493   self->last = 0;
7494   self->runLen = 0;
7495 }
7496
7497 /** genArrayInit - Special code for initialising an array with constant
7498    data.
7499 */
7500 static void
7501 genArrayInit (iCode * ic)
7502 {
7503   literalList *iLoop;
7504   int         ix;
7505   int         elementSize = 0, eIndex, i;
7506   unsigned    val, lastVal;
7507   sym_link    *type;
7508   RLECTX      rle;
7509
7510   memset(&rle, 0, sizeof(rle));
7511
7512   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7513
7514   _saveRegsForCall(ic, 0);
7515
7516   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7517   emit2 ("call __initrleblock");
7518     
7519   type = operandType(IC_LEFT(ic));
7520     
7521   if (type && type->next)
7522     {
7523       if (IS_SPEC(type->next) || IS_PTR(type->next))
7524         {
7525           elementSize = getSize(type->next);
7526         }
7527       else if (IS_ARRAY(type->next) && type->next->next)
7528         {
7529           elementSize = getSize(type->next->next);
7530         }
7531       else
7532         {
7533           printTypeChainRaw (type, NULL);
7534           wassertl (0, "Can't determine element size in genArrayInit.");
7535         }
7536     }
7537   else
7538     {
7539       wassertl (0, "Can't determine element size in genArrayInit.");
7540     }
7541
7542   wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7543
7544   iLoop = IC_ARRAYILIST(ic);
7545   lastVal = (unsigned)-1;
7546
7547   /* Feed all the bytes into the run length encoder which will handle
7548      the actual output.
7549      This works well for mixed char data, and for random int and long
7550      data.
7551   */
7552   while (iLoop)
7553     {
7554       ix = iLoop->count;
7555
7556       for (i = 0; i < ix; i++)
7557         {
7558           for (eIndex = 0; eIndex < elementSize; eIndex++)
7559             {
7560               val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7561               _rleAppend(&rle, val);
7562             }
7563         }
7564         
7565       iLoop = iLoop->next;
7566     }
7567
7568   _rleFlush(&rle);
7569   /* Mark the end of the run. */
7570   emit2(".db 0");
7571
7572   _restoreRegsAfterCall();
7573
7574   spillCached ();
7575
7576   freeAsmop (IC_LEFT(ic), NULL, ic);
7577 }
7578
7579 static void
7580 _swap (PAIR_ID one, PAIR_ID two)
7581 {
7582   if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7583     {
7584       emit2 ("ex de,hl");
7585     }
7586   else
7587     {
7588       emit2 ("ld a,%s", _pairs[one].l);
7589       emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7590       emit2 ("ld %s,a", _pairs[two].l);
7591       emit2 ("ld a,%s", _pairs[one].h);
7592       emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7593       emit2 ("ld %s,a", _pairs[two].h);
7594     }
7595 }
7596
7597 /* The problem is that we may have all three pairs used and they may
7598    be needed in a different order.
7599
7600    Note: Have ex de,hl
7601
7602    Combinations:
7603      hl = hl            => unity, fine
7604      bc = bc
7605      de = de
7606
7607      hl = hl            hl = hl, swap de <=> bc
7608      bc = de
7609      de = bc
7610
7611      hl = bc            Worst case
7612      bc = de
7613      de = hl
7614      
7615      hl = bc            de = de, swap bc <=> hl
7616      bc = hl
7617      de = de
7618
7619      hl = de            Worst case
7620      bc = hl
7621      de = bc
7622
7623      hl = de            bc = bc, swap hl <=> de
7624      bc = bc
7625      de = hl
7626
7627    Break it down into:
7628     * Any pair = pair are done last
7629     * Any pair = iTemp are done last
7630     * Any swaps can be done any time
7631
7632    A worst case:
7633     push p1
7634     p1 = p2
7635     p2 = p3
7636     pop  p3
7637
7638    So how do we detect the cases?
7639    How about a 3x3 matrix?
7640         source
7641    dest x x x x
7642         x x x x
7643         x x x x (Fourth for iTemp/other)
7644
7645    First determin which mode to use by counting the number of unity and
7646    iTemp assigns.
7647      Three - any order
7648      Two - Assign the pair first, then the rest
7649      One - Swap the two, then the rest
7650      Zero - Worst case.
7651 */
7652 static void
7653 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7654 {
7655   PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7656   PAIR_ID dest[3] = {
7657     PAIR_BC, PAIR_HL, PAIR_DE
7658   };
7659   int i, j, nunity = 0;
7660   memset (ids, PAIR_INVALID, sizeof (ids));
7661
7662   /* Sanity checks */
7663   wassert (nparams == 3);
7664
7665   /* First save everything that needs to be saved. */
7666   _saveRegsForCall (ic, 0);
7667
7668   /* Loading HL first means that DE is always fine. */
7669   for (i = 0; i < nparams; i++)
7670     {
7671       aopOp (pparams[i], ic, FALSE, FALSE);
7672       ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7673     }
7674
7675   /* Count the number of unity or iTemp assigns. */
7676   for (i = 0; i < 3; i++) 
7677     {
7678       if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7679         {
7680           nunity++;
7681         }
7682     }
7683
7684   if (nunity == 3)
7685     {
7686       /* Any order, fall through. */
7687     }
7688   else if (nunity == 2)
7689     {
7690       /* One is assigned.  Pull it out and assign. */
7691       for (i = 0; i < 3; i++)
7692         {
7693           for (j = 0; j < NUM_PAIRS; j++)
7694             {
7695               if (ids[dest[i]][j] == TRUE)
7696                 {
7697                   /* Found it.  See if it's the right one. */
7698                   if (j == PAIR_INVALID || j == dest[i])
7699                     {
7700                       /* Keep looking. */
7701                     }
7702                   else
7703                     {
7704                       fetchPair(dest[i], AOP (pparams[i]));
7705                       goto done;
7706                     }
7707                 }
7708             }
7709         }
7710     }
7711   else if (nunity == 1)
7712     {
7713       /* Find the pairs to swap. */
7714       for (i = 0; i < 3; i++)
7715         {
7716           for (j = 0; j < NUM_PAIRS; j++)
7717             {
7718               if (ids[dest[i]][j] == TRUE)
7719                 {
7720                   if (j == PAIR_INVALID || j == dest[i])
7721                     {
7722                       /* Keep looking. */
7723                     }
7724                   else
7725                     {
7726                       _swap (j, dest[i]);
7727                       goto done;
7728                     }
7729                 }
7730             }
7731         }
7732     }
7733   else
7734     {
7735       int next = getPairId (AOP (pparams[0]));
7736       emit2 ("push %s", _pairs[next].name);
7737
7738       if (next == dest[1])
7739         {
7740           fetchPair (dest[1], AOP (pparams[1]));
7741           fetchPair (dest[2], AOP (pparams[2]));
7742         }
7743       else
7744         {
7745           fetchPair (dest[2], AOP (pparams[2]));
7746           fetchPair (dest[1], AOP (pparams[1]));
7747         }
7748       emit2 ("pop %s", _pairs[dest[0]].name);
7749     }
7750  done:
7751   /* Finally pull out all of the iTemps */
7752   for (i = 0; i < 3; i++)
7753     {
7754       if (ids[dest[i]][PAIR_INVALID] == 1)
7755         {
7756           fetchPair (dest[i], AOP (pparams[i]));
7757         }
7758     }
7759 }
7760
7761 static void
7762 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7763 {
7764   operand *from, *to;
7765   symbol *label;
7766   bool deInUse;
7767
7768   wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7769   to = pparams[0];
7770   from = pparams[1];
7771
7772   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7773
7774   setupForBuiltin3 (ic, nParams, pparams);
7775
7776   label = newiTempLabel(NULL);
7777
7778   emitLabel (label->key);
7779   emit2 ("ld a,(hl)");
7780   emit2 ("ldi");
7781   emit2 ("or a");
7782   emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7783
7784   freeAsmop (from, NULL, ic->next);
7785   freeAsmop (to, NULL, ic);
7786 }
7787
7788 static void
7789 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7790 {
7791   operand *from, *to, *count;
7792   bool deInUse;
7793
7794   wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7795   to = pparams[2];
7796   from = pparams[1];
7797   count = pparams[0];
7798
7799   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7800
7801   setupForBuiltin3 (ic, nParams, pparams);
7802
7803   emit2 ("ldir");
7804
7805   freeAsmop (count, NULL, ic->next->next);
7806   freeAsmop (from, NULL, ic);
7807
7808   _restoreRegsAfterCall();
7809
7810   /* if we need assign a result value */
7811   if ((IS_ITEMP (IC_RESULT (ic)) &&
7812        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7813         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7814       IS_TRUE_SYMOP (IC_RESULT (ic)))
7815     {
7816       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7817       movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7818       freeAsmop (IC_RESULT (ic), NULL, ic);
7819     }
7820
7821   freeAsmop (to, NULL, ic->next);
7822 }
7823
7824 /*-----------------------------------------------------------------*/
7825 /* genBuiltIn - calls the appropriate function to  generating code */
7826 /* for a built in function                                         */
7827 /*-----------------------------------------------------------------*/
7828 static void genBuiltIn (iCode *ic)
7829 {
7830     operand *bi_parms[MAX_BUILTIN_ARGS];
7831     int nbi_parms;
7832     iCode *bi_iCode;
7833     symbol *bif;
7834
7835     /* get all the arguments for a built in function */
7836     bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7837
7838     /* which function is it */
7839     bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7840
7841     if (strcmp(bif->name,"__builtin_strcpy")==0) 
7842       {
7843         genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7844       } 
7845     else if (strcmp(bif->name,"__builtin_memcpy")==0) 
7846       {
7847         genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7848       } 
7849     else 
7850       {
7851         wassertl (0, "Unknown builtin function encountered");
7852       }
7853 }
7854
7855 /*-----------------------------------------------------------------*/
7856 /* genZ80Code - generate code for Z80 based controllers            */
7857 /*-----------------------------------------------------------------*/
7858 void
7859 genZ80Code (iCode * lic)
7860 {
7861   iCode *ic;
7862   int cln = 0;
7863
7864   /* Hack */
7865   if (IS_GB)
7866     {
7867       _fReturn = _gbz80_return;
7868       _fTmp = _gbz80_return;
7869     }
7870   else
7871     {
7872       _fReturn = _z80_return;
7873       _fTmp = _z80_return;
7874     }
7875
7876   _G.lines.head = _G.lines.current = NULL;
7877   
7878   /* if debug information required */
7879   if (options.debug && currFunc)
7880     {
7881       debugFile->writeFunction (currFunc, lic);
7882     }
7883
7884   for (ic = lic; ic; ic = ic->next)
7885     {
7886       _G.current_iCode = ic;
7887
7888       if (ic->lineno && cln != ic->lineno)
7889         {
7890           if (options.debug)
7891             {
7892               debugFile->writeCLine (ic);
7893             }
7894           if (!options.noCcodeInAsm) {
7895             emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7896                    printCLine(ic->filename, ic->lineno));
7897           }
7898           cln = ic->lineno;
7899         }
7900       if (options.iCodeInAsm) {
7901         emit2 (";ic:%d: %s", ic->key, printILine(ic));
7902       }
7903       /* if the result is marked as
7904          spilt and rematerializable or code for
7905          this has already been generated then
7906          do nothing */
7907       if (resultRemat (ic) || ic->generated)
7908         continue;
7909
7910       /* depending on the operation */
7911       switch (ic->op)
7912         {
7913         case '!':
7914           emitDebug ("; genNot");
7915           genNot (ic);
7916           break;
7917
7918         case '~':
7919           emitDebug ("; genCpl");
7920           genCpl (ic);
7921           break;
7922
7923         case UNARYMINUS:
7924           emitDebug ("; genUminus");
7925           genUminus (ic);
7926           break;
7927
7928         case IPUSH:
7929           emitDebug ("; genIpush");
7930           genIpush (ic);
7931           break;
7932
7933         case IPOP:
7934           /* IPOP happens only when trying to restore a
7935              spilt live range, if there is an ifx statement
7936              following this pop then the if statement might
7937              be using some of the registers being popped which
7938              would destory the contents of the register so
7939              we need to check for this condition and handle it */
7940           if (ic->next &&
7941               ic->next->op == IFX &&
7942               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7943             {
7944               emitDebug ("; genIfx");
7945               genIfx (ic->next, ic);
7946             }
7947           else
7948             {
7949               emitDebug ("; genIpop");
7950               genIpop (ic);
7951             }
7952           break;
7953
7954         case CALL:
7955           emitDebug ("; genCall");
7956           genCall (ic);
7957           break;
7958
7959         case PCALL:
7960           emitDebug ("; genPcall");
7961           genPcall (ic);
7962           break;
7963
7964         case FUNCTION:
7965           emitDebug ("; genFunction");
7966           genFunction (ic);
7967           break;
7968
7969         case ENDFUNCTION:
7970           emitDebug ("; genEndFunction");
7971           genEndFunction (ic);
7972           break;
7973
7974         case RETURN:
7975           emitDebug ("; genRet");
7976           genRet (ic);
7977           break;
7978
7979         case LABEL:
7980           emitDebug ("; genLabel");
7981           genLabel (ic);
7982           break;
7983
7984         case GOTO:
7985           emitDebug ("; genGoto");
7986           genGoto (ic);
7987           break;
7988
7989         case '+':
7990           emitDebug ("; genPlus");
7991           genPlus (ic);
7992           break;
7993
7994         case '-':
7995           emitDebug ("; genMinus");
7996           genMinus (ic);
7997           break;
7998
7999         case '*':
8000           emitDebug ("; genMult");
8001           genMult (ic);
8002           break;
8003
8004         case '/':
8005           emitDebug ("; genDiv");
8006           genDiv (ic);
8007           break;
8008
8009         case '%':
8010           emitDebug ("; genMod");
8011           genMod (ic);
8012           break;
8013
8014         case '>':
8015           emitDebug ("; genCmpGt");
8016           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8017           break;
8018
8019         case '<':
8020           emitDebug ("; genCmpLt");
8021           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8022           break;
8023
8024         case LE_OP:
8025         case GE_OP:
8026         case NE_OP:
8027
8028           /* note these two are xlated by algebraic equivalence
8029              during parsing SDCC.y */
8030           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8031                   "got '>=' or '<=' shouldn't have come here");
8032           break;
8033
8034         case EQ_OP:
8035           emitDebug ("; genCmpEq");
8036           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8037           break;
8038
8039         case AND_OP:
8040           emitDebug ("; genAndOp");
8041           genAndOp (ic);
8042           break;
8043
8044         case OR_OP:
8045           emitDebug ("; genOrOp");
8046           genOrOp (ic);
8047           break;
8048
8049         case '^':
8050           emitDebug ("; genXor");
8051           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8052           break;
8053
8054         case '|':
8055           emitDebug ("; genOr");
8056           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8057           break;
8058
8059         case BITWISEAND:
8060           emitDebug ("; genAnd");
8061           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8062           break;
8063
8064         case INLINEASM:
8065           emitDebug ("; genInline");
8066           genInline (ic);
8067           break;
8068
8069         case RRC:
8070           emitDebug ("; genRRC");
8071           genRRC (ic);
8072           break;
8073
8074         case RLC:
8075           emitDebug ("; genRLC");
8076           genRLC (ic);
8077           break;
8078
8079         case GETHBIT:
8080           emitDebug ("; genGetHBIT");
8081           genGetHbit (ic);
8082           break;
8083
8084         case LEFT_OP:
8085           emitDebug ("; genLeftShift");
8086           genLeftShift (ic);
8087           break;
8088
8089         case RIGHT_OP:
8090           emitDebug ("; genRightShift");
8091           genRightShift (ic);
8092           break;
8093
8094         case GET_VALUE_AT_ADDRESS:
8095           emitDebug ("; genPointerGet");
8096           genPointerGet (ic);
8097           break;
8098
8099         case '=':
8100
8101           if (POINTER_SET (ic))
8102             {
8103               emitDebug ("; genAssign (pointer)");
8104               genPointerSet (ic);
8105             }
8106           else
8107             {
8108               emitDebug ("; genAssign");
8109               genAssign (ic);
8110             }
8111           break;
8112
8113         case IFX:
8114           emitDebug ("; genIfx");
8115           genIfx (ic, NULL);
8116           break;
8117
8118         case ADDRESS_OF:
8119           emitDebug ("; genAddrOf");
8120           genAddrOf (ic);
8121           break;
8122
8123         case JUMPTABLE:
8124           emitDebug ("; genJumpTab");
8125           genJumpTab (ic);
8126           break;
8127
8128         case CAST:
8129           emitDebug ("; genCast");
8130           genCast (ic);
8131           break;
8132
8133         case RECEIVE:
8134           emitDebug ("; genReceive");
8135           genReceive (ic);
8136           break;
8137
8138         case SEND:
8139           if (ic->builtinSEND)
8140             {
8141               emitDebug ("; genBuiltIn");
8142               genBuiltIn(ic);
8143             }
8144           else
8145             {
8146               emitDebug ("; addSet");
8147               addSet (&_G.sendSet, ic);
8148             }
8149           break;
8150
8151         case ARRAYINIT:
8152           emitDebug ("; genArrayInit");
8153           genArrayInit(ic);
8154           break;
8155
8156         case DUMMY_READ_VOLATILE:
8157           emitDebug ("; genDummyRead");
8158           genDummyRead (ic);
8159           break;
8160
8161         default:
8162           ic = ic;
8163         }
8164     }
8165
8166
8167   /* now we are ready to call the
8168      peep hole optimizer */
8169   if (!options.nopeep)
8170     peepHole (&_G.lines.head);
8171
8172   /* This is unfortunate */
8173   /* now do the actual printing */
8174   {
8175     FILE *fp = codeOutFile;
8176     if (isInHome () && codeOutFile == code->oFile)
8177       codeOutFile = home->oFile;
8178     printLine (_G.lines.head, codeOutFile);
8179     if (_G.flushStatics)
8180       {
8181         flushStatics ();
8182         _G.flushStatics = 0;
8183       }
8184     codeOutFile = fp;
8185   }
8186
8187   freeTrace(&_G.lines.trace);
8188   freeTrace(&_G.trace.aops);
8189 }
8190
8191 /*
8192   Attic
8193 static int
8194 _isPairUsed (iCode * ic, PAIR_ID pairId)
8195 {
8196   int ret = 0;
8197   switch (pairId)
8198     {
8199     case PAIR_DE:
8200       if (bitVectBitValue (ic->rMask, D_IDX))
8201         ret++;
8202       if (bitVectBitValue (ic->rMask, E_IDX))
8203         ret++;
8204       break;
8205     default:
8206       wassert (0);
8207     }
8208   return ret;
8209 }
8210
8211 static char *
8212 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8213 {
8214   unsigned long v;
8215   value *val = aop->aopu.aop_lit;
8216
8217   wassert (aop->type == AOP_LIT);
8218   wassert (!IS_FLOAT (val->type));
8219
8220   v = (unsigned long) floatFromVal (val);
8221
8222   if (xor)
8223     v ^= 0x8000;
8224   if (negate)
8225     v = 0-v;
8226   v &= 0xFFFF;
8227
8228   tsprintf (buffer, sizeof(buffer), "!immedword", v);
8229   return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
8230 }
8231
8232
8233 */