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