Added support for gsinit packing.
[fw/sdcc] / src / z80 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - Z80 specific code generator.
3
4   Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
5                                        ticks dhry  size
6   Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
7   Improved WORD push                    22784 144 19AE
8   With label1 on                        22694 144 197E
9   With label2 on                        22743 144 198A
10   With label3 on                        22776 144 1999
11   With label4 on                        22776 144 1999
12   With all 'label' on                   22661 144 196F
13   With loopInvariant on                 20919 156 19AB
14   With loopInduction on                 Breaks    198B
15   With all working on                   20796 158 196C
16   Slightly better genCmp(signed)        20597 159 195B
17   Better reg packing, first peephole    20038 163 1873
18   With assign packing                   19281 165 1849
19   5/3/00                                17741 185 17B6
20   With reg params for mul and div       16234 202 162D
21
22   1. Starting again at 3 Aug 01         34965  93 219C
23    No asm strings
24    Includes long mul/div in code
25   2. Optimised memcpy for acc use       32102 102 226B
26   3. Optimised strcpy for acc use       27819 117 2237
27   3a Optimised memcpy fun
28   4. Optimised strcmp fun               21999 149 2294
29   5. Optimised strcmp further           21660 151 228C
30   6. Optimised memcpy by unroling       20885 157 2201
31   7. After turning loop induction on    19862 165 236D
32
33   Michael Hope <michaelh@juju.net.nz> 2000
34   Based on the mcs51 generator -
35       Sandeep Dutta . sandeep.dutta@usa.net (1998)
36    and -  Jean-Louis VERN.jlvern@writeme.com (1999)
37
38   This program is free software; you can redistribute it and/or modify it
39   under the terms of the GNU General Public License as published by the
40   Free Software Foundation; either version 2, or (at your option) any
41   later version.
42
43   This program is distributed in the hope that it will be useful,
44   but WITHOUT ANY WARRANTY; without even the implied warranty of
45   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
46   GNU General Public License for more details.
47
48
49   You should have received a copy of the GNU General Public License
50   along with this program; if not, write to the Free Software
51   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
52
53   In other words, you are welcome to use, share and improve this program.
54   You are forbidden to forbid anyone else to use, share and improve
55   what you give them.   Help stamp out software-hoarding!
56
57 -------------------------------------------------------------------------*/
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <ctype.h>
63
64 #ifdef HAVE_SYS_ISA_DEFS_H
65 #include <sys/isa_defs.h>
66 #endif
67
68 #include "z80.h"
69 #include "SDCCglobl.h"
70 #include "SDCCpeeph.h"
71 #include "gen.h"
72 #include "SDCCglue.h"
73 #include "newalloc.h"
74
75 /* this is the down and dirty file with all kinds of kludgy & hacky
76    stuff. This is what it is all about CODE GENERATION for a specific MCU.
77    Some of the routines may be reusable, will have to see */
78
79 /* Z80 calling convention description.
80    Parameters are passed right to left.  As the stack grows downwards,
81    the parameters are arranged in left to right in memory.
82    Parameters may be passed in the HL and DE registers with one
83    parameter per pair.
84    PENDING: What if the parameter is a long?
85    Everything is caller saves. i.e. the caller must save any registers
86    that it wants to preserve over the call.
87    The return value is returned in DEHL.  DE is normally used as a
88    working register pair.  Caller saves allows it to be used for a
89    return value.
90    va args functions do not use register parameters.  All arguments
91    are passed on the stack.
92    IX is used as an index register to the top of the local variable
93    area.  ix-0 is the top most local variable.
94 */
95
96 enum {
97   DISABLE_DEBUG = 1
98 };
99
100 static char *_z80_return[] =
101 {"l", "h", "e", "d"};
102 static char *_gbz80_return[] =
103 {"e", "d", "l", "h"};
104 static char *_fReceive[] =
105   { "c", "b", "e", "d" };
106
107 static char **_fReturn;
108 static char **_fTmp;
109
110 extern FILE *codeOutFile;
111
112 typedef enum
113   {
114     PAIR_INVALID,
115     PAIR_AF,
116     PAIR_BC,
117     PAIR_DE,
118     PAIR_HL,
119     PAIR_IY,
120     PAIR_IX,
121     NUM_PAIRS
122   } PAIR_ID;
123
124 static struct
125 {
126   const char *name;
127   const char *l;
128   const char *h;
129 } _pairs[NUM_PAIRS] = {
130   {    "??1", "?2", "?3" },
131   {    "af", "f", "a" },
132   {    "bc", "c", "b" },
133   {    "de", "e", "d" },
134   {    "hl", "l", "h" },
135   {    "iy", "iy.l?", "iy.h?" },
136   {    "ix", "ix.l?", "ix.h?" }
137 };
138
139 // PENDING
140 #define ACC_NAME        _pairs[PAIR_AF].h
141
142 #define RESULTONSTACK(x) \
143                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
144                          IC_RESULT(x)->aop->type == AOP_STK )
145
146 enum 
147   {
148     LSB,
149     MSB16,
150     MSB24,
151     MSB32
152   };
153
154 static struct 
155 {
156   struct 
157   {
158     AOP_TYPE last_type;
159     const char *lit;
160     int offset;
161   } pairs[NUM_PAIRS];
162   struct 
163   {
164     int last;
165     int pushed;
166     int param_offset;
167     int offset;
168     int pushedBC;
169     int pushedDE;
170   } stack;
171   int frameId;
172   int receiveOffset;
173   bool flushStatics;
174   bool in_home;
175   const char *lastFunctionName;
176
177   set *sendSet;
178
179   struct
180   {
181     /** TRUE if the registers have already been saved. */
182     bool saved;
183   } saves;
184
185   struct 
186   {
187     lineNode *head;
188     lineNode *current;
189     int isInline;
190   } lines;
191
192 } _G;
193
194 static const char *aopGet (asmop * aop, int offset, bool bit16);
195
196 static void
197 _tidyUp (char *buf)
198 {
199   /* Clean up the line so that it is 'prettier' */
200   if (strchr (buf, ':'))
201     {
202       /* Is a label - cant do anything */
203       return;
204     }
205   /* Change the first (and probably only) ' ' to a tab so
206      everything lines up.
207   */
208   while (*buf)
209     {
210       if (*buf == ' ')
211         {
212           *buf = '\t';
213           break;
214         }
215       buf++;
216     }
217 }
218
219 static void
220 _vemit2 (const char *szFormat, va_list ap)
221 {
222   char buffer[256];
223
224   tvsprintf (buffer, szFormat, ap);
225
226   _tidyUp (buffer);
227   _G.lines.current = (_G.lines.current ?
228               connectLine (_G.lines.current, newLineNode (buffer)) :
229               (_G.lines.head = newLineNode (buffer)));
230
231   _G.lines.current->isInline = _G.lines.isInline;
232 }
233
234 static void
235 emit2 (const char *szFormat,...)
236 {
237   va_list ap;
238
239   va_start (ap, szFormat);
240
241   _vemit2 (szFormat, ap);
242
243   va_end (ap);
244 }
245
246 static void
247 emitDebug (const char *szFormat,...)
248 {
249   if (!DISABLE_DEBUG)
250     {
251       va_list ap;
252       
253       va_start (ap, szFormat);
254       
255       _vemit2 (szFormat, ap);
256       
257       va_end (ap);
258     }
259 }
260
261 /*-----------------------------------------------------------------*/
262 /* emit2 - writes the code into a file : for now it is simple    */
263 /*-----------------------------------------------------------------*/
264 void
265 _emit2 (const char *inst, const char *fmt,...)
266 {
267   va_list ap;
268   char lb[INITIAL_INLINEASM];
269   char *lbp = lb;
270
271   va_start (ap, fmt);
272
273   if (*inst != '\0')
274     {
275       sprintf (lb, "%s\t", inst);
276       vsprintf (lb + (strlen (lb)), fmt, ap);
277     }
278   else
279     vsprintf (lb, fmt, ap);
280
281   while (isspace (*lbp))
282     lbp++;
283
284   if (lbp && *lbp)
285     {
286       _G.lines.current = (_G.lines.current ?
287                   connectLine (_G.lines.current, newLineNode (lb)) :
288                   (_G.lines.head = newLineNode (lb)));
289     }
290   _G.lines.current->isInline = _G.lines.isInline;
291   va_end (ap);
292 }
293
294 static void
295 _emitMove(const char *to, const char *from)
296 {
297   if (strcasecmp(to, from) != 0) 
298     {
299       emit2("ld %s,%s", to, from);
300     }
301   else 
302     {
303       // Optimise it out.
304       // Could leave this to the peephole, but sometimes the peephole is inhibited.
305     }
306 }
307
308 static void
309 _moveA(const char *moveFrom)
310 {
311     // Let the peephole optimiser take care of redundent loads
312     _emitMove(ACC_NAME, moveFrom);
313 }
314
315 static void
316 _clearCarry(void)
317 {
318     emit2("xor a,a");
319 }
320
321 const char *
322 getPairName (asmop * aop)
323 {
324   if (aop->type == AOP_REG)
325     {
326       switch (aop->aopu.aop_reg[0]->rIdx)
327         {
328         case C_IDX:
329           return "bc";
330           break;
331         case E_IDX:
332           return "de";
333           break;
334         case L_IDX:
335           return "hl";
336           break;
337         }
338     }
339   else if (aop->type == AOP_STR)
340     {
341       switch (*aop->aopu.aop_str[0])
342         {
343         case 'c':
344           return "bc";
345           break;
346         case 'e':
347           return "de";
348           break;
349         case 'l':
350           return "hl";
351           break;
352         }
353     }
354   wassert (0);
355   return NULL;
356 }
357
358 static PAIR_ID
359 getPairId (asmop * aop)
360 {
361   if (aop->size == 2)
362     {
363       if (aop->type == AOP_REG)
364         {
365           if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
366             {
367               return PAIR_BC;
368             }
369           if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
370             {
371               return PAIR_DE;
372             }
373           if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
374             {
375               return PAIR_HL;
376             }
377         }
378       if (aop->type == AOP_STR)
379         {
380           if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
381             {
382               return PAIR_BC;
383             }
384           if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
385             {
386               return PAIR_DE;
387             }
388           if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
389             {
390               return PAIR_HL;
391             }
392         }
393     }
394   return PAIR_INVALID;
395 }
396
397 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
398 bool
399 isPair (asmop * aop)
400 {
401   return (getPairId (aop) != PAIR_INVALID);
402 }
403
404 bool
405 isPtrPair (asmop * aop)
406 {
407   PAIR_ID pairId = getPairId (aop);
408   switch (pairId)
409     {
410     case PAIR_HL:
411     case PAIR_IY:
412     case PAIR_IX:
413       return TRUE;
414     default:
415       return FALSE;
416     }
417 }
418 /** Push a register pair onto the stack */
419 void
420 genPairPush (asmop * aop)
421 {
422   emit2 ("push %s", getPairName (aop));
423 }
424
425
426 /*-----------------------------------------------------------------*/
427 /* newAsmop - creates a new asmOp                                  */
428 /*-----------------------------------------------------------------*/
429 static asmop *
430 newAsmop (short type)
431 {
432   asmop *aop;
433
434   aop = Safe_calloc (1, sizeof (asmop));
435   aop->type = type;
436   return aop;
437 }
438
439 /*-----------------------------------------------------------------*/
440 /* aopForSym - for a true symbol                                   */
441 /*-----------------------------------------------------------------*/
442 static asmop *
443 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
444 {
445   asmop *aop;
446   memmap *space;
447
448   wassert (ic);
449   wassert (sym);
450   wassert (sym->etype);
451
452   space = SPEC_OCLS (sym->etype);
453
454   /* if already has one */
455   if (sym->aop)
456     return sym->aop;
457
458   /* Assign depending on the storage class */
459   if (sym->onStack || sym->iaccess)
460     {
461       emitDebug ("; AOP_STK for %s", sym->rname);
462       sym->aop = aop = newAsmop (AOP_STK);
463       aop->size = getSize (sym->type);
464       aop->aopu.aop_stk = sym->stack;
465       return aop;
466     }
467
468   /* special case for a function */
469   if (IS_FUNC (sym->type))
470     {
471       sym->aop = aop = newAsmop (AOP_IMMD);
472       aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
473       strcpy (aop->aopu.aop_immd, sym->rname);
474       aop->size = 2;
475       return aop;
476     }
477
478   if (IS_GB)
479     {
480       /* if it is in direct space */
481       if (IN_REGSP (space) && !requires_a)
482         {
483           sym->aop = aop = newAsmop (AOP_SFR);
484           aop->aopu.aop_dir = sym->rname;
485           aop->size = getSize (sym->type);
486           emitDebug ("; AOP_SFR for %s", sym->rname);
487           return aop;
488         }
489     }
490
491   /* only remaining is far space */
492   /* in which case DPTR gets the address */
493   if (IS_GB)
494     {
495       emitDebug ("; AOP_HL for %s", sym->rname);
496       sym->aop = aop = newAsmop (AOP_HL);
497     }
498   else
499     {
500       sym->aop = aop = newAsmop (AOP_IY);
501     }
502   aop->size = getSize (sym->type);
503   aop->aopu.aop_dir = sym->rname;
504
505   /* if it is in code space */
506   if (IN_CODESPACE (space))
507     aop->code = 1;
508
509   return aop;
510 }
511
512 /*-----------------------------------------------------------------*/
513 /* aopForRemat - rematerialzes an object                           */
514 /*-----------------------------------------------------------------*/
515 static asmop *
516 aopForRemat (symbol * sym)
517 {
518   char *s = buffer;
519   iCode *ic = sym->rematiCode;
520   asmop *aop = newAsmop (AOP_IMMD);
521
522   while (1)
523     {
524       /* if plus or minus print the right hand side */
525       if (ic->op == '+' || ic->op == '-')
526         {
527           /* PENDING: for re-target */
528           sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
529                    ic->op);
530           s += strlen (s);
531           ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
532           continue;
533         }
534       /* we reached the end */
535       sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
536       break;
537     }
538
539   aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
540   strcpy (aop->aopu.aop_immd, buffer);
541   return aop;
542 }
543
544 /*-----------------------------------------------------------------*/
545 /* regsInCommon - two operands have some registers in common       */
546 /*-----------------------------------------------------------------*/
547 bool
548 regsInCommon (operand * op1, operand * op2)
549 {
550   symbol *sym1, *sym2;
551   int i;
552
553   /* if they have registers in common */
554   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
555     return FALSE;
556
557   sym1 = OP_SYMBOL (op1);
558   sym2 = OP_SYMBOL (op2);
559
560   if (sym1->nRegs == 0 || sym2->nRegs == 0)
561     return FALSE;
562
563   for (i = 0; i < sym1->nRegs; i++)
564     {
565       int j;
566       if (!sym1->regs[i])
567         continue;
568
569       for (j = 0; j < sym2->nRegs; j++)
570         {
571           if (!sym2->regs[j])
572             continue;
573
574           if (sym2->regs[j] == sym1->regs[i])
575             return TRUE;
576         }
577     }
578
579   return FALSE;
580 }
581
582 /*-----------------------------------------------------------------*/
583 /* operandsEqu - equivalent                                        */
584 /*-----------------------------------------------------------------*/
585 bool
586 operandsEqu (operand * op1, operand * op2)
587 {
588   symbol *sym1, *sym2;
589
590   /* if they not symbols */
591   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
592     return FALSE;
593
594   sym1 = OP_SYMBOL (op1);
595   sym2 = OP_SYMBOL (op2);
596
597   /* if both are itemps & one is spilt
598      and the other is not then false */
599   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
600       sym1->isspilt != sym2->isspilt)
601     return FALSE;
602
603   /* if they are the same */
604   if (sym1 == sym2)
605     return 1;
606
607   if (strcmp (sym1->rname, sym2->rname) == 0)
608     return 2;
609
610
611   /* if left is a tmp & right is not */
612   if (IS_ITEMP (op1) &&
613       !IS_ITEMP (op2) &&
614       sym1->isspilt &&
615       (sym1->usl.spillLoc == sym2))
616     return 3;
617
618   if (IS_ITEMP (op2) &&
619       !IS_ITEMP (op1) &&
620       sym2->isspilt &&
621       sym1->level > 0 &&
622       (sym2->usl.spillLoc == sym1))
623     return 4;
624
625   return FALSE;
626 }
627
628 /*-----------------------------------------------------------------*/
629 /* sameRegs - two asmops have the same registers                   */
630 /*-----------------------------------------------------------------*/
631 bool
632 sameRegs (asmop * aop1, asmop * aop2)
633 {
634   int i;
635
636   if (aop1->type == AOP_SFR ||
637       aop2->type == AOP_SFR)
638     return FALSE;
639
640   if (aop1 == aop2)
641     return TRUE;
642
643   if (aop1->type != AOP_REG ||
644       aop2->type != AOP_REG)
645     return FALSE;
646
647   if (aop1->size != aop2->size)
648     return FALSE;
649
650   for (i = 0; i < aop1->size; i++)
651     if (aop1->aopu.aop_reg[i] !=
652         aop2->aopu.aop_reg[i])
653       return FALSE;
654
655   return TRUE;
656 }
657
658 /*-----------------------------------------------------------------*/
659 /* aopOp - allocates an asmop for an operand  :                    */
660 /*-----------------------------------------------------------------*/
661 static void
662 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
663 {
664   asmop *aop;
665   symbol *sym;
666   int i;
667
668   if (!op)
669     return;
670
671   /* if this a literal */
672   if (IS_OP_LITERAL (op))
673     {
674       op->aop = aop = newAsmop (AOP_LIT);
675       aop->aopu.aop_lit = op->operand.valOperand;
676       aop->size = getSize (operandType (op));
677       return;
678     }
679
680   /* if already has a asmop then continue */
681   if (op->aop)
682     return;
683
684   /* if the underlying symbol has a aop */
685   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
686     {
687       op->aop = OP_SYMBOL (op)->aop;
688       return;
689     }
690
691   /* if this is a true symbol */
692   if (IS_TRUE_SYMOP (op))
693     {
694       op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
695       return;
696     }
697
698   /* this is a temporary : this has
699      only four choices :
700      a) register
701      b) spillocation
702      c) rematerialize
703      d) conditional
704      e) can be a return use only */
705
706   sym = OP_SYMBOL (op);
707
708   /* if the type is a conditional */
709   if (sym->regType == REG_CND)
710     {
711       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
712       aop->size = 0;
713       return;
714     }
715
716   /* if it is spilt then two situations
717      a) is rematerialize
718      b) has a spill location */
719   if (sym->isspilt || sym->nRegs == 0)
720     {
721       /* rematerialize it NOW */
722       if (sym->remat)
723         {
724           sym->aop = op->aop = aop =
725             aopForRemat (sym);
726           aop->size = getSize (sym->type);
727           return;
728         }
729
730       if (sym->accuse)
731         {
732           if (sym->accuse == ACCUSE_A)
733             {
734               aop = op->aop = sym->aop = newAsmop (AOP_ACC);
735               aop->size = getSize (sym->type);
736               wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
737
738               aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
739             }
740           else if (sym->accuse == ACCUSE_HL)
741             {
742               wassert (!IS_GB);
743               aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
744               aop->size = getSize (sym->type);
745               wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
746               aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
747               aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
748             }
749           else 
750               {
751                   wassert (0);
752               }
753           return;
754         }
755
756       if (sym->ruonly)
757         {
758           int i;
759           aop = op->aop = sym->aop = newAsmop (AOP_STR);
760           aop->size = getSize (sym->type);
761           for (i = 0; i < 4; i++)
762             aop->aopu.aop_str[i] = _fReturn[i];
763           return;
764         }
765
766       /* else spill location  */
767       sym->aop = op->aop = aop =
768         aopForSym (ic, sym->usl.spillLoc, result, requires_a);
769       aop->size = getSize (sym->type);
770       return;
771     }
772
773   /* must be in a register */
774   sym->aop = op->aop = aop = newAsmop (AOP_REG);
775   aop->size = sym->nRegs;
776   for (i = 0; i < sym->nRegs; i++)
777     aop->aopu.aop_reg[i] = sym->regs[i];
778 }
779
780 /*-----------------------------------------------------------------*/
781 /* freeAsmop - free up the asmop given to an operand               */
782 /*----------------------------------------------------------------*/
783 static void
784 freeAsmop (operand * op, asmop * aaop, iCode * ic)
785 {
786   asmop *aop;
787
788   if (!op)
789     aop = aaop;
790   else
791     aop = op->aop;
792
793   if (!aop)
794     return;
795
796   if (aop->freed)
797     goto dealloc;
798
799   aop->freed = 1;
800
801 dealloc:
802   /* all other cases just dealloc */
803   if (op)
804     {
805       op->aop = NULL;
806       if (IS_SYMOP (op))
807         {
808           OP_SYMBOL (op)->aop = NULL;
809           /* if the symbol has a spill */
810           if (SPIL_LOC (op))
811             SPIL_LOC (op)->aop = NULL;
812         }
813     }
814 }
815
816 bool
817 isLitWord (asmop * aop)
818 {
819   /*    if (aop->size != 2)
820      return FALSE; */
821   switch (aop->type)
822     {
823     case AOP_IMMD:
824     case AOP_LIT:
825       return TRUE;
826     default:
827       return FALSE;
828     }
829 }
830
831 char *
832 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
833 {
834   char *s = buffer;
835   char *rs;
836
837   /* depending on type */
838   switch (aop->type)
839     {
840     case AOP_HL:
841     case AOP_IY:
842     case AOP_IMMD:
843       /* PENDING: for re-target */
844       if (with_hash)
845         tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
846       else
847         tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
848
849       return gc_strdup(s);
850
851     case AOP_LIT:
852       {
853         value *val = aop->aopu.aop_lit;
854         /* if it is a float then it gets tricky */
855         /* otherwise it is fairly simple */
856         if (!IS_FLOAT (val->type))
857           {
858             unsigned long v = (unsigned long) floatFromVal (val);
859
860             if (offset == 2)
861               {
862                 v >>= 16;
863               }
864             else if (offset == 0)
865               {
866                 // OK
867               }
868             else 
869               {
870                 wassertl(0, "Encountered an invalid offset while fetching a literal");
871               }
872
873             if (with_hash)
874               tsprintf (buffer, "!immedword", v);
875             else
876               tsprintf (buffer, "!constword", v);
877
878             return gc_strdup(buffer);
879           }
880         else
881           {
882             /* A float */
883             Z80_FLOAT f;
884             convertFloat (&f, floatFromVal (val));
885             if (with_hash)
886               tsprintf (buffer, "!immedword", f.w[offset / 2]);
887             else
888               tsprintf (buffer, "!constword", f.w[offset / 2]);
889             rs = Safe_calloc (1, strlen (buffer) + 1);
890             return strcpy (rs, buffer);
891           }
892       }
893     default:
894       return NULL;
895     }
896 }
897
898 char *
899 aopGetWord (asmop * aop, int offset)
900 {
901   return aopGetLitWordLong (aop, offset, TRUE);
902 }
903
904 bool
905 isPtr (const char *s)
906 {
907   if (!strcmp (s, "hl"))
908     return TRUE;
909   if (!strcmp (s, "ix"))
910     return TRUE;
911   if (!strcmp (s, "iy"))
912     return TRUE;
913   return FALSE;
914 }
915
916 static void
917 adjustPair (const char *pair, int *pold, int new)
918 {
919   wassert (pair);
920
921   while (*pold < new)
922     {
923       emit2 ("inc %s", pair);
924       (*pold)++;
925     }
926   while (*pold > new)
927     {
928       emit2 ("dec %s", pair);
929       (*pold)--;
930     }
931 }
932
933 static void
934 spillPair (PAIR_ID pairId)
935 {
936   _G.pairs[pairId].last_type = AOP_INVALID;
937   _G.pairs[pairId].lit = NULL;
938 }
939
940 static void
941 spillCached (void)
942 {
943   spillPair (PAIR_HL);
944   spillPair (PAIR_IY);
945 }
946
947 static bool
948 requiresHL (asmop * aop)
949 {
950   switch (aop->type)
951     {
952     case AOP_IY:
953     case AOP_HL:
954     case AOP_STK:
955       return TRUE;
956     default:
957       return FALSE;
958     }
959 }
960
961 static char *
962 fetchLitSpecial (asmop * aop, bool negate, bool xor)
963 {
964   unsigned long v;
965   value *val = aop->aopu.aop_lit;
966
967   wassert (aop->type == AOP_LIT);
968   wassert (!IS_FLOAT (val->type));
969
970   v = (unsigned long) floatFromVal (val);
971
972   if (xor)
973     v ^= 0x8000;
974   if (negate)
975     v = 0-v;
976   v &= 0xFFFF;
977
978   tsprintf (buffer, "!immedword", v);
979   return gc_strdup (buffer);
980 }
981
982 static void
983 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
984 {
985   const char *l;
986   const char *pair = _pairs[pairId].name;
987   l = aopGetLitWordLong (left, offset, FALSE);
988   wassert (l && pair);
989
990   if (isPtr (pair))
991     {
992       if (pairId == PAIR_HL || pairId == PAIR_IY)
993         {
994           if (_G.pairs[pairId].last_type == left->type)
995             {
996               if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
997                 {
998                   if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
999                     {
1000                       adjustPair (pair, &_G.pairs[pairId].offset, offset);
1001                       return;
1002                     }
1003                   if (pairId == PAIR_IY && abs (offset) < 127)
1004                     {
1005                       return;
1006                     }
1007                 }
1008             }
1009         }
1010       _G.pairs[pairId].last_type = left->type;
1011       _G.pairs[pairId].lit = gc_strdup (l);
1012       _G.pairs[pairId].offset = offset;
1013     }
1014   if (IS_GB && pairId == PAIR_DE && 0)
1015     {
1016       if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1017         {
1018           if (abs (_G.pairs[pairId].offset - offset) < 3)
1019             {
1020               adjustPair (pair, &_G.pairs[pairId].offset, offset);
1021               return;
1022             }
1023         }
1024       _G.pairs[pairId].last_type = left->type;
1025       _G.pairs[pairId].lit = gc_strdup (l);
1026       _G.pairs[pairId].offset = offset;
1027     }
1028   /* Both a lit on the right and a true symbol on the left */
1029   emit2 ("ld %s,!hashedstr", pair, l);
1030 }
1031
1032 static void
1033 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1034 {
1035     /* if this is remateriazable */
1036     if (isLitWord (aop)) {
1037         fetchLitPair (pairId, aop, offset);
1038     }
1039     else {
1040         /* we need to get it byte by byte */
1041         if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1042             aopGet (aop, offset, FALSE);
1043             switch (aop->size) {
1044             case 1:
1045                 emit2 ("ld l,!*hl");
1046                 emit2 ("ld h,!immedbyte", 0);
1047                             break;
1048             case 2:
1049                 emit2 ("!ldahli");
1050                 emit2 ("ld h,!*hl");
1051                 emit2 ("ld l,a");
1052                 break;
1053             default:
1054                 emitDebug ("; WARNING: mlh woosed out.  This code is invalid.");
1055             }
1056         }
1057         else if (IS_Z80 && aop->type == AOP_IY) {
1058             /* Instead of fetching relative to IY, just grab directly
1059                from the address IY refers to */
1060             char *l = aopGetLitWordLong (aop, offset, FALSE);
1061             wassert (l);
1062             emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1063
1064             if (aop->size < 2) {
1065                 emit2("ld %s,!zero", _pairs[pairId].h);
1066             }
1067         }
1068         else {
1069             emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1070             emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1071         }
1072         /* PENDING: check? */
1073         if (pairId == PAIR_HL)
1074             spillPair (PAIR_HL);
1075     }
1076 }
1077
1078 static void
1079 fetchPair (PAIR_ID pairId, asmop * aop)
1080 {
1081   fetchPairLong (pairId, aop, 0);
1082 }
1083
1084 static void
1085 fetchHL (asmop * aop)
1086 {
1087   fetchPair (PAIR_HL, aop);
1088 }
1089
1090 static void
1091 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1092 {
1093   assert (pairId == PAIR_HL || pairId == PAIR_IY);
1094
1095   switch (aop->type)
1096     {
1097     case AOP_IY:
1098       fetchLitPair (pairId, aop, 0);
1099       break;
1100     case AOP_HL:
1101       fetchLitPair (pairId, aop, offset);
1102       _G.pairs[pairId].offset = offset;
1103       break;
1104     case AOP_STK:
1105       {
1106         /* Doesnt include _G.stack.pushed */
1107         int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1108         if (aop->aopu.aop_stk > 0)
1109           {
1110             abso += _G.stack.param_offset;
1111           }
1112         assert (pairId == PAIR_HL);
1113         /* In some cases we can still inc or dec hl */
1114         if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1115           {
1116             adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1117           }
1118         else
1119           {
1120             emit2 ("!ldahlsp", abso + _G.stack.pushed);
1121           }
1122         _G.pairs[pairId].offset = abso;
1123         break;
1124       }
1125     default:
1126       wassert (0);
1127     }
1128   _G.pairs[pairId].last_type = aop->type;
1129 }
1130
1131 static void
1132 emitLabel (int key)
1133 {
1134   emit2 ("!tlabeldef", key);
1135   spillCached ();
1136 }
1137
1138 /*-----------------------------------------------------------------*/
1139 /* aopGet - for fetching value of the aop                          */
1140 /*-----------------------------------------------------------------*/
1141 static const char *
1142 aopGet (asmop * aop, int offset, bool bit16)
1143 {
1144   char *s = buffer;
1145
1146   /* offset is greater than size then zero */
1147   /* PENDING: this seems a bit screwed in some pointer cases. */
1148   if (offset > (aop->size - 1) &&
1149       aop->type != AOP_LIT) 
1150     {
1151       tsprintf (s, "!zero");
1152       return gc_strdup(s);
1153     }
1154
1155   /* depending on type */
1156   switch (aop->type)
1157     {
1158     case AOP_IMMD:
1159       /* PENDING: re-target */
1160       if (bit16)
1161         tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1162       else
1163         switch (offset)
1164           {
1165           case 2:
1166             tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1167             break;
1168           case 1:
1169             tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1170             break;
1171           case 0:
1172             tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1173             break;
1174           default:
1175             wassert (0);
1176           }
1177
1178       return gc_strdup(s);
1179
1180     case AOP_DIR:
1181       wassert (IS_GB);
1182       emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1183       sprintf (s, "a");
1184
1185       return gc_strdup(s);
1186
1187     case AOP_SFR:
1188       wassert (IS_GB);
1189       emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1190       sprintf (s, "a");
1191
1192       return gc_strdup(s);
1193
1194     case AOP_REG:
1195       return aop->aopu.aop_reg[offset]->name;
1196
1197     case AOP_HL:
1198       wassert (IS_GB);
1199       setupPair (PAIR_HL, aop, offset);
1200       tsprintf (s, "!*hl");
1201
1202       return gc_strdup (s);
1203
1204     case AOP_IY:
1205       wassert (IS_Z80);
1206       setupPair (PAIR_IY, aop, offset);
1207       tsprintf (s, "!*iyx", offset);
1208
1209       return gc_strdup(s);
1210
1211     case AOP_STK:
1212       if (IS_GB)
1213         {
1214           setupPair (PAIR_HL, aop, offset);
1215           tsprintf (s, "!*hl");
1216         }
1217       else
1218         {
1219           if (aop->aopu.aop_stk >= 0)
1220             offset += _G.stack.param_offset;
1221           tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1222         }
1223
1224       return gc_strdup(s);
1225
1226     case AOP_CRY:
1227       wassert (0);
1228
1229     case AOP_ACC:
1230       if (!offset)
1231         {
1232           return "a";
1233         }
1234       else
1235         {
1236           tsprintf(s, "!zero");
1237           return gc_strdup(s);
1238         }
1239
1240     case AOP_HLREG:
1241       wassert (offset < 2);
1242       return aop->aopu.aop_str[offset];
1243
1244     case AOP_LIT:
1245       return aopLiteral (aop->aopu.aop_lit, offset);
1246
1247     case AOP_STR:
1248       aop->coff = offset;
1249       return aop->aopu.aop_str[offset];
1250
1251     default:
1252       break;
1253     }
1254   wassertl (0, "aopget got unsupported aop->type");
1255   exit (0);
1256 }
1257
1258 bool
1259 isRegString (const char *s)
1260 {
1261   if (!strcmp (s, "b") ||
1262       !strcmp (s, "c") ||
1263       !strcmp (s, "d") ||
1264       !strcmp (s, "e") ||
1265       !strcmp (s, "a") ||
1266       !strcmp (s, "h") ||
1267       !strcmp (s, "l"))
1268     return TRUE;
1269   return FALSE;
1270 }
1271
1272 bool
1273 isConstant (const char *s)
1274 {
1275   /* This is a bit of a hack... */
1276   return (*s == '#' || *s == '$');
1277 }
1278
1279 bool
1280 canAssignToPtr (const char *s)
1281 {
1282   if (isRegString (s))
1283     return TRUE;
1284   if (isConstant (s))
1285     return TRUE;
1286   return FALSE;
1287 }
1288
1289 /*-----------------------------------------------------------------*/
1290 /* aopPut - puts a string for a aop                                */
1291 /*-----------------------------------------------------------------*/
1292 static void
1293 aopPut (asmop * aop, const char *s, int offset)
1294 {
1295   char buffer2[256];
1296
1297   if (aop->size && offset > (aop->size - 1))
1298     {
1299       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1300               "aopPut got offset > aop->size");
1301       exit (0);
1302     }
1303
1304   // PENDING
1305   tsprintf(buffer2, s);
1306   s = buffer2;
1307
1308   /* will assign value to value */
1309   /* depending on where it is ofcourse */
1310   switch (aop->type)
1311     {
1312     case AOP_DIR:
1313       /* Direct.  Hmmm. */
1314       wassert (IS_GB);
1315       if (strcmp (s, "a"))
1316         emit2 ("ld a,%s", s);
1317       emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1318       break;
1319
1320     case AOP_SFR:
1321       wassert (IS_GB);
1322       if (strcmp (s, "a"))
1323         emit2 ("ld a,%s", s);
1324       emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1325       break;
1326
1327     case AOP_REG:
1328       if (!strcmp (s, "!*hl"))
1329         emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1330       else
1331         emit2 ("ld %s,%s",
1332                aop->aopu.aop_reg[offset]->name, s);
1333       break;
1334
1335     case AOP_IY:
1336       wassert (!IS_GB);
1337       setupPair (PAIR_IY, aop, offset);
1338       if (!canAssignToPtr (s))
1339         {
1340           emit2 ("ld a,%s", s);
1341           emit2 ("ld !*iyx,a", offset);
1342         }
1343       else
1344         emit2 ("ld !*iyx,%s", offset, s);
1345       break;
1346
1347     case AOP_HL:
1348       wassert (IS_GB);
1349       /* PENDING: for re-target */
1350       if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1351         {
1352           emit2 ("ld a,!*hl");
1353           s = "a";
1354         }
1355       setupPair (PAIR_HL, aop, offset);
1356
1357       emit2 ("ld !*hl,%s", s);
1358       break;
1359
1360     case AOP_STK:
1361       if (IS_GB)
1362         {
1363           /* PENDING: re-target */
1364           if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1365             {
1366               emit2 ("ld a,!*hl");
1367               s = "a";
1368             }
1369           setupPair (PAIR_HL, aop, offset);
1370           if (!canAssignToPtr (s))
1371             {
1372               emit2 ("ld a,%s", s);
1373               emit2 ("ld !*hl,a");
1374             }
1375           else
1376             emit2 ("ld !*hl,%s", s);
1377         }
1378       else
1379         {
1380           if (aop->aopu.aop_stk >= 0)
1381             offset += _G.stack.param_offset;
1382           if (!canAssignToPtr (s))
1383             {
1384               emit2 ("ld a,%s", s);
1385               emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1386             }
1387           else
1388             emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1389         }
1390       break;
1391
1392     case AOP_CRY:
1393       /* if bit variable */
1394       if (!aop->aopu.aop_dir)
1395         {
1396           emit2 ("ld a,#0");
1397           emit2 ("rla");
1398         }
1399       else
1400         {
1401           /* In bit space but not in C - cant happen */
1402           wassert (0);
1403         }
1404       break;
1405
1406     case AOP_STR:
1407       aop->coff = offset;
1408       if (strcmp (aop->aopu.aop_str[offset], s))
1409         {
1410           emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1411         }
1412       break;
1413
1414     case AOP_ACC:
1415       aop->coff = offset;
1416       if (!offset && (strcmp (s, "acc") == 0))
1417         break;
1418       if (offset > 0)
1419         {
1420
1421           emitDebug ("; Error aopPut AOP_ACC");
1422         }
1423       else
1424         {
1425           if (strcmp (aop->aopu.aop_str[offset], s))
1426             emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1427         }
1428       break;
1429
1430     case AOP_HLREG:
1431       wassert (offset < 2);
1432       emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1433       break;
1434
1435     default:
1436       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1437               "aopPut got unsupported aop->type");
1438       exit (0);
1439     }
1440 }
1441
1442 #define AOP(op) op->aop
1443 #define AOP_TYPE(op) AOP(op)->type
1444 #define AOP_SIZE(op) AOP(op)->size
1445 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1446
1447 static void
1448 commitPair (asmop * aop, PAIR_ID id)
1449 {
1450   if (id == PAIR_HL && requiresHL (aop))
1451     {
1452       emit2 ("ld a,l");
1453       emit2 ("ld d,h");
1454       aopPut (aop, "a", 0);
1455       aopPut (aop, "d", 1);
1456     }
1457   else
1458     {
1459       aopPut (aop, _pairs[id].l, 0);
1460       aopPut (aop, _pairs[id].h, 1);
1461     }
1462 }
1463
1464 /*-----------------------------------------------------------------*/
1465 /* getDataSize - get the operand data size                         */
1466 /*-----------------------------------------------------------------*/
1467 int
1468 getDataSize (operand * op)
1469 {
1470   int size;
1471   size = AOP_SIZE (op);
1472   if (size == 3)
1473     {
1474       /* pointer */
1475       wassert (0);
1476     }
1477   return size;
1478 }
1479
1480 /*-----------------------------------------------------------------*/
1481 /* movLeft2Result - move byte from left to result                  */
1482 /*-----------------------------------------------------------------*/
1483 static void
1484 movLeft2Result (operand * left, int offl,
1485                 operand * result, int offr, int sign)
1486 {
1487     const char *l;
1488   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1489     {
1490       l = aopGet (AOP (left), offl, FALSE);
1491
1492       if (!sign)
1493         {
1494           aopPut (AOP (result), l, offr);
1495         }
1496       else
1497         {
1498           wassert (0);
1499         }
1500     }
1501 }
1502
1503
1504 /** Put Acc into a register set
1505  */
1506 void
1507 outAcc (operand * result)
1508 {
1509   int size, offset;
1510   size = getDataSize (result);
1511   if (size)
1512     {
1513       aopPut (AOP (result), "a", 0);
1514       size--;
1515       offset = 1;
1516       /* unsigned or positive */
1517       while (size--)
1518         {
1519           aopPut (AOP (result), "!zero", offset++);
1520         }
1521     }
1522 }
1523
1524 /** Take the value in carry and put it into a register
1525  */
1526 void
1527 outBitCLong (operand * result, bool swap_sense)
1528 {
1529   /* if the result is bit */
1530   if (AOP_TYPE (result) == AOP_CRY)
1531     {
1532       emitDebug ("; Note: outBitC form 1");
1533       aopPut (AOP (result), "blah", 0);
1534     }
1535   else
1536     {
1537       emit2 ("ld a,!zero");
1538       emit2 ("rla");
1539       if (swap_sense)
1540         emit2 ("xor a,!immedbyte", 1);
1541       outAcc (result);
1542     }
1543 }
1544
1545 void
1546 outBitC (operand * result)
1547 {
1548   outBitCLong (result, FALSE);
1549 }
1550
1551 /*-----------------------------------------------------------------*/
1552 /* toBoolean - emit code for orl a,operator(sizeop)                */
1553 /*-----------------------------------------------------------------*/
1554 void
1555 _toBoolean (operand * oper)
1556 {
1557   int size = AOP_SIZE (oper);
1558   int offset = 0;
1559   if (size > 1)
1560     {
1561       emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1562       size--;
1563       while (size--)
1564         emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1565     }
1566   else
1567     {
1568       if (AOP (oper)->type != AOP_ACC)
1569         {
1570           _clearCarry();
1571           emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1572         }
1573     }
1574 }
1575
1576 /*-----------------------------------------------------------------*/
1577 /* genNot - generate code for ! operation                          */
1578 /*-----------------------------------------------------------------*/
1579 static void
1580 genNot (iCode * ic)
1581 {
1582   sym_link *optype = operandType (IC_LEFT (ic));
1583
1584   /* assign asmOps to operand & result */
1585   aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1586   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1587
1588   /* if in bit space then a special case */
1589   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1590     {
1591       wassert (0);
1592     }
1593
1594   /* if type float then do float */
1595   if (IS_FLOAT (optype))
1596     {
1597       wassert (0);
1598     }
1599
1600   _toBoolean (IC_LEFT (ic));
1601
1602   /* Not of A:
1603      If A == 0, !A = 1
1604      else A = 0
1605      So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1606   emit2 ("sub a,!one");
1607   outBitC (IC_RESULT (ic));
1608
1609   /* release the aops */
1610   freeAsmop (IC_LEFT (ic), NULL, ic);
1611   freeAsmop (IC_RESULT (ic), NULL, ic);
1612 }
1613
1614 /*-----------------------------------------------------------------*/
1615 /* genCpl - generate code for complement                           */
1616 /*-----------------------------------------------------------------*/
1617 static void
1618 genCpl (iCode * ic)
1619 {
1620   int offset = 0;
1621   int size;
1622
1623
1624   /* assign asmOps to operand & result */
1625   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1626   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1627
1628   /* if both are in bit space then
1629      a special case */
1630   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1631       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1632     {
1633       wassert (0);
1634     }
1635
1636   size = AOP_SIZE (IC_RESULT (ic));
1637   while (size--)
1638     {
1639       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1640       _moveA (l);
1641       emit2("cpl");
1642       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1643     }
1644
1645   /* release the aops */
1646   freeAsmop (IC_LEFT (ic), NULL, ic);
1647   freeAsmop (IC_RESULT (ic), NULL, ic);
1648 }
1649
1650 /*-----------------------------------------------------------------*/
1651 /* genUminus - unary minus code generation                         */
1652 /*-----------------------------------------------------------------*/
1653 static void
1654 genUminus (iCode * ic)
1655 {
1656   int offset, size;
1657   sym_link *optype, *rtype;
1658
1659   /* assign asmops */
1660   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1661   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1662
1663   /* if both in bit space then special
1664      case */
1665   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1666       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1667     {
1668       wassert (0);
1669       goto release;
1670     }
1671
1672   optype = operandType (IC_LEFT (ic));
1673   rtype = operandType (IC_RESULT (ic));
1674
1675   /* if float then do float stuff */
1676   if (IS_FLOAT (optype))
1677     {
1678       wassert (0);
1679       goto release;
1680     }
1681
1682   /* otherwise subtract from zero */
1683   size = AOP_SIZE (IC_LEFT (ic));
1684   offset = 0;
1685   _clearCarry();
1686   while (size--)
1687     {
1688       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1689       emit2 ("ld a,!zero");
1690       emit2 ("sbc a,%s", l);
1691       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1692     }
1693
1694   /* if any remaining bytes in the result */
1695   /* we just need to propagate the sign   */
1696   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1697     {
1698       emit2 ("rlc a");
1699       emit2 ("sbc a,a");
1700       while (size--)
1701         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1702     }
1703
1704 release:
1705   /* release the aops */
1706   freeAsmop (IC_LEFT (ic), NULL, ic);
1707   freeAsmop (IC_RESULT (ic), NULL, ic);
1708 }
1709
1710 static void
1711 _push (PAIR_ID pairId)
1712 {
1713   emit2 ("push %s", _pairs[pairId].name);
1714   _G.stack.pushed += 2;
1715 }
1716
1717 static void
1718 _pop (PAIR_ID pairId)
1719 {
1720   emit2 ("pop %s", _pairs[pairId].name);
1721   _G.stack.pushed -= 2;
1722 }
1723
1724
1725 /*-----------------------------------------------------------------*/
1726 /* assignResultValue -               */
1727 /*-----------------------------------------------------------------*/
1728 void
1729 assignResultValue (operand * oper)
1730 {
1731   int size = AOP_SIZE (oper);
1732   bool topInA = 0;
1733
1734   wassert (size <= 4);
1735   topInA = requiresHL (AOP (oper));
1736
1737 #if 0
1738   if (!IS_GB)
1739     wassert (size <= 2);
1740 #endif
1741   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1742     {
1743       /* We do it the hard way here. */
1744       _push (PAIR_HL);
1745       aopPut (AOP (oper), _fReturn[0], 0);
1746       aopPut (AOP (oper), _fReturn[1], 1);
1747       emit2 ("pop de");
1748       _G.stack.pushed -= 2;
1749       aopPut (AOP (oper), _fReturn[0], 2);
1750       aopPut (AOP (oper), _fReturn[1], 3);
1751     }
1752   else
1753     {
1754       while (size--)
1755         {
1756           aopPut (AOP (oper), _fReturn[size], size);
1757         }
1758     }
1759 }
1760
1761 static void
1762 _saveRegsForCall(iCode *ic, int sendSetSize)
1763 {
1764   /* Rules:
1765       o Stack parameters are pushed before this function enters
1766       o DE and BC may be used in this function.
1767       o HL and DE may be used to return the result.
1768       o HL and DE may be used to send variables.
1769       o DE and BC may be used to store the result value.
1770       o HL may be used in computing the sent value of DE
1771       o The iPushes for other parameters occur before any addSets
1772
1773      Logic: (to be run inside the first iPush or if none, before sending)
1774       o Compute if DE and/or BC are in use over the call
1775       o Compute if DE is used in the send set
1776       o Compute if DE and/or BC are used to hold the result value
1777       o If (DE is used, or in the send set) and is not used in the result, push.
1778       o If BC is used and is not in the result, push
1779       o 
1780       o If DE is used in the send set, fetch
1781       o If HL is used in the send set, fetch
1782       o Call
1783       o ...
1784   */
1785   if (_G.saves.saved == FALSE) {
1786     bool deInUse, bcInUse;
1787     bool deSending;
1788     bool bcInRet = FALSE, deInRet = FALSE;
1789     bitVect *rInUse;
1790
1791 #if 1
1792     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1793 #else
1794     if (IC_RESULT(ic))
1795       {
1796         rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
1797       }
1798     else 
1799       {
1800         /* Has no result, so in use is all of in use */
1801         rInUse = ic->rMask;
1802       }
1803 #endif
1804
1805     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1806     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1807
1808     deSending = (sendSetSize > 1);
1809
1810     emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1811
1812     if (bcInUse && bcInRet == FALSE) {
1813       _push(PAIR_BC);
1814       _G.stack.pushedBC = TRUE;
1815     }
1816     if (deInUse && deInRet == FALSE) {
1817       _push(PAIR_DE);
1818       _G.stack.pushedDE = TRUE;
1819     }
1820
1821     _G.saves.saved = TRUE;
1822   }
1823   else {
1824     /* Already saved. */
1825   }
1826 }
1827
1828 /*-----------------------------------------------------------------*/
1829 /* genIpush - genrate code for pushing this gets a little complex  */
1830 /*-----------------------------------------------------------------*/
1831 static void
1832 genIpush (iCode * ic)
1833 {
1834   int size, offset = 0;
1835   const char *l;
1836
1837   /* if this is not a parm push : ie. it is spill push
1838      and spill push is always done on the local stack */
1839   if (!ic->parmPush)
1840     {
1841       wassertl(0, "Encountered an unsupported spill push.");
1842       return;
1843     }
1844
1845   if (_G.saves.saved == FALSE) {
1846     /* Caller saves, and this is the first iPush. */
1847     /* Scan ahead until we find the function that we are pushing parameters to.
1848        Count the number of addSets on the way to figure out what registers
1849        are used in the send set.
1850     */
1851     int nAddSets = 0;
1852     iCode *walk = ic->next;
1853     
1854     while (walk) {
1855       if (walk->op == SEND) {
1856         nAddSets++;
1857       }
1858       else if (walk->op == CALL || walk->op == PCALL) {
1859         /* Found it. */
1860         break;
1861       }
1862       else {
1863         /* Keep looking. */
1864       }
1865       walk = walk->next;
1866     }
1867     _saveRegsForCall(walk, nAddSets);
1868   }
1869   else {
1870     /* Already saved by another iPush. */
1871   }
1872
1873   /* then do the push */
1874   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1875
1876   size = AOP_SIZE (IC_LEFT (ic));
1877
1878   if (isPair (AOP (IC_LEFT (ic))))
1879     {
1880       _G.stack.pushed += 2;
1881       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1882     }
1883   else
1884     {
1885       if (size == 2)
1886         {
1887           fetchHL (AOP (IC_LEFT (ic)));
1888           emit2 ("push hl");
1889           spillPair (PAIR_HL);
1890           _G.stack.pushed += 2;
1891           goto release;
1892         }
1893       if (size == 4)
1894         {
1895           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
1896           emit2 ("push hl");
1897           spillPair (PAIR_HL);
1898           _G.stack.pushed += 2;
1899           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
1900           emit2 ("push hl");
1901           spillPair (PAIR_HL);
1902           _G.stack.pushed += 2;
1903           goto release;
1904         }
1905       offset = size;
1906       while (size--)
1907         {
1908           if (AOP (IC_LEFT (ic))->type == AOP_IY)
1909             {
1910               char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
1911               wassert (l);
1912               emit2 ("ld a,(%s)", l);
1913             }
1914           else
1915             {
1916               l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
1917               emit2 ("ld a,%s", l);
1918             }
1919           emit2 ("push af");
1920           emit2 ("inc sp");
1921           _G.stack.pushed++;
1922         }
1923     }
1924 release:
1925   freeAsmop (IC_LEFT (ic), NULL, ic);
1926 }
1927
1928 /*-----------------------------------------------------------------*/
1929 /* genIpop - recover the registers: can happen only for spilling   */
1930 /*-----------------------------------------------------------------*/
1931 static void
1932 genIpop (iCode * ic)
1933 {
1934   int size, offset;
1935
1936
1937   /* if the temp was not pushed then */
1938   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
1939     return;
1940
1941   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1942   size = AOP_SIZE (IC_LEFT (ic));
1943   offset = (size - 1);
1944   if (isPair (AOP (IC_LEFT (ic))))
1945     {
1946       emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
1947     }
1948   else
1949     {
1950       while (size--)
1951         {
1952           emit2 ("dec sp");
1953           emit2 ("pop hl");
1954           spillPair (PAIR_HL);
1955           aopPut (AOP (IC_LEFT (ic)), "l", offset--);
1956         }
1957     }
1958
1959   freeAsmop (IC_LEFT (ic), NULL, ic);
1960 }
1961
1962 /* This is quite unfortunate */
1963 static void
1964 setArea (int inHome)
1965 {
1966   /*
1967     static int lastArea = 0;
1968
1969      if (_G.in_home != inHome) {
1970      if (inHome) {
1971      const char *sz = port->mem.code_name;
1972      port->mem.code_name = "HOME";
1973      emit2("!area", CODE_NAME);
1974      port->mem.code_name = sz;
1975      }
1976      else
1977      emit2("!area", CODE_NAME); */
1978   _G.in_home = inHome;
1979   //    }
1980 }
1981
1982 static bool
1983 isInHome (void)
1984 {
1985   return _G.in_home;
1986 }
1987
1988 static int
1989 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
1990 {
1991   int ret = 0;
1992   asmop *aop;
1993   symbol *sym = OP_SYMBOL (op);
1994
1995   if (sym->isspilt || sym->nRegs == 0)
1996     return 0;
1997
1998   aopOp (op, ic, FALSE, FALSE);
1999
2000   aop = AOP (op);
2001   if (aop->type == AOP_REG)
2002     {
2003       int i;
2004       for (i = 0; i < aop->size; i++)
2005         {
2006           if (pairId == PAIR_DE)
2007             {
2008               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2009               if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2010                 ret++;
2011               if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2012                 ret++;
2013             }
2014           else if (pairId == PAIR_BC)
2015             {
2016               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2017               if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2018                 ret++;
2019               if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2020                 ret++;
2021             }
2022           else
2023             {
2024               wassert (0);
2025             }
2026         }
2027     }
2028
2029   freeAsmop (IC_LEFT (ic), NULL, ic);
2030   return ret;
2031 }
2032
2033 /** Emit the code for a call statement
2034  */
2035 static void
2036 emitCall (iCode * ic, bool ispcall)
2037 {
2038   sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2039
2040   bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2041
2042   /* if caller saves & we have not saved then */
2043   if (!ic->regsSaved)
2044     {
2045       /* PENDING */
2046     }
2047
2048   _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2049
2050   /* if send set is not empty then assign */
2051   if (_G.sendSet)
2052     {
2053       iCode *sic;
2054       int send = 0;
2055       int nSend = elementsInSet(_G.sendSet);
2056       bool swapped = FALSE;
2057
2058       int _z80_sendOrder[] = {
2059         PAIR_BC, PAIR_DE
2060       };
2061
2062       if (nSend > 1) {
2063         /* Check if the parameters are swapped.  If so route through hl instead. */
2064         wassertl (nSend == 2, "Pedantic check.  Code only checks for the two send items case.");
2065
2066         sic = setFirstItem(_G.sendSet);
2067         sic = setNextItem(_G.sendSet);
2068
2069         if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2070           /* The second send value is loaded from one the one that holds the first
2071              send, i.e. it is overwritten. */
2072           /* Cache the first in HL, and load the second from HL instead. */
2073           emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2074           emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2075
2076           swapped = TRUE;
2077         }
2078       }
2079
2080       for (sic = setFirstItem (_G.sendSet); sic;
2081            sic = setNextItem (_G.sendSet))
2082         {
2083           int size;
2084           aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2085
2086           size = AOP_SIZE (IC_LEFT (sic));
2087           wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2088           wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2089
2090           // PENDING: Mild hack
2091           if (swapped == TRUE && send == 1) {
2092             if (size > 1) {
2093               emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2094             }
2095             else {
2096               emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2097             }
2098             emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2099           }
2100           else {
2101             fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2102           }
2103
2104           send++;
2105           freeAsmop (IC_LEFT (sic), NULL, sic);
2106         }
2107       _G.sendSet = NULL;
2108     }
2109
2110   if (ispcall)
2111     {
2112       if (IS_BANKEDCALL (detype))
2113         {
2114           werror (W_INDIR_BANKED);
2115         }
2116       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2117
2118       if (isLitWord (AOP (IC_LEFT (ic))))
2119         {
2120           emitDebug ("; Special case where the pCall is to a constant");
2121           emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2122         }
2123       else
2124         {
2125           symbol *rlbl = newiTempLabel (NULL);
2126           spillPair (PAIR_HL);
2127           emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2128           emit2 ("push hl");
2129           _G.stack.pushed += 2;
2130
2131           fetchHL (AOP (IC_LEFT (ic)));
2132           emit2 ("jp !*hl");
2133           emit2 ("!tlabeldef", (rlbl->key + 100));
2134           _G.stack.pushed -= 2;
2135         }
2136       freeAsmop (IC_LEFT (ic), NULL, ic);
2137     }
2138   else
2139     {
2140       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2141       OP_SYMBOL (IC_LEFT (ic))->rname :
2142       OP_SYMBOL (IC_LEFT (ic))->name;
2143       if (IS_BANKEDCALL (detype))
2144         {
2145           emit2 ("call banked_call");
2146           emit2 ("!dws", name);
2147           emit2 ("!dw !bankimmeds", name);
2148         }
2149       else
2150         {
2151           /* make the call */
2152           emit2 ("call %s", name);
2153         }
2154     }
2155   spillCached ();
2156
2157   /* Mark the regsiters as restored. */
2158   _G.saves.saved = FALSE;
2159
2160   /* if we need assign a result value */
2161   if ((IS_ITEMP (IC_RESULT (ic)) &&
2162        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2163         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2164       IS_TRUE_SYMOP (IC_RESULT (ic)))
2165     {
2166
2167       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2168
2169       assignResultValue (IC_RESULT (ic));
2170
2171       freeAsmop (IC_RESULT (ic), NULL, ic);
2172     }
2173
2174   /* adjust the stack for parameters if required */
2175   if (ic->parmBytes)
2176     {
2177       int i = ic->parmBytes;
2178
2179       _G.stack.pushed -= i;
2180       if (IS_GB)
2181         {
2182           emit2 ("!ldaspsp", i);
2183         }
2184       else
2185         {
2186           spillCached ();
2187           if (i > 6)
2188             {
2189               emit2 ("ld hl,#%d", i);
2190               emit2 ("add hl,sp");
2191               emit2 ("ld sp,hl");
2192             }
2193           else
2194             {
2195               while (i > 1)
2196                 {
2197                   emit2 ("pop hl");
2198                   i -= 2;
2199                 }
2200               if (i)
2201                 emit2 ("inc sp");
2202             }
2203           spillCached ();
2204         }
2205     }
2206
2207   if (_G.stack.pushedDE) 
2208     {
2209       bool dInUse = bitVectBitValue(rInUse, D_IDX);
2210       bool eInUse = bitVectBitValue(rInUse, E_IDX);
2211
2212       if (dInUse && eInUse) 
2213         {
2214           _pop (PAIR_DE);
2215         }
2216       else if (dInUse)
2217         {
2218           _pop(PAIR_HL);
2219           emit2 ("ld d,h");
2220         }
2221       else if (eInUse)
2222         {
2223           _pop(PAIR_HL);
2224           emit2 ("ld e,l");
2225         }
2226       else
2227         {
2228           wassertl (0, "Neither D or E were in use but it was pushed.");
2229         }
2230       _G.stack.pushedDE = FALSE;
2231     }
2232   
2233   if (_G.stack.pushedBC) 
2234     {
2235       bool bInUse = bitVectBitValue(rInUse, B_IDX);
2236       bool cInUse = bitVectBitValue(rInUse, C_IDX);
2237
2238       // If both B and C are used in the return value, then we won't get
2239       // here.
2240       if (bInUse && cInUse) 
2241         {
2242           _pop (PAIR_BC);
2243         }
2244       else if (bInUse)
2245         {
2246           _pop(PAIR_HL);
2247           emit2 ("ld b,h");
2248         }
2249       else if (cInUse)
2250         {
2251           _pop(PAIR_HL);
2252           emit2 ("ld c,l");
2253         }
2254       else
2255         {
2256           wassertl (0, "Neither B or C were in use but it was pushed.");
2257         }
2258       _G.stack.pushedBC = FALSE;
2259     }
2260 }
2261
2262 /*-----------------------------------------------------------------*/
2263 /* genCall - generates a call statement                            */
2264 /*-----------------------------------------------------------------*/
2265 static void
2266 genCall (iCode * ic)
2267 {
2268   emitCall (ic, FALSE);
2269 }
2270
2271 /*-----------------------------------------------------------------*/
2272 /* genPcall - generates a call by pointer statement                */
2273 /*-----------------------------------------------------------------*/
2274 static void
2275 genPcall (iCode * ic)
2276 {
2277   emitCall (ic, TRUE);
2278 }
2279
2280 /*-----------------------------------------------------------------*/
2281 /* resultRemat - result  is rematerializable                       */
2282 /*-----------------------------------------------------------------*/
2283 static int
2284 resultRemat (iCode * ic)
2285 {
2286   if (SKIP_IC (ic) || ic->op == IFX)
2287     return 0;
2288
2289   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2290     {
2291       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2292       if (sym->remat && !POINTER_SET (ic))
2293         return 1;
2294     }
2295
2296   return 0;
2297 }
2298
2299 extern set *publics;
2300
2301 /*-----------------------------------------------------------------*/
2302 /* genFunction - generated code for function entry                 */
2303 /*-----------------------------------------------------------------*/
2304 static void
2305 genFunction (iCode * ic)
2306 {
2307   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2308   sym_link *fetype;
2309
2310 #if CALLEE_SAVES
2311   bool bcInUse = FALSE;
2312   bool deInUse = FALSE;
2313 #endif
2314
2315   setArea (IS_NONBANKED (sym->etype));
2316
2317   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2318      else.
2319   */
2320   _G.receiveOffset = 0;
2321
2322 #if 0
2323   /* PENDING: hack */
2324   if (!IS_STATIC (sym->etype))
2325     {
2326       addSetIfnotP (&publics, sym);
2327     }
2328 #endif
2329
2330   /* Record the last function name for debugging. */
2331   _G.lastFunctionName = sym->rname;
2332   
2333   /* Create the function header */
2334   emit2 ("!functionheader", sym->name);
2335   /* PENDING: portability. */
2336   emit2 ("__%s_start:", sym->rname);
2337   emit2 ("!functionlabeldef", sym->rname);
2338
2339   if (options.profile) 
2340     {
2341       emit2 ("!profileenter");
2342     }
2343
2344   fetype = getSpec (operandType (IC_LEFT (ic)));
2345
2346   /* if critical function then turn interrupts off */
2347   if (SPEC_CRTCL (fetype))
2348     emit2 ("!di");
2349
2350   /* if this is an interrupt service routine then save all potentially used registers. */
2351   if (IS_ISR (sym->etype))
2352     {
2353       emit2 ("!pusha");
2354     }
2355
2356   /* PENDING: callee-save etc */
2357
2358   _G.stack.param_offset = 0;
2359
2360 #if CALLEE_SAVES
2361   /* Detect which registers are used. */
2362   if (sym->regsUsed)
2363     {
2364       int i;
2365       for (i = 0; i < sym->regsUsed->size; i++)
2366         {
2367           if (bitVectBitValue (sym->regsUsed, i))
2368             {
2369               switch (i)
2370                 {
2371                 case C_IDX:
2372                 case B_IDX:
2373                   bcInUse = TRUE;
2374                   break;
2375                 case D_IDX:
2376                 case E_IDX:
2377                   if (IS_Z80) {
2378                     deInUse = TRUE;
2379                   }
2380                   else {
2381                     /* Other systems use DE as a temporary. */
2382                   }
2383                   break;
2384                 }
2385             }
2386         }
2387     }
2388
2389   if (bcInUse) 
2390     {
2391       emit2 ("push bc");
2392       _G.stack.param_offset += 2;
2393     }
2394
2395   _G.stack.pushedBC = bcInUse;
2396
2397   if (deInUse)
2398     {
2399       emit2 ("push de");
2400       _G.stack.param_offset += 2;
2401     }
2402
2403   _G.stack.pushedDE = deInUse;
2404 #endif
2405
2406   /* adjust the stack for the function */
2407   _G.stack.last = sym->stack;
2408
2409   if (sym->stack)
2410     emit2 ("!enterx", sym->stack);
2411   else
2412     emit2 ("!enter");
2413   _G.stack.offset = sym->stack;
2414 }
2415
2416 /*-----------------------------------------------------------------*/
2417 /* genEndFunction - generates epilogue for functions               */
2418 /*-----------------------------------------------------------------*/
2419 static void
2420 genEndFunction (iCode * ic)
2421 {
2422   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2423
2424   if (IS_ISR (sym->etype))
2425     {
2426       wassert (0);
2427     }
2428   else
2429     {
2430       if (SPEC_CRTCL (sym->etype))
2431         emit2 ("!ei");
2432
2433       /* PENDING: calleeSave */
2434
2435       if (_G.stack.offset)
2436         {
2437           emit2 ("!leavex", _G.stack.offset);
2438         }
2439       else
2440         {
2441           emit2 ("!leave");
2442         }
2443
2444 #if CALLEE_SAVES
2445       if (_G.stack.pushedDE) 
2446         {
2447           emit2 ("pop de");
2448           _G.stack.pushedDE = FALSE;
2449         }
2450
2451       if (_G.stack.pushedDE) 
2452         {
2453           emit2 ("pop bc");
2454           _G.stack.pushedDE = FALSE;
2455         }
2456 #endif
2457
2458       if (options.profile) 
2459         {
2460           emit2 ("!profileexit");
2461         }
2462
2463
2464       /* Both baned and non-banked just ret */
2465       emit2 ("ret");
2466
2467       /* PENDING: portability. */
2468       emit2 ("__%s_end:", sym->rname);
2469     }
2470   _G.flushStatics = 1;
2471   _G.stack.pushed = 0;
2472   _G.stack.offset = 0;
2473 }
2474
2475 /*-----------------------------------------------------------------*/
2476 /* genRet - generate code for return statement                     */
2477 /*-----------------------------------------------------------------*/
2478 static void
2479 genRet (iCode * ic)
2480 {
2481     const char *l;
2482   /* Errk.  This is a hack until I can figure out how
2483      to cause dehl to spill on a call */
2484   int size, offset = 0;
2485
2486   /* if we have no return value then
2487      just generate the "ret" */
2488   if (!IC_LEFT (ic))
2489     goto jumpret;
2490
2491   /* we have something to return then
2492      move the return value into place */
2493   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2494   size = AOP_SIZE (IC_LEFT (ic));
2495
2496   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2497     {
2498       if (IS_GB)
2499         {
2500           emit2 ("ld de,%s", l);
2501         }
2502       else
2503         {
2504           emit2 ("ld hl,%s", l);
2505         }
2506     }
2507   else
2508     {
2509       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2510         {
2511           fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2512           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2513         }
2514       else
2515         {
2516           while (size--)
2517             {
2518               l = aopGet (AOP (IC_LEFT (ic)), offset,
2519                           FALSE);
2520               if (strcmp (_fReturn[offset], l))
2521                 emit2 ("ld %s,%s", _fReturn[offset++], l);
2522             }
2523         }
2524     }
2525   freeAsmop (IC_LEFT (ic), NULL, ic);
2526
2527 jumpret:
2528   /* generate a jump to the return label
2529      if the next is not the return statement */
2530   if (!(ic->next && ic->next->op == LABEL &&
2531         IC_LABEL (ic->next) == returnLabel))
2532
2533     emit2 ("jp !tlabel", returnLabel->key + 100);
2534 }
2535
2536 /*-----------------------------------------------------------------*/
2537 /* genLabel - generates a label                                    */
2538 /*-----------------------------------------------------------------*/
2539 static void
2540 genLabel (iCode * ic)
2541 {
2542   /* special case never generate */
2543   if (IC_LABEL (ic) == entryLabel)
2544     return;
2545
2546   emitLabel (IC_LABEL (ic)->key + 100);
2547 }
2548
2549 /*-----------------------------------------------------------------*/
2550 /* genGoto - generates a ljmp                                      */
2551 /*-----------------------------------------------------------------*/
2552 static void
2553 genGoto (iCode * ic)
2554 {
2555   emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2556 }
2557
2558 /*-----------------------------------------------------------------*/
2559 /* genPlusIncr :- does addition with increment if possible         */
2560 /*-----------------------------------------------------------------*/
2561 static bool
2562 genPlusIncr (iCode * ic)
2563 {
2564   unsigned int icount;
2565   unsigned int size = getDataSize (IC_RESULT (ic));
2566   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2567
2568   /* will try to generate an increment */
2569   /* if the right side is not a literal
2570      we cannot */
2571   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2572     return FALSE;
2573
2574   emitDebug ("; genPlusIncr");
2575
2576   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2577
2578   /* If result is a pair */
2579   if (resultId != PAIR_INVALID)
2580     {
2581       if (isLitWord (AOP (IC_LEFT (ic))))
2582         {
2583           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2584           return TRUE;
2585         }
2586       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2587         {
2588           fetchPair (resultId, AOP (IC_RIGHT (ic)));
2589           emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2590           return TRUE;
2591         }
2592       if (icount > 5)
2593         return FALSE;
2594       /* Inc a pair */
2595       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2596         {
2597           if (icount > 2)
2598             return FALSE;
2599           movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2600           movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2601         }
2602       while (icount--)
2603         {
2604           emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2605         }
2606       return TRUE;
2607     }
2608
2609   /* if the literal value of the right hand side
2610      is greater than 4 then it is not worth it */
2611   if (icount > 4)
2612     return FALSE;
2613
2614   /* if increment 16 bits in register */
2615   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2616       size > 1 &&
2617       icount == 1
2618     )
2619     {
2620       int offset = 0;
2621       symbol *tlbl = NULL;
2622       tlbl = newiTempLabel (NULL);
2623       while (size--)
2624         {
2625           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2626           if (size)
2627             {
2628               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2629             }
2630         }
2631       emitLabel (tlbl->key + 100);
2632       return TRUE;
2633     }
2634
2635   /* if the sizes are greater than 1 then we cannot */
2636   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2637       AOP_SIZE (IC_LEFT (ic)) > 1)
2638     return FALSE;
2639
2640   /* we can if the aops of the left & result match or
2641      if they are in registers and the registers are the
2642      same */
2643   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2644     {
2645       while (icount--)
2646         {
2647           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2648         }
2649       return TRUE;
2650     }
2651
2652   return FALSE;
2653 }
2654
2655 /*-----------------------------------------------------------------*/
2656 /* outBitAcc - output a bit in acc                                 */
2657 /*-----------------------------------------------------------------*/
2658 void
2659 outBitAcc (operand * result)
2660 {
2661   symbol *tlbl = newiTempLabel (NULL);
2662   /* if the result is a bit */
2663   if (AOP_TYPE (result) == AOP_CRY)
2664     {
2665       wassert (0);
2666     }
2667   else
2668     {
2669       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2670       emit2 ("ld a,!one");
2671       emitLabel (tlbl->key + 100);
2672       outAcc (result);
2673     }
2674 }
2675
2676 /*-----------------------------------------------------------------*/
2677 /* genPlus - generates code for addition                           */
2678 /*-----------------------------------------------------------------*/
2679 static void
2680 genPlus (iCode * ic)
2681 {
2682   int size, offset = 0;
2683
2684   /* special cases :- */
2685
2686   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2687   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2688   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2689
2690   /* Swap the left and right operands if:
2691
2692      if literal, literal on the right or
2693      if left requires ACC or right is already
2694      in ACC */
2695
2696   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2697       (AOP_NEEDSACC (IC_LEFT (ic))) ||
2698       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2699     {
2700       operand *t = IC_RIGHT (ic);
2701       IC_RIGHT (ic) = IC_LEFT (ic);
2702       IC_LEFT (ic) = t;
2703     }
2704
2705   /* if both left & right are in bit
2706      space */
2707   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2708       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2709     {
2710       /* Cant happen */
2711       wassert (0);
2712     }
2713
2714   /* if left in bit space & right literal */
2715   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2716       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2717     {
2718       /* Can happen I guess */
2719       wassert (0);
2720     }
2721
2722   /* if I can do an increment instead
2723      of add then GOOD for ME */
2724   if (genPlusIncr (ic) == TRUE)
2725     goto release;
2726
2727   emitDebug ("; genPlusIncr failed");
2728
2729   size = getDataSize (IC_RESULT (ic));
2730
2731   /* Special case when left and right are constant */
2732   if (isPair (AOP (IC_RESULT (ic))))
2733     {
2734       char *left, *right;
2735
2736       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2737       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2738       if (left && right)
2739         {
2740           /* It's a pair */
2741           /* PENDING: fix */
2742           char buffer[100];
2743           sprintf (buffer, "#(%s + %s)", left, right);
2744           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2745           goto release;
2746         }
2747     }
2748
2749   if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2750     {
2751       /* Fetch into HL then do the add */
2752       spillPair (PAIR_HL);
2753       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2754       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2755       goto release;
2756     }
2757
2758   /* Special case:
2759      ld hl,sp+n trashes C so we cant afford to do it during an
2760      add with stack based varibles.  Worst case is:
2761      ld  hl,sp+left
2762      ld  a,(hl)
2763      ld  hl,sp+right
2764      add (hl)
2765      ld  hl,sp+result
2766      ld  (hl),a
2767      ld  hl,sp+left+1
2768      ld  a,(hl)
2769      ld  hl,sp+right+1
2770      adc (hl)
2771      ld  hl,sp+result+1
2772      ld  (hl),a
2773      So you cant afford to load up hl if either left, right, or result
2774      is on the stack (*sigh*)  The alt is:
2775      ld  hl,sp+left
2776      ld  de,(hl)
2777      ld  hl,sp+right
2778      ld  hl,(hl)
2779      add hl,de
2780      ld  hl,sp+result
2781      ld  (hl),hl
2782      Combinations in here are:
2783      * If left or right are in bc then the loss is small - trap later
2784      * If the result is in bc then the loss is also small
2785    */
2786   if (IS_GB)
2787     {
2788       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2789           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2790           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2791         {
2792           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2793                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2794               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2795                AOP_SIZE (IC_RIGHT (ic)) <= 2))
2796             {
2797               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2798                 {
2799                   /* Swap left and right */
2800                   operand *t = IC_RIGHT (ic);
2801                   IC_RIGHT (ic) = IC_LEFT (ic);
2802                   IC_LEFT (ic) = t;
2803                 }
2804               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2805                 {
2806                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2807                   emit2 ("add hl,bc");
2808                 }
2809               else
2810                 {
2811                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2812                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2813                   emit2 ("add hl,de");
2814                 }
2815               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2816               goto release;
2817             }
2818           else if (size == 4)
2819             {
2820               emitDebug ("; WARNING: This add is probably broken.\n");
2821             }
2822         }
2823     }
2824
2825   while (size--)
2826     {
2827       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2828         {
2829           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2830           if (offset == 0)
2831             emit2 ("add a,%s",
2832                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2833           else
2834             emit2 ("adc a,%s",
2835                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2836         }
2837       else
2838         {
2839           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2840           if (offset == 0)
2841             emit2 ("add a,%s",
2842                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2843           else
2844             emit2 ("adc a,%s",
2845                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2846         }
2847       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2848     }
2849
2850 release:
2851   freeAsmop (IC_LEFT (ic), NULL, ic);
2852   freeAsmop (IC_RIGHT (ic), NULL, ic);
2853   freeAsmop (IC_RESULT (ic), NULL, ic);
2854
2855 }
2856
2857 /*-----------------------------------------------------------------*/
2858 /* genMinusDec :- does subtraction with deccrement if possible     */
2859 /*-----------------------------------------------------------------*/
2860 static bool
2861 genMinusDec (iCode * ic)
2862 {
2863   unsigned int icount;
2864   unsigned int size = getDataSize (IC_RESULT (ic));
2865
2866   /* will try to generate an increment */
2867   /* if the right side is not a literal we cannot */
2868   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2869     return FALSE;
2870
2871   /* if the literal value of the right hand side
2872      is greater than 4 then it is not worth it */
2873   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2874     return FALSE;
2875
2876   size = getDataSize (IC_RESULT (ic));
2877
2878   /* if decrement 16 bits in register */
2879   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2880       (size > 1) && isPair (AOP (IC_RESULT (ic))))
2881     {
2882       while (icount--)
2883         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2884       return TRUE;
2885     }
2886
2887   /* If result is a pair */
2888   if (isPair (AOP (IC_RESULT (ic))))
2889     {
2890       movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2891       movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2892       while (icount--)
2893         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2894       return TRUE;
2895     }
2896
2897   /* if increment 16 bits in register */
2898   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2899       (size == 2))
2900     {
2901       fetchPair (PAIR_HL, AOP (IC_RESULT (ic)));
2902
2903       while (icount--) {
2904         emit2 ("dec hl");
2905       }
2906       aopPut (AOP (IC_RESULT (ic)), "l", LSB);
2907       aopPut (AOP (IC_RESULT (ic)), "h", MSB16);
2908
2909       return TRUE;
2910     }
2911
2912
2913   /* if the sizes are greater than 1 then we cannot */
2914   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2915       AOP_SIZE (IC_LEFT (ic)) > 1)
2916     return FALSE;
2917
2918   /* we can if the aops of the left & result match or if they are in
2919      registers and the registers are the same */
2920   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2921     {
2922       while (icount--)
2923         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
2924       return TRUE;
2925     }
2926
2927   return FALSE;
2928 }
2929
2930 /*-----------------------------------------------------------------*/
2931 /* genMinus - generates code for subtraction                       */
2932 /*-----------------------------------------------------------------*/
2933 static void
2934 genMinus (iCode * ic)
2935 {
2936   int size, offset = 0;
2937   unsigned long lit = 0L;
2938
2939   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2940   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2941   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2942
2943   /* special cases :- */
2944   /* if both left & right are in bit space */
2945   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2946       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2947     {
2948       wassert (0);
2949       goto release;
2950     }
2951
2952   /* if I can do an decrement instead of subtract then GOOD for ME */
2953   if (genMinusDec (ic) == TRUE)
2954     goto release;
2955
2956   size = getDataSize (IC_RESULT (ic));
2957
2958   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2959     {
2960     }
2961   else
2962     {
2963       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2964       lit = -(long) lit;
2965     }
2966
2967   /* Same logic as genPlus */
2968   if (IS_GB)
2969     {
2970       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2971           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2972           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2973         {
2974           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2975                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2976               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2977                AOP_SIZE (IC_RIGHT (ic)) <= 2))
2978             {
2979               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
2980               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
2981
2982               if (left == PAIR_INVALID && right == PAIR_INVALID)
2983                 {
2984                   left = PAIR_DE;
2985                   right = PAIR_HL;
2986                 }
2987               else if (right == PAIR_INVALID)
2988                 right = PAIR_DE;
2989               else if (left == PAIR_INVALID)
2990                 left = PAIR_DE;
2991
2992               fetchPair (left, AOP (IC_LEFT (ic)));
2993               /* Order is important.  Right may be HL */
2994               fetchPair (right, AOP (IC_RIGHT (ic)));
2995
2996               emit2 ("ld a,%s", _pairs[left].l);
2997               emit2 ("sub a,%s", _pairs[right].l);
2998               emit2 ("ld e,a");
2999               emit2 ("ld a,%s", _pairs[left].h);
3000               emit2 ("sbc a,%s", _pairs[right].h);
3001
3002               aopPut (AOP (IC_RESULT (ic)), "a", 1);
3003               aopPut (AOP (IC_RESULT (ic)), "e", 0);
3004               goto release;
3005             }
3006           else if (size == 4)
3007             {
3008               emitDebug ("; WARNING: This sub is probably broken.\n");
3009             }
3010         }
3011     }
3012
3013   /* if literal, add a,#-lit, else normal subb */
3014   while (size--)
3015     {
3016       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3017       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3018         {
3019           if (!offset)
3020             emit2 ("sub a,%s",
3021                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3022           else
3023             emit2 ("sbc a,%s",
3024                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3025         }
3026       else
3027         {
3028           /* first add without previous c */
3029           if (!offset)
3030             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3031           else
3032             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3033         }
3034       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3035     }
3036
3037   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3038       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3039       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3040     wassert (0);
3041
3042 release:
3043   freeAsmop (IC_LEFT (ic), NULL, ic);
3044   freeAsmop (IC_RIGHT (ic), NULL, ic);
3045   freeAsmop (IC_RESULT (ic), NULL, ic);
3046 }
3047
3048 /*-----------------------------------------------------------------*/
3049 /* genMult - generates code for multiplication                     */
3050 /*-----------------------------------------------------------------*/
3051 static void
3052 genMult (iCode * ic)
3053 {
3054   /* Shouldn't occur - all done through function calls */
3055   wassert (0);
3056 }
3057
3058 /*-----------------------------------------------------------------*/
3059 /* genDiv - generates code for division                            */
3060 /*-----------------------------------------------------------------*/
3061 static void
3062 genDiv (iCode * ic)
3063 {
3064   /* Shouldn't occur - all done through function calls */
3065   wassert (0);
3066 }
3067
3068 /*-----------------------------------------------------------------*/
3069 /* genMod - generates code for division                            */
3070 /*-----------------------------------------------------------------*/
3071 static void
3072 genMod (iCode * ic)
3073 {
3074   /* Shouldn't occur - all done through function calls */
3075   wassert (0);
3076 }
3077
3078 /*-----------------------------------------------------------------*/
3079 /* genIfxJump :- will create a jump depending on the ifx           */
3080 /*-----------------------------------------------------------------*/
3081 static void
3082 genIfxJump (iCode * ic, char *jval)
3083 {
3084   symbol *jlbl;
3085   const char *inst;
3086
3087   /* if true label then we jump if condition
3088      supplied is true */
3089   if (IC_TRUE (ic))
3090     {
3091       jlbl = IC_TRUE (ic);
3092       if (!strcmp (jval, "a"))
3093         {
3094           inst = "nz";
3095         }
3096       else if (!strcmp (jval, "c"))
3097         {
3098           inst = "c";
3099         }
3100       else if (!strcmp (jval, "nc"))
3101         {
3102           inst = "nc";
3103         }
3104       else
3105         {
3106           /* The buffer contains the bit on A that we should test */
3107           inst = "nz";
3108         }
3109     }
3110   else
3111     {
3112       /* false label is present */
3113       jlbl = IC_FALSE (ic);
3114       if (!strcmp (jval, "a"))
3115         {
3116           inst = "z";
3117         }
3118       else if (!strcmp (jval, "c"))
3119         {
3120           inst = "nc";
3121         }
3122       else if (!strcmp (jval, "nc"))
3123         {
3124           inst = "c";
3125         }
3126       else
3127         {
3128           /* The buffer contains the bit on A that we should test */
3129           inst = "z";
3130         }
3131     }
3132   /* Z80 can do a conditional long jump */
3133   if (!strcmp (jval, "a"))
3134     {
3135       emit2 ("or a,a");
3136     }
3137   else if (!strcmp (jval, "c"))
3138     {
3139     }
3140   else if (!strcmp (jval, "nc"))
3141     {
3142     }
3143   else
3144     {
3145       emit2 ("bit %s,a", jval);
3146     }
3147   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3148
3149   /* mark the icode as generated */
3150   ic->generated = 1;
3151 }
3152
3153 static const char *
3154 _getPairIdName (PAIR_ID id)
3155 {
3156   return _pairs[id].name;
3157 }
3158
3159 /** Generic compare for > or <
3160  */
3161 static void
3162 genCmp (operand * left, operand * right,
3163         operand * result, iCode * ifx, int sign)
3164 {
3165   int size, offset = 0;
3166   unsigned long lit = 0L;
3167   bool swap_sense = FALSE;
3168
3169   /* if left & right are bit variables */
3170   if (AOP_TYPE (left) == AOP_CRY &&
3171       AOP_TYPE (right) == AOP_CRY)
3172     {
3173       /* Cant happen on the Z80 */
3174       wassert (0);
3175     }
3176   else
3177     {
3178       /* subtract right from left if at the
3179          end the carry flag is set then we know that
3180          left is greater than right */
3181       size = max (AOP_SIZE (left), AOP_SIZE (right));
3182
3183       /* if unsigned char cmp with lit, just compare */
3184       if ((size == 1) &&
3185           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3186         {
3187           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3188           if (sign)
3189             {
3190               emit2 ("xor a,!immedbyte", 0x80);
3191               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3192             }
3193           else
3194             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3195         }
3196       else
3197         {
3198           /* Special cases:
3199              On the GB:
3200              If the left or the right is a lit:
3201              Load -lit into HL, add to right via, check sense.
3202            */
3203           if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3204             {
3205               PAIR_ID id = PAIR_DE;
3206               asmop *lit = AOP (right);
3207               asmop *op = AOP (left);
3208               swap_sense = TRUE;
3209
3210               if (AOP_TYPE (left) == AOP_LIT)
3211                 {
3212                   swap_sense = FALSE;
3213                   lit = AOP (left);
3214                   op = AOP (right);
3215                 }
3216               if (sign)
3217                 {
3218                   emit2 ("ld e,%s", aopGet (op, 0, 0));
3219                   emit2 ("ld a,%s", aopGet (op, 1, 0));
3220                   emit2 ("xor a,!immedbyte", 0x80);
3221                   emit2 ("ld d,a");
3222                 }
3223               else
3224                 {
3225                   id = getPairId (op);
3226                   if (id == PAIR_INVALID)
3227                     {
3228                       fetchPair (PAIR_DE, op);
3229                       id = PAIR_DE;
3230                     }
3231                 }
3232               spillPair (PAIR_HL);
3233               emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3234               emit2 ("add hl,%s", _getPairIdName (id));
3235               goto release;
3236             }
3237           if (AOP_TYPE (right) == AOP_LIT)
3238             {
3239               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3240               /* optimize if(x < 0) or if(x >= 0) */
3241               if (lit == 0L)
3242                 {
3243                   if (!sign)
3244                     {
3245                       /* No sign so it's always false */
3246                       _clearCarry();
3247                     }
3248                   else
3249                     {
3250                       /* Just load in the top most bit */
3251                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3252                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3253                         {
3254                           genIfxJump (ifx, "7");
3255                           return;
3256                         }
3257                       else
3258                         emit2 ("rlc a");
3259                     }
3260                   goto release;
3261                 }
3262             }
3263           if (sign)
3264             {
3265               /* First setup h and l contaning the top most bytes XORed */
3266               bool fDidXor = FALSE;
3267               if (AOP_TYPE (left) == AOP_LIT)
3268                 {
3269                   unsigned long lit = (unsigned long)
3270                   floatFromVal (AOP (left)->aopu.aop_lit);
3271                   emit2 ("ld %s,!immedbyte", _fTmp[0],
3272                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3273                 }
3274               else
3275                 {
3276                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3277                   emit2 ("xor a,!immedbyte", 0x80);
3278                   emit2 ("ld %s,a", _fTmp[0]);
3279                   fDidXor = TRUE;
3280                 }
3281               if (AOP_TYPE (right) == AOP_LIT)
3282                 {
3283                   unsigned long lit = (unsigned long)
3284                   floatFromVal (AOP (right)->aopu.aop_lit);
3285                   emit2 ("ld %s,!immedbyte", _fTmp[1],
3286                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3287                 }
3288               else
3289                 {
3290                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3291                   emit2 ("xor a,!immedbyte", 0x80);
3292                   emit2 ("ld %s,a", _fTmp[1]);
3293                   fDidXor = TRUE;
3294                 }
3295               if (!fDidXor)
3296                 _clearCarry();
3297             }
3298           else
3299             {
3300               _clearCarry();
3301             }
3302           while (size--)
3303             {
3304               /* Do a long subtract */
3305               if (!sign || size)
3306                 {
3307                   _moveA (aopGet (AOP (left), offset, FALSE));
3308                 }
3309               if (sign && size == 0)
3310                 {
3311                   emit2 ("ld a,%s", _fTmp[0]);
3312                   emit2 ("sbc a,%s", _fTmp[1]);
3313                 }
3314               else
3315                 {
3316                   /* Subtract through, propagating the carry */
3317                   emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
3318                 }
3319             }
3320         }
3321     }
3322
3323 release:
3324   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3325     {
3326       outBitCLong (result, swap_sense);
3327     }
3328   else
3329     {
3330       /* if the result is used in the next
3331          ifx conditional branch then generate
3332          code a little differently */
3333       if (ifx)
3334         genIfxJump (ifx, swap_sense ? "nc" : "c");
3335       else
3336         outBitCLong (result, swap_sense);
3337       /* leave the result in acc */
3338     }
3339 }
3340
3341 /*-----------------------------------------------------------------*/
3342 /* genCmpGt :- greater than comparison                             */
3343 /*-----------------------------------------------------------------*/
3344 static void
3345 genCmpGt (iCode * ic, iCode * ifx)
3346 {
3347   operand *left, *right, *result;
3348   sym_link *letype, *retype;
3349   int sign;
3350
3351   left = IC_LEFT (ic);
3352   right = IC_RIGHT (ic);
3353   result = IC_RESULT (ic);
3354
3355   letype = getSpec (operandType (left));
3356   retype = getSpec (operandType (right));
3357   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3358   /* assign the amsops */
3359   aopOp (left, ic, FALSE, FALSE);
3360   aopOp (right, ic, FALSE, FALSE);
3361   aopOp (result, ic, TRUE, FALSE);
3362
3363   genCmp (right, left, result, ifx, sign);
3364
3365   freeAsmop (left, NULL, ic);
3366   freeAsmop (right, NULL, ic);
3367   freeAsmop (result, NULL, ic);
3368 }
3369
3370 /*-----------------------------------------------------------------*/
3371 /* genCmpLt - less than comparisons                                */
3372 /*-----------------------------------------------------------------*/
3373 static void
3374 genCmpLt (iCode * ic, iCode * ifx)
3375 {
3376   operand *left, *right, *result;
3377   sym_link *letype, *retype;
3378   int sign;
3379
3380   left = IC_LEFT (ic);
3381   right = IC_RIGHT (ic);
3382   result = IC_RESULT (ic);
3383
3384   letype = getSpec (operandType (left));
3385   retype = getSpec (operandType (right));
3386   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3387
3388   /* assign the amsops */
3389   aopOp (left, ic, FALSE, FALSE);
3390   aopOp (right, ic, FALSE, FALSE);
3391   aopOp (result, ic, TRUE, FALSE);
3392
3393   genCmp (left, right, result, ifx, sign);
3394
3395   freeAsmop (left, NULL, ic);
3396   freeAsmop (right, NULL, ic);
3397   freeAsmop (result, NULL, ic);
3398 }
3399
3400 /*-----------------------------------------------------------------*/
3401 /* gencjneshort - compare and jump if not equal                    */
3402 /*-----------------------------------------------------------------*/
3403 static void
3404 gencjneshort (operand * left, operand * right, symbol * lbl)
3405 {
3406   int size = max (AOP_SIZE (left), AOP_SIZE (right));
3407   int offset = 0;
3408   unsigned long lit = 0L;
3409
3410   /* Swap the left and right if it makes the computation easier */
3411   if (AOP_TYPE (left) == AOP_LIT)
3412     {
3413       operand *t = right;
3414       right = left;
3415       left = t;
3416     }
3417
3418   if (AOP_TYPE (right) == AOP_LIT)
3419     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3420
3421   /* if the right side is a literal then anything goes */
3422   if (AOP_TYPE (right) == AOP_LIT &&
3423       AOP_TYPE (left) != AOP_DIR)
3424     {
3425       if (lit == 0)
3426         {
3427           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3428           if (size > 1)
3429             {
3430               size--;
3431               offset++;
3432               while (size--)
3433                 {
3434                   emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3435                 }
3436             }
3437           else
3438             {
3439               emit2 ("or a,a");
3440             }
3441           emit2 ("jp nz,!tlabel", lbl->key + 100);
3442         }
3443       else
3444         {
3445           while (size--)
3446             {
3447               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3448               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3449                 emit2 ("or a,a");
3450               else
3451                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3452               emit2 ("jp nz,!tlabel", lbl->key + 100);
3453               offset++;
3454             }
3455         }
3456     }
3457   /* if the right side is in a register or in direct space or
3458      if the left is a pointer register & right is not */
3459   else if (AOP_TYPE (right) == AOP_REG ||
3460            AOP_TYPE (right) == AOP_DIR ||
3461            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3462     {
3463       while (size--)
3464         {
3465           _moveA (aopGet (AOP (left), offset, FALSE));
3466           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3467               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3468             /* PENDING */
3469             emit2 ("jp nz,!tlabel", lbl->key + 100);
3470           else
3471             {
3472               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3473               emit2 ("jp nz,!tlabel", lbl->key + 100);
3474             }
3475           offset++;
3476         }
3477     }
3478   else
3479     {
3480       /* right is a pointer reg need both a & b */
3481       /* PENDING: is this required? */
3482       while (size--)
3483         {
3484           _moveA (aopGet (AOP (right), offset, FALSE));
3485           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3486           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3487           offset++;
3488         }
3489     }
3490 }
3491
3492 /*-----------------------------------------------------------------*/
3493 /* gencjne - compare and jump if not equal                         */
3494 /*-----------------------------------------------------------------*/
3495 static void
3496 gencjne (operand * left, operand * right, symbol * lbl)
3497 {
3498   symbol *tlbl = newiTempLabel (NULL);
3499
3500   gencjneshort (left, right, lbl);
3501
3502   /* PENDING: ?? */
3503   emit2 ("ld a,!one");
3504   emit2 ("!shortjp !tlabel", tlbl->key + 100);
3505   emitLabel (lbl->key + 100);
3506   emit2 ("xor a,a");
3507   emitLabel (tlbl->key + 100);
3508 }
3509
3510 /*-----------------------------------------------------------------*/
3511 /* genCmpEq - generates code for equal to                          */
3512 /*-----------------------------------------------------------------*/
3513 static void
3514 genCmpEq (iCode * ic, iCode * ifx)
3515 {
3516   operand *left, *right, *result;
3517
3518   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3519   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3520   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3521
3522   emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3523
3524   /* Swap operands if it makes the operation easier. ie if:
3525      1.  Left is a literal.
3526    */
3527   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3528     {
3529       operand *t = IC_RIGHT (ic);
3530       IC_RIGHT (ic) = IC_LEFT (ic);
3531       IC_LEFT (ic) = t;
3532     }
3533
3534   if (ifx && !AOP_SIZE (result))
3535     {
3536       symbol *tlbl;
3537       /* if they are both bit variables */
3538       if (AOP_TYPE (left) == AOP_CRY &&
3539           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3540         {
3541           wassert (0);
3542         }
3543       else
3544         {
3545           tlbl = newiTempLabel (NULL);
3546           gencjneshort (left, right, tlbl);
3547           if (IC_TRUE (ifx))
3548             {
3549               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3550               emitLabel (tlbl->key + 100);
3551             }
3552           else
3553             {
3554               /* PENDING: do this better */
3555               symbol *lbl = newiTempLabel (NULL);
3556               emit2 ("!shortjp !tlabel", lbl->key + 100);
3557               emitLabel (tlbl->key + 100);
3558               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3559               emitLabel (lbl->key + 100);
3560             }
3561         }
3562       /* mark the icode as generated */
3563       ifx->generated = 1;
3564       goto release;
3565     }
3566
3567   /* if they are both bit variables */
3568   if (AOP_TYPE (left) == AOP_CRY &&
3569       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3570     {
3571       wassert (0);
3572     }
3573   else
3574     {
3575       gencjne (left, right, newiTempLabel (NULL));
3576       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3577         {
3578           wassert (0);
3579         }
3580       if (ifx)
3581         {
3582           genIfxJump (ifx, "a");
3583           goto release;
3584         }
3585       /* if the result is used in an arithmetic operation
3586          then put the result in place */
3587       if (AOP_TYPE (result) != AOP_CRY)
3588         {
3589           outAcc (result);
3590         }
3591       /* leave the result in acc */
3592     }
3593
3594 release:
3595   freeAsmop (left, NULL, ic);
3596   freeAsmop (right, NULL, ic);
3597   freeAsmop (result, NULL, ic);
3598 }
3599
3600 /*-----------------------------------------------------------------*/
3601 /* ifxForOp - returns the icode containing the ifx for operand     */
3602 /*-----------------------------------------------------------------*/
3603 static iCode *
3604 ifxForOp (operand * op, iCode * ic)
3605 {
3606   /* if true symbol then needs to be assigned */
3607   if (IS_TRUE_SYMOP (op))
3608     return NULL;
3609
3610   /* if this has register type condition and
3611      the next instruction is ifx with the same operand
3612      and live to of the operand is upto the ifx only then */
3613   if (ic->next &&
3614       ic->next->op == IFX &&
3615       IC_COND (ic->next)->key == op->key &&
3616       OP_SYMBOL (op)->liveTo <= ic->next->seq)
3617     return ic->next;
3618
3619   return NULL;
3620 }
3621
3622 /*-----------------------------------------------------------------*/
3623 /* genAndOp - for && operation                                     */
3624 /*-----------------------------------------------------------------*/
3625 static void
3626 genAndOp (iCode * ic)
3627 {
3628   operand *left, *right, *result;
3629   symbol *tlbl;
3630
3631   /* note here that && operations that are in an if statement are
3632      taken away by backPatchLabels only those used in arthmetic
3633      operations remain */
3634   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3635   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3636   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3637
3638   /* if both are bit variables */
3639   if (AOP_TYPE (left) == AOP_CRY &&
3640       AOP_TYPE (right) == AOP_CRY)
3641     {
3642       wassert (0);
3643     }
3644   else
3645     {
3646       tlbl = newiTempLabel (NULL);
3647       _toBoolean (left);
3648       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3649       _toBoolean (right);
3650       emitLabel (tlbl->key + 100);
3651       outBitAcc (result);
3652     }
3653
3654   freeAsmop (left, NULL, ic);
3655   freeAsmop (right, NULL, ic);
3656   freeAsmop (result, NULL, ic);
3657 }
3658
3659 /*-----------------------------------------------------------------*/
3660 /* genOrOp - for || operation                                      */
3661 /*-----------------------------------------------------------------*/
3662 static void
3663 genOrOp (iCode * ic)
3664 {
3665   operand *left, *right, *result;
3666   symbol *tlbl;
3667
3668   /* note here that || operations that are in an
3669      if statement are taken away by backPatchLabels
3670      only those used in arthmetic operations remain */
3671   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3672   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3673   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3674
3675   /* if both are bit variables */
3676   if (AOP_TYPE (left) == AOP_CRY &&
3677       AOP_TYPE (right) == AOP_CRY)
3678     {
3679       wassert (0);
3680     }
3681   else
3682     {
3683       tlbl = newiTempLabel (NULL);
3684       _toBoolean (left);
3685       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3686       _toBoolean (right);
3687       emitLabel (tlbl->key + 100);
3688       outBitAcc (result);
3689     }
3690
3691   freeAsmop (left, NULL, ic);
3692   freeAsmop (right, NULL, ic);
3693   freeAsmop (result, NULL, ic);
3694 }
3695
3696 /*-----------------------------------------------------------------*/
3697 /* isLiteralBit - test if lit == 2^n                               */
3698 /*-----------------------------------------------------------------*/
3699 int
3700 isLiteralBit (unsigned long lit)
3701 {
3702   unsigned long pw[32] =
3703   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3704    0x100L, 0x200L, 0x400L, 0x800L,
3705    0x1000L, 0x2000L, 0x4000L, 0x8000L,
3706    0x10000L, 0x20000L, 0x40000L, 0x80000L,
3707    0x100000L, 0x200000L, 0x400000L, 0x800000L,
3708    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3709    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3710   int idx;
3711
3712   for (idx = 0; idx < 32; idx++)
3713     if (lit == pw[idx])
3714       return idx + 1;
3715   return 0;
3716 }
3717
3718 /*-----------------------------------------------------------------*/
3719 /* jmpTrueOrFalse -                                                */
3720 /*-----------------------------------------------------------------*/
3721 static void
3722 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3723 {
3724   // ugly but optimized by peephole
3725   if (IC_TRUE (ic))
3726     {
3727       symbol *nlbl = newiTempLabel (NULL);
3728       emit2 ("jp !tlabel", nlbl->key + 100);
3729       emitLabel (tlbl->key + 100);
3730       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3731       emitLabel (nlbl->key + 100);
3732     }
3733   else
3734     {
3735       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3736       emitLabel (tlbl->key + 100);
3737     }
3738   ic->generated = 1;
3739 }
3740
3741 /*-----------------------------------------------------------------*/
3742 /* genAnd  - code for and                                          */
3743 /*-----------------------------------------------------------------*/
3744 static void
3745 genAnd (iCode * ic, iCode * ifx)
3746 {
3747   operand *left, *right, *result;
3748   int size, offset = 0;
3749   unsigned long lit = 0L;
3750   int bytelit = 0;
3751
3752   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3753   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3754   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3755
3756 #ifdef DEBUG_TYPE
3757   emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3758             AOP_TYPE (result),
3759             AOP_TYPE (left), AOP_TYPE (right));
3760   emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3761             AOP_SIZE (result),
3762             AOP_SIZE (left), AOP_SIZE (right));
3763 #endif
3764
3765   /* if left is a literal & right is not then exchange them */
3766   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3767       AOP_NEEDSACC (left))
3768     {
3769       operand *tmp = right;
3770       right = left;
3771       left = tmp;
3772     }
3773
3774   /* if result = right then exchange them */
3775   if (sameRegs (AOP (result), AOP (right)))
3776     {
3777       operand *tmp = right;
3778       right = left;
3779       left = tmp;
3780     }
3781
3782   /* if right is bit then exchange them */
3783   if (AOP_TYPE (right) == AOP_CRY &&
3784       AOP_TYPE (left) != AOP_CRY)
3785     {
3786       operand *tmp = right;
3787       right = left;
3788       left = tmp;
3789     }
3790   if (AOP_TYPE (right) == AOP_LIT)
3791     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3792
3793   size = AOP_SIZE (result);
3794
3795   if (AOP_TYPE (left) == AOP_CRY)
3796     {
3797       wassert (0);
3798       goto release;
3799     }
3800
3801   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
3802   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
3803   if ((AOP_TYPE (right) == AOP_LIT) &&
3804       (AOP_TYPE (result) == AOP_CRY) &&
3805       (AOP_TYPE (left) != AOP_CRY))
3806     {
3807       int posbit = isLiteralBit (lit);
3808       /* left &  2^n */
3809       if (posbit)
3810         {
3811           posbit--;
3812           _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3813           // bit = left & 2^n
3814           if (size)
3815             {
3816               wassert (0);
3817               emit2 ("mov c,acc.%d", posbit & 0x07);
3818             }
3819           // if(left &  2^n)
3820           else
3821             {
3822               if (ifx)
3823                 {
3824                   sprintf (buffer, "%d", posbit & 0x07);
3825                   genIfxJump (ifx, buffer);
3826                 }
3827               else
3828                 {
3829                   wassert (0);
3830                 }
3831               goto release;
3832             }
3833         }
3834       else
3835         {
3836           symbol *tlbl = newiTempLabel (NULL);
3837           int sizel = AOP_SIZE (left);
3838           if (size)
3839             {
3840               wassert (0);
3841               emit2 ("setb c");
3842             }
3843           while (sizel--)
3844             {
3845               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3846                 {
3847                   _moveA (aopGet (AOP (left), offset, FALSE));
3848                   // byte ==  2^n ?
3849                   if ((posbit = isLiteralBit (bytelit)) != 0)
3850                     {
3851                       wassert (0);
3852                       emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
3853                     }
3854                   else
3855                     {
3856                       if (bytelit != 0x0FFL)
3857                         emit2 ("and a,%s",
3858                                   aopGet (AOP (right), offset, FALSE));
3859                       else
3860                         /* For the flags */
3861                         emit2 ("or a,a");
3862                       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3863                     }
3864                 }
3865               offset++;
3866             }
3867           // bit = left & literal
3868           if (size)
3869             {
3870               emit2 ("clr c");
3871               emit2 ("!tlabeldef", tlbl->key + 100);
3872             }
3873           // if(left & literal)
3874           else
3875             {
3876               if (ifx)
3877                 jmpTrueOrFalse (ifx, tlbl);
3878               goto release;
3879             }
3880         }
3881       outBitC (result);
3882       goto release;
3883     }
3884
3885   /* if left is same as result */
3886   if (sameRegs (AOP (result), AOP (left)))
3887     {
3888       for (; size--; offset++)
3889         {
3890           if (AOP_TYPE (right) == AOP_LIT)
3891             {
3892               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3893                 continue;
3894               else
3895                 {
3896                   if (bytelit == 0)
3897                     aopPut (AOP (result), "!zero", offset);
3898                   else
3899                     {
3900                       _moveA (aopGet (AOP (left), offset, FALSE));
3901                       emit2 ("and a,%s",
3902                                 aopGet (AOP (right), offset, FALSE));
3903                       aopPut (AOP (left), "a", offset);
3904                     }
3905                 }
3906
3907             }
3908           else
3909             {
3910               if (AOP_TYPE (left) == AOP_ACC)
3911                 {
3912                   wassert (0);
3913                 }
3914               else
3915                 {
3916                   _moveA (aopGet (AOP (left), offset, FALSE));
3917                   emit2 ("and a,%s",
3918                             aopGet (AOP (right), offset, FALSE));
3919                   aopPut (AOP (left), "a", offset);
3920                 }
3921             }
3922         }
3923     }
3924   else
3925     {
3926       // left & result in different registers
3927       if (AOP_TYPE (result) == AOP_CRY)
3928         {
3929           wassert (0);
3930         }
3931       else
3932         {
3933           for (; (size--); offset++)
3934             {
3935               // normal case
3936               // result = left & right
3937               if (AOP_TYPE (right) == AOP_LIT)
3938                 {
3939                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3940                     {
3941                       aopPut (AOP (result),
3942                               aopGet (AOP (left), offset, FALSE),
3943                               offset);
3944                       continue;
3945                     }
3946                   else if (bytelit == 0)
3947                     {
3948                       aopPut (AOP (result), "!zero", offset);
3949                       continue;
3950                     }
3951                 }
3952               // faster than result <- left, anl result,right
3953               // and better if result is SFR
3954               if (AOP_TYPE (left) == AOP_ACC)
3955                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
3956               else
3957                 {
3958                   _moveA (aopGet (AOP (left), offset, FALSE));
3959                   emit2 ("and a,%s",
3960                             aopGet (AOP (right), offset, FALSE));
3961                 }
3962               aopPut (AOP (result), "a", offset);
3963             }
3964         }
3965
3966     }
3967
3968 release:
3969   freeAsmop (left, NULL, ic);
3970   freeAsmop (right, NULL, ic);
3971   freeAsmop (result, NULL, ic);
3972 }
3973
3974 /*-----------------------------------------------------------------*/
3975 /* genOr  - code for or                                            */
3976 /*-----------------------------------------------------------------*/
3977 static void
3978 genOr (iCode * ic, iCode * ifx)
3979 {
3980   operand *left, *right, *result;
3981   int size, offset = 0;
3982   unsigned long lit = 0L;
3983
3984   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3985   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3986   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3987
3988 #if 1
3989   emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3990             AOP_TYPE (result),
3991             AOP_TYPE (left), AOP_TYPE (right));
3992   emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3993             AOP_SIZE (result),
3994             AOP_SIZE (left), AOP_SIZE (right));
3995 #endif
3996
3997   /* if left is a literal & right is not then exchange them */
3998   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3999       AOP_NEEDSACC (left))
4000     {
4001       operand *tmp = right;
4002       right = left;
4003       left = tmp;
4004     }
4005
4006   /* if result = right then exchange them */
4007   if (sameRegs (AOP (result), AOP (right)))
4008     {
4009       operand *tmp = right;
4010       right = left;
4011       left = tmp;
4012     }
4013
4014   /* if right is bit then exchange them */
4015   if (AOP_TYPE (right) == AOP_CRY &&
4016       AOP_TYPE (left) != AOP_CRY)
4017     {
4018       operand *tmp = right;
4019       right = left;
4020       left = tmp;
4021     }
4022   if (AOP_TYPE (right) == AOP_LIT)
4023     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4024
4025   size = AOP_SIZE (result);
4026
4027   if (AOP_TYPE (left) == AOP_CRY)
4028     {
4029       wassert (0);
4030       goto release;
4031     }
4032
4033   if ((AOP_TYPE (right) == AOP_LIT) &&
4034       (AOP_TYPE (result) == AOP_CRY) &&
4035       (AOP_TYPE (left) != AOP_CRY))
4036     {
4037       wassert (0);
4038       goto release;
4039     }
4040
4041   /* if left is same as result */
4042   if (sameRegs (AOP (result), AOP (left)))
4043     {
4044       for (; size--; offset++)
4045         {
4046           if (AOP_TYPE (right) == AOP_LIT)
4047             {
4048               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4049                 continue;
4050               else
4051                 {
4052                   _moveA (aopGet (AOP (left), offset, FALSE));
4053                   emit2 ("or a,%s",
4054                             aopGet (AOP (right), offset, FALSE));
4055                   aopPut (AOP (result), "a", offset);
4056                 }
4057             }
4058           else
4059             {
4060               if (AOP_TYPE (left) == AOP_ACC)
4061                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4062               else
4063                 {
4064                   _moveA (aopGet (AOP (left), offset, FALSE));
4065                   emit2 ("or a,%s",
4066                             aopGet (AOP (right), offset, FALSE));
4067                   aopPut (AOP (result), "a", offset);
4068                 }
4069             }
4070         }
4071     }
4072   else
4073     {
4074       // left & result in different registers
4075       if (AOP_TYPE (result) == AOP_CRY)
4076         {
4077           wassert (0);
4078         }
4079       else
4080         for (; (size--); offset++)
4081           {
4082             // normal case
4083             // result = left & right
4084             if (AOP_TYPE (right) == AOP_LIT)
4085               {
4086                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4087                   {
4088                     aopPut (AOP (result),
4089                             aopGet (AOP (left), offset, FALSE),
4090                             offset);
4091                     continue;
4092                   }
4093               }
4094             // faster than result <- left, anl result,right
4095             // and better if result is SFR
4096             if (AOP_TYPE (left) == AOP_ACC)
4097               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4098             else
4099               {
4100                 _moveA (aopGet (AOP (left), offset, FALSE));
4101                 emit2 ("or a,%s",
4102                           aopGet (AOP (right), offset, FALSE));
4103               }
4104             aopPut (AOP (result), "a", offset);
4105             /* PENDING: something weird is going on here.  Add exception. */
4106             if (AOP_TYPE (result) == AOP_ACC)
4107               break;
4108           }
4109     }
4110
4111 release:
4112   freeAsmop (left, NULL, ic);
4113   freeAsmop (right, NULL, ic);
4114   freeAsmop (result, NULL, ic);
4115 }
4116
4117 /*-----------------------------------------------------------------*/
4118 /* genXor - code for xclusive or                                   */
4119 /*-----------------------------------------------------------------*/
4120 static void
4121 genXor (iCode * ic, iCode * ifx)
4122 {
4123   operand *left, *right, *result;
4124   int size, offset = 0;
4125   unsigned long lit = 0L;
4126
4127   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4128   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4129   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4130
4131   /* if left is a literal & right is not then exchange them */
4132   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4133       AOP_NEEDSACC (left))
4134     {
4135       operand *tmp = right;
4136       right = left;
4137       left = tmp;
4138     }
4139
4140   /* if result = right then exchange them */
4141   if (sameRegs (AOP (result), AOP (right)))
4142     {
4143       operand *tmp = right;
4144       right = left;
4145       left = tmp;
4146     }
4147
4148   /* if right is bit then exchange them */
4149   if (AOP_TYPE (right) == AOP_CRY &&
4150       AOP_TYPE (left) != AOP_CRY)
4151     {
4152       operand *tmp = right;
4153       right = left;
4154       left = tmp;
4155     }
4156   if (AOP_TYPE (right) == AOP_LIT)
4157     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4158
4159   size = AOP_SIZE (result);
4160
4161   if (AOP_TYPE (left) == AOP_CRY)
4162     {
4163       wassert (0);
4164       goto release;
4165     }
4166
4167   if ((AOP_TYPE (right) == AOP_LIT) &&
4168       (AOP_TYPE (result) == AOP_CRY) &&
4169       (AOP_TYPE (left) != AOP_CRY))
4170     {
4171       wassert (0);
4172       goto release;
4173     }
4174
4175   /* if left is same as result */
4176   if (sameRegs (AOP (result), AOP (left)))
4177     {
4178       for (; size--; offset++)
4179         {
4180           if (AOP_TYPE (right) == AOP_LIT)
4181             {
4182               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4183                 continue;
4184               else
4185                 {
4186                   _moveA (aopGet (AOP (right), offset, FALSE));
4187                   emit2 ("xor a,%s",
4188                             aopGet (AOP (left), offset, FALSE));
4189                   aopPut (AOP (result), "a", offset);
4190                 }
4191             }
4192           else
4193             {
4194               if (AOP_TYPE (left) == AOP_ACC)
4195                 {
4196                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4197                 }
4198               else
4199                 {
4200                   _moveA (aopGet (AOP (right), offset, FALSE));
4201                   emit2 ("xor a,%s",
4202                             aopGet (AOP (left), offset, FALSE));
4203                   aopPut (AOP (result), "a", 0);
4204                 }
4205             }
4206         }
4207     }
4208   else
4209     {
4210       // left & result in different registers
4211       if (AOP_TYPE (result) == AOP_CRY)
4212         {
4213           wassert (0);
4214         }
4215       else
4216         for (; (size--); offset++)
4217           {
4218             // normal case
4219             // result = left & right
4220             if (AOP_TYPE (right) == AOP_LIT)
4221               {
4222                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4223                   {
4224                     aopPut (AOP (result),
4225                             aopGet (AOP (left), offset, FALSE),
4226                             offset);
4227                     continue;
4228                   }
4229               }
4230             // faster than result <- left, anl result,right
4231             // and better if result is SFR
4232             if (AOP_TYPE (left) == AOP_ACC) 
4233               {
4234                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4235               }
4236             else
4237               {
4238                 _moveA (aopGet (AOP (right), offset, FALSE));
4239                 emit2 ("xor a,%s",
4240                           aopGet (AOP (left), offset, FALSE));
4241               }
4242             aopPut (AOP (result), "a", offset);
4243           }
4244     }
4245
4246 release:
4247   freeAsmop (left, NULL, ic);
4248   freeAsmop (right, NULL, ic);
4249   freeAsmop (result, NULL, ic);
4250 }
4251
4252 /*-----------------------------------------------------------------*/
4253 /* genInline - write the inline code out                           */
4254 /*-----------------------------------------------------------------*/
4255 static void
4256 genInline (iCode * ic)
4257 {
4258   char *buffer, *bp, *bp1;
4259
4260   _G.lines.isInline += (!options.asmpeep);
4261
4262   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4263   strcpy (buffer, IC_INLINE (ic));
4264
4265   /* emit each line as a code */
4266   while (*bp)
4267     {
4268       if (*bp == '\n')
4269         {
4270           *bp++ = '\0';
4271           emit2 (bp1);
4272           bp1 = bp;
4273         }
4274       else
4275         {
4276           if (*bp == ':')
4277             {
4278               bp++;
4279               *bp = '\0';
4280               bp++;
4281               emit2 (bp1);
4282               bp1 = bp;
4283             }
4284           else
4285             bp++;
4286         }
4287     }
4288   if (bp1 != bp)
4289     emit2 (bp1);
4290   _G.lines.isInline -= (!options.asmpeep);
4291
4292 }
4293
4294 /*-----------------------------------------------------------------*/
4295 /* genRRC - rotate right with carry                                */
4296 /*-----------------------------------------------------------------*/
4297 static void
4298 genRRC (iCode * ic)
4299 {
4300   wassert (0);
4301 }
4302
4303 /*-----------------------------------------------------------------*/
4304 /* genRLC - generate code for rotate left with carry               */
4305 /*-----------------------------------------------------------------*/
4306 static void
4307 genRLC (iCode * ic)
4308 {
4309   wassert (0);
4310 }
4311
4312 /*-----------------------------------------------------------------*/
4313 /* genGetHbit - generates code get highest order bit               */
4314 /*-----------------------------------------------------------------*/
4315 static void
4316 genGetHbit (iCode * ic)
4317 {
4318   operand *left, *result;
4319   left = IC_LEFT (ic);
4320   result = IC_RESULT (ic);
4321   aopOp (left, ic, FALSE, FALSE);
4322   aopOp (result, ic, FALSE, FALSE);
4323
4324   /* get the highest order byte into a */
4325   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4326
4327   if (AOP_TYPE (result) == AOP_CRY)
4328     {
4329       emit2 ("rl a");
4330       outBitC (result);
4331     }
4332   else
4333     {
4334       emit2 ("rlc a");
4335       /* PENDING: For re-target. */
4336       emit2 ("and a,#1");
4337       outAcc (result);
4338     }
4339
4340
4341   freeAsmop (left, NULL, ic);
4342   freeAsmop (result, NULL, ic);
4343 }
4344
4345 static void
4346 emitRsh2 (asmop *aop, int size, int is_signed)
4347 {
4348   int offset = 0;
4349
4350   while (size--)
4351     {
4352       const char *l = aopGet (aop, size, FALSE);
4353       if (offset == 0)
4354         {
4355           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4356         }
4357       else
4358         {
4359           emit2 ("rr %s", l);
4360         }
4361       offset++;
4362     }
4363 }
4364
4365 /*-----------------------------------------------------------------*/
4366 /* shiftR2Left2Result - shift right two bytes from left to result  */
4367 /*-----------------------------------------------------------------*/
4368 static void
4369 shiftR2Left2Result (operand * left, int offl,
4370                     operand * result, int offr,
4371                     int shCount, int is_signed)
4372 {
4373   int size = 2;
4374   symbol *tlbl, *tlbl1;
4375
4376   movLeft2Result (left, offl, result, offr, 0);
4377   movLeft2Result (left, offl + 1, result, offr + 1, 0);
4378
4379   /*  if (AOP(result)->type == AOP_REG) { */
4380   
4381   tlbl = newiTempLabel (NULL);
4382   tlbl1 = newiTempLabel (NULL);
4383
4384   /* Left is already in result - so now do the shift */
4385   if (shCount <= 2)
4386     {
4387       while (shCount--)
4388         {
4389           emitRsh2 (AOP (result), size, is_signed);
4390         }
4391     }
4392   else
4393     {
4394       emit2 ("ld a,!immedbyte+1", shCount);
4395       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4396       emitLabel (tlbl->key + 100);
4397
4398       emitRsh2 (AOP (result), size, is_signed);
4399
4400       emitLabel (tlbl1->key + 100);
4401       emit2 ("dec a");
4402       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4403     }
4404 }
4405
4406 /*-----------------------------------------------------------------*/
4407 /* shiftL2Left2Result - shift left two bytes from left to result   */
4408 /*-----------------------------------------------------------------*/
4409 static void
4410 shiftL2Left2Result (operand * left, int offl,
4411                     operand * result, int offr, int shCount)
4412 {
4413   if (sameRegs (AOP (result), AOP (left)) &&
4414       ((offl + MSB16) == offr))
4415     {
4416       wassert (0);
4417     }
4418   else
4419     {
4420       /* Copy left into result */
4421       movLeft2Result (left, offl, result, offr, 0);
4422       movLeft2Result (left, offl + 1, result, offr + 1, 0);
4423     }
4424   /* PENDING: for now just see if it'll work. */
4425   /*if (AOP(result)->type == AOP_REG) { */
4426   {
4427     int size = 2;
4428     int offset = 0;
4429     symbol *tlbl, *tlbl1;
4430     const char *l;
4431
4432     tlbl = newiTempLabel (NULL);
4433     tlbl1 = newiTempLabel (NULL);
4434
4435     /* Left is already in result - so now do the shift */
4436     if (shCount > 1)
4437       {
4438         emit2 ("ld a,!immedbyte+1", shCount);
4439         emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4440         emitLabel (tlbl->key + 100);
4441       }
4442
4443     emit2 ("or a,a");
4444     while (size--)
4445       {
4446         l = aopGet (AOP (result), offset, FALSE);
4447
4448         emit2 ("rl %s", l);
4449
4450         offset++;
4451       }
4452     if (shCount > 1)
4453       {
4454         emitLabel (tlbl1->key + 100);
4455         emit2 ("dec a");
4456         emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4457       }
4458   }
4459 }
4460
4461 /*-----------------------------------------------------------------*/
4462 /* AccRol - rotate left accumulator by known count                 */
4463 /*-----------------------------------------------------------------*/
4464 static void
4465 AccRol (int shCount)
4466 {
4467   shCount &= 0x0007;            // shCount : 0..7
4468
4469   switch (shCount)
4470     {
4471     case 0:
4472       break;
4473     case 1:
4474       emit2 ("rl a");
4475       break;
4476     case 2:
4477       emit2 ("rl a");
4478       emit2 ("rl a");
4479       break;
4480     case 3:
4481       emit2 ("rl a");
4482       emit2 ("rl a");
4483       emit2 ("rl a");
4484       break;
4485     case 4:
4486       emit2 ("rl a");
4487       emit2 ("rl a");
4488       emit2 ("rl a");
4489       emit2 ("rl a");
4490       break;
4491     case 5:
4492       emit2 ("rr a");
4493       emit2 ("rr a");
4494       emit2 ("rr a");
4495       break;
4496     case 6:
4497       emit2 ("rr a");
4498       emit2 ("rr a");
4499       break;
4500     case 7:
4501       emit2 ("rr a");
4502       break;
4503     }
4504 }
4505
4506 /*-----------------------------------------------------------------*/
4507 /* AccLsh - left shift accumulator by known count                  */
4508 /*-----------------------------------------------------------------*/
4509 static void
4510 AccLsh (int shCount)
4511 {
4512   static const unsigned char SLMask[] =
4513     {
4514       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4515     };
4516
4517   if (shCount != 0)
4518     {
4519       if (shCount == 1)
4520         {
4521           emit2 ("add a,a");
4522         }
4523       else if (shCount == 2)
4524         {
4525           emit2 ("add a,a");
4526           emit2 ("add a,a");
4527         }
4528       else
4529         {
4530           /* rotate left accumulator */
4531           AccRol (shCount);
4532           /* and kill the lower order bits */
4533           emit2 ("and a,!immedbyte", SLMask[shCount]);
4534         }
4535     }
4536 }
4537
4538 /*-----------------------------------------------------------------*/
4539 /* shiftL1Left2Result - shift left one byte from left to result    */
4540 /*-----------------------------------------------------------------*/
4541 static void
4542 shiftL1Left2Result (operand * left, int offl,
4543                     operand * result, int offr, int shCount)
4544 {
4545   const char *l;
4546   l = aopGet (AOP (left), offl, FALSE);
4547   _moveA (l);
4548   /* shift left accumulator */
4549   AccLsh (shCount);
4550   aopPut (AOP (result), "a", offr);
4551 }
4552
4553
4554 /*-----------------------------------------------------------------*/
4555 /* genlshTwo - left shift two bytes by known amount != 0           */
4556 /*-----------------------------------------------------------------*/
4557 static void
4558 genlshTwo (operand * result, operand * left, int shCount)
4559 {
4560   int size = AOP_SIZE (result);
4561
4562   wassert (size == 2);
4563
4564   /* if shCount >= 8 */
4565   if (shCount >= 8)
4566     {
4567       shCount -= 8;
4568       if (size > 1)
4569         {
4570           if (shCount)
4571             {
4572               movLeft2Result (left, LSB, result, MSB16, 0);
4573               aopPut (AOP (result), "!zero", 0);
4574               shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4575             }
4576           else
4577             {
4578               movLeft2Result (left, LSB, result, MSB16, 0);
4579               aopPut (AOP (result), "!zero", 0);
4580             }
4581         }
4582       else
4583         {
4584           aopPut (AOP (result), "!zero", LSB);
4585         }
4586     }
4587   /*  1 <= shCount <= 7 */
4588   else
4589     {
4590       if (size == 1)
4591         {
4592           wassert (0);
4593         }
4594       else
4595         {
4596           shiftL2Left2Result (left, LSB, result, LSB, shCount);
4597         }
4598     }
4599 }
4600
4601 /*-----------------------------------------------------------------*/
4602 /* genlshOne - left shift a one byte quantity by known count       */
4603 /*-----------------------------------------------------------------*/
4604 static void
4605 genlshOne (operand * result, operand * left, int shCount)
4606 {
4607   shiftL1Left2Result (left, LSB, result, LSB, shCount);
4608 }
4609
4610 /*-----------------------------------------------------------------*/
4611 /* genLeftShiftLiteral - left shifting by known count              */
4612 /*-----------------------------------------------------------------*/
4613 static void
4614 genLeftShiftLiteral (operand * left,
4615                      operand * right,
4616                      operand * result,
4617                      iCode * ic)
4618 {
4619   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4620   int size;
4621
4622   freeAsmop (right, NULL, ic);
4623
4624   aopOp (left, ic, FALSE, FALSE);
4625   aopOp (result, ic, FALSE, FALSE);
4626
4627   size = getSize (operandType (result));
4628
4629 #if VIEW_SIZE
4630   emitDebug ("; shift left  result %d, left %d", size,
4631             AOP_SIZE (left));
4632 #endif
4633
4634   /* I suppose that the left size >= result size */
4635   if (shCount == 0)
4636     {
4637       wassert (0);
4638     }
4639
4640   else if (shCount >= (size * 8)) 
4641     {
4642       while (size--)
4643         {
4644           aopPut (AOP (result), "!zero", size);
4645         }
4646     }
4647   else
4648     {
4649       switch (size)
4650         {
4651         case 1:
4652           genlshOne (result, left, shCount);
4653           break;
4654         case 2:
4655           genlshTwo (result, left, shCount);
4656           break;
4657         case 4:
4658           wassertl (0, "Shifting of longs is currently unsupported");
4659           break;
4660         default:
4661           wassert (0);
4662         }
4663     }
4664   freeAsmop (left, NULL, ic);
4665   freeAsmop (result, NULL, ic);
4666 }
4667
4668 /*-----------------------------------------------------------------*/
4669 /* genLeftShift - generates code for left shifting                 */
4670 /*-----------------------------------------------------------------*/
4671 static void
4672 genLeftShift (iCode * ic)
4673 {
4674   int size, offset;
4675   const char *l;
4676   symbol *tlbl, *tlbl1;
4677   operand *left, *right, *result;
4678
4679   right = IC_RIGHT (ic);
4680   left = IC_LEFT (ic);
4681   result = IC_RESULT (ic);
4682
4683   aopOp (right, ic, FALSE, FALSE);
4684
4685   /* if the shift count is known then do it
4686      as efficiently as possible */
4687   if (AOP_TYPE (right) == AOP_LIT)
4688     {
4689       genLeftShiftLiteral (left, right, result, ic);
4690       return;
4691     }
4692
4693   /* shift count is unknown then we have to form a loop get the loop
4694      count in B : Note: we take only the lower order byte since
4695      shifting more that 32 bits make no sense anyway, ( the largest
4696      size of an object can be only 32 bits ) */
4697   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4698   emit2 ("inc a");
4699   freeAsmop (right, NULL, ic);
4700   aopOp (left, ic, FALSE, FALSE);
4701   aopOp (result, ic, FALSE, FALSE);
4702
4703   /* now move the left to the result if they are not the
4704      same */
4705 #if 1
4706   if (!sameRegs (AOP (left), AOP (result)))
4707     {
4708
4709       size = AOP_SIZE (result);
4710       offset = 0;
4711       while (size--)
4712         {
4713           l = aopGet (AOP (left), offset, FALSE);
4714           aopPut (AOP (result), l, offset);
4715           offset++;
4716         }
4717     }
4718 #else
4719   size = AOP_SIZE (result);
4720   offset = 0;
4721   while (size--)
4722     {
4723       l = aopGet (AOP (left), offset, FALSE);
4724       aopPut (AOP (result), l, offset);
4725       offset++;
4726     }
4727 #endif
4728
4729
4730   tlbl = newiTempLabel (NULL);
4731   size = AOP_SIZE (result);
4732   offset = 0;
4733   tlbl1 = newiTempLabel (NULL);
4734
4735   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4736   emitLabel (tlbl->key + 100);
4737   l = aopGet (AOP (result), offset, FALSE);
4738
4739   emit2 ("or a,a");
4740
4741   while (size--)
4742     {
4743       l = aopGet (AOP (result), offset++, FALSE);
4744       emit2 ("rl %s", l);
4745     }
4746   emitLabel (tlbl1->key + 100);
4747   emit2 ("dec a");
4748   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4749
4750   freeAsmop (left, NULL, ic);
4751   freeAsmop (result, NULL, ic);
4752 }
4753
4754 /*-----------------------------------------------------------------*/
4755 /* genrshOne - left shift two bytes by known amount != 0           */
4756 /*-----------------------------------------------------------------*/
4757 static void
4758 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4759 {
4760   /* Errk */
4761   int size = AOP_SIZE (result);
4762   const char *l;
4763
4764   wassert (size == 1);
4765   wassert (shCount < 8);
4766
4767   l = aopGet (AOP (left), 0, FALSE);
4768
4769   emit2 ("or a,a");
4770
4771   if (AOP (result)->type == AOP_REG)
4772     {
4773       aopPut (AOP (result), l, 0);
4774       l = aopGet (AOP (result), 0, FALSE);
4775       while (shCount--)
4776         {
4777           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4778         }
4779     }
4780   else
4781     {
4782       _moveA (l);
4783       while (shCount--)
4784         {
4785           emit2 ("%s a", is_signed ? "sra" : "srl");
4786         }
4787       aopPut (AOP (result), "a", 0);
4788     }
4789 }
4790
4791 /*-----------------------------------------------------------------*/
4792 /* AccRsh - right shift accumulator by known count                 */
4793 /*-----------------------------------------------------------------*/
4794 static void
4795 AccRsh (int shCount)
4796 {
4797   static const unsigned char SRMask[] =
4798     {
4799       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4800     };
4801
4802   if (shCount != 0)
4803     {
4804       /* rotate right accumulator */
4805       AccRol (8 - shCount);
4806       /* and kill the higher order bits */
4807       emit2 ("and a,!immedbyte", SRMask[shCount]);
4808     }
4809 }
4810
4811 /*-----------------------------------------------------------------*/
4812 /* shiftR1Left2Result - shift right one byte from left to result   */
4813 /*-----------------------------------------------------------------*/
4814 static void
4815 shiftR1Left2Result (operand * left, int offl,
4816                     operand * result, int offr,
4817                     int shCount, int sign)
4818 {
4819   _moveA (aopGet (AOP (left), offl, FALSE));
4820   if (sign)
4821     {
4822       wassert (0);
4823     }
4824   else
4825     {
4826       AccRsh (shCount);
4827     }
4828   aopPut (AOP (result), "a", offr);
4829 }
4830
4831 /*-----------------------------------------------------------------*/
4832 /* genrshTwo - right shift two bytes by known amount != 0          */
4833 /*-----------------------------------------------------------------*/
4834 static void
4835 genrshTwo (operand * result, operand * left,
4836            int shCount, int sign)
4837 {
4838   /* if shCount >= 8 */
4839   if (shCount >= 8)
4840     {
4841       shCount -= 8;
4842       if (shCount)
4843         {
4844           shiftR1Left2Result (left, MSB16, result, LSB,
4845                               shCount, sign);
4846         }
4847       else
4848         {
4849           movLeft2Result (left, MSB16, result, LSB, sign);
4850         }
4851       aopPut (AOP (result), "!zero", 1);
4852     }
4853   /*  1 <= shCount <= 7 */
4854   else
4855     {
4856       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4857     }
4858 }
4859
4860 /*-----------------------------------------------------------------*/
4861 /* genRightShiftLiteral - left shifting by known count              */
4862 /*-----------------------------------------------------------------*/
4863 static void
4864 genRightShiftLiteral (operand * left,
4865                       operand * right,
4866                       operand * result,
4867                       iCode * ic,
4868                       int sign)
4869 {
4870   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4871   int size;
4872
4873   freeAsmop (right, NULL, ic);
4874
4875   aopOp (left, ic, FALSE, FALSE);
4876   aopOp (result, ic, FALSE, FALSE);
4877
4878   size = getSize (operandType (result));
4879
4880   emitDebug ("; shift right  result %d, left %d", size,
4881             AOP_SIZE (left));
4882
4883   /* I suppose that the left size >= result size */
4884   if (shCount == 0)
4885     {
4886       wassert (0);
4887     }
4888
4889   else if (shCount >= (size * 8))
4890     while (size--)
4891       aopPut (AOP (result), "!zero", size);
4892   else
4893     {
4894       switch (size)
4895         {
4896         case 1:
4897           genrshOne (result, left, shCount, sign);
4898           break;
4899         case 2:
4900           /* PENDING: sign support */
4901           genrshTwo (result, left, shCount, sign);
4902           break;
4903         case 4:
4904           wassertl (0, "Asked to shift right a long which should be a function call");
4905           break;
4906         default:
4907           wassertl (0, "Entered default case in right shift delegate");
4908         }
4909     }
4910   freeAsmop (left, NULL, ic);
4911   freeAsmop (result, NULL, ic);
4912 }
4913
4914 /*-----------------------------------------------------------------*/
4915 /* genRightShift - generate code for right shifting                */
4916 /*-----------------------------------------------------------------*/
4917 static void
4918 genRightShift (iCode * ic)
4919 {
4920   operand *right, *left, *result;
4921   sym_link *retype;
4922   int size, offset, first = 1;
4923   const char *l;
4924   bool is_signed;
4925
4926   symbol *tlbl, *tlbl1;
4927
4928   /* if signed then we do it the hard way preserve the
4929      sign bit moving it inwards */
4930   retype = getSpec (operandType (IC_RESULT (ic)));
4931
4932   is_signed = !SPEC_USIGN (retype);
4933
4934   /* signed & unsigned types are treated the same : i.e. the
4935      signed is NOT propagated inwards : quoting from the
4936      ANSI - standard : "for E1 >> E2, is equivalent to division
4937      by 2**E2 if unsigned or if it has a non-negative value,
4938      otherwise the result is implementation defined ", MY definition
4939      is that the sign does not get propagated */
4940
4941   right = IC_RIGHT (ic);
4942   left = IC_LEFT (ic);
4943   result = IC_RESULT (ic);
4944
4945   aopOp (right, ic, FALSE, FALSE);
4946
4947   /* if the shift count is known then do it
4948      as efficiently as possible */
4949   if (AOP_TYPE (right) == AOP_LIT)
4950     {
4951       genRightShiftLiteral (left, right, result, ic, is_signed);
4952       return;
4953     }
4954
4955   aopOp (left, ic, FALSE, FALSE);
4956   aopOp (result, ic, FALSE, FALSE);
4957
4958   /* now move the left to the result if they are not the
4959      same */
4960   if (!sameRegs (AOP (left), AOP (result)) &&
4961       AOP_SIZE (result) > 1)
4962     {
4963
4964       size = AOP_SIZE (result);
4965       offset = 0;
4966       while (size--)
4967         {
4968           l = aopGet (AOP (left), offset, FALSE);
4969           aopPut (AOP (result), l, offset);
4970           offset++;
4971         }
4972     }
4973
4974   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4975   emit2 ("inc a");
4976   freeAsmop (right, NULL, ic);
4977
4978   tlbl = newiTempLabel (NULL);
4979   tlbl1 = newiTempLabel (NULL);
4980   size = AOP_SIZE (result);
4981   offset = size - 1;
4982
4983   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4984   emitLabel (tlbl->key + 100);
4985   while (size--)
4986     {
4987       l = aopGet (AOP (result), offset--, FALSE);
4988       if (first)
4989         {
4990           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4991           first = 0;
4992         }
4993       else
4994         {
4995           emit2 ("rr %s", l);
4996         }
4997     }
4998   emitLabel (tlbl1->key + 100);
4999   emit2 ("dec a");
5000   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5001
5002   freeAsmop (left, NULL, ic);
5003   freeAsmop (result, NULL, ic);
5004 }
5005
5006 /*-----------------------------------------------------------------*/
5007 /* genGenPointerGet -  get value from generic pointer space        */
5008 /*-----------------------------------------------------------------*/
5009 static void
5010 genGenPointerGet (operand * left,
5011                   operand * result, iCode * ic)
5012 {
5013   int size, offset;
5014   sym_link *retype = getSpec (operandType (result));
5015   int pair = PAIR_HL;
5016
5017   if (IS_GB)
5018     pair = PAIR_DE;
5019
5020   aopOp (left, ic, FALSE, FALSE);
5021   aopOp (result, ic, FALSE, FALSE);
5022
5023   if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5024     {
5025       /* Just do it */
5026       if (isPtrPair (AOP (left)))
5027         {
5028           tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5029           aopPut (AOP (result), buffer, 0);
5030         }
5031       else
5032         {
5033           emit2 ("ld a,!*pair", getPairName (AOP (left)));
5034           aopPut (AOP (result), "a", 0);
5035         }
5036       freeAsmop (left, NULL, ic);
5037       goto release;
5038     }
5039
5040   /* For now we always load into IY */
5041   /* if this is remateriazable */
5042   fetchPair (pair, AOP (left));
5043
5044   /* so iy now contains the address */
5045   freeAsmop (left, NULL, ic);
5046
5047   /* if bit then unpack */
5048   if (IS_BITVAR (retype))
5049     {
5050       wassert (0);
5051     }
5052   else
5053     {
5054       size = AOP_SIZE (result);
5055       offset = 0;
5056
5057       while (size--)
5058         {
5059           /* PENDING: make this better */
5060           if (!IS_GB && AOP (result)->type == AOP_REG)
5061             {
5062               aopPut (AOP (result), "!*hl", offset++);
5063             }
5064           else
5065             {
5066               emit2 ("ld a,!*pair", _pairs[pair].name);
5067               aopPut (AOP (result), "a", offset++);
5068             }
5069           if (size)
5070             {
5071               emit2 ("inc %s", _pairs[pair].name);
5072               _G.pairs[pair].offset++;
5073             }
5074         }
5075     }
5076
5077 release:
5078   freeAsmop (result, NULL, ic);
5079 }
5080
5081 /*-----------------------------------------------------------------*/
5082 /* genPointerGet - generate code for pointer get                   */
5083 /*-----------------------------------------------------------------*/
5084 static void
5085 genPointerGet (iCode * ic)
5086 {
5087   operand *left, *result;
5088   sym_link *type, *etype;
5089
5090   left = IC_LEFT (ic);
5091   result = IC_RESULT (ic);
5092
5093   /* depending on the type of pointer we need to
5094      move it to the correct pointer register */
5095   type = operandType (left);
5096   etype = getSpec (type);
5097
5098   genGenPointerGet (left, result, ic);
5099 }
5100
5101 bool
5102 isRegOrLit (asmop * aop)
5103 {
5104   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5105     return TRUE;
5106   return FALSE;
5107 }
5108
5109 /*-----------------------------------------------------------------*/
5110 /* genGenPointerSet - stores the value into a pointer location        */
5111 /*-----------------------------------------------------------------*/
5112 static void
5113 genGenPointerSet (operand * right,
5114                   operand * result, iCode * ic)
5115 {
5116   int size, offset;
5117   sym_link *retype = getSpec (operandType (right));
5118   PAIR_ID pairId = PAIR_HL;
5119
5120   aopOp (result, ic, FALSE, FALSE);
5121   aopOp (right, ic, FALSE, FALSE);
5122
5123   if (IS_GB)
5124     pairId = PAIR_DE;
5125
5126   /* Handle the exceptions first */
5127   if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5128     {
5129       /* Just do it */
5130       const char *l = aopGet (AOP (right), 0, FALSE);
5131       const char *pair = getPairName (AOP (result));
5132       if (canAssignToPtr (l) && isPtr (pair))
5133         {
5134           emit2 ("ld !*pair,%s", pair, l);
5135         }
5136       else
5137         {
5138           _moveA (l);
5139           emit2 ("ld !*pair,a", pair);
5140         }
5141       goto release;
5142     }
5143
5144   /* if the operand is already in dptr
5145      then we do nothing else we move the value to dptr */
5146   if (AOP_TYPE (result) != AOP_STR)
5147     {
5148       fetchPair (pairId, AOP (result));
5149     }
5150   /* so hl know contains the address */
5151   freeAsmop (result, NULL, ic);
5152
5153   /* if bit then unpack */
5154   if (IS_BITVAR (retype))
5155     {
5156       wassert (0);
5157     }
5158   else
5159     {
5160       size = AOP_SIZE (right);
5161       offset = 0;
5162
5163       while (size--)
5164         {
5165           const char *l = aopGet (AOP (right), offset, FALSE);
5166           if (isRegOrLit (AOP (right)) && !IS_GB)
5167             {
5168               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5169             }
5170           else
5171             {
5172               _moveA (l);
5173               emit2 ("ld !*pair,a", _pairs[pairId].name);
5174             }
5175           if (size)
5176             {
5177               emit2 ("inc %s", _pairs[pairId].name);
5178               _G.pairs[pairId].offset++;
5179             }
5180           offset++;
5181         }
5182     }
5183 release:
5184   freeAsmop (right, NULL, ic);
5185 }
5186
5187 /*-----------------------------------------------------------------*/
5188 /* genPointerSet - stores the value into a pointer location        */
5189 /*-----------------------------------------------------------------*/
5190 static void
5191 genPointerSet (iCode * ic)
5192 {
5193   operand *right, *result;
5194   sym_link *type, *etype;
5195
5196   right = IC_RIGHT (ic);
5197   result = IC_RESULT (ic);
5198
5199   /* depending on the type of pointer we need to
5200      move it to the correct pointer register */
5201   type = operandType (result);
5202   etype = getSpec (type);
5203
5204   genGenPointerSet (right, result, ic);
5205 }
5206
5207 /*-----------------------------------------------------------------*/
5208 /* genIfx - generate code for Ifx statement                        */
5209 /*-----------------------------------------------------------------*/
5210 static void
5211 genIfx (iCode * ic, iCode * popIc)
5212 {
5213   operand *cond = IC_COND (ic);
5214   int isbit = 0;
5215
5216   aopOp (cond, ic, FALSE, TRUE);
5217
5218   /* get the value into acc */
5219   if (AOP_TYPE (cond) != AOP_CRY)
5220     _toBoolean (cond);
5221   else
5222     isbit = 1;
5223   /* the result is now in the accumulator */
5224   freeAsmop (cond, NULL, ic);
5225
5226   /* if there was something to be popped then do it */
5227   if (popIc)
5228     genIpop (popIc);
5229
5230   /* if the condition is  a bit variable */
5231   if (isbit && IS_ITEMP (cond) &&
5232       SPIL_LOC (cond))
5233     genIfxJump (ic, SPIL_LOC (cond)->rname);
5234   else if (isbit && !IS_ITEMP (cond))
5235     genIfxJump (ic, OP_SYMBOL (cond)->rname);
5236   else
5237     genIfxJump (ic, "a");
5238
5239   ic->generated = 1;
5240 }
5241
5242 /*-----------------------------------------------------------------*/
5243 /* genAddrOf - generates code for address of                       */
5244 /*-----------------------------------------------------------------*/
5245 static void
5246 genAddrOf (iCode * ic)
5247 {
5248   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5249
5250   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5251
5252   /* if the operand is on the stack then we
5253      need to get the stack offset of this
5254      variable */
5255   if (IS_GB)
5256     {
5257       if (sym->onStack)
5258         {
5259           spillCached ();
5260           if (sym->stack <= 0)
5261             {
5262               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5263             }
5264           else
5265             {
5266               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5267             }
5268           emit2 ("ld d,h");
5269           emit2 ("ld e,l");
5270         }
5271       else
5272         {
5273           emit2 ("ld de,!hashedstr", sym->rname);
5274         }
5275       aopPut (AOP (IC_RESULT (ic)), "e", 0);
5276       aopPut (AOP (IC_RESULT (ic)), "d", 1);
5277     }
5278   else
5279     {
5280       spillCached ();
5281       if (sym->onStack)
5282         {
5283           /* if it has an offset  then we need to compute it */
5284           if (sym->stack > 0)
5285             emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5286           else
5287             emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5288           emit2 ("add hl,sp");
5289         }
5290       else
5291         {
5292           emit2 ("ld hl,#%s", sym->rname);
5293         }
5294       aopPut (AOP (IC_RESULT (ic)), "l", 0);
5295       aopPut (AOP (IC_RESULT (ic)), "h", 1);
5296     }
5297   freeAsmop (IC_RESULT (ic), NULL, ic);
5298 }
5299
5300 /*-----------------------------------------------------------------*/
5301 /* genAssign - generate code for assignment                        */
5302 /*-----------------------------------------------------------------*/
5303 static void
5304 genAssign (iCode * ic)
5305 {
5306   operand *result, *right;
5307   int size, offset;
5308   unsigned long lit = 0L;
5309
5310   result = IC_RESULT (ic);
5311   right = IC_RIGHT (ic);
5312
5313 #if 1
5314   /* Dont bother assigning if they are the same */
5315   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5316     {
5317       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5318       return;
5319     }
5320 #endif
5321
5322   aopOp (right, ic, FALSE, FALSE);
5323   aopOp (result, ic, TRUE, FALSE);
5324
5325   /* if they are the same registers */
5326   if (sameRegs (AOP (right), AOP (result)))
5327     {
5328       emitDebug ("; (registers are the same)");
5329       goto release;
5330     }
5331
5332   /* if the result is a bit */
5333   if (AOP_TYPE (result) == AOP_CRY)
5334     {
5335       wassert (0);
5336     }
5337
5338   /* general case */
5339   size = AOP_SIZE (result);
5340   offset = 0;
5341
5342   if (AOP_TYPE (right) == AOP_LIT)
5343     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5344   if (isPair (AOP (result)))
5345     {
5346       fetchPair (getPairId (AOP (result)), AOP (right));
5347     }
5348   else if ((size > 1) &&
5349            (AOP_TYPE (result) != AOP_REG) &&
5350            (AOP_TYPE (right) == AOP_LIT) &&
5351            !IS_FLOAT (operandType (right)) &&
5352            (lit < 256L))
5353     {
5354       bool fXored = FALSE;
5355       offset = 0;
5356       /* Work from the top down.
5357          Done this way so that we can use the cached copy of 0
5358          in A for a fast clear */
5359       while (size--)
5360         {
5361           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5362             {
5363               if (!fXored && size > 1)
5364                 {
5365                   emit2 ("xor a,a");
5366                   fXored = TRUE;
5367                 }
5368               if (fXored)
5369                 {
5370                   aopPut (AOP (result), "a", offset);
5371                 }
5372               else
5373                 {
5374                   aopPut (AOP (result), "!zero", offset);
5375                 }
5376             }
5377           else
5378             aopPut (AOP (result),
5379                     aopGet (AOP (right), offset, FALSE),
5380                     offset);
5381           offset++;
5382         }
5383     }
5384   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5385     {
5386       /* Special case.  Load into a and d, then load out. */
5387       _moveA (aopGet (AOP (right), 0, FALSE));
5388       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5389       aopPut (AOP (result), "a", 0);
5390       aopPut (AOP (result), "e", 1);
5391     }
5392   else
5393     {
5394       while (size--)
5395         {
5396           /* PENDING: do this check better */
5397           if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5398             {
5399               _moveA (aopGet (AOP (right), offset, FALSE));
5400               aopPut (AOP (result), "a", offset);
5401             }
5402           else
5403             aopPut (AOP (result),
5404                     aopGet (AOP (right), offset, FALSE),
5405                     offset);
5406           offset++;
5407         }
5408     }
5409
5410 release:
5411   freeAsmop (right, NULL, ic);
5412   freeAsmop (result, NULL, ic);
5413 }
5414
5415 /*-----------------------------------------------------------------*/
5416 /* genJumpTab - genrates code for jump table                       */
5417 /*-----------------------------------------------------------------*/
5418 static void
5419 genJumpTab (iCode * ic)
5420 {
5421   symbol *jtab;
5422   const char *l;
5423
5424   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5425   /* get the condition into accumulator */
5426   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5427   if (!IS_GB)
5428     emit2 ("push de");
5429   emit2 ("ld e,%s", l);
5430   emit2 ("ld d,!zero");
5431   jtab = newiTempLabel (NULL);
5432   spillCached ();
5433   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5434   emit2 ("add hl,de");
5435   emit2 ("add hl,de");
5436   emit2 ("add hl,de");
5437   freeAsmop (IC_JTCOND (ic), NULL, ic);
5438   if (!IS_GB)
5439     emit2 ("pop de");
5440   emit2 ("jp !*hl");
5441   emitLabel (jtab->key + 100);
5442   /* now generate the jump labels */
5443   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5444        jtab = setNextItem (IC_JTLABELS (ic)))
5445     emit2 ("jp !tlabel", jtab->key + 100);
5446 }
5447
5448 /*-----------------------------------------------------------------*/
5449 /* genCast - gen code for casting                                  */
5450 /*-----------------------------------------------------------------*/
5451 static void
5452 genCast (iCode * ic)
5453 {
5454   operand *result = IC_RESULT (ic);
5455   sym_link *ctype = operandType (IC_LEFT (ic));
5456   operand *right = IC_RIGHT (ic);
5457   int size, offset;
5458
5459   /* if they are equivalent then do nothing */
5460   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5461     return;
5462
5463   aopOp (right, ic, FALSE, FALSE);
5464   aopOp (result, ic, FALSE, FALSE);
5465
5466   /* if the result is a bit */
5467   if (AOP_TYPE (result) == AOP_CRY)
5468     {
5469       wassert (0);
5470     }
5471
5472   /* if they are the same size : or less */
5473   if (AOP_SIZE (result) <= AOP_SIZE (right))
5474     {
5475
5476       /* if they are in the same place */
5477       if (sameRegs (AOP (right), AOP (result)))
5478         goto release;
5479
5480       /* if they in different places then copy */
5481       size = AOP_SIZE (result);
5482       offset = 0;
5483       while (size--)
5484         {
5485           aopPut (AOP (result),
5486                   aopGet (AOP (right), offset, FALSE),
5487                   offset);
5488           offset++;
5489         }
5490       goto release;
5491     }
5492
5493   /* PENDING: should be OK. */
5494 #if 0
5495   /* if the result is of type pointer */
5496   if (IS_PTR (ctype))
5497     {
5498       wassert (0);
5499     }
5500 #endif
5501
5502   /* so we now know that the size of destination is greater
5503      than the size of the source */
5504   /* we move to result for the size of source */
5505   size = AOP_SIZE (right);
5506   offset = 0;
5507   while (size--)
5508     {
5509       aopPut (AOP (result),
5510               aopGet (AOP (right), offset, FALSE),
5511               offset);
5512       offset++;
5513     }
5514
5515   /* now depending on the sign of the destination */
5516   size = AOP_SIZE (result) - AOP_SIZE (right);
5517   /* Unsigned or not an integral type - right fill with zeros */
5518   if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5519     {
5520       while (size--)
5521         aopPut (AOP (result), "!zero", offset++);
5522     }
5523   else
5524     {
5525       /* we need to extend the sign :{ */
5526         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5527                         FALSE);
5528       _moveA (l);
5529       emitDebug ("; genCast: sign extend untested.");
5530       emit2 ("rla ");
5531       emit2 ("sbc a,a");
5532       while (size--)
5533         aopPut (AOP (result), "a", offset++);
5534     }
5535
5536 release:
5537   freeAsmop (right, NULL, ic);
5538   freeAsmop (result, NULL, ic);
5539 }
5540
5541 /*-----------------------------------------------------------------*/
5542 /* genReceive - generate code for a receive iCode                  */
5543 /*-----------------------------------------------------------------*/
5544 static void
5545 genReceive (iCode * ic)
5546 {
5547   if (isOperandInFarSpace (IC_RESULT (ic)) &&
5548       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5549        IS_TRUE_SYMOP (IC_RESULT (ic))))
5550     {
5551       wassert (0);
5552     }
5553   else
5554     {
5555         // PENDING: HACK
5556         int size;
5557         int i;
5558
5559         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5560         size = AOP_SIZE(IC_RESULT(ic));
5561
5562         for (i = 0; i < size; i++) {
5563             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5564         }
5565     }
5566
5567   freeAsmop (IC_RESULT (ic), NULL, ic);
5568 }
5569
5570 enum
5571   {
5572     /** Maximum number of bytes to emit per line. */
5573     DBEMIT_MAX_RUN = 8
5574   };
5575
5576 /** Context for the byte output chunker. */
5577 typedef struct
5578 {
5579   unsigned char buffer[DBEMIT_MAX_RUN];
5580   int pos;
5581 } DBEMITCTX;
5582
5583
5584 /** Flushes a byte chunker by writing out all in the buffer and
5585     reseting. 
5586 */
5587 static void
5588 _dbFlush(DBEMITCTX *self)
5589 {
5590   char line[256];
5591
5592   if (self->pos > 0)
5593     {
5594       int i;
5595       sprintf(line, ".db 0x%02X", self->buffer[0]);
5596
5597       for (i = 1; i < self->pos; i++)
5598         {
5599           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5600         }
5601       emit2(line);
5602     }
5603   self->pos = 0;
5604 }
5605
5606 /** Write out another byte, buffering until a decent line is
5607     generated.
5608 */
5609 static void
5610 _dbEmit(DBEMITCTX *self, int c)
5611 {
5612   if (self->pos == DBEMIT_MAX_RUN)
5613     {
5614       _dbFlush(self);
5615     }
5616   self->buffer[self->pos++] = c;
5617 }
5618
5619 /** Context for a simple run length encoder. */
5620 typedef struct
5621 {
5622   unsigned last;
5623   unsigned char buffer[128];
5624   int pos;
5625   /** runLen may be equivalent to pos. */
5626   int runLen;
5627 } RLECTX;
5628
5629 enum
5630   {
5631     RLE_CHANGE_COST = 4,
5632     RLE_MAX_BLOCK = 127
5633   };
5634
5635 /** Flush the buffer of a run length encoder by writing out the run or
5636     data that it currently contains.
5637 */
5638 static void
5639 _rleCommit(RLECTX *self)
5640 {
5641   int i;
5642   if (self->pos != 0)
5643     {
5644       DBEMITCTX db;
5645       memset(&db, 0, sizeof(db));
5646           
5647       emit2(".db %u", self->pos);
5648       
5649       for (i = 0; i < self->pos; i++)
5650         {
5651           _dbEmit(&db, self->buffer[i]);
5652         }
5653       _dbFlush(&db);
5654     }
5655   /* Reset */
5656   self->pos = 0;
5657 }
5658
5659 /* Encoder design:
5660    Can get either a run or a block of random stuff.
5661    Only want to change state if a good run comes in or a run ends.
5662    Detecting run end is easy.
5663    Initial state?
5664
5665    Say initial state is in run, len zero, last zero.  Then if you get a
5666    few zeros then something else then a short run will be output.
5667    Seems OK.  While in run mode, keep counting.  While in random mode,
5668    keep a count of the run.  If run hits margin, output all up to run,
5669    restart, enter run mode.
5670 */
5671
5672 /** Add another byte into the run length encoder, flushing as
5673     required.  The run length encoder uses the Amiga IFF style, where
5674     a block is prefixed by its run length.  A positive length means
5675     the next n bytes pass straight through.  A negative length means
5676     that the next byte is repeated -n times.  A zero terminates the
5677     chunks.
5678 */
5679 static void
5680 _rleAppend(RLECTX *self, int c)
5681 {
5682   int i;
5683
5684   if (c != self->last)
5685     {
5686       /* The run has stopped.  See if it is worthwhile writing it out
5687          as a run.  Note that the random data comes in as runs of
5688          length one.
5689       */
5690       if (self->runLen > RLE_CHANGE_COST)
5691         {
5692           /* Yes, worthwhile. */
5693           /* Commit whatever was in the buffer. */
5694           _rleCommit(self);
5695           emit2(".db -%u,0x%02X", self->runLen, self->last);
5696         }
5697       else
5698         {
5699           /* Not worthwhile.  Append to the end of the random list. */
5700           for (i = 0; i < self->runLen; i++)
5701             {
5702               if (self->pos >= RLE_MAX_BLOCK)
5703                 {
5704                   /* Commit. */
5705                   _rleCommit(self);
5706                 }
5707               self->buffer[self->pos++] = self->last;
5708             }
5709         }
5710       self->runLen = 1;
5711       self->last = c;
5712     }
5713   else
5714     {
5715       if (self->runLen >= RLE_MAX_BLOCK)
5716         {
5717           /* Commit whatever was in the buffer. */
5718           _rleCommit(self);
5719
5720           emit2 (".db -%u,0x%02X", self->runLen, self->last);
5721           self->runLen = 0;
5722         }
5723       self->runLen++;
5724     }
5725 }
5726
5727 static void
5728 _rleFlush(RLECTX *self)
5729 {
5730   _rleAppend(self, -1);
5731   _rleCommit(self);
5732   self->pos = 0;
5733   self->last = 0;
5734   self->runLen = 0;
5735 }
5736
5737 /** genArrayInit - Special code for initialising an array with constant
5738    data.
5739 */
5740 static void
5741 genArrayInit (iCode * ic)
5742 {
5743   literalList *iLoop;
5744   int         ix;
5745   int         elementSize = 0, eIndex, i;
5746   unsigned    val, lastVal;
5747   sym_link    *type;
5748   RLECTX      rle;
5749
5750   memset(&rle, 0, sizeof(rle));
5751
5752   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5753
5754   if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5755     {
5756       /* Emit the support function call and the destination address. */
5757       emit2("call __initrleblock");
5758       emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5759     }
5760   else
5761     {
5762       wassertl (0, "Unexpected operand to genArrayInit.\n");
5763     }
5764     
5765   type = operandType(IC_LEFT(ic));
5766     
5767   if (type && type->next)
5768     {
5769       elementSize = getSize(type->next);
5770     }
5771   else
5772     {
5773       wassertl (0, "Can't determine element size in genArrayInit.");
5774     }
5775
5776   iLoop = IC_ARRAYILIST(ic);
5777   lastVal = (unsigned)-1;
5778
5779   /* Feed all the bytes into the run length encoder which will handle
5780      the actual output.
5781      This works well for mixed char data, and for random int and long
5782      data.
5783   */
5784   while (iLoop)
5785     {
5786       ix = iLoop->count;
5787
5788       if (ix != 0)
5789         {
5790           for (i = 0; i < ix; i++)
5791             {
5792               for (eIndex = 0; eIndex < elementSize; eIndex++)
5793                 {
5794                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5795                   _rleAppend(&rle, val);
5796                 }
5797             }
5798         }
5799         
5800       iLoop = iLoop->next;
5801     }
5802
5803   _rleFlush(&rle);
5804   /* Mark the end of the run. */
5805   emit2(".db 0");
5806
5807   freeAsmop (IC_LEFT(ic), NULL, ic);
5808 }
5809
5810 /*-----------------------------------------------------------------*/
5811 /* genZ80Code - generate code for Z80 based controllers            */
5812 /*-----------------------------------------------------------------*/
5813 void
5814 genZ80Code (iCode * lic)
5815 {
5816   iCode *ic;
5817   int cln = 0;
5818
5819   /* HACK */
5820   if (IS_GB)
5821     {
5822       _fReturn = _gbz80_return;
5823       _fTmp = _gbz80_return;
5824     }
5825   else
5826     {
5827       _fReturn = _z80_return;
5828       _fTmp = _z80_return;
5829     }
5830
5831   _G.lines.head = _G.lines.current = NULL;
5832
5833   for (ic = lic; ic; ic = ic->next)
5834     {
5835
5836       if (cln != ic->lineno)
5837         {
5838           emit2 ("; %s %d", ic->filename, ic->lineno);
5839           cln = ic->lineno;
5840         }
5841       /* if the result is marked as
5842          spilt and rematerializable or code for
5843          this has already been generated then
5844          do nothing */
5845       if (resultRemat (ic) || ic->generated)
5846         continue;
5847
5848       /* depending on the operation */
5849       switch (ic->op)
5850         {
5851         case '!':
5852           emitDebug ("; genNot");
5853           genNot (ic);
5854           break;
5855
5856         case '~':
5857           emitDebug ("; genCpl");
5858           genCpl (ic);
5859           break;
5860
5861         case UNARYMINUS:
5862           emitDebug ("; genUminus");
5863           genUminus (ic);
5864           break;
5865
5866         case IPUSH:
5867           emitDebug ("; genIpush");
5868           genIpush (ic);
5869           break;
5870
5871         case IPOP:
5872           /* IPOP happens only when trying to restore a
5873              spilt live range, if there is an ifx statement
5874              following this pop then the if statement might
5875              be using some of the registers being popped which
5876              would destory the contents of the register so
5877              we need to check for this condition and handle it */
5878           if (ic->next &&
5879               ic->next->op == IFX &&
5880               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5881             {
5882               emitDebug ("; genIfx");
5883               genIfx (ic->next, ic);
5884             }
5885           else
5886             {
5887               emitDebug ("; genIpop");
5888               genIpop (ic);
5889             }
5890           break;
5891
5892         case CALL:
5893           emitDebug ("; genCall");
5894           genCall (ic);
5895           break;
5896
5897         case PCALL:
5898           emitDebug ("; genPcall");
5899           genPcall (ic);
5900           break;
5901
5902         case FUNCTION:
5903           emitDebug ("; genFunction");
5904           genFunction (ic);
5905           break;
5906
5907         case ENDFUNCTION:
5908           emitDebug ("; genEndFunction");
5909           genEndFunction (ic);
5910           break;
5911
5912         case RETURN:
5913           emitDebug ("; genRet");
5914           genRet (ic);
5915           break;
5916
5917         case LABEL:
5918           emitDebug ("; genLabel");
5919           genLabel (ic);
5920           break;
5921
5922         case GOTO:
5923           emitDebug ("; genGoto");
5924           genGoto (ic);
5925           break;
5926
5927         case '+':
5928           emitDebug ("; genPlus");
5929           genPlus (ic);
5930           break;
5931
5932         case '-':
5933           emitDebug ("; genMinus");
5934           genMinus (ic);
5935           break;
5936
5937         case '*':
5938           emitDebug ("; genMult");
5939           genMult (ic);
5940           break;
5941
5942         case '/':
5943           emitDebug ("; genDiv");
5944           genDiv (ic);
5945           break;
5946
5947         case '%':
5948           emitDebug ("; genMod");
5949           genMod (ic);
5950           break;
5951
5952         case '>':
5953           emitDebug ("; genCmpGt");
5954           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
5955           break;
5956
5957         case '<':
5958           emitDebug ("; genCmpLt");
5959           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
5960           break;
5961
5962         case LE_OP:
5963         case GE_OP:
5964         case NE_OP:
5965
5966           /* note these two are xlated by algebraic equivalence
5967              during parsing SDCC.y */
5968           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5969                   "got '>=' or '<=' shouldn't have come here");
5970           break;
5971
5972         case EQ_OP:
5973           emitDebug ("; genCmpEq");
5974           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
5975           break;
5976
5977         case AND_OP:
5978           emitDebug ("; genAndOp");
5979           genAndOp (ic);
5980           break;
5981
5982         case OR_OP:
5983           emitDebug ("; genOrOp");
5984           genOrOp (ic);
5985           break;
5986
5987         case '^':
5988           emitDebug ("; genXor");
5989           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
5990           break;
5991
5992         case '|':
5993           emitDebug ("; genOr");
5994           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
5995           break;
5996
5997         case BITWISEAND:
5998           emitDebug ("; genAnd");
5999           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6000           break;
6001
6002         case INLINEASM:
6003           emitDebug ("; genInline");
6004           genInline (ic);
6005           break;
6006
6007         case RRC:
6008           emitDebug ("; genRRC");
6009           genRRC (ic);
6010           break;
6011
6012         case RLC:
6013           emitDebug ("; genRLC");
6014           genRLC (ic);
6015           break;
6016
6017         case GETHBIT:
6018           emitDebug ("; genGetHBIT");
6019           genGetHbit (ic);
6020           break;
6021
6022         case LEFT_OP:
6023           emitDebug ("; genLeftShift");
6024           genLeftShift (ic);
6025           break;
6026
6027         case RIGHT_OP:
6028           emitDebug ("; genRightShift");
6029           genRightShift (ic);
6030           break;
6031
6032         case GET_VALUE_AT_ADDRESS:
6033           emitDebug ("; genPointerGet");
6034           genPointerGet (ic);
6035           break;
6036
6037         case '=':
6038
6039           if (POINTER_SET (ic))
6040             {
6041               emitDebug ("; genAssign (pointer)");
6042               genPointerSet (ic);
6043             }
6044           else
6045             {
6046               emitDebug ("; genAssign");
6047               genAssign (ic);
6048             }
6049           break;
6050
6051         case IFX:
6052           emitDebug ("; genIfx");
6053           genIfx (ic, NULL);
6054           break;
6055
6056         case ADDRESS_OF:
6057           emitDebug ("; genAddrOf");
6058           genAddrOf (ic);
6059           break;
6060
6061         case JUMPTABLE:
6062           emitDebug ("; genJumpTab");
6063           genJumpTab (ic);
6064           break;
6065
6066         case CAST:
6067           emitDebug ("; genCast");
6068           genCast (ic);
6069           break;
6070
6071         case RECEIVE:
6072           emitDebug ("; genReceive");
6073           genReceive (ic);
6074           break;
6075
6076         case SEND:
6077           emitDebug ("; addSet");
6078           addSet (&_G.sendSet, ic);
6079           break;
6080
6081         case ARRAYINIT:
6082             genArrayInit(ic);
6083             break;
6084             
6085         default:
6086           ic = ic;
6087           /*      piCode(ic,stdout); */
6088
6089         }
6090     }
6091
6092
6093   /* now we are ready to call the
6094      peep hole optimizer */
6095   if (!options.nopeep)
6096     peepHole (&_G.lines.head);
6097
6098   /* This is unfortunate */
6099   /* now do the actual printing */
6100   {
6101     FILE *fp = codeOutFile;
6102     if (isInHome () && codeOutFile == code->oFile)
6103       codeOutFile = home->oFile;
6104     printLine (_G.lines.head, codeOutFile);
6105     if (_G.flushStatics)
6106       {
6107         flushStatics ();
6108         _G.flushStatics = 0;
6109       }
6110     codeOutFile = fp;
6111   }
6112 }
6113
6114 /*
6115   Attic
6116 static int
6117 _isPairUsed (iCode * ic, PAIR_ID pairId)
6118 {
6119   int ret = 0;
6120   switch (pairId)
6121     {
6122     case PAIR_DE:
6123       if (bitVectBitValue (ic->rMask, D_IDX))
6124         ret++;
6125       if (bitVectBitValue (ic->rMask, E_IDX))
6126         ret++;
6127       break;
6128     default:
6129       wassert (0);
6130     }
6131   return ret;
6132 }
6133
6134 */