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