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