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