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