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