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