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