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