* support/regression/tests/fetchoverlap.c: Added new test case.
[fw/sdcc] / src / z80 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - Z80 specific code generator.
3      
4   Michael Hope <michaelh@juju.net.nz> 2000
5   Based on the mcs51 generator -
6       Sandeep Dutta . sandeep.dutta@usa.net (1998)
7    and -  Jean-Louis VERN.jlvern@writeme.com (1999)
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24   In other words, you are welcome to use, share and improve this program.
25   You are forbidden to forbid anyone else to use, share and improve
26   what you give them.   Help stamp out software-hoarding!
27
28 -------------------------------------------------------------------------*/
29
30 /*
31   Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
32                                        ticks dhry  size
33   Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34   Improved WORD push                    22784 144 19AE
35   With label1 on                        22694 144 197E
36   With label2 on                        22743 144 198A
37   With label3 on                        22776 144 1999
38   With label4 on                        22776 144 1999
39   With all 'label' on                   22661 144 196F
40   With loopInvariant on                 20919 156 19AB
41   With loopInduction on                 Breaks    198B
42   With all working on                   20796 158 196C
43   Slightly better genCmp(signed)        20597 159 195B
44   Better reg packing, first peephole    20038 163 1873
45   With assign packing                   19281 165 1849
46   5/3/00                                17741 185 17B6
47   With reg params for mul and div       16234 202 162D
48
49   1. Starting again at 3 Aug 01         34965  93 219C
50    No asm strings
51    Includes long mul/div in code
52   2. Optimised memcpy for acc use       32102 102 226B
53   3. Optimised strcpy for acc use       27819 117 2237
54   3a Optimised memcpy fun
55   4. Optimised strcmp fun               21999 149 2294
56   5. Optimised strcmp further           21660 151 228C
57   6. Optimised memcpy by unroling       20885 157 2201
58   7. After turning loop induction on    19862 165 236D
59   8. Same as 7 but with more info       
60   9. With asm optimised strings         17030 192 2223
61
62   10 and below are with asm strings off.
63   
64   Apparent advantage of turning on regparams:
65   1.  Cost of push
66         Decent case is push of a constant 
67           - ld hl,#n; push hl: (10+11)*nargs
68   2.  Cost of pull from stack
69         Using asm with ld hl, etc
70           - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
71             10+11+(7+6+7+6)*nargs
72   3.  Cost of fixing stack
73           - pop hl*nargs
74             10*nargs
75   
76   So cost is (10+11+7+6+7+10)*nargs+10+11 
77       = 51*nargs+21
78       = 123 for mul, div, strcmp, strcpy
79   Saving of (98298+32766+32766+32766)*123 = 24181308
80   At 192 d/s for 682411768t, speed up to 199.  Hmm.
81 */
82
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <ctype.h>
87
88 #ifdef HAVE_SYS_ISA_DEFS_H
89 #include <sys/isa_defs.h>
90 #endif
91
92 #include "z80.h"
93 #include "SDCCglobl.h"
94 #include "SDCCpeeph.h"
95 #include "gen.h"
96 #include "SDCCglue.h"
97 #include "newalloc.h"
98
99 /* This is the down and dirty file with all kinds of kludgy & hacky
100    stuff. This is what it is all about CODE GENERATION for a specific MCU.
101    Some of the routines may be reusable, will have to see */
102
103 /* Z80 calling convention description.
104    Parameters are passed right to left.  As the stack grows downwards,
105    the parameters are arranged in left to right in memory.
106    Parameters may be passed in the HL and DE registers with one
107    parameter per pair.
108    PENDING: What if the parameter is a long?
109    Everything is caller saves. i.e. the caller must save any registers
110    that it wants to preserve over the call.
111    GB: The return value is returned in DEHL.  DE is normally used as a
112    working register pair.  Caller saves allows it to be used for a
113    return value.
114    va args functions do not use register parameters.  All arguments
115    are passed on the stack.
116    IX is used as an index register to the top of the local variable
117    area.  ix-0 is the top most local variable.
118 */
119
120 enum 
121 {
122   /* Set to enable debugging trace statements in the output assembly code. */
123   DISABLE_DEBUG = 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 <= 2)
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   emit2 ("or a,a");
4832
4833   if (AOP (result)->type == AOP_REG)
4834     {
4835       aopPut (AOP (result), l, 0);
4836       l = aopGet (AOP (result), 0, FALSE);
4837       while (shCount--)
4838         {
4839           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4840         }
4841     }
4842   else
4843     {
4844       _moveA (l);
4845       while (shCount--)
4846         {
4847           emit2 ("%s a", is_signed ? "sra" : "srl");
4848         }
4849       aopPut (AOP (result), "a", 0);
4850     }
4851 }
4852
4853 /*-----------------------------------------------------------------*/
4854 /* AccRsh - right shift accumulator by known count                 */
4855 /*-----------------------------------------------------------------*/
4856 static void
4857 AccRsh (int shCount)
4858 {
4859   static const unsigned char SRMask[] =
4860     {
4861       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4862     };
4863
4864   if (shCount != 0)
4865     {
4866       /* rotate right accumulator */
4867       AccRol (8 - shCount);
4868       /* and kill the higher order bits */
4869       emit2 ("and a,!immedbyte", SRMask[shCount]);
4870     }
4871 }
4872
4873 /*-----------------------------------------------------------------*/
4874 /* shiftR1Left2Result - shift right one byte from left to result   */
4875 /*-----------------------------------------------------------------*/
4876 static void
4877 shiftR1Left2Result (operand * left, int offl,
4878                     operand * result, int offr,
4879                     int shCount, int sign)
4880 {
4881   _moveA (aopGet (AOP (left), offl, FALSE));
4882   if (sign)
4883     {
4884       while (shCount--)
4885         {
4886           emit2 ("%s a", sign ? "sra" : "srl");
4887         }
4888     }
4889   else
4890     {
4891       AccRsh (shCount);
4892     }
4893   aopPut (AOP (result), "a", offr);
4894 }
4895
4896 /*-----------------------------------------------------------------*/
4897 /* genrshTwo - right shift two bytes by known amount != 0          */
4898 /*-----------------------------------------------------------------*/
4899 static void
4900 genrshTwo (operand * result, operand * left,
4901            int shCount, int sign)
4902 {
4903   /* if shCount >= 8 */
4904   if (shCount >= 8)
4905     {
4906       shCount -= 8;
4907       if (shCount)
4908         {
4909           shiftR1Left2Result (left, MSB16, result, LSB,
4910                               shCount, sign);
4911         }
4912       else
4913         {
4914           movLeft2Result (left, MSB16, result, LSB, sign);
4915         }
4916       aopPut (AOP (result), "!zero", 1);
4917     }
4918   /*  1 <= shCount <= 7 */
4919   else
4920     {
4921       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4922     }
4923 }
4924
4925 /*-----------------------------------------------------------------*/
4926 /* genRightShiftLiteral - left shifting by known count              */
4927 /*-----------------------------------------------------------------*/
4928 static void
4929 genRightShiftLiteral (operand * left,
4930                       operand * right,
4931                       operand * result,
4932                       iCode * ic,
4933                       int sign)
4934 {
4935   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4936   int size;
4937
4938   freeAsmop (right, NULL, ic);
4939
4940   aopOp (left, ic, FALSE, FALSE);
4941   aopOp (result, ic, FALSE, FALSE);
4942
4943   size = getSize (operandType (result));
4944
4945   /* I suppose that the left size >= result size */
4946   if (shCount == 0)
4947     {
4948       wassert (0);
4949     }
4950
4951   else if (shCount >= (size * 8))
4952     while (size--)
4953       aopPut (AOP (result), "!zero", size);
4954   else
4955     {
4956       switch (size)
4957         {
4958         case 1:
4959           genrshOne (result, left, shCount, sign);
4960           break;
4961         case 2:
4962           /* PENDING: sign support */
4963           genrshTwo (result, left, shCount, sign);
4964           break;
4965         case 4:
4966           wassertl (0, "Asked to shift right a long which should be a function call");
4967           break;
4968         default:
4969           wassertl (0, "Entered default case in right shift delegate");
4970         }
4971     }
4972   freeAsmop (left, NULL, ic);
4973   freeAsmop (result, NULL, ic);
4974 }
4975
4976 /*-----------------------------------------------------------------*/
4977 /* genRightShift - generate code for right shifting                */
4978 /*-----------------------------------------------------------------*/
4979 static void
4980 genRightShift (iCode * ic)
4981 {
4982   operand *right, *left, *result;
4983   sym_link *retype;
4984   int size, offset, first = 1;
4985   const char *l;
4986   bool is_signed;
4987
4988   symbol *tlbl, *tlbl1;
4989
4990   /* if signed then we do it the hard way preserve the
4991      sign bit moving it inwards */
4992   retype = getSpec (operandType (IC_RESULT (ic)));
4993
4994   is_signed = !SPEC_USIGN (retype);
4995
4996   /* signed & unsigned types are treated the same : i.e. the
4997      signed is NOT propagated inwards : quoting from the
4998      ANSI - standard : "for E1 >> E2, is equivalent to division
4999      by 2**E2 if unsigned or if it has a non-negative value,
5000      otherwise the result is implementation defined ", MY definition
5001      is that the sign does not get propagated */
5002
5003   right = IC_RIGHT (ic);
5004   left = IC_LEFT (ic);
5005   result = IC_RESULT (ic);
5006
5007   aopOp (right, ic, FALSE, FALSE);
5008
5009   /* if the shift count is known then do it
5010      as efficiently as possible */
5011   if (AOP_TYPE (right) == AOP_LIT)
5012     {
5013       genRightShiftLiteral (left, right, result, ic, is_signed);
5014       return;
5015     }
5016
5017   aopOp (left, ic, FALSE, FALSE);
5018   aopOp (result, ic, FALSE, FALSE);
5019
5020   /* now move the left to the result if they are not the
5021      same */
5022   if (!sameRegs (AOP (left), AOP (result)) &&
5023       AOP_SIZE (result) > 1)
5024     {
5025
5026       size = AOP_SIZE (result);
5027       offset = 0;
5028       while (size--)
5029         {
5030           l = aopGet (AOP (left), offset, FALSE);
5031           aopPut (AOP (result), l, offset);
5032           offset++;
5033         }
5034     }
5035
5036   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5037   emit2 ("inc a");
5038   freeAsmop (right, NULL, ic);
5039
5040   tlbl = newiTempLabel (NULL);
5041   tlbl1 = newiTempLabel (NULL);
5042   size = AOP_SIZE (result);
5043   offset = size - 1;
5044
5045   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5046   emitLabel (tlbl->key + 100);
5047   while (size--)
5048     {
5049       l = aopGet (AOP (result), offset--, FALSE);
5050       if (first)
5051         {
5052           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5053           first = 0;
5054         }
5055       else
5056         {
5057           emit2 ("rr %s", l);
5058         }
5059     }
5060   emitLabel (tlbl1->key + 100);
5061   emit2 ("dec a");
5062   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5063
5064   freeAsmop (left, NULL, ic);
5065   freeAsmop (result, NULL, ic);
5066 }
5067
5068 /*-----------------------------------------------------------------*/
5069 /* genGenPointerGet -  get value from generic pointer space        */
5070 /*-----------------------------------------------------------------*/
5071 static void
5072 genGenPointerGet (operand * left,
5073                   operand * result, iCode * ic)
5074 {
5075   int size, offset;
5076   sym_link *retype = getSpec (operandType (result));
5077   int pair = PAIR_HL;
5078
5079   if (IS_GB)
5080     pair = PAIR_DE;
5081
5082   aopOp (left, ic, FALSE, FALSE);
5083   aopOp (result, ic, FALSE, FALSE);
5084
5085   if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5086     {
5087       /* Just do it */
5088       if (isPtrPair (AOP (left)))
5089         {
5090           tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5091           aopPut (AOP (result), buffer, 0);
5092         }
5093       else
5094         {
5095           emit2 ("ld a,!*pair", getPairName (AOP (left)));
5096           aopPut (AOP (result), "a", 0);
5097         }
5098       freeAsmop (left, NULL, ic);
5099       goto release;
5100     }
5101
5102   /* For now we always load into IY */
5103   /* if this is remateriazable */
5104   fetchPair (pair, AOP (left));
5105
5106   /* so iy now contains the address */
5107   freeAsmop (left, NULL, ic);
5108
5109   /* if bit then unpack */
5110   if (IS_BITVAR (retype))
5111     {
5112       wassert (0);
5113     }
5114   else
5115     {
5116       size = AOP_SIZE (result);
5117       offset = 0;
5118
5119       while (size--)
5120         {
5121           /* PENDING: make this better */
5122           if (!IS_GB && AOP (result)->type == AOP_REG)
5123             {
5124               aopPut (AOP (result), "!*hl", offset++);
5125             }
5126           else
5127             {
5128               emit2 ("ld a,!*pair", _pairs[pair].name);
5129               aopPut (AOP (result), "a", offset++);
5130             }
5131           if (size)
5132             {
5133               emit2 ("inc %s", _pairs[pair].name);
5134               _G.pairs[pair].offset++;
5135             }
5136         }
5137     }
5138
5139 release:
5140   freeAsmop (result, NULL, ic);
5141 }
5142
5143 /*-----------------------------------------------------------------*/
5144 /* genPointerGet - generate code for pointer get                   */
5145 /*-----------------------------------------------------------------*/
5146 static void
5147 genPointerGet (iCode * ic)
5148 {
5149   operand *left, *result;
5150   sym_link *type, *etype;
5151
5152   left = IC_LEFT (ic);
5153   result = IC_RESULT (ic);
5154
5155   /* depending on the type of pointer we need to
5156      move it to the correct pointer register */
5157   type = operandType (left);
5158   etype = getSpec (type);
5159
5160   genGenPointerGet (left, result, ic);
5161 }
5162
5163 bool
5164 isRegOrLit (asmop * aop)
5165 {
5166   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5167     return TRUE;
5168   return FALSE;
5169 }
5170
5171 /*-----------------------------------------------------------------*/
5172 /* genGenPointerSet - stores the value into a pointer location        */
5173 /*-----------------------------------------------------------------*/
5174 static void
5175 genGenPointerSet (operand * right,
5176                   operand * result, iCode * ic)
5177 {
5178   int size, offset;
5179   sym_link *retype = getSpec (operandType (right));
5180   PAIR_ID pairId = PAIR_HL;
5181
5182   aopOp (result, ic, FALSE, FALSE);
5183   aopOp (right, ic, FALSE, FALSE);
5184
5185   if (IS_GB)
5186     pairId = PAIR_DE;
5187
5188   /* Handle the exceptions first */
5189   if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5190     {
5191       /* Just do it */
5192       const char *l = aopGet (AOP (right), 0, FALSE);
5193       const char *pair = getPairName (AOP (result));
5194       if (canAssignToPtr (l) && isPtr (pair))
5195         {
5196           emit2 ("ld !*pair,%s", pair, l);
5197         }
5198       else
5199         {
5200           _moveA (l);
5201           emit2 ("ld !*pair,a", pair);
5202         }
5203       goto release;
5204     }
5205
5206   /* if the operand is already in dptr
5207      then we do nothing else we move the value to dptr */
5208   if (AOP_TYPE (result) != AOP_STR)
5209     {
5210       fetchPair (pairId, AOP (result));
5211     }
5212   /* so hl know contains the address */
5213   freeAsmop (result, NULL, ic);
5214
5215   /* if bit then unpack */
5216   if (IS_BITVAR (retype))
5217     {
5218       wassert (0);
5219     }
5220   else
5221     {
5222       size = AOP_SIZE (right);
5223       offset = 0;
5224
5225       while (size--)
5226         {
5227           const char *l = aopGet (AOP (right), offset, FALSE);
5228           if (isRegOrLit (AOP (right)) && !IS_GB)
5229             {
5230               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5231             }
5232           else
5233             {
5234               _moveA (l);
5235               emit2 ("ld !*pair,a", _pairs[pairId].name);
5236             }
5237           if (size)
5238             {
5239               emit2 ("inc %s", _pairs[pairId].name);
5240               _G.pairs[pairId].offset++;
5241             }
5242           offset++;
5243         }
5244     }
5245 release:
5246   freeAsmop (right, NULL, ic);
5247 }
5248
5249 /*-----------------------------------------------------------------*/
5250 /* genPointerSet - stores the value into a pointer location        */
5251 /*-----------------------------------------------------------------*/
5252 static void
5253 genPointerSet (iCode * ic)
5254 {
5255   operand *right, *result;
5256   sym_link *type, *etype;
5257
5258   right = IC_RIGHT (ic);
5259   result = IC_RESULT (ic);
5260
5261   /* depending on the type of pointer we need to
5262      move it to the correct pointer register */
5263   type = operandType (result);
5264   etype = getSpec (type);
5265
5266   genGenPointerSet (right, result, ic);
5267 }
5268
5269 /*-----------------------------------------------------------------*/
5270 /* genIfx - generate code for Ifx statement                        */
5271 /*-----------------------------------------------------------------*/
5272 static void
5273 genIfx (iCode * ic, iCode * popIc)
5274 {
5275   operand *cond = IC_COND (ic);
5276   int isbit = 0;
5277
5278   aopOp (cond, ic, FALSE, TRUE);
5279
5280   /* get the value into acc */
5281   if (AOP_TYPE (cond) != AOP_CRY)
5282     _toBoolean (cond);
5283   else
5284     isbit = 1;
5285   /* the result is now in the accumulator */
5286   freeAsmop (cond, NULL, ic);
5287
5288   /* if there was something to be popped then do it */
5289   if (popIc)
5290     genIpop (popIc);
5291
5292   /* if the condition is  a bit variable */
5293   if (isbit && IS_ITEMP (cond) &&
5294       SPIL_LOC (cond))
5295     genIfxJump (ic, SPIL_LOC (cond)->rname);
5296   else if (isbit && !IS_ITEMP (cond))
5297     genIfxJump (ic, OP_SYMBOL (cond)->rname);
5298   else
5299     genIfxJump (ic, "a");
5300
5301   ic->generated = 1;
5302 }
5303
5304 /*-----------------------------------------------------------------*/
5305 /* genAddrOf - generates code for address of                       */
5306 /*-----------------------------------------------------------------*/
5307 static void
5308 genAddrOf (iCode * ic)
5309 {
5310   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5311
5312   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5313
5314   /* if the operand is on the stack then we
5315      need to get the stack offset of this
5316      variable */
5317   if (IS_GB)
5318     {
5319       if (sym->onStack)
5320         {
5321           spillCached ();
5322           if (sym->stack <= 0)
5323             {
5324               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5325             }
5326           else
5327             {
5328               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5329             }
5330           emit2 ("ld d,h");
5331           emit2 ("ld e,l");
5332         }
5333       else
5334         {
5335           emit2 ("ld de,!hashedstr", sym->rname);
5336         }
5337       aopPut (AOP (IC_RESULT (ic)), "e", 0);
5338       aopPut (AOP (IC_RESULT (ic)), "d", 1);
5339     }
5340   else
5341     {
5342       spillCached ();
5343       if (sym->onStack)
5344         {
5345           /* if it has an offset  then we need to compute it */
5346           if (sym->stack > 0)
5347             emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5348           else
5349             emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5350           emit2 ("add hl,sp");
5351         }
5352       else
5353         {
5354           emit2 ("ld hl,#%s", sym->rname);
5355         }
5356       aopPut (AOP (IC_RESULT (ic)), "l", 0);
5357       aopPut (AOP (IC_RESULT (ic)), "h", 1);
5358     }
5359   freeAsmop (IC_RESULT (ic), NULL, ic);
5360 }
5361
5362 /*-----------------------------------------------------------------*/
5363 /* genAssign - generate code for assignment                        */
5364 /*-----------------------------------------------------------------*/
5365 static void
5366 genAssign (iCode * ic)
5367 {
5368   operand *result, *right;
5369   int size, offset;
5370   unsigned long lit = 0L;
5371
5372   result = IC_RESULT (ic);
5373   right = IC_RIGHT (ic);
5374
5375   /* Dont bother assigning if they are the same */
5376   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5377     {
5378       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5379       return;
5380     }
5381
5382   aopOp (right, ic, FALSE, FALSE);
5383   aopOp (result, ic, TRUE, FALSE);
5384
5385   /* if they are the same registers */
5386   if (sameRegs (AOP (right), AOP (result)))
5387     {
5388       emitDebug ("; (registers are the same)");
5389       goto release;
5390     }
5391
5392   /* if the result is a bit */
5393   if (AOP_TYPE (result) == AOP_CRY)
5394     {
5395       wassert (0);
5396     }
5397
5398   /* general case */
5399   size = AOP_SIZE (result);
5400   offset = 0;
5401
5402   if (AOP_TYPE (right) == AOP_LIT)
5403     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5404   if (isPair (AOP (result)))
5405     {
5406       fetchPair (getPairId (AOP (result)), AOP (right));
5407     }
5408   else if ((size > 1) &&
5409            (AOP_TYPE (result) != AOP_REG) &&
5410            (AOP_TYPE (right) == AOP_LIT) &&
5411            !IS_FLOAT (operandType (right)) &&
5412            (lit < 256L))
5413     {
5414       bool fXored = FALSE;
5415       offset = 0;
5416       /* Work from the top down.
5417          Done this way so that we can use the cached copy of 0
5418          in A for a fast clear */
5419       while (size--)
5420         {
5421           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5422             {
5423               if (!fXored && size > 1)
5424                 {
5425                   emit2 ("xor a,a");
5426                   fXored = TRUE;
5427                 }
5428               if (fXored)
5429                 {
5430                   aopPut (AOP (result), "a", offset);
5431                 }
5432               else
5433                 {
5434                   aopPut (AOP (result), "!zero", offset);
5435                 }
5436             }
5437           else
5438             aopPut (AOP (result),
5439                     aopGet (AOP (right), offset, FALSE),
5440                     offset);
5441           offset++;
5442         }
5443     }
5444   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5445     {
5446       /* Special case.  Load into a and d, then load out. */
5447       _moveA (aopGet (AOP (right), 0, FALSE));
5448       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5449       aopPut (AOP (result), "a", 0);
5450       aopPut (AOP (result), "e", 1);
5451     }
5452   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5453     {
5454       /* Special case - simple memcpy */
5455       aopGet (AOP (right), LSB, FALSE);
5456       emit2 ("ld d,h");
5457       emit2 ("ld e,l");
5458       aopGet (AOP (result), LSB, FALSE);
5459
5460       while (size--)
5461         {
5462           emit2 ("ld a,(de)");
5463           /* Peephole will optimise this. */
5464           emit2 ("ld (hl),a");
5465
5466           if (size != 0)
5467             {
5468               emit2 ("inc hl");
5469               emit2 ("inc de");
5470             }
5471         }
5472       spillPair (PAIR_HL);
5473     }
5474   else
5475     {
5476       while (size--)
5477         {
5478           /* PENDING: do this check better */
5479           if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5480             {
5481               _moveA (aopGet (AOP (right), offset, FALSE));
5482               aopPut (AOP (result), "a", offset);
5483             }
5484           else
5485             aopPut (AOP (result),
5486                     aopGet (AOP (right), offset, FALSE),
5487                     offset);
5488           offset++;
5489         }
5490     }
5491
5492 release:
5493   freeAsmop (right, NULL, ic);
5494   freeAsmop (result, NULL, ic);
5495 }
5496
5497 /*-----------------------------------------------------------------*/
5498 /* genJumpTab - genrates code for jump table                       */
5499 /*-----------------------------------------------------------------*/
5500 static void
5501 genJumpTab (iCode * ic)
5502 {
5503   symbol *jtab;
5504   const char *l;
5505
5506   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5507   /* get the condition into accumulator */
5508   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5509   if (!IS_GB)
5510     emit2 ("push de");
5511   emit2 ("ld e,%s", l);
5512   emit2 ("ld d,!zero");
5513   jtab = newiTempLabel (NULL);
5514   spillCached ();
5515   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5516   emit2 ("add hl,de");
5517   emit2 ("add hl,de");
5518   emit2 ("add hl,de");
5519   freeAsmop (IC_JTCOND (ic), NULL, ic);
5520   if (!IS_GB)
5521     emit2 ("pop de");
5522   emit2 ("jp !*hl");
5523   emitLabel (jtab->key + 100);
5524   /* now generate the jump labels */
5525   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5526        jtab = setNextItem (IC_JTLABELS (ic)))
5527     emit2 ("jp !tlabel", jtab->key + 100);
5528 }
5529
5530 /*-----------------------------------------------------------------*/
5531 /* genCast - gen code for casting                                  */
5532 /*-----------------------------------------------------------------*/
5533 static void
5534 genCast (iCode * ic)
5535 {
5536   operand *result = IC_RESULT (ic);
5537   sym_link *ctype = operandType (IC_LEFT (ic));
5538   operand *right = IC_RIGHT (ic);
5539   int size, offset;
5540
5541   /* if they are equivalent then do nothing */
5542   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5543     return;
5544
5545   aopOp (right, ic, FALSE, FALSE);
5546   aopOp (result, ic, FALSE, FALSE);
5547
5548   /* if the result is a bit */
5549   if (AOP_TYPE (result) == AOP_CRY)
5550     {
5551       wassert (0);
5552     }
5553
5554   /* if they are the same size : or less */
5555   if (AOP_SIZE (result) <= AOP_SIZE (right))
5556     {
5557
5558       /* if they are in the same place */
5559       if (sameRegs (AOP (right), AOP (result)))
5560         goto release;
5561
5562       /* if they in different places then copy */
5563       size = AOP_SIZE (result);
5564       offset = 0;
5565       while (size--)
5566         {
5567           aopPut (AOP (result),
5568                   aopGet (AOP (right), offset, FALSE),
5569                   offset);
5570           offset++;
5571         }
5572       goto release;
5573     }
5574
5575   /* So we now know that the size of destination is greater
5576      than the size of the source */
5577   /* we move to result for the size of source */
5578   size = AOP_SIZE (right);
5579   offset = 0;
5580   while (size--)
5581     {
5582       aopPut (AOP (result),
5583               aopGet (AOP (right), offset, FALSE),
5584               offset);
5585       offset++;
5586     }
5587
5588   /* now depending on the sign of the destination */
5589   size = AOP_SIZE (result) - AOP_SIZE (right);
5590   /* Unsigned or not an integral type - right fill with zeros */
5591   if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5592     {
5593       while (size--)
5594         aopPut (AOP (result), "!zero", offset++);
5595     }
5596   else
5597     {
5598       /* we need to extend the sign :{ */
5599         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5600                         FALSE);
5601       _moveA (l);
5602       emit2 ("rla ");
5603       emit2 ("sbc a,a");
5604       while (size--)
5605         aopPut (AOP (result), "a", offset++);
5606     }
5607
5608 release:
5609   freeAsmop (right, NULL, ic);
5610   freeAsmop (result, NULL, ic);
5611 }
5612
5613 /*-----------------------------------------------------------------*/
5614 /* genReceive - generate code for a receive iCode                  */
5615 /*-----------------------------------------------------------------*/
5616 static void
5617 genReceive (iCode * ic)
5618 {
5619   if (isOperandInFarSpace (IC_RESULT (ic)) &&
5620       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5621        IS_TRUE_SYMOP (IC_RESULT (ic))))
5622     {
5623       wassert (0);
5624     }
5625   else
5626     {
5627         // PENDING: HACK
5628         int size;
5629         int i;
5630
5631         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5632         size = AOP_SIZE(IC_RESULT(ic));
5633
5634         for (i = 0; i < size; i++) {
5635             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5636         }
5637     }
5638
5639   freeAsmop (IC_RESULT (ic), NULL, ic);
5640 }
5641
5642 enum
5643   {
5644     /** Maximum number of bytes to emit per line. */
5645     DBEMIT_MAX_RUN = 8
5646   };
5647
5648 /** Context for the byte output chunker. */
5649 typedef struct
5650 {
5651   unsigned char buffer[DBEMIT_MAX_RUN];
5652   int pos;
5653 } DBEMITCTX;
5654
5655
5656 /** Flushes a byte chunker by writing out all in the buffer and
5657     reseting. 
5658 */
5659 static void
5660 _dbFlush(DBEMITCTX *self)
5661 {
5662   char line[256];
5663
5664   if (self->pos > 0)
5665     {
5666       int i;
5667       sprintf(line, ".db 0x%02X", self->buffer[0]);
5668
5669       for (i = 1; i < self->pos; i++)
5670         {
5671           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5672         }
5673       emit2(line);
5674     }
5675   self->pos = 0;
5676 }
5677
5678 /** Write out another byte, buffering until a decent line is
5679     generated.
5680 */
5681 static void
5682 _dbEmit(DBEMITCTX *self, int c)
5683 {
5684   if (self->pos == DBEMIT_MAX_RUN)
5685     {
5686       _dbFlush(self);
5687     }
5688   self->buffer[self->pos++] = c;
5689 }
5690
5691 /** Context for a simple run length encoder. */
5692 typedef struct
5693 {
5694   unsigned last;
5695   unsigned char buffer[128];
5696   int pos;
5697   /** runLen may be equivalent to pos. */
5698   int runLen;
5699 } RLECTX;
5700
5701 enum
5702   {
5703     RLE_CHANGE_COST = 4,
5704     RLE_MAX_BLOCK = 127
5705   };
5706
5707 /** Flush the buffer of a run length encoder by writing out the run or
5708     data that it currently contains.
5709 */
5710 static void
5711 _rleCommit(RLECTX *self)
5712 {
5713   int i;
5714   if (self->pos != 0)
5715     {
5716       DBEMITCTX db;
5717       memset(&db, 0, sizeof(db));
5718           
5719       emit2(".db %u", self->pos);
5720       
5721       for (i = 0; i < self->pos; i++)
5722         {
5723           _dbEmit(&db, self->buffer[i]);
5724         }
5725       _dbFlush(&db);
5726     }
5727   /* Reset */
5728   self->pos = 0;
5729 }
5730
5731 /* Encoder design:
5732    Can get either a run or a block of random stuff.
5733    Only want to change state if a good run comes in or a run ends.
5734    Detecting run end is easy.
5735    Initial state?
5736
5737    Say initial state is in run, len zero, last zero.  Then if you get a
5738    few zeros then something else then a short run will be output.
5739    Seems OK.  While in run mode, keep counting.  While in random mode,
5740    keep a count of the run.  If run hits margin, output all up to run,
5741    restart, enter run mode.
5742 */
5743
5744 /** Add another byte into the run length encoder, flushing as
5745     required.  The run length encoder uses the Amiga IFF style, where
5746     a block is prefixed by its run length.  A positive length means
5747     the next n bytes pass straight through.  A negative length means
5748     that the next byte is repeated -n times.  A zero terminates the
5749     chunks.
5750 */
5751 static void
5752 _rleAppend(RLECTX *self, int c)
5753 {
5754   int i;
5755
5756   if (c != self->last)
5757     {
5758       /* The run has stopped.  See if it is worthwhile writing it out
5759          as a run.  Note that the random data comes in as runs of
5760          length one.
5761       */
5762       if (self->runLen > RLE_CHANGE_COST)
5763         {
5764           /* Yes, worthwhile. */
5765           /* Commit whatever was in the buffer. */
5766           _rleCommit(self);
5767           emit2(".db -%u,0x%02X", self->runLen, self->last);
5768         }
5769       else
5770         {
5771           /* Not worthwhile.  Append to the end of the random list. */
5772           for (i = 0; i < self->runLen; i++)
5773             {
5774               if (self->pos >= RLE_MAX_BLOCK)
5775                 {
5776                   /* Commit. */
5777                   _rleCommit(self);
5778                 }
5779               self->buffer[self->pos++] = self->last;
5780             }
5781         }
5782       self->runLen = 1;
5783       self->last = c;
5784     }
5785   else
5786     {
5787       if (self->runLen >= RLE_MAX_BLOCK)
5788         {
5789           /* Commit whatever was in the buffer. */
5790           _rleCommit(self);
5791
5792           emit2 (".db -%u,0x%02X", self->runLen, self->last);
5793           self->runLen = 0;
5794         }
5795       self->runLen++;
5796     }
5797 }
5798
5799 static void
5800 _rleFlush(RLECTX *self)
5801 {
5802   _rleAppend(self, -1);
5803   _rleCommit(self);
5804   self->pos = 0;
5805   self->last = 0;
5806   self->runLen = 0;
5807 }
5808
5809 /** genArrayInit - Special code for initialising an array with constant
5810    data.
5811 */
5812 static void
5813 genArrayInit (iCode * ic)
5814 {
5815   literalList *iLoop;
5816   int         ix;
5817   int         elementSize = 0, eIndex, i;
5818   unsigned    val, lastVal;
5819   sym_link    *type;
5820   RLECTX      rle;
5821
5822   memset(&rle, 0, sizeof(rle));
5823
5824   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5825
5826   if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5827     {
5828       /* Emit the support function call and the destination address. */
5829       emit2("call __initrleblock");
5830       emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5831     }
5832   else
5833     {
5834       wassertl (0, "Unexpected operand to genArrayInit.\n");
5835     }
5836     
5837   type = operandType(IC_LEFT(ic));
5838     
5839   if (type && type->next)
5840     {
5841       elementSize = getSize(type->next);
5842     }
5843   else
5844     {
5845       wassertl (0, "Can't determine element size in genArrayInit.");
5846     }
5847
5848   iLoop = IC_ARRAYILIST(ic);
5849   lastVal = (unsigned)-1;
5850
5851   /* Feed all the bytes into the run length encoder which will handle
5852      the actual output.
5853      This works well for mixed char data, and for random int and long
5854      data.
5855   */
5856   while (iLoop)
5857     {
5858       ix = iLoop->count;
5859
5860       if (ix != 0)
5861         {
5862           for (i = 0; i < ix; i++)
5863             {
5864               for (eIndex = 0; eIndex < elementSize; eIndex++)
5865                 {
5866                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5867                   _rleAppend(&rle, val);
5868                 }
5869             }
5870         }
5871         
5872       iLoop = iLoop->next;
5873     }
5874
5875   _rleFlush(&rle);
5876   /* Mark the end of the run. */
5877   emit2(".db 0");
5878
5879   freeAsmop (IC_LEFT(ic), NULL, ic);
5880 }
5881
5882 /*-----------------------------------------------------------------*/
5883 /* genZ80Code - generate code for Z80 based controllers            */
5884 /*-----------------------------------------------------------------*/
5885 void
5886 genZ80Code (iCode * lic)
5887 {
5888   iCode *ic;
5889   int cln = 0;
5890
5891   /* HACK */
5892   if (IS_GB)
5893     {
5894       _fReturn = _gbz80_return;
5895       _fTmp = _gbz80_return;
5896     }
5897   else
5898     {
5899       _fReturn = _z80_return;
5900       _fTmp = _z80_return;
5901     }
5902
5903   _G.lines.head = _G.lines.current = NULL;
5904
5905   for (ic = lic; ic; ic = ic->next)
5906     {
5907
5908       if (cln != ic->lineno)
5909         {
5910           emit2 ("; %s %d", ic->filename, ic->lineno);
5911           cln = ic->lineno;
5912         }
5913       /* if the result is marked as
5914          spilt and rematerializable or code for
5915          this has already been generated then
5916          do nothing */
5917       if (resultRemat (ic) || ic->generated)
5918         continue;
5919
5920       /* depending on the operation */
5921       switch (ic->op)
5922         {
5923         case '!':
5924           emitDebug ("; genNot");
5925           genNot (ic);
5926           break;
5927
5928         case '~':
5929           emitDebug ("; genCpl");
5930           genCpl (ic);
5931           break;
5932
5933         case UNARYMINUS:
5934           emitDebug ("; genUminus");
5935           genUminus (ic);
5936           break;
5937
5938         case IPUSH:
5939           emitDebug ("; genIpush");
5940           genIpush (ic);
5941           break;
5942
5943         case IPOP:
5944           /* IPOP happens only when trying to restore a
5945              spilt live range, if there is an ifx statement
5946              following this pop then the if statement might
5947              be using some of the registers being popped which
5948              would destory the contents of the register so
5949              we need to check for this condition and handle it */
5950           if (ic->next &&
5951               ic->next->op == IFX &&
5952               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5953             {
5954               emitDebug ("; genIfx");
5955               genIfx (ic->next, ic);
5956             }
5957           else
5958             {
5959               emitDebug ("; genIpop");
5960               genIpop (ic);
5961             }
5962           break;
5963
5964         case CALL:
5965           emitDebug ("; genCall");
5966           genCall (ic);
5967           break;
5968
5969         case PCALL:
5970           emitDebug ("; genPcall");
5971           genPcall (ic);
5972           break;
5973
5974         case FUNCTION:
5975           emitDebug ("; genFunction");
5976           genFunction (ic);
5977           break;
5978
5979         case ENDFUNCTION:
5980           emitDebug ("; genEndFunction");
5981           genEndFunction (ic);
5982           break;
5983
5984         case RETURN:
5985           emitDebug ("; genRet");
5986           genRet (ic);
5987           break;
5988
5989         case LABEL:
5990           emitDebug ("; genLabel");
5991           genLabel (ic);
5992           break;
5993
5994         case GOTO:
5995           emitDebug ("; genGoto");
5996           genGoto (ic);
5997           break;
5998
5999         case '+':
6000           emitDebug ("; genPlus");
6001           genPlus (ic);
6002           break;
6003
6004         case '-':
6005           emitDebug ("; genMinus");
6006           genMinus (ic);
6007           break;
6008
6009         case '*':
6010           emitDebug ("; genMult");
6011           genMult (ic);
6012           break;
6013
6014         case '/':
6015           emitDebug ("; genDiv");
6016           genDiv (ic);
6017           break;
6018
6019         case '%':
6020           emitDebug ("; genMod");
6021           genMod (ic);
6022           break;
6023
6024         case '>':
6025           emitDebug ("; genCmpGt");
6026           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6027           break;
6028
6029         case '<':
6030           emitDebug ("; genCmpLt");
6031           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6032           break;
6033
6034         case LE_OP:
6035         case GE_OP:
6036         case NE_OP:
6037
6038           /* note these two are xlated by algebraic equivalence
6039              during parsing SDCC.y */
6040           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6041                   "got '>=' or '<=' shouldn't have come here");
6042           break;
6043
6044         case EQ_OP:
6045           emitDebug ("; genCmpEq");
6046           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6047           break;
6048
6049         case AND_OP:
6050           emitDebug ("; genAndOp");
6051           genAndOp (ic);
6052           break;
6053
6054         case OR_OP:
6055           emitDebug ("; genOrOp");
6056           genOrOp (ic);
6057           break;
6058
6059         case '^':
6060           emitDebug ("; genXor");
6061           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6062           break;
6063
6064         case '|':
6065           emitDebug ("; genOr");
6066           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6067           break;
6068
6069         case BITWISEAND:
6070           emitDebug ("; genAnd");
6071           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6072           break;
6073
6074         case INLINEASM:
6075           emitDebug ("; genInline");
6076           genInline (ic);
6077           break;
6078
6079         case RRC:
6080           emitDebug ("; genRRC");
6081           genRRC (ic);
6082           break;
6083
6084         case RLC:
6085           emitDebug ("; genRLC");
6086           genRLC (ic);
6087           break;
6088
6089         case GETHBIT:
6090           emitDebug ("; genGetHBIT");
6091           genGetHbit (ic);
6092           break;
6093
6094         case LEFT_OP:
6095           emitDebug ("; genLeftShift");
6096           genLeftShift (ic);
6097           break;
6098
6099         case RIGHT_OP:
6100           emitDebug ("; genRightShift");
6101           genRightShift (ic);
6102           break;
6103
6104         case GET_VALUE_AT_ADDRESS:
6105           emitDebug ("; genPointerGet");
6106           genPointerGet (ic);
6107           break;
6108
6109         case '=':
6110
6111           if (POINTER_SET (ic))
6112             {
6113               emitDebug ("; genAssign (pointer)");
6114               genPointerSet (ic);
6115             }
6116           else
6117             {
6118               emitDebug ("; genAssign");
6119               genAssign (ic);
6120             }
6121           break;
6122
6123         case IFX:
6124           emitDebug ("; genIfx");
6125           genIfx (ic, NULL);
6126           break;
6127
6128         case ADDRESS_OF:
6129           emitDebug ("; genAddrOf");
6130           genAddrOf (ic);
6131           break;
6132
6133         case JUMPTABLE:
6134           emitDebug ("; genJumpTab");
6135           genJumpTab (ic);
6136           break;
6137
6138         case CAST:
6139           emitDebug ("; genCast");
6140           genCast (ic);
6141           break;
6142
6143         case RECEIVE:
6144           emitDebug ("; genReceive");
6145           genReceive (ic);
6146           break;
6147
6148         case SEND:
6149           emitDebug ("; addSet");
6150           addSet (&_G.sendSet, ic);
6151           break;
6152
6153         case ARRAYINIT:
6154           genArrayInit(ic);
6155           break;
6156             
6157         default:
6158           ic = ic;
6159         }
6160     }
6161
6162
6163   /* now we are ready to call the
6164      peep hole optimizer */
6165   if (!options.nopeep)
6166     peepHole (&_G.lines.head);
6167
6168   /* This is unfortunate */
6169   /* now do the actual printing */
6170   {
6171     FILE *fp = codeOutFile;
6172     if (isInHome () && codeOutFile == code->oFile)
6173       codeOutFile = home->oFile;
6174     printLine (_G.lines.head, codeOutFile);
6175     if (_G.flushStatics)
6176       {
6177         flushStatics ();
6178         _G.flushStatics = 0;
6179       }
6180     codeOutFile = fp;
6181   }
6182 }
6183
6184 /*
6185   Attic
6186 static int
6187 _isPairUsed (iCode * ic, PAIR_ID pairId)
6188 {
6189   int ret = 0;
6190   switch (pairId)
6191     {
6192     case PAIR_DE:
6193       if (bitVectBitValue (ic->rMask, D_IDX))
6194         ret++;
6195       if (bitVectBitValue (ic->rMask, E_IDX))
6196         ret++;
6197       break;
6198     default:
6199       wassert (0);
6200     }
6201   return ret;
6202 }
6203
6204 static char *
6205 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6206 {
6207   unsigned long v;
6208   value *val = aop->aopu.aop_lit;
6209
6210   wassert (aop->type == AOP_LIT);
6211   wassert (!IS_FLOAT (val->type));
6212
6213   v = (unsigned long) floatFromVal (val);
6214
6215   if (xor)
6216     v ^= 0x8000;
6217   if (negate)
6218     v = 0-v;
6219   v &= 0xFFFF;
6220
6221   tsprintf (buffer, "!immedword", v);
6222   return gc_strdup (buffer);
6223 }
6224
6225
6226 */