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