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