* src/z80/gen.c (genLeftShift, genRightShift): fixed second part of
[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   if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6047      _push (PAIR_AF);
6048   
6049   /* now move the left to the result if they are not the
6050      same */
6051
6052   if (!sameRegs (AOP (left), AOP (result)))
6053     {
6054
6055       size = AOP_SIZE (result);
6056       offset = 0;
6057       while (size--)
6058         {
6059           l = aopGet (AOP (left), offset, FALSE);
6060           aopPut (AOP (result), l, offset);
6061           offset++;
6062         }
6063     }
6064
6065   tlbl = newiTempLabel (NULL);
6066   size = AOP_SIZE (result);
6067   offset = 0;
6068   tlbl1 = newiTempLabel (NULL);
6069
6070   if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6071      _pop (PAIR_AF);
6072   
6073   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6074   emitLabel (tlbl->key + 100);
6075   l = aopGet (AOP (result), offset, FALSE);
6076
6077   while (size--)
6078     {
6079       l = aopGet (AOP (result), offset, FALSE);
6080
6081       if (offset == 0)
6082         {
6083           emit2 ("sla %s", l);
6084         }
6085       else
6086         {
6087           emit2 ("rl %s", l);
6088         }
6089       offset++;
6090     }
6091   emitLabel (tlbl1->key + 100);
6092   emit2 ("dec a");
6093   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6094
6095   freeAsmop (left, NULL, ic);
6096   freeAsmop (result, NULL, ic);
6097 }
6098
6099 /*-----------------------------------------------------------------*/
6100 /* genrshOne - left shift two bytes by known amount != 0           */
6101 /*-----------------------------------------------------------------*/
6102 static void
6103 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6104 {
6105   /* Errk */
6106   int size = AOP_SIZE (result);
6107   const char *l;
6108
6109   wassert (size == 1);
6110   wassert (shCount < 8);
6111
6112   l = aopGet (AOP (left), 0, FALSE);
6113
6114   if (AOP (result)->type == AOP_REG)
6115     {
6116       aopPut (AOP (result), l, 0);
6117       l = aopGet (AOP (result), 0, FALSE);
6118       while (shCount--)
6119         {
6120           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6121         }
6122     }
6123   else
6124     {
6125       _moveA (l);
6126       while (shCount--)
6127         {
6128           emit2 ("%s a", is_signed ? "sra" : "srl");
6129         }
6130       aopPut (AOP (result), "a", 0);
6131     }
6132 }
6133
6134 /*-----------------------------------------------------------------*/
6135 /* AccRsh - right shift accumulator by known count                 */
6136 /*-----------------------------------------------------------------*/
6137 static void
6138 AccRsh (int shCount)
6139 {
6140   static const unsigned char SRMask[] =
6141     {
6142       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6143     };
6144
6145   if (shCount != 0)
6146     {
6147       /* rotate right accumulator */
6148       AccRol (8 - shCount);
6149       /* and kill the higher order bits */
6150       emit2 ("and a,!immedbyte", SRMask[shCount]);
6151     }
6152 }
6153
6154 /*-----------------------------------------------------------------*/
6155 /* shiftR1Left2Result - shift right one byte from left to result   */
6156 /*-----------------------------------------------------------------*/
6157 static void
6158 shiftR1Left2Result (operand * left, int offl,
6159                     operand * result, int offr,
6160                     int shCount, int sign)
6161 {
6162   _moveA (aopGet (AOP (left), offl, FALSE));
6163   if (sign)
6164     {
6165       while (shCount--)
6166         {
6167           emit2 ("%s a", sign ? "sra" : "srl");
6168         }
6169     }
6170   else
6171     {
6172       AccRsh (shCount);
6173     }
6174   aopPut (AOP (result), "a", offr);
6175 }
6176
6177 /*-----------------------------------------------------------------*/
6178 /* genrshTwo - right shift two bytes by known amount != 0          */
6179 /*-----------------------------------------------------------------*/
6180 static void
6181 genrshTwo (operand * result, operand * left,
6182            int shCount, int sign)
6183 {
6184   /* if shCount >= 8 */
6185   if (shCount >= 8)
6186     {
6187       shCount -= 8;
6188       if (shCount)
6189         {
6190           shiftR1Left2Result (left, MSB16, result, LSB,
6191                               shCount, sign);
6192         }
6193       else
6194         {
6195           movLeft2Result (left, MSB16, result, LSB, sign);
6196         }
6197       if (sign)
6198         {
6199           /* Sign extend the result */
6200           _moveA(aopGet (AOP (result), 0, FALSE));
6201           emit2 ("rlc a");
6202           emit2 ("sbc a,a");
6203
6204           aopPut (AOP (result), ACC_NAME, MSB16);
6205         }
6206       else
6207         {
6208           aopPut (AOP (result), "!zero", 1);
6209         }
6210     }
6211   /*  1 <= shCount <= 7 */
6212   else
6213     {
6214       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6215     }
6216 }
6217
6218 /*-----------------------------------------------------------------*/
6219 /* genRightShiftLiteral - left shifting by known count              */
6220 /*-----------------------------------------------------------------*/
6221 static void
6222 genRightShiftLiteral (operand * left,
6223                       operand * right,
6224                       operand * result,
6225                       iCode * ic,
6226                       int sign)
6227 {
6228   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6229   int size;
6230
6231   freeAsmop (right, NULL, ic);
6232
6233   aopOp (left, ic, FALSE, FALSE);
6234   aopOp (result, ic, FALSE, FALSE);
6235
6236   size = getSize (operandType (result));
6237
6238   /* I suppose that the left size >= result size */
6239   if (shCount == 0)
6240     {
6241       wassert (0);
6242     }
6243
6244   else if (shCount >= (size * 8)) {
6245     const char *s;
6246     if (!SPEC_USIGN(getSpec(operandType(left)))) {
6247       _moveA(aopGet (AOP (left), 0, FALSE));
6248       emit2 ("rlc a");
6249       emit2 ("sbc a,a");
6250       s=ACC_NAME;
6251     } else {
6252       s="!zero";
6253     }
6254     while (size--)
6255       aopPut (AOP (result), s, size);
6256   }
6257   else
6258     {
6259       switch (size)
6260         {
6261         case 1:
6262           genrshOne (result, left, shCount, sign);
6263           break;
6264         case 2:
6265           genrshTwo (result, left, shCount, sign);
6266           break;
6267         case 4:
6268           wassertl (0, "Asked to shift right a long which should be a function call");
6269           break;
6270         default:
6271           wassertl (0, "Entered default case in right shift delegate");
6272         }
6273     }
6274   freeAsmop (left, NULL, ic);
6275   freeAsmop (result, NULL, ic);
6276 }
6277
6278 /*-----------------------------------------------------------------*/
6279 /* genRightShift - generate code for right shifting                */
6280 /*-----------------------------------------------------------------*/
6281 static void
6282 genRightShift (iCode * ic)
6283 {
6284   operand *right, *left, *result;
6285   sym_link *retype;
6286   int size, offset, first = 1;
6287   const char *l;
6288   bool is_signed;
6289
6290   symbol *tlbl, *tlbl1;
6291
6292   /* if signed then we do it the hard way preserve the
6293      sign bit moving it inwards */
6294   retype = getSpec (operandType (IC_RESULT (ic)));
6295
6296   is_signed = !SPEC_USIGN (retype);
6297
6298   /* signed & unsigned types are treated the same : i.e. the
6299      signed is NOT propagated inwards : quoting from the
6300      ANSI - standard : "for E1 >> E2, is equivalent to division
6301      by 2**E2 if unsigned or if it has a non-negative value,
6302      otherwise the result is implementation defined ", MY definition
6303      is that the sign does not get propagated */
6304
6305   right = IC_RIGHT (ic);
6306   left = IC_LEFT (ic);
6307   result = IC_RESULT (ic);
6308
6309   aopOp (right, ic, FALSE, FALSE);
6310
6311   /* if the shift count is known then do it
6312      as efficiently as possible */
6313   if (AOP_TYPE (right) == AOP_LIT)
6314     {
6315       genRightShiftLiteral (left, right, result, ic, is_signed);
6316       return;
6317     }
6318
6319   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6320   emit2 ("inc a");
6321   freeAsmop (right, NULL, ic);
6322
6323   aopOp (left, ic, FALSE, FALSE);
6324   aopOp (result, ic, FALSE, FALSE);
6325
6326   if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6327      _push (PAIR_AF);
6328   
6329   /* now move the left to the result if they are not the
6330      same */
6331   if (!sameRegs (AOP (left), AOP (result)))
6332     {
6333
6334       size = AOP_SIZE (result);
6335       offset = 0;
6336       while (size--)
6337         {
6338           l = aopGet (AOP (left), offset, FALSE);
6339           aopPut (AOP (result), l, offset);
6340           offset++;
6341         }
6342     }
6343
6344   tlbl = newiTempLabel (NULL);
6345   tlbl1 = newiTempLabel (NULL);
6346   size = AOP_SIZE (result);
6347   offset = size - 1;
6348   
6349   if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
6350      _pop (PAIR_AF);
6351
6352   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6353   emitLabel (tlbl->key + 100);
6354   while (size--)
6355     {
6356       l = aopGet (AOP (result), offset--, FALSE);
6357       if (first)
6358         {
6359           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6360           first = 0;
6361         }
6362       else
6363         {
6364           emit2 ("rr %s", l);
6365         }
6366     }
6367   emitLabel (tlbl1->key + 100);
6368   emit2 ("dec a");
6369   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6370
6371   freeAsmop (left, NULL, ic);
6372   freeAsmop (result, NULL, ic);
6373 }
6374
6375
6376 /*-----------------------------------------------------------------*/
6377 /* genUnpackBits - generates code for unpacking bits               */
6378 /*-----------------------------------------------------------------*/
6379 static void
6380 genUnpackBits (operand * result, int pair)
6381 {
6382   int offset = 0;       /* result byte offset */
6383   int rsize;            /* result size */
6384   int rlen = 0;         /* remaining bitfield length */
6385   sym_link *etype;      /* bitfield type information */
6386   int blen;             /* bitfield length */
6387   int bstr;             /* bitfield starting bit within byte */
6388
6389   emitDebug ("; genUnpackBits");
6390
6391   etype = getSpec (operandType (result));
6392   rsize = getSize (operandType (result));
6393   blen = SPEC_BLEN (etype);
6394   bstr = SPEC_BSTR (etype);
6395
6396   /* If the bitfield length is less than a byte */
6397   if (blen < 8)
6398     {
6399       emit2 ("ld a,!*pair", _pairs[pair].name);
6400       AccRsh (bstr);
6401       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6402       aopPut (AOP (result), "a", offset++);
6403       goto finish;
6404     }
6405
6406   /* TODO: what if pair == PAIR_DE ? */
6407   if (getPairId (AOP (result)) == PAIR_HL)
6408     {
6409       wassertl (rsize == 2, "HL must be of size 2");
6410       emit2 ("ld a,!*hl");
6411       emit2 ("inc hl");
6412       emit2 ("ld h,!*hl");
6413       emit2 ("ld l,a");
6414       emit2 ("ld a,h");
6415       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6416       emit2 ("ld h,a");
6417       spillPair (PAIR_HL);
6418       return;
6419     }
6420
6421   /* Bit field did not fit in a byte. Copy all
6422      but the partial byte at the end.  */
6423   for (rlen=blen;rlen>=8;rlen-=8)
6424     {
6425       emit2 ("ld a,!*pair", _pairs[pair].name);
6426       aopPut (AOP (result), "a", offset++);
6427       if (rlen>8)
6428         {
6429           emit2 ("inc %s", _pairs[pair].name);
6430           _G.pairs[pair].offset++;
6431         }
6432     }
6433
6434   /* Handle the partial byte at the end */
6435   if (rlen)
6436     {
6437       emit2 ("ld a,!*pair", _pairs[pair].name);
6438       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6439       aopPut (AOP (result), "a", offset++);
6440     }
6441
6442 finish:
6443   if (offset < rsize)
6444     {
6445       rsize -= offset;
6446       while (rsize--)
6447         aopPut (AOP (result), "!zero", offset++);
6448     }
6449 }
6450
6451 /*-----------------------------------------------------------------*/
6452 /* genGenPointerGet -  get value from generic pointer space        */
6453 /*-----------------------------------------------------------------*/
6454 static void
6455 genGenPointerGet (operand * left,
6456                   operand * result, iCode * ic)
6457 {
6458   int size, offset;
6459   sym_link *retype = getSpec (operandType (result));
6460   int pair = PAIR_HL;
6461
6462   if (IS_GB)
6463     pair = PAIR_DE;
6464
6465   aopOp (left, ic, FALSE, FALSE);
6466   aopOp (result, ic, FALSE, FALSE);
6467
6468   size = AOP_SIZE (result);
6469
6470   if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6471     {
6472       /* Just do it */
6473       if (isPtrPair (AOP (left)))
6474         {
6475           tsprintf (buffer, sizeof(buffer), 
6476                     "!*pair", getPairName (AOP (left)));
6477           aopPut (AOP (result), buffer, 0);
6478         }
6479       else
6480         {
6481           emit2 ("ld a,!*pair", getPairName (AOP (left)));
6482           aopPut (AOP (result), "a", 0);
6483         }
6484       freeAsmop (left, NULL, ic);
6485       goto release;
6486     }
6487
6488   if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6489     {
6490       /* Just do it */
6491       offset = 0;
6492       while (size--) 
6493         {
6494           char at[20];
6495           tsprintf (at, sizeof(at), "!*iyx", offset);
6496           aopPut (AOP (result), at, offset);
6497           offset++;
6498         }
6499  
6500       freeAsmop (left, NULL, ic);
6501       goto release;
6502     }
6503
6504   /* For now we always load into IY */
6505   /* if this is remateriazable */
6506   fetchPair (pair, AOP (left));
6507
6508   /* if bit then unpack */
6509   if (IS_BITVAR (retype))
6510     {
6511       genUnpackBits (result, pair);
6512       freeAsmop (left, NULL, ic);
6513       goto release;
6514       //wassert (0);
6515     }
6516   else if (getPairId (AOP (result)) == PAIR_HL)
6517     {
6518       wassertl (size == 2, "HL must be of size 2");
6519       emit2 ("ld a,!*hl");
6520       emit2 ("inc hl");
6521       emit2 ("ld h,!*hl");
6522       emit2 ("ld l,a");
6523       spillPair (PAIR_HL);
6524     }
6525   else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6526     {
6527       size = AOP_SIZE (result);
6528       offset = 0;
6529
6530       while (size--)
6531         {
6532           /* PENDING: make this better */
6533           if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6534             {
6535               aopPut (AOP (result), "!*hl", offset++);
6536             }
6537           else
6538             {
6539               emit2 ("ld a,!*pair", _pairs[pair].name);
6540               aopPut (AOP (result), "a", offset++);
6541             }
6542           if (size)
6543             {
6544               emit2 ("inc %s", _pairs[pair].name);
6545               _G.pairs[pair].offset++;
6546             }
6547         }
6548       /* Fixup HL back down */
6549       for (size = AOP_SIZE (result)-1; size; size--)
6550         {
6551           emit2 ("dec %s", _pairs[pair].name);
6552         }
6553     }
6554   else
6555     {
6556       size = AOP_SIZE (result);
6557       offset = 0;
6558
6559       while (size--)
6560         {
6561           /* PENDING: make this better */
6562           if (!IS_GB && 
6563               (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6564             {
6565               aopPut (AOP (result), "!*hl", offset++);
6566             }
6567           else
6568             {
6569               emit2 ("ld a,!*pair", _pairs[pair].name);
6570               aopPut (AOP (result), "a", offset++);
6571             }
6572           if (size)
6573             {
6574               emit2 ("inc %s", _pairs[pair].name);
6575               _G.pairs[pair].offset++;
6576             }
6577         }
6578     }
6579
6580   freeAsmop (left, NULL, ic);
6581
6582 release:
6583   freeAsmop (result, NULL, ic);
6584 }
6585
6586 /*-----------------------------------------------------------------*/
6587 /* genPointerGet - generate code for pointer get                   */
6588 /*-----------------------------------------------------------------*/
6589 static void
6590 genPointerGet (iCode * ic)
6591 {
6592   operand *left, *result;
6593   sym_link *type, *etype;
6594
6595   left = IC_LEFT (ic);
6596   result = IC_RESULT (ic);
6597
6598   /* depending on the type of pointer we need to
6599      move it to the correct pointer register */
6600   type = operandType (left);
6601   etype = getSpec (type);
6602
6603   genGenPointerGet (left, result, ic);
6604 }
6605
6606 bool
6607 isRegOrLit (asmop * aop)
6608 {
6609   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6610     return TRUE;
6611   return FALSE;
6612 }
6613
6614
6615 /*-----------------------------------------------------------------*/
6616 /* genPackBits - generates code for packed bit storage             */
6617 /*-----------------------------------------------------------------*/
6618 static void
6619 genPackBits (sym_link * etype,
6620              operand * right,
6621              int pair,
6622              iCode *ic)
6623 {
6624   int offset = 0;       /* source byte offset */
6625   int rlen = 0;         /* remaining bitfield length */
6626   int blen;             /* bitfield length */
6627   int bstr;             /* bitfield starting bit within byte */
6628   int litval;           /* source literal value (if AOP_LIT) */
6629   unsigned char mask;   /* bitmask within current byte */
6630   int extraPair;        /* a tempory register */
6631   bool needPopExtra=0;  /* need to restore original value of temp reg */
6632
6633   emitDebug (";     genPackBits","");
6634
6635   blen = SPEC_BLEN (etype);
6636   bstr = SPEC_BSTR (etype);
6637
6638   /* If the bitfield length is less than a byte */
6639   if (blen < 8)
6640     {
6641       mask = ((unsigned char) (0xFF << (blen + bstr)) |
6642               (unsigned char) (0xFF >> (8 - bstr)));
6643
6644       if (AOP_TYPE (right) == AOP_LIT)
6645         {
6646           /* Case with a bitfield length <8 and literal source
6647           */
6648           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6649           litval <<= bstr;
6650           litval &= (~mask) & 0xff;
6651           emit2 ("ld a,!*pair", _pairs[pair].name);
6652           if ((mask|litval)!=0xff)
6653             emit2 ("and a,!immedbyte", mask);
6654           if (litval)
6655             emit2 ("or a,!immedbyte", litval);
6656           emit2 ("ld !*pair,a", _pairs[pair].name);
6657           return;
6658         }
6659       else
6660         {
6661           /* Case with a bitfield length <8 and arbitrary source
6662           */
6663           _moveA (aopGet (AOP (right), 0, FALSE));
6664           /* shift and mask source value */
6665           AccLsh (bstr);
6666           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6667
6668           extraPair = getFreePairId(ic);
6669           if (extraPair == PAIR_INVALID)
6670             {
6671               extraPair = PAIR_BC;
6672               if (getPairId (AOP (right)) != PAIR_BC
6673                   || !isLastUse (ic, right))
6674                 {
6675                   _push (extraPair);
6676                   needPopExtra = 1;
6677                 }
6678             }
6679           emit2 ("ld %s,a", _pairs[extraPair].l);
6680           emit2 ("ld a,!*pair", _pairs[pair].name);
6681
6682           emit2 ("and a,!immedbyte", mask);
6683           emit2 ("or a,%s", _pairs[extraPair].l);
6684           emit2 ("ld !*pair,a", _pairs[pair].name);
6685           if (needPopExtra)
6686             _pop (extraPair);
6687           return;
6688         }
6689     }
6690
6691   /* Bit length is greater than 7 bits. In this case, copy  */
6692   /* all except the partial byte at the end                 */
6693   for (rlen=blen;rlen>=8;rlen-=8)
6694     {
6695       emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6696       emit2 ("ld !*pair,a", _pairs[pair].name);
6697       if (rlen>8)
6698         {
6699           emit2 ("inc %s", _pairs[pair].name);
6700           _G.pairs[pair].offset++;
6701         }
6702     }
6703
6704   /* If there was a partial byte at the end */
6705   if (rlen)
6706     {
6707       mask = (((unsigned char) -1 << rlen) & 0xff);
6708       
6709       if (AOP_TYPE (right) == AOP_LIT)
6710         {
6711           /* Case with partial byte and literal source
6712           */
6713           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6714           litval >>= (blen-rlen);
6715           litval &= (~mask) & 0xff;
6716           emit2 ("ld a,!*pair", _pairs[pair].name);
6717           if ((mask|litval)!=0xff)
6718             emit2 ("and a,!immedbyte", mask);
6719           if (litval)
6720             emit2 ("or a,!immedbyte", litval);
6721         }
6722       else
6723         {
6724           /* Case with partial byte and arbitrary source
6725           */
6726           _moveA (aopGet (AOP (right), offset++, FALSE));
6727           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6728
6729           extraPair = getFreePairId(ic);
6730           if (extraPair == PAIR_INVALID)
6731             {
6732               extraPair = getPairId (AOP (right));
6733               if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6734                 extraPair = PAIR_BC;
6735
6736               if (getPairId (AOP (right)) != PAIR_BC
6737                   || !isLastUse (ic, right))
6738                 {
6739                   _push (extraPair);
6740                   needPopExtra = 1;
6741                 }
6742             }
6743           emit2 ("ld %s,a", _pairs[extraPair].l);
6744           emit2 ("ld a,!*pair", _pairs[pair].name);
6745
6746           emit2 ("and a,!immedbyte", mask);
6747           emit2 ("or a,%s", _pairs[extraPair].l);
6748           if (needPopExtra)
6749             _pop (extraPair);
6750
6751         }
6752       emit2 ("ld !*pair,a", _pairs[pair].name);
6753     }
6754 }
6755
6756
6757 /*-----------------------------------------------------------------*/
6758 /* genGenPointerSet - stores the value into a pointer location        */
6759 /*-----------------------------------------------------------------*/
6760 static void
6761 genGenPointerSet (operand * right,
6762                   operand * result, iCode * ic)
6763 {
6764   int size, offset;
6765   sym_link *retype = getSpec (operandType (right));
6766   sym_link *letype = getSpec (operandType (result));
6767   PAIR_ID pairId = PAIR_HL;
6768   bool isBitvar;
6769   
6770   aopOp (result, ic, FALSE, FALSE);
6771   aopOp (right, ic, FALSE, FALSE);
6772
6773   if (IS_GB)
6774     pairId = PAIR_DE;
6775
6776   size = AOP_SIZE (right);
6777
6778   isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6779   emitDebug("; isBitvar = %d", isBitvar);
6780
6781   /* Handle the exceptions first */
6782   if (isPair (AOP (result)) && size == 1 && !isBitvar)
6783     {
6784       /* Just do it */
6785       const char *l = aopGet (AOP (right), 0, FALSE);
6786       const char *pair = getPairName (AOP (result));
6787       if (canAssignToPtr (l) && isPtr (pair))
6788         {
6789           emit2 ("ld !*pair,%s", pair, l);
6790         }
6791       else
6792         {
6793           _moveA (l);
6794           emit2 ("ld !*pair,a", pair);
6795         }
6796       goto release;
6797     }
6798   
6799   if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6800     {
6801       /* Just do it */
6802       const char *l = aopGet (AOP (right), 0, FALSE);
6803
6804       offset = 0;
6805       while (size--) 
6806         {
6807           if (canAssignToPtr (l))
6808             {
6809               emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6810             }
6811           else
6812             {
6813               _moveA (aopGet (AOP (right), offset, FALSE));
6814               emit2 ("ld !*iyx,a", offset);
6815             }
6816           offset++;
6817         }
6818       goto release;
6819     }
6820   else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6821            && !isBitvar)
6822     {
6823       offset = 0;
6824
6825       while (size--)
6826         {
6827           const char *l = aopGet (AOP (right), offset, FALSE);
6828           if (isRegOrLit (AOP (right)) && !IS_GB)
6829             {
6830               emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6831             }
6832           else
6833             {
6834               _moveA (l);
6835               emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6836             }
6837           if (size)
6838             {
6839               emit2 ("inc %s", _pairs[PAIR_HL].name);
6840               _G.pairs[PAIR_HL].offset++;
6841             }
6842           offset++;
6843         }
6844
6845       /* Fixup HL back down */
6846       for (size = AOP_SIZE (right)-1; size; size--)
6847         {
6848           emit2 ("dec %s", _pairs[PAIR_HL].name);
6849         }
6850       goto release;
6851     }
6852
6853   /* if the operand is already in dptr
6854      then we do nothing else we move the value to dptr */
6855   if (AOP_TYPE (result) != AOP_STR)
6856     {
6857       fetchPair (pairId, AOP (result));
6858     }
6859   /* so hl now contains the address */
6860   freeAsmop (result, NULL, ic);
6861
6862   /* if bit then unpack */
6863   if (isBitvar)
6864     {
6865       genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6866       goto release;
6867       //wassert (0);
6868     }
6869   else
6870     {
6871       offset = 0;
6872
6873       while (size--)
6874         {
6875           const char *l = aopGet (AOP (right), offset, FALSE);
6876           if (isRegOrLit (AOP (right)) && !IS_GB)
6877             {
6878               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6879             }
6880           else
6881             {
6882               _moveA (l);
6883               emit2 ("ld !*pair,a", _pairs[pairId].name);
6884             }
6885           if (size)
6886             {
6887               emit2 ("inc %s", _pairs[pairId].name);
6888               _G.pairs[pairId].offset++;
6889             }
6890           offset++;
6891         }
6892     }
6893 release:
6894   freeAsmop (right, NULL, ic);
6895 }
6896
6897 /*-----------------------------------------------------------------*/
6898 /* genPointerSet - stores the value into a pointer location        */
6899 /*-----------------------------------------------------------------*/
6900 static void
6901 genPointerSet (iCode * ic)
6902 {
6903   operand *right, *result;
6904   sym_link *type, *etype;
6905
6906   right = IC_RIGHT (ic);
6907   result = IC_RESULT (ic);
6908
6909   /* depending on the type of pointer we need to
6910      move it to the correct pointer register */
6911   type = operandType (result);
6912   etype = getSpec (type);
6913
6914   genGenPointerSet (right, result, ic);
6915 }
6916
6917 /*-----------------------------------------------------------------*/
6918 /* genIfx - generate code for Ifx statement                        */
6919 /*-----------------------------------------------------------------*/
6920 static void
6921 genIfx (iCode * ic, iCode * popIc)
6922 {
6923   operand *cond = IC_COND (ic);
6924   int isbit = 0;
6925
6926   aopOp (cond, ic, FALSE, TRUE);
6927
6928   /* get the value into acc */
6929   if (AOP_TYPE (cond) != AOP_CRY)
6930     _toBoolean (cond);
6931   else
6932     isbit = 1;
6933   /* the result is now in the accumulator */
6934   freeAsmop (cond, NULL, ic);
6935
6936   /* if there was something to be popped then do it */
6937   if (popIc)
6938     genIpop (popIc);
6939
6940   /* if the condition is  a bit variable */
6941   if (isbit && IS_ITEMP (cond) &&
6942       SPIL_LOC (cond))
6943     genIfxJump (ic, SPIL_LOC (cond)->rname);
6944   else if (isbit && !IS_ITEMP (cond))
6945     genIfxJump (ic, OP_SYMBOL (cond)->rname);
6946   else
6947     genIfxJump (ic, "a");
6948
6949   ic->generated = 1;
6950 }
6951
6952 /*-----------------------------------------------------------------*/
6953 /* genAddrOf - generates code for address of                       */
6954 /*-----------------------------------------------------------------*/
6955 static void
6956 genAddrOf (iCode * ic)
6957 {
6958   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6959
6960   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6961
6962   /* if the operand is on the stack then we
6963      need to get the stack offset of this
6964      variable */
6965   if (IS_GB)
6966     {
6967       if (sym->onStack)
6968         {
6969           spillCached ();
6970           if (sym->stack <= 0)
6971             {
6972               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6973             }
6974           else
6975             {
6976               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6977             }
6978           commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6979         }
6980       else
6981         {
6982           emit2 ("ld de,!hashedstr", sym->rname);
6983           commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6984         }
6985     }
6986   else
6987     {
6988       spillCached ();
6989       if (sym->onStack)
6990         {
6991           /* if it has an offset  then we need to compute it */
6992           if (sym->stack > 0)
6993             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6994           else
6995             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6996           emit2 ("add hl,sp");
6997         }
6998       else
6999         {
7000           emit2 ("ld hl,!hashedstr", sym->rname);
7001         }
7002       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
7003     }
7004   freeAsmop (IC_RESULT (ic), NULL, ic);
7005 }
7006
7007 /*-----------------------------------------------------------------*/
7008 /* genAssign - generate code for assignment                        */
7009 /*-----------------------------------------------------------------*/
7010 static void
7011 genAssign (iCode * ic)
7012 {
7013   operand *result, *right;
7014   int size, offset;
7015   unsigned long lit = 0L;
7016
7017   result = IC_RESULT (ic);
7018   right = IC_RIGHT (ic);
7019
7020   /* Dont bother assigning if they are the same */
7021   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7022     {
7023       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
7024       return;
7025     }
7026
7027   aopOp (right, ic, FALSE, FALSE);
7028   aopOp (result, ic, TRUE, FALSE);
7029
7030   /* if they are the same registers */
7031   if (sameRegs (AOP (right), AOP (result)))
7032     {
7033       emitDebug ("; (registers are the same)");
7034       goto release;
7035     }
7036
7037   /* if the result is a bit */
7038   if (AOP_TYPE (result) == AOP_CRY)
7039     {
7040       wassertl (0, "Tried to assign to a bit");
7041     }
7042
7043   /* general case */
7044   size = AOP_SIZE (result);
7045   offset = 0;
7046
7047   if (AOP_TYPE (right) == AOP_LIT)
7048     {
7049       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7050     }
7051
7052   if (isPair (AOP (result)))
7053     {
7054       fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7055     }
7056   else if ((size > 1) &&
7057            (AOP_TYPE (result) != AOP_REG) &&
7058            (AOP_TYPE (right) == AOP_LIT) &&
7059            !IS_FLOAT (operandType (right)) &&
7060            (lit < 256L))
7061     {
7062       bool fXored = FALSE;
7063       offset = 0;
7064       /* Work from the top down.
7065          Done this way so that we can use the cached copy of 0
7066          in A for a fast clear */
7067       while (size--)
7068         {
7069           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7070             {
7071               if (!fXored && size > 1)
7072                 {
7073                   emit2 ("xor a,a");
7074                   fXored = TRUE;
7075                 }
7076               if (fXored)
7077                 {
7078                   aopPut (AOP (result), "a", offset);
7079                 }
7080               else
7081                 {
7082                   aopPut (AOP (result), "!zero", offset);
7083                 }
7084             }
7085           else
7086             aopPut (AOP (result),
7087                     aopGet (AOP (right), offset, FALSE),
7088                     offset);
7089           offset++;
7090         }
7091     }
7092   else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7093     {
7094       emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7095       aopPut (AOP (result), "l", LSB);
7096       aopPut (AOP (result), "h", MSB16);
7097     }
7098   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7099     {
7100       /* Special case.  Load into a and d, then load out. */
7101       _moveA (aopGet (AOP (right), 0, FALSE));
7102       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7103       aopPut (AOP (result), "a", 0);
7104       aopPut (AOP (result), "e", 1);
7105     }
7106   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7107     {
7108       /* Special case - simple memcpy */
7109       aopGet (AOP (right), LSB, FALSE);
7110       emit2 ("ld d,h");
7111       emit2 ("ld e,l");
7112       aopGet (AOP (result), LSB, FALSE);
7113
7114       while (size--)
7115         {
7116           emit2 ("ld a,(de)");
7117           /* Peephole will optimise this. */
7118           emit2 ("ld (hl),a");
7119
7120           if (size != 0)
7121             {
7122               emit2 ("inc hl");
7123               emit2 ("inc de");
7124             }
7125         }
7126       spillPair (PAIR_HL);
7127     }
7128   else
7129     {
7130       while (size--)
7131         {
7132           /* PENDING: do this check better */
7133           if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7134             {
7135               _moveA (aopGet (AOP (right), offset, FALSE));
7136               aopPut (AOP (result), "a", offset);
7137             }
7138           else
7139             aopPut (AOP (result),
7140                     aopGet (AOP (right), offset, FALSE),
7141                     offset);
7142           offset++;
7143         }
7144     }
7145
7146 release:
7147   freeAsmop (right, NULL, ic);
7148   freeAsmop (result, NULL, ic);
7149 }
7150
7151 /*-----------------------------------------------------------------*/
7152 /* genJumpTab - genrates code for jump table                       */
7153 /*-----------------------------------------------------------------*/
7154 static void
7155 genJumpTab (iCode * ic)
7156 {
7157   symbol *jtab;
7158   const char *l;
7159
7160   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7161   /* get the condition into accumulator */
7162   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7163   if (!IS_GB)
7164     emit2 ("push de");
7165   emit2 ("ld e,%s", l);
7166   emit2 ("ld d,!zero");
7167   jtab = newiTempLabel (NULL);
7168   spillCached ();
7169   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7170   emit2 ("add hl,de");
7171   emit2 ("add hl,de");
7172   emit2 ("add hl,de");
7173   freeAsmop (IC_JTCOND (ic), NULL, ic);
7174   if (!IS_GB)
7175     emit2 ("pop de");
7176   emit2 ("jp !*hl");
7177   emitLabel (jtab->key + 100);
7178   /* now generate the jump labels */
7179   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7180        jtab = setNextItem (IC_JTLABELS (ic)))
7181     emit2 ("jp !tlabel", jtab->key + 100);
7182 }
7183
7184 /*-----------------------------------------------------------------*/
7185 /* genCast - gen code for casting                                  */
7186 /*-----------------------------------------------------------------*/
7187 static void
7188 genCast (iCode * ic)
7189 {
7190   operand *result = IC_RESULT (ic);
7191   sym_link *rtype = operandType (IC_RIGHT (ic));
7192   operand *right = IC_RIGHT (ic);
7193   int size, offset;
7194
7195   /* if they are equivalent then do nothing */
7196   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7197     return;
7198
7199   aopOp (right, ic, FALSE, FALSE);
7200   aopOp (result, ic, FALSE, FALSE);
7201
7202   /* if the result is a bit */
7203   if (AOP_TYPE (result) == AOP_CRY)
7204     {
7205       wassertl (0, "Tried to cast to a bit");
7206     }
7207
7208   /* if they are the same size : or less */
7209   if (AOP_SIZE (result) <= AOP_SIZE (right))
7210     {
7211
7212       /* if they are in the same place */
7213       if (sameRegs (AOP (right), AOP (result)))
7214         goto release;
7215
7216       /* if they in different places then copy */
7217       size = AOP_SIZE (result);
7218       offset = 0;
7219       while (size--)
7220         {
7221           aopPut (AOP (result),
7222                   aopGet (AOP (right), offset, FALSE),
7223                   offset);
7224           offset++;
7225         }
7226       goto release;
7227     }
7228
7229   /* So we now know that the size of destination is greater
7230      than the size of the source */
7231   /* we move to result for the size of source */
7232   size = AOP_SIZE (right);
7233   offset = 0;
7234   while (size--)
7235     {
7236       aopPut (AOP (result),
7237               aopGet (AOP (right), offset, FALSE),
7238               offset);
7239       offset++;
7240     }
7241
7242   /* now depending on the sign of the destination */
7243   size = AOP_SIZE (result) - AOP_SIZE (right);
7244   /* Unsigned or not an integral type - right fill with zeros */
7245   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7246     {
7247       while (size--)
7248         aopPut (AOP (result), "!zero", offset++);
7249     }
7250   else
7251     {
7252       /* we need to extend the sign :{ */
7253         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7254                         FALSE);
7255       _moveA (l);
7256       emit2 ("rla ");
7257       emit2 ("sbc a,a");
7258       while (size--)
7259         aopPut (AOP (result), "a", offset++);
7260     }
7261
7262 release:
7263   freeAsmop (right, NULL, ic);
7264   freeAsmop (result, NULL, ic);
7265 }
7266
7267 /*-----------------------------------------------------------------*/
7268 /* genReceive - generate code for a receive iCode                  */
7269 /*-----------------------------------------------------------------*/
7270 static void
7271 genReceive (iCode * ic)
7272 {
7273   if (isOperandInFarSpace (IC_RESULT (ic)) &&
7274       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7275        IS_TRUE_SYMOP (IC_RESULT (ic))))
7276     {
7277       wassert (0);
7278     }
7279   else
7280     {
7281         // PENDING: HACK
7282         int size;
7283         int i;
7284
7285         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7286         size = AOP_SIZE(IC_RESULT(ic));
7287
7288         for (i = 0; i < size; i++) {
7289             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7290         }
7291     }
7292
7293   freeAsmop (IC_RESULT (ic), NULL, ic);
7294 }
7295
7296 /*-----------------------------------------------------------------*/
7297 /* genDummyRead - generate code for dummy read of volatiles        */
7298 /*-----------------------------------------------------------------*/
7299 static void
7300 genDummyRead (iCode * ic)
7301 {
7302   operand *op;
7303   int size, offset;
7304
7305   op = IC_RIGHT (ic);
7306   if (op && IS_SYMOP (op))
7307     {
7308       aopOp (op, ic, FALSE, FALSE);
7309   
7310       /* general case */
7311       size = AOP_SIZE (op);
7312       offset = 0;
7313
7314       while (size--)
7315         {
7316           _moveA (aopGet (AOP (op), offset, FALSE));
7317           offset++;
7318         }
7319
7320       freeAsmop (op, NULL, ic);
7321     }
7322   
7323   op = IC_LEFT (ic);
7324   if (op && IS_SYMOP (op))
7325     {
7326       aopOp (op, ic, FALSE, FALSE);
7327   
7328       /* general case */
7329       size = AOP_SIZE (op);
7330       offset = 0;
7331
7332       while (size--)
7333         {
7334           _moveA (aopGet (AOP (op), offset, FALSE));
7335           offset++;
7336         }
7337
7338       freeAsmop (op, NULL, ic);
7339     }
7340 }
7341
7342 enum
7343   {
7344     /** Maximum number of bytes to emit per line. */
7345     DBEMIT_MAX_RUN = 8
7346   };
7347
7348 /** Context for the byte output chunker. */
7349 typedef struct
7350 {
7351   unsigned char buffer[DBEMIT_MAX_RUN];
7352   int pos;
7353 } DBEMITCTX;
7354
7355
7356 /** Flushes a byte chunker by writing out all in the buffer and
7357     reseting. 
7358 */
7359 static void
7360 _dbFlush(DBEMITCTX *self)
7361 {
7362   char line[256];
7363
7364   if (self->pos > 0)
7365     {
7366       int i;
7367       sprintf(line, ".db 0x%02X", self->buffer[0]);
7368
7369       for (i = 1; i < self->pos; i++)
7370         {
7371           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7372         }
7373       emit2(line);
7374     }
7375   self->pos = 0;
7376 }
7377
7378 /** Write out another byte, buffering until a decent line is
7379     generated.
7380 */
7381 static void
7382 _dbEmit(DBEMITCTX *self, int c)
7383 {
7384   if (self->pos == DBEMIT_MAX_RUN)
7385     {
7386       _dbFlush(self);
7387     }
7388   self->buffer[self->pos++] = c;
7389 }
7390
7391 /** Context for a simple run length encoder. */
7392 typedef struct
7393 {
7394   unsigned last;
7395   unsigned char buffer[128];
7396   int pos;
7397   /** runLen may be equivalent to pos. */
7398   int runLen;
7399 } RLECTX;
7400
7401 enum
7402   {
7403     RLE_CHANGE_COST = 4,
7404     RLE_MAX_BLOCK = 127
7405   };
7406
7407 /** Flush the buffer of a run length encoder by writing out the run or
7408     data that it currently contains.
7409 */
7410 static void
7411 _rleCommit(RLECTX *self)
7412 {
7413   int i;
7414   if (self->pos != 0)
7415     {
7416       DBEMITCTX db;
7417       memset(&db, 0, sizeof(db));
7418           
7419       emit2(".db %u", self->pos);
7420       
7421       for (i = 0; i < self->pos; i++)
7422         {
7423           _dbEmit(&db, self->buffer[i]);
7424         }
7425       _dbFlush(&db);
7426     }
7427   /* Reset */
7428   self->pos = 0;
7429 }
7430
7431 /* Encoder design:
7432    Can get either a run or a block of random stuff.
7433    Only want to change state if a good run comes in or a run ends.
7434    Detecting run end is easy.
7435    Initial state?
7436
7437    Say initial state is in run, len zero, last zero.  Then if you get a
7438    few zeros then something else then a short run will be output.
7439    Seems OK.  While in run mode, keep counting.  While in random mode,
7440    keep a count of the run.  If run hits margin, output all up to run,
7441    restart, enter run mode.
7442 */
7443
7444 /** Add another byte into the run length encoder, flushing as
7445     required.  The run length encoder uses the Amiga IFF style, where
7446     a block is prefixed by its run length.  A positive length means
7447     the next n bytes pass straight through.  A negative length means
7448     that the next byte is repeated -n times.  A zero terminates the
7449     chunks.
7450 */
7451 static void
7452 _rleAppend(RLECTX *self, unsigned c)
7453 {
7454   int i;
7455
7456   if (c != self->last)
7457     {
7458       /* The run has stopped.  See if it is worthwhile writing it out
7459          as a run.  Note that the random data comes in as runs of
7460          length one.
7461       */
7462       if (self->runLen > RLE_CHANGE_COST)
7463         {
7464           /* Yes, worthwhile. */
7465           /* Commit whatever was in the buffer. */
7466           _rleCommit(self);
7467           emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7468         }
7469       else
7470         {
7471           /* Not worthwhile.  Append to the end of the random list. */
7472           for (i = 0; i < self->runLen; i++)
7473             {
7474               if (self->pos >= RLE_MAX_BLOCK)
7475                 {
7476                   /* Commit. */
7477                   _rleCommit(self);
7478                 }
7479               self->buffer[self->pos++] = self->last;
7480             }
7481         }
7482       self->runLen = 1;
7483       self->last = c;
7484     }
7485   else
7486     {
7487       if (self->runLen >= RLE_MAX_BLOCK)
7488         {
7489           /* Commit whatever was in the buffer. */
7490           _rleCommit(self);
7491
7492           emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7493           self->runLen = 0;
7494         }
7495       self->runLen++;
7496     }
7497 }
7498
7499 static void
7500 _rleFlush(RLECTX *self)
7501 {
7502   _rleAppend(self, -1);
7503   _rleCommit(self);
7504   self->pos = 0;
7505   self->last = 0;
7506   self->runLen = 0;
7507 }
7508
7509 /** genArrayInit - Special code for initialising an array with constant
7510    data.
7511 */
7512 static void
7513 genArrayInit (iCode * ic)
7514 {
7515   literalList *iLoop;
7516   int         ix;
7517   int         elementSize = 0, eIndex, i;
7518   unsigned    val, lastVal;
7519   sym_link    *type;
7520   RLECTX      rle;
7521
7522   memset(&rle, 0, sizeof(rle));
7523
7524   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7525
7526   _saveRegsForCall(ic, 0);
7527
7528   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7529   emit2 ("call __initrleblock");
7530     
7531   type = operandType(IC_LEFT(ic));
7532     
7533   if (type && type->next)
7534     {
7535       if (IS_SPEC(type->next) || IS_PTR(type->next))
7536         {
7537           elementSize = getSize(type->next);
7538         }
7539       else if (IS_ARRAY(type->next) && type->next->next)
7540         {
7541           elementSize = getSize(type->next->next);
7542         }
7543       else
7544         {
7545           printTypeChainRaw (type, NULL);
7546           wassertl (0, "Can't determine element size in genArrayInit.");
7547         }
7548     }
7549   else
7550     {
7551       wassertl (0, "Can't determine element size in genArrayInit.");
7552     }
7553
7554   wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
7555
7556   iLoop = IC_ARRAYILIST(ic);
7557   lastVal = (unsigned)-1;
7558
7559   /* Feed all the bytes into the run length encoder which will handle
7560      the actual output.
7561      This works well for mixed char data, and for random int and long
7562      data.
7563   */
7564   while (iLoop)
7565     {
7566       ix = iLoop->count;
7567
7568       for (i = 0; i < ix; i++)
7569         {
7570           for (eIndex = 0; eIndex < elementSize; eIndex++)
7571             {
7572               val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7573               _rleAppend(&rle, val);
7574             }
7575         }
7576         
7577       iLoop = iLoop->next;
7578     }
7579
7580   _rleFlush(&rle);
7581   /* Mark the end of the run. */
7582   emit2(".db 0");
7583
7584   _restoreRegsAfterCall();
7585
7586   spillCached ();
7587
7588   freeAsmop (IC_LEFT(ic), NULL, ic);
7589 }
7590
7591 static void
7592 _swap (PAIR_ID one, PAIR_ID two)
7593 {
7594   if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7595     {
7596       emit2 ("ex de,hl");
7597     }
7598   else
7599     {
7600       emit2 ("ld a,%s", _pairs[one].l);
7601       emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7602       emit2 ("ld %s,a", _pairs[two].l);
7603       emit2 ("ld a,%s", _pairs[one].h);
7604       emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7605       emit2 ("ld %s,a", _pairs[two].h);
7606     }
7607 }
7608
7609 /* The problem is that we may have all three pairs used and they may
7610    be needed in a different order.
7611
7612    Note: Have ex de,hl
7613
7614    Combinations:
7615      hl = hl            => unity, fine
7616      bc = bc
7617      de = de
7618
7619      hl = hl            hl = hl, swap de <=> bc
7620      bc = de
7621      de = bc
7622
7623      hl = bc            Worst case
7624      bc = de
7625      de = hl
7626      
7627      hl = bc            de = de, swap bc <=> hl
7628      bc = hl
7629      de = de
7630
7631      hl = de            Worst case
7632      bc = hl
7633      de = bc
7634
7635      hl = de            bc = bc, swap hl <=> de
7636      bc = bc
7637      de = hl
7638
7639    Break it down into:
7640     * Any pair = pair are done last
7641     * Any pair = iTemp are done last
7642     * Any swaps can be done any time
7643
7644    A worst case:
7645     push p1
7646     p1 = p2
7647     p2 = p3
7648     pop  p3
7649
7650    So how do we detect the cases?
7651    How about a 3x3 matrix?
7652         source
7653    dest x x x x
7654         x x x x
7655         x x x x (Fourth for iTemp/other)
7656
7657    First determin which mode to use by counting the number of unity and
7658    iTemp assigns.
7659      Three - any order
7660      Two - Assign the pair first, then the rest
7661      One - Swap the two, then the rest
7662      Zero - Worst case.
7663 */
7664 static void
7665 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7666 {
7667   PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7668   PAIR_ID dest[3] = {
7669     PAIR_BC, PAIR_HL, PAIR_DE
7670   };
7671   int i, j, nunity = 0;
7672   memset (ids, PAIR_INVALID, sizeof (ids));
7673
7674   /* Sanity checks */
7675   wassert (nparams == 3);
7676
7677   /* First save everything that needs to be saved. */
7678   _saveRegsForCall (ic, 0);
7679
7680   /* Loading HL first means that DE is always fine. */
7681   for (i = 0; i < nparams; i++)
7682     {
7683       aopOp (pparams[i], ic, FALSE, FALSE);
7684       ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7685     }
7686
7687   /* Count the number of unity or iTemp assigns. */
7688   for (i = 0; i < 3; i++) 
7689     {
7690       if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7691         {
7692           nunity++;
7693         }
7694     }
7695
7696   if (nunity == 3)
7697     {
7698       /* Any order, fall through. */
7699     }
7700   else if (nunity == 2)
7701     {
7702       /* One is assigned.  Pull it out and assign. */
7703       for (i = 0; i < 3; i++)
7704         {
7705           for (j = 0; j < NUM_PAIRS; j++)
7706             {
7707               if (ids[dest[i]][j] == TRUE)
7708                 {
7709                   /* Found it.  See if it's the right one. */
7710                   if (j == PAIR_INVALID || j == dest[i])
7711                     {
7712                       /* Keep looking. */
7713                     }
7714                   else
7715                     {
7716                       fetchPair(dest[i], AOP (pparams[i]));
7717                       goto done;
7718                     }
7719                 }
7720             }
7721         }
7722     }
7723   else if (nunity == 1)
7724     {
7725       /* Find the pairs to swap. */
7726       for (i = 0; i < 3; i++)
7727         {
7728           for (j = 0; j < NUM_PAIRS; j++)
7729             {
7730               if (ids[dest[i]][j] == TRUE)
7731                 {
7732                   if (j == PAIR_INVALID || j == dest[i])
7733                     {
7734                       /* Keep looking. */
7735                     }
7736                   else
7737                     {
7738                       _swap (j, dest[i]);
7739                       goto done;
7740                     }
7741                 }
7742             }
7743         }
7744     }
7745   else
7746     {
7747       int next = getPairId (AOP (pparams[0]));
7748       emit2 ("push %s", _pairs[next].name);
7749
7750       if (next == dest[1])
7751         {
7752           fetchPair (dest[1], AOP (pparams[1]));
7753           fetchPair (dest[2], AOP (pparams[2]));
7754         }
7755       else
7756         {
7757           fetchPair (dest[2], AOP (pparams[2]));
7758           fetchPair (dest[1], AOP (pparams[1]));
7759         }
7760       emit2 ("pop %s", _pairs[dest[0]].name);
7761     }
7762  done:
7763   /* Finally pull out all of the iTemps */
7764   for (i = 0; i < 3; i++)
7765     {
7766       if (ids[dest[i]][PAIR_INVALID] == 1)
7767         {
7768           fetchPair (dest[i], AOP (pparams[i]));
7769         }
7770     }
7771 }
7772
7773 static void
7774 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7775 {
7776   operand *from, *to;
7777   symbol *label;
7778   bool deInUse;
7779
7780   wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7781   to = pparams[0];
7782   from = pparams[1];
7783
7784   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7785
7786   setupForBuiltin3 (ic, nParams, pparams);
7787
7788   label = newiTempLabel(NULL);
7789
7790   emitLabel (label->key);
7791   emit2 ("ld a,(hl)");
7792   emit2 ("ldi");
7793   emit2 ("or a");
7794   emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7795
7796   freeAsmop (from, NULL, ic->next);
7797   freeAsmop (to, NULL, ic);
7798 }
7799
7800 static void
7801 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7802 {
7803   operand *from, *to, *count;
7804   bool deInUse;
7805
7806   wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7807   to = pparams[2];
7808   from = pparams[1];
7809   count = pparams[0];
7810
7811   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7812
7813   setupForBuiltin3 (ic, nParams, pparams);
7814
7815   emit2 ("ldir");
7816
7817   freeAsmop (count, NULL, ic->next->next);
7818   freeAsmop (from, NULL, ic);
7819
7820   _restoreRegsAfterCall();
7821
7822   /* if we need assign a result value */
7823   if ((IS_ITEMP (IC_RESULT (ic)) &&
7824        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7825         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7826       IS_TRUE_SYMOP (IC_RESULT (ic)))
7827     {
7828       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7829       movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7830       freeAsmop (IC_RESULT (ic), NULL, ic);
7831     }
7832
7833   freeAsmop (to, NULL, ic->next);
7834 }
7835
7836 /*-----------------------------------------------------------------*/
7837 /* genBuiltIn - calls the appropriate function to  generating code */
7838 /* for a built in function                                         */
7839 /*-----------------------------------------------------------------*/
7840 static void genBuiltIn (iCode *ic)
7841 {
7842     operand *bi_parms[MAX_BUILTIN_ARGS];
7843     int nbi_parms;
7844     iCode *bi_iCode;
7845     symbol *bif;
7846
7847     /* get all the arguments for a built in function */
7848     bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7849
7850     /* which function is it */
7851     bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7852
7853     if (strcmp(bif->name,"__builtin_strcpy")==0) 
7854       {
7855         genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7856       } 
7857     else if (strcmp(bif->name,"__builtin_memcpy")==0) 
7858       {
7859         genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7860       } 
7861     else 
7862       {
7863         wassertl (0, "Unknown builtin function encountered");
7864       }
7865 }
7866
7867 /*-----------------------------------------------------------------*/
7868 /* genZ80Code - generate code for Z80 based controllers            */
7869 /*-----------------------------------------------------------------*/
7870 void
7871 genZ80Code (iCode * lic)
7872 {
7873   iCode *ic;
7874   int cln = 0;
7875
7876   /* Hack */
7877   if (IS_GB)
7878     {
7879       _fReturn = _gbz80_return;
7880       _fTmp = _gbz80_return;
7881     }
7882   else
7883     {
7884       _fReturn = _z80_return;
7885       _fTmp = _z80_return;
7886     }
7887
7888   _G.lines.head = _G.lines.current = NULL;
7889   
7890   /* if debug information required */
7891   if (options.debug && currFunc)
7892     {
7893       debugFile->writeFunction (currFunc, lic);
7894     }
7895
7896   for (ic = lic; ic; ic = ic->next)
7897     {
7898       _G.current_iCode = ic;
7899
7900       if (ic->lineno && cln != ic->lineno)
7901         {
7902           if (options.debug)
7903             {
7904               debugFile->writeCLine (ic);
7905             }
7906           if (!options.noCcodeInAsm) {
7907             emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7908                    printCLine(ic->filename, ic->lineno));
7909           }
7910           cln = ic->lineno;
7911         }
7912       if (options.iCodeInAsm) {
7913         emit2 (";ic:%d: %s", ic->key, printILine(ic));
7914       }
7915       /* if the result is marked as
7916          spilt and rematerializable or code for
7917          this has already been generated then
7918          do nothing */
7919       if (resultRemat (ic) || ic->generated)
7920         continue;
7921
7922       /* depending on the operation */
7923       switch (ic->op)
7924         {
7925         case '!':
7926           emitDebug ("; genNot");
7927           genNot (ic);
7928           break;
7929
7930         case '~':
7931           emitDebug ("; genCpl");
7932           genCpl (ic);
7933           break;
7934
7935         case UNARYMINUS:
7936           emitDebug ("; genUminus");
7937           genUminus (ic);
7938           break;
7939
7940         case IPUSH:
7941           emitDebug ("; genIpush");
7942           genIpush (ic);
7943           break;
7944
7945         case IPOP:
7946           /* IPOP happens only when trying to restore a
7947              spilt live range, if there is an ifx statement
7948              following this pop then the if statement might
7949              be using some of the registers being popped which
7950              would destory the contents of the register so
7951              we need to check for this condition and handle it */
7952           if (ic->next &&
7953               ic->next->op == IFX &&
7954               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7955             {
7956               emitDebug ("; genIfx");
7957               genIfx (ic->next, ic);
7958             }
7959           else
7960             {
7961               emitDebug ("; genIpop");
7962               genIpop (ic);
7963             }
7964           break;
7965
7966         case CALL:
7967           emitDebug ("; genCall");
7968           genCall (ic);
7969           break;
7970
7971         case PCALL:
7972           emitDebug ("; genPcall");
7973           genPcall (ic);
7974           break;
7975
7976         case FUNCTION:
7977           emitDebug ("; genFunction");
7978           genFunction (ic);
7979           break;
7980
7981         case ENDFUNCTION:
7982           emitDebug ("; genEndFunction");
7983           genEndFunction (ic);
7984           break;
7985
7986         case RETURN:
7987           emitDebug ("; genRet");
7988           genRet (ic);
7989           break;
7990
7991         case LABEL:
7992           emitDebug ("; genLabel");
7993           genLabel (ic);
7994           break;
7995
7996         case GOTO:
7997           emitDebug ("; genGoto");
7998           genGoto (ic);
7999           break;
8000
8001         case '+':
8002           emitDebug ("; genPlus");
8003           genPlus (ic);
8004           break;
8005
8006         case '-':
8007           emitDebug ("; genMinus");
8008           genMinus (ic);
8009           break;
8010
8011         case '*':
8012           emitDebug ("; genMult");
8013           genMult (ic);
8014           break;
8015
8016         case '/':
8017           emitDebug ("; genDiv");
8018           genDiv (ic);
8019           break;
8020
8021         case '%':
8022           emitDebug ("; genMod");
8023           genMod (ic);
8024           break;
8025
8026         case '>':
8027           emitDebug ("; genCmpGt");
8028           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
8029           break;
8030
8031         case '<':
8032           emitDebug ("; genCmpLt");
8033           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
8034           break;
8035
8036         case LE_OP:
8037         case GE_OP:
8038         case NE_OP:
8039
8040           /* note these two are xlated by algebraic equivalence
8041              during parsing SDCC.y */
8042           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8043                   "got '>=' or '<=' shouldn't have come here");
8044           break;
8045
8046         case EQ_OP:
8047           emitDebug ("; genCmpEq");
8048           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8049           break;
8050
8051         case AND_OP:
8052           emitDebug ("; genAndOp");
8053           genAndOp (ic);
8054           break;
8055
8056         case OR_OP:
8057           emitDebug ("; genOrOp");
8058           genOrOp (ic);
8059           break;
8060
8061         case '^':
8062           emitDebug ("; genXor");
8063           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8064           break;
8065
8066         case '|':
8067           emitDebug ("; genOr");
8068           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8069           break;
8070
8071         case BITWISEAND:
8072           emitDebug ("; genAnd");
8073           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8074           break;
8075
8076         case INLINEASM:
8077           emitDebug ("; genInline");
8078           genInline (ic);
8079           break;
8080
8081         case RRC:
8082           emitDebug ("; genRRC");
8083           genRRC (ic);
8084           break;
8085
8086         case RLC:
8087           emitDebug ("; genRLC");
8088           genRLC (ic);
8089           break;
8090
8091         case GETHBIT:
8092           emitDebug ("; genGetHBIT");
8093           genGetHbit (ic);
8094           break;
8095
8096         case LEFT_OP:
8097           emitDebug ("; genLeftShift");
8098           genLeftShift (ic);
8099           break;
8100
8101         case RIGHT_OP:
8102           emitDebug ("; genRightShift");
8103           genRightShift (ic);
8104           break;
8105
8106         case GET_VALUE_AT_ADDRESS:
8107           emitDebug ("; genPointerGet");
8108           genPointerGet (ic);
8109           break;
8110
8111         case '=':
8112
8113           if (POINTER_SET (ic))
8114             {
8115               emitDebug ("; genAssign (pointer)");
8116               genPointerSet (ic);
8117             }
8118           else
8119             {
8120               emitDebug ("; genAssign");
8121               genAssign (ic);
8122             }
8123           break;
8124
8125         case IFX:
8126           emitDebug ("; genIfx");
8127           genIfx (ic, NULL);
8128           break;
8129
8130         case ADDRESS_OF:
8131           emitDebug ("; genAddrOf");
8132           genAddrOf (ic);
8133           break;
8134
8135         case JUMPTABLE:
8136           emitDebug ("; genJumpTab");
8137           genJumpTab (ic);
8138           break;
8139
8140         case CAST:
8141           emitDebug ("; genCast");
8142           genCast (ic);
8143           break;
8144
8145         case RECEIVE:
8146           emitDebug ("; genReceive");
8147           genReceive (ic);
8148           break;
8149
8150         case SEND:
8151           if (ic->builtinSEND)
8152             {
8153               emitDebug ("; genBuiltIn");
8154               genBuiltIn(ic);
8155             }
8156           else
8157             {
8158               emitDebug ("; addSet");
8159               addSet (&_G.sendSet, ic);
8160             }
8161           break;
8162
8163         case ARRAYINIT:
8164           emitDebug ("; genArrayInit");
8165           genArrayInit(ic);
8166           break;
8167
8168         case DUMMY_READ_VOLATILE:
8169           emitDebug ("; genDummyRead");
8170           genDummyRead (ic);
8171           break;
8172
8173         default:
8174           ic = ic;
8175         }
8176     }
8177
8178
8179   /* now we are ready to call the
8180      peep hole optimizer */
8181   if (!options.nopeep)
8182     peepHole (&_G.lines.head);
8183
8184   /* This is unfortunate */
8185   /* now do the actual printing */
8186   {
8187     FILE *fp = codeOutFile;
8188     if (isInHome () && codeOutFile == code->oFile)
8189       codeOutFile = home->oFile;
8190     printLine (_G.lines.head, codeOutFile);
8191     if (_G.flushStatics)
8192       {
8193         flushStatics ();
8194         _G.flushStatics = 0;
8195       }
8196     codeOutFile = fp;
8197   }
8198
8199   freeTrace(&_G.lines.trace);
8200   freeTrace(&_G.trace.aops);
8201 }
8202
8203 /*
8204   Attic
8205 static int
8206 _isPairUsed (iCode * ic, PAIR_ID pairId)
8207 {
8208   int ret = 0;
8209   switch (pairId)
8210     {
8211     case PAIR_DE:
8212       if (bitVectBitValue (ic->rMask, D_IDX))
8213         ret++;
8214       if (bitVectBitValue (ic->rMask, E_IDX))
8215         ret++;
8216       break;
8217     default:
8218       wassert (0);
8219     }
8220   return ret;
8221 }
8222
8223 static char *
8224 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8225 {
8226   unsigned long v;
8227   value *val = aop->aopu.aop_lit;
8228
8229   wassert (aop->type == AOP_LIT);
8230   wassert (!IS_FLOAT (val->type));
8231
8232   v = (unsigned long) floatFromVal (val);
8233
8234   if (xor)
8235     v ^= 0x8000;
8236   if (negate)
8237     v = 0-v;
8238   v &= 0xFFFF;
8239
8240   tsprintf (buffer, sizeof(buffer), "!immedword", v);
8241   return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
8242 }
8243
8244
8245 */