* src/z80/gen.h,
[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 release:
7136   freeAsmop (right, NULL, ic);
7137 }
7138
7139 enum
7140   {
7141     /** Maximum number of bytes to emit per line. */
7142     DBEMIT_MAX_RUN = 8
7143   };
7144
7145 /** Context for the byte output chunker. */
7146 typedef struct
7147 {
7148   unsigned char buffer[DBEMIT_MAX_RUN];
7149   int pos;
7150 } DBEMITCTX;
7151
7152
7153 /** Flushes a byte chunker by writing out all in the buffer and
7154     reseting. 
7155 */
7156 static void
7157 _dbFlush(DBEMITCTX *self)
7158 {
7159   char line[256];
7160
7161   if (self->pos > 0)
7162     {
7163       int i;
7164       sprintf(line, ".db 0x%02X", self->buffer[0]);
7165
7166       for (i = 1; i < self->pos; i++)
7167         {
7168           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7169         }
7170       emit2(line);
7171     }
7172   self->pos = 0;
7173 }
7174
7175 /** Write out another byte, buffering until a decent line is
7176     generated.
7177 */
7178 static void
7179 _dbEmit(DBEMITCTX *self, int c)
7180 {
7181   if (self->pos == DBEMIT_MAX_RUN)
7182     {
7183       _dbFlush(self);
7184     }
7185   self->buffer[self->pos++] = c;
7186 }
7187
7188 /** Context for a simple run length encoder. */
7189 typedef struct
7190 {
7191   unsigned last;
7192   unsigned char buffer[128];
7193   int pos;
7194   /** runLen may be equivalent to pos. */
7195   int runLen;
7196 } RLECTX;
7197
7198 enum
7199   {
7200     RLE_CHANGE_COST = 4,
7201     RLE_MAX_BLOCK = 127
7202   };
7203
7204 /** Flush the buffer of a run length encoder by writing out the run or
7205     data that it currently contains.
7206 */
7207 static void
7208 _rleCommit(RLECTX *self)
7209 {
7210   int i;
7211   if (self->pos != 0)
7212     {
7213       DBEMITCTX db;
7214       memset(&db, 0, sizeof(db));
7215           
7216       emit2(".db %u", self->pos);
7217       
7218       for (i = 0; i < self->pos; i++)
7219         {
7220           _dbEmit(&db, self->buffer[i]);
7221         }
7222       _dbFlush(&db);
7223     }
7224   /* Reset */
7225   self->pos = 0;
7226 }
7227
7228 /* Encoder design:
7229    Can get either a run or a block of random stuff.
7230    Only want to change state if a good run comes in or a run ends.
7231    Detecting run end is easy.
7232    Initial state?
7233
7234    Say initial state is in run, len zero, last zero.  Then if you get a
7235    few zeros then something else then a short run will be output.
7236    Seems OK.  While in run mode, keep counting.  While in random mode,
7237    keep a count of the run.  If run hits margin, output all up to run,
7238    restart, enter run mode.
7239 */
7240
7241 /** Add another byte into the run length encoder, flushing as
7242     required.  The run length encoder uses the Amiga IFF style, where
7243     a block is prefixed by its run length.  A positive length means
7244     the next n bytes pass straight through.  A negative length means
7245     that the next byte is repeated -n times.  A zero terminates the
7246     chunks.
7247 */
7248 static void
7249 _rleAppend(RLECTX *self, int c)
7250 {
7251   int i;
7252
7253   if (c != self->last)
7254     {
7255       /* The run has stopped.  See if it is worthwhile writing it out
7256          as a run.  Note that the random data comes in as runs of
7257          length one.
7258       */
7259       if (self->runLen > RLE_CHANGE_COST)
7260         {
7261           /* Yes, worthwhile. */
7262           /* Commit whatever was in the buffer. */
7263           _rleCommit(self);
7264           emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7265         }
7266       else
7267         {
7268           /* Not worthwhile.  Append to the end of the random list. */
7269           for (i = 0; i < self->runLen; i++)
7270             {
7271               if (self->pos >= RLE_MAX_BLOCK)
7272                 {
7273                   /* Commit. */
7274                   _rleCommit(self);
7275                 }
7276               self->buffer[self->pos++] = self->last;
7277             }
7278         }
7279       self->runLen = 1;
7280       self->last = c;
7281     }
7282   else
7283     {
7284       if (self->runLen >= RLE_MAX_BLOCK)
7285         {
7286           /* Commit whatever was in the buffer. */
7287           _rleCommit(self);
7288
7289           emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7290           self->runLen = 0;
7291         }
7292       self->runLen++;
7293     }
7294 }
7295
7296 static void
7297 _rleFlush(RLECTX *self)
7298 {
7299   _rleAppend(self, -1);
7300   _rleCommit(self);
7301   self->pos = 0;
7302   self->last = 0;
7303   self->runLen = 0;
7304 }
7305
7306 /** genArrayInit - Special code for initialising an array with constant
7307    data.
7308 */
7309 static void
7310 genArrayInit (iCode * ic)
7311 {
7312   literalList *iLoop;
7313   int         ix;
7314   int         elementSize = 0, eIndex, i;
7315   unsigned    val, lastVal;
7316   sym_link    *type;
7317   RLECTX      rle;
7318
7319   memset(&rle, 0, sizeof(rle));
7320
7321   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7322
7323   _saveRegsForCall(ic, 0);
7324
7325   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7326   emit2 ("call __initrleblock");
7327     
7328   type = operandType(IC_LEFT(ic));
7329     
7330   if (type && type->next)
7331     {
7332       elementSize = getSize(type->next);
7333     }
7334   else
7335     {
7336       wassertl (0, "Can't determine element size in genArrayInit.");
7337     }
7338
7339   iLoop = IC_ARRAYILIST(ic);
7340   lastVal = (unsigned)-1;
7341
7342   /* Feed all the bytes into the run length encoder which will handle
7343      the actual output.
7344      This works well for mixed char data, and for random int and long
7345      data.
7346   */
7347   while (iLoop)
7348     {
7349       ix = iLoop->count;
7350
7351       if (ix != 0)
7352         {
7353           for (i = 0; i < ix; i++)
7354             {
7355               for (eIndex = 0; eIndex < elementSize; eIndex++)
7356                 {
7357                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7358                   _rleAppend(&rle, val);
7359                 }
7360             }
7361         }
7362         
7363       iLoop = iLoop->next;
7364     }
7365
7366   _rleFlush(&rle);
7367   /* Mark the end of the run. */
7368   emit2(".db 0");
7369
7370   _restoreRegsAfterCall();
7371
7372   spillCached ();
7373
7374   freeAsmop (IC_LEFT(ic), NULL, ic);
7375 }
7376
7377 static void
7378 _swap (PAIR_ID one, PAIR_ID two)
7379 {
7380   if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7381     {
7382       emit2 ("ex de,hl");
7383     }
7384   else
7385     {
7386       emit2 ("ld a,%s", _pairs[one].l);
7387       emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7388       emit2 ("ld %s,a", _pairs[two].l);
7389       emit2 ("ld a,%s", _pairs[one].h);
7390       emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7391       emit2 ("ld %s,a", _pairs[two].h);
7392     }
7393 }
7394
7395 /* The problem is that we may have all three pairs used and they may
7396    be needed in a different order.
7397
7398    Note: Have ex de,hl
7399
7400    Combinations:
7401      hl = hl            => unity, fine
7402      bc = bc
7403      de = de
7404
7405      hl = hl            hl = hl, swap de <=> bc
7406      bc = de
7407      de = bc
7408
7409      hl = bc            Worst case
7410      bc = de
7411      de = hl
7412      
7413      hl = bc            de = de, swap bc <=> hl
7414      bc = hl
7415      de = de
7416
7417      hl = de            Worst case
7418      bc = hl
7419      de = bc
7420
7421      hl = de            bc = bc, swap hl <=> de
7422      bc = bc
7423      de = hl
7424
7425    Break it down into:
7426     * Any pair = pair are done last
7427     * Any pair = iTemp are done last
7428     * Any swaps can be done any time
7429
7430    A worst case:
7431     push p1
7432     p1 = p2
7433     p2 = p3
7434     pop  p3
7435
7436    So how do we detect the cases?
7437    How about a 3x3 matrix?
7438         source
7439    dest x x x x
7440         x x x x
7441         x x x x (Fourth for iTemp/other)
7442
7443    First determin which mode to use by counting the number of unity and
7444    iTemp assigns.
7445      Three - any order
7446      Two - Assign the pair first, then the rest
7447      One - Swap the two, then the rest
7448      Zero - Worst case.
7449 */
7450 static void
7451 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7452 {
7453   PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7454   PAIR_ID dest[3] = {
7455     PAIR_BC, PAIR_HL, PAIR_DE
7456   };
7457   int i, j, nunity = 0;
7458   memset (ids, PAIR_INVALID, sizeof (ids));
7459
7460   /* Sanity checks */
7461   wassert (nparams == 3);
7462
7463   /* First save everything that needs to be saved. */
7464   _saveRegsForCall (ic, 0);
7465
7466   /* Loading HL first means that DE is always fine. */
7467   for (i = 0; i < nparams; i++)
7468     {
7469       aopOp (pparams[i], ic, FALSE, FALSE);
7470       ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7471     }
7472
7473   /* Count the number of unity or iTemp assigns. */
7474   for (i = 0; i < 3; i++) 
7475     {
7476       if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7477         {
7478           nunity++;
7479         }
7480     }
7481
7482   if (nunity == 3)
7483     {
7484       /* Any order, fall through. */
7485     }
7486   else if (nunity == 2)
7487     {
7488       /* One is assigned.  Pull it out and assign. */
7489       for (i = 0; i < 3; i++)
7490         {
7491           for (j = 0; j < NUM_PAIRS; j++)
7492             {
7493               if (ids[dest[i]][j] == TRUE)
7494                 {
7495                   /* Found it.  See if it's the right one. */
7496                   if (j == PAIR_INVALID || j == dest[i])
7497                     {
7498                       /* Keep looking. */
7499                     }
7500                   else
7501                     {
7502                       fetchPair(dest[i], AOP (pparams[i]));
7503                       goto done;
7504                     }
7505                 }
7506             }
7507         }
7508     }
7509   else if (nunity == 1)
7510     {
7511       /* Find the pairs to swap. */
7512       for (i = 0; i < 3; i++)
7513         {
7514           for (j = 0; j < NUM_PAIRS; j++)
7515             {
7516               if (ids[dest[i]][j] == TRUE)
7517                 {
7518                   if (j == PAIR_INVALID || j == dest[i])
7519                     {
7520                       /* Keep looking. */
7521                     }
7522                   else
7523                     {
7524                       _swap (j, dest[i]);
7525                       goto done;
7526                     }
7527                 }
7528             }
7529         }
7530     }
7531   else
7532     {
7533       int next = getPairId (AOP (pparams[0]));
7534       emit2 ("push %s", _pairs[next].name);
7535
7536       if (next == dest[1])
7537         {
7538           fetchPair (dest[1], AOP (pparams[1]));
7539           fetchPair (dest[2], AOP (pparams[2]));
7540         }
7541       else
7542         {
7543           fetchPair (dest[2], AOP (pparams[2]));
7544           fetchPair (dest[1], AOP (pparams[1]));
7545         }
7546       emit2 ("pop %s", _pairs[dest[0]].name);
7547     }
7548  done:
7549   /* Finally pull out all of the iTemps */
7550   for (i = 0; i < 3; i++)
7551     {
7552       if (ids[dest[i]][PAIR_INVALID] == 1)
7553         {
7554           fetchPair (dest[i], AOP (pparams[i]));
7555         }
7556     }
7557 }
7558
7559 static void
7560 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7561 {
7562   operand *from, *to;
7563   symbol *label;
7564   bool deInUse;
7565
7566   wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7567   to = pparams[0];
7568   from = pparams[1];
7569
7570   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7571
7572   setupForBuiltin3 (ic, nParams, pparams);
7573
7574   label = newiTempLabel(NULL);
7575
7576   emitLabel (label->key);
7577   emit2 ("ld a,(hl)");
7578   emit2 ("ldi");
7579   emit2 ("or a");
7580   emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7581
7582   freeAsmop (from, NULL, ic->next);
7583   freeAsmop (to, NULL, ic);
7584 }
7585
7586 static void
7587 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7588 {
7589   operand *from, *to, *count;
7590   bool deInUse;
7591
7592   wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7593   to = pparams[2];
7594   from = pparams[1];
7595   count = pparams[0];
7596
7597   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7598
7599   setupForBuiltin3 (ic, nParams, pparams);
7600
7601   emit2 ("ldir");
7602
7603   freeAsmop (count, NULL, ic->next->next);
7604   freeAsmop (from, NULL, ic);
7605
7606   _restoreRegsAfterCall();
7607
7608   /* if we need assign a result value */
7609   if ((IS_ITEMP (IC_RESULT (ic)) &&
7610        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7611         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7612       IS_TRUE_SYMOP (IC_RESULT (ic)))
7613     {
7614       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7615       movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7616       freeAsmop (IC_RESULT (ic), NULL, ic);
7617     }
7618
7619   freeAsmop (to, NULL, ic->next);
7620 }
7621
7622 /*-----------------------------------------------------------------*/
7623 /* genBuiltIn - calls the appropriate function to  generating code */
7624 /* for a built in function                                         */
7625 /*-----------------------------------------------------------------*/
7626 static void genBuiltIn (iCode *ic)
7627 {
7628     operand *bi_parms[MAX_BUILTIN_ARGS];
7629     int nbi_parms;
7630     iCode *bi_iCode;
7631     symbol *bif;
7632
7633     /* get all the arguments for a built in function */
7634     bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7635
7636     /* which function is it */
7637     bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7638
7639     if (strcmp(bif->name,"__builtin_strcpy")==0) 
7640       {
7641         genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7642       } 
7643     else if (strcmp(bif->name,"__builtin_memcpy")==0) 
7644       {
7645         genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7646       } 
7647     else 
7648       {
7649         wassertl (0, "Unknown builtin function encountered");
7650       }
7651 }
7652
7653 /*-----------------------------------------------------------------*/
7654 /* genZ80Code - generate code for Z80 based controllers            */
7655 /*-----------------------------------------------------------------*/
7656 void
7657 genZ80Code (iCode * lic)
7658 {
7659   iCode *ic;
7660   int cln = 0;
7661
7662   /* Hack */
7663   if (IS_GB)
7664     {
7665       _fReturn = _gbz80_return;
7666       _fTmp = _gbz80_return;
7667     }
7668   else
7669     {
7670       _fReturn = _z80_return;
7671       _fTmp = _z80_return;
7672     }
7673
7674   _G.lines.head = _G.lines.current = NULL;
7675
7676   for (ic = lic; ic; ic = ic->next)
7677     {
7678       _G.current_iCode = ic;
7679
7680       if (cln != ic->lineno)
7681         {
7682           if (!options.noCcodeInAsm) {
7683             emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7684                    printCLine(ic->filename, ic->lineno));
7685           }
7686           cln = ic->lineno;
7687         }
7688       if (options.iCodeInAsm) {
7689         emit2 (";ic:%d: %s", ic->key, printILine(ic));
7690       }
7691       /* if the result is marked as
7692          spilt and rematerializable or code for
7693          this has already been generated then
7694          do nothing */
7695       if (resultRemat (ic) || ic->generated)
7696         continue;
7697
7698       /* depending on the operation */
7699       switch (ic->op)
7700         {
7701         case '!':
7702           emitDebug ("; genNot");
7703           genNot (ic);
7704           break;
7705
7706         case '~':
7707           emitDebug ("; genCpl");
7708           genCpl (ic);
7709           break;
7710
7711         case UNARYMINUS:
7712           emitDebug ("; genUminus");
7713           genUminus (ic);
7714           break;
7715
7716         case IPUSH:
7717           emitDebug ("; genIpush");
7718           genIpush (ic);
7719           break;
7720
7721         case IPOP:
7722           /* IPOP happens only when trying to restore a
7723              spilt live range, if there is an ifx statement
7724              following this pop then the if statement might
7725              be using some of the registers being popped which
7726              would destory the contents of the register so
7727              we need to check for this condition and handle it */
7728           if (ic->next &&
7729               ic->next->op == IFX &&
7730               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7731             {
7732               emitDebug ("; genIfx");
7733               genIfx (ic->next, ic);
7734             }
7735           else
7736             {
7737               emitDebug ("; genIpop");
7738               genIpop (ic);
7739             }
7740           break;
7741
7742         case CALL:
7743           emitDebug ("; genCall");
7744           genCall (ic);
7745           break;
7746
7747         case PCALL:
7748           emitDebug ("; genPcall");
7749           genPcall (ic);
7750           break;
7751
7752         case FUNCTION:
7753           emitDebug ("; genFunction");
7754           genFunction (ic);
7755           break;
7756
7757         case ENDFUNCTION:
7758           emitDebug ("; genEndFunction");
7759           genEndFunction (ic);
7760           break;
7761
7762         case RETURN:
7763           emitDebug ("; genRet");
7764           genRet (ic);
7765           break;
7766
7767         case LABEL:
7768           emitDebug ("; genLabel");
7769           genLabel (ic);
7770           break;
7771
7772         case GOTO:
7773           emitDebug ("; genGoto");
7774           genGoto (ic);
7775           break;
7776
7777         case '+':
7778           emitDebug ("; genPlus");
7779           genPlus (ic);
7780           break;
7781
7782         case '-':
7783           emitDebug ("; genMinus");
7784           genMinus (ic);
7785           break;
7786
7787         case '*':
7788           emitDebug ("; genMult");
7789           genMult (ic);
7790           break;
7791
7792         case '/':
7793           emitDebug ("; genDiv");
7794           genDiv (ic);
7795           break;
7796
7797         case '%':
7798           emitDebug ("; genMod");
7799           genMod (ic);
7800           break;
7801
7802         case '>':
7803           emitDebug ("; genCmpGt");
7804           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7805           break;
7806
7807         case '<':
7808           emitDebug ("; genCmpLt");
7809           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7810           break;
7811
7812         case LE_OP:
7813         case GE_OP:
7814         case NE_OP:
7815
7816           /* note these two are xlated by algebraic equivalence
7817              during parsing SDCC.y */
7818           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7819                   "got '>=' or '<=' shouldn't have come here");
7820           break;
7821
7822         case EQ_OP:
7823           emitDebug ("; genCmpEq");
7824           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7825           break;
7826
7827         case AND_OP:
7828           emitDebug ("; genAndOp");
7829           genAndOp (ic);
7830           break;
7831
7832         case OR_OP:
7833           emitDebug ("; genOrOp");
7834           genOrOp (ic);
7835           break;
7836
7837         case '^':
7838           emitDebug ("; genXor");
7839           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7840           break;
7841
7842         case '|':
7843           emitDebug ("; genOr");
7844           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7845           break;
7846
7847         case BITWISEAND:
7848           emitDebug ("; genAnd");
7849           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7850           break;
7851
7852         case INLINEASM:
7853           emitDebug ("; genInline");
7854           genInline (ic);
7855           break;
7856
7857         case RRC:
7858           emitDebug ("; genRRC");
7859           genRRC (ic);
7860           break;
7861
7862         case RLC:
7863           emitDebug ("; genRLC");
7864           genRLC (ic);
7865           break;
7866
7867         case GETHBIT:
7868           emitDebug ("; genGetHBIT");
7869           genGetHbit (ic);
7870           break;
7871
7872         case LEFT_OP:
7873           emitDebug ("; genLeftShift");
7874           genLeftShift (ic);
7875           break;
7876
7877         case RIGHT_OP:
7878           emitDebug ("; genRightShift");
7879           genRightShift (ic);
7880           break;
7881
7882         case GET_VALUE_AT_ADDRESS:
7883           emitDebug ("; genPointerGet");
7884           genPointerGet (ic);
7885           break;
7886
7887         case '=':
7888
7889           if (POINTER_SET (ic))
7890             {
7891               emitDebug ("; genAssign (pointer)");
7892               genPointerSet (ic);
7893             }
7894           else
7895             {
7896               emitDebug ("; genAssign");
7897               genAssign (ic);
7898             }
7899           break;
7900
7901         case IFX:
7902           emitDebug ("; genIfx");
7903           genIfx (ic, NULL);
7904           break;
7905
7906         case ADDRESS_OF:
7907           emitDebug ("; genAddrOf");
7908           genAddrOf (ic);
7909           break;
7910
7911         case JUMPTABLE:
7912           emitDebug ("; genJumpTab");
7913           genJumpTab (ic);
7914           break;
7915
7916         case CAST:
7917           emitDebug ("; genCast");
7918           genCast (ic);
7919           break;
7920
7921         case RECEIVE:
7922           emitDebug ("; genReceive");
7923           genReceive (ic);
7924           break;
7925
7926         case SEND:
7927           if (ic->builtinSEND)
7928             {
7929               emitDebug ("; genBuiltIn");
7930               genBuiltIn(ic);
7931             }
7932           else
7933             {
7934               emitDebug ("; addSet");
7935               addSet (&_G.sendSet, ic);
7936             }
7937           break;
7938
7939         case ARRAYINIT:
7940           emitDebug ("; genArrayInit");
7941           genArrayInit(ic);
7942           break;
7943
7944         case DUMMY_READ_VOLATILE:
7945           emitDebug ("; genDummyRead");
7946           genDummyRead (ic);
7947           break;
7948
7949         default:
7950           ic = ic;
7951         }
7952     }
7953
7954
7955   /* now we are ready to call the
7956      peep hole optimizer */
7957   if (!options.nopeep)
7958     peepHole (&_G.lines.head);
7959
7960   /* This is unfortunate */
7961   /* now do the actual printing */
7962   {
7963     FILE *fp = codeOutFile;
7964     if (isInHome () && codeOutFile == code->oFile)
7965       codeOutFile = home->oFile;
7966     printLine (_G.lines.head, codeOutFile);
7967     if (_G.flushStatics)
7968       {
7969         flushStatics ();
7970         _G.flushStatics = 0;
7971       }
7972     codeOutFile = fp;
7973   }
7974
7975   freeTrace(&_G.lines.trace);
7976   freeTrace(&_G.trace.aops);
7977 }
7978
7979 /*
7980   Attic
7981 static int
7982 _isPairUsed (iCode * ic, PAIR_ID pairId)
7983 {
7984   int ret = 0;
7985   switch (pairId)
7986     {
7987     case PAIR_DE:
7988       if (bitVectBitValue (ic->rMask, D_IDX))
7989         ret++;
7990       if (bitVectBitValue (ic->rMask, E_IDX))
7991         ret++;
7992       break;
7993     default:
7994       wassert (0);
7995     }
7996   return ret;
7997 }
7998
7999 static char *
8000 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8001 {
8002   unsigned long v;
8003   value *val = aop->aopu.aop_lit;
8004
8005   wassert (aop->type == AOP_LIT);
8006   wassert (!IS_FLOAT (val->type));
8007
8008   v = (unsigned long) floatFromVal (val);
8009
8010   if (xor)
8011     v ^= 0x8000;
8012   if (negate)
8013     v = 0-v;
8014   v &= 0xFFFF;
8015
8016   tsprintf (buffer, sizeof(buffer), "!immedword", v);
8017   return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
8018 }
8019
8020
8021 */