8c3df03facc4074631cce92f31e7204cac3732fa
[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 /* genGetHbit - generates code get highest order bit               */
4274 /*-----------------------------------------------------------------*/
4275 static void
4276 genGetHbit (iCode * ic)
4277 {
4278   operand *left, *result;
4279   left = IC_LEFT (ic);
4280   result = IC_RESULT (ic);
4281   aopOp (left, ic, FALSE, FALSE);
4282   aopOp (result, ic, FALSE, FALSE);
4283
4284   /* get the highest order byte into a */
4285   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4286
4287   if (AOP_TYPE (result) == AOP_CRY)
4288     {
4289       emit2 ("rl a");
4290       outBitC (result);
4291     }
4292   else
4293     {
4294       emit2 ("rlc a");
4295       /* PENDING: For re-target. */
4296       emit2 ("and a,#1");
4297       outAcc (result);
4298     }
4299
4300
4301   freeAsmop (left, NULL, ic);
4302   freeAsmop (result, NULL, ic);
4303 }
4304
4305 /*-----------------------------------------------------------------*/
4306 /* shiftR2Left2Result - shift right two bytes from left to result  */
4307 /*-----------------------------------------------------------------*/
4308 static void
4309 shiftR2Left2Result (operand * left, int offl,
4310                     operand * result, int offr,
4311                     int shCount, int is_signed)
4312 {
4313   int size = 2;
4314   int offset = 0;
4315   symbol *tlbl, *tlbl1;
4316   const char *l;
4317
4318   movLeft2Result (left, offl, result, offr, 0);
4319   movLeft2Result (left, offl + 1, result, offr + 1, 0);
4320
4321   /*  if (AOP(result)->type == AOP_REG) { */
4322   
4323   tlbl = newiTempLabel (NULL);
4324   tlbl1 = newiTempLabel (NULL);
4325   
4326   /* Left is already in result - so now do the shift */
4327   if (shCount > 1)
4328     {
4329       emit2 ("ld a,!immedbyte+1", shCount);
4330       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4331       emitLabel (tlbl->key + 100);
4332     }
4333   
4334   offset = 0;
4335   while (size--)
4336     {
4337       l = aopGet (AOP (result), size, FALSE);
4338       if (offset == 0)
4339         {
4340           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4341         }
4342       else
4343         {
4344           emit2 ("rr %s", l);
4345         }
4346       offset++;
4347     }
4348   if (shCount > 1)
4349     {
4350       emitLabel (tlbl1->key + 100);
4351       emit2 ("dec a");
4352       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4353     }
4354 }
4355
4356 /*-----------------------------------------------------------------*/
4357 /* shiftL2Left2Result - shift left two bytes from left to result   */
4358 /*-----------------------------------------------------------------*/
4359 static void
4360 shiftL2Left2Result (operand * left, int offl,
4361                     operand * result, int offr, int shCount)
4362 {
4363   if (sameRegs (AOP (result), AOP (left)) &&
4364       ((offl + MSB16) == offr))
4365     {
4366       wassert (0);
4367     }
4368   else
4369     {
4370       /* Copy left into result */
4371       movLeft2Result (left, offl, result, offr, 0);
4372       movLeft2Result (left, offl + 1, result, offr + 1, 0);
4373     }
4374   /* PENDING: for now just see if it'll work. */
4375   /*if (AOP(result)->type == AOP_REG) { */
4376   {
4377     int size = 2;
4378     int offset = 0;
4379     symbol *tlbl, *tlbl1;
4380     const char *l;
4381
4382     tlbl = newiTempLabel (NULL);
4383     tlbl1 = newiTempLabel (NULL);
4384
4385     /* Left is already in result - so now do the shift */
4386     if (shCount > 1)
4387       {
4388         emit2 ("ld a,!immedbyte+1", shCount);
4389         emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4390         emitLabel (tlbl->key + 100);
4391       }
4392
4393     emit2 ("or a,a");
4394     while (size--)
4395       {
4396         l = aopGet (AOP (result), offset, FALSE);
4397
4398         emit2 ("rl %s", l);
4399
4400         offset++;
4401       }
4402     if (shCount > 1)
4403       {
4404         emitLabel (tlbl1->key + 100);
4405         emit2 ("dec a");
4406         emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4407       }
4408   }
4409 }
4410
4411 /*-----------------------------------------------------------------*/
4412 /* AccRol - rotate left accumulator by known count                 */
4413 /*-----------------------------------------------------------------*/
4414 static void
4415 AccRol (int shCount)
4416 {
4417   shCount &= 0x0007;            // shCount : 0..7
4418
4419   switch (shCount)
4420     {
4421     case 0:
4422       break;
4423     case 1:
4424       emit2 ("rl a");
4425       break;
4426     case 2:
4427       emit2 ("rl a");
4428       emit2 ("rl a");
4429       break;
4430     case 3:
4431       emit2 ("rl a");
4432       emit2 ("rl a");
4433       emit2 ("rl a");
4434       break;
4435     case 4:
4436       emit2 ("rl a");
4437       emit2 ("rl a");
4438       emit2 ("rl a");
4439       emit2 ("rl a");
4440       break;
4441     case 5:
4442       emit2 ("rr a");
4443       emit2 ("rr a");
4444       emit2 ("rr a");
4445       break;
4446     case 6:
4447       emit2 ("rr a");
4448       emit2 ("rr a");
4449       break;
4450     case 7:
4451       emit2 ("rr a");
4452       break;
4453     }
4454 }
4455
4456 /*-----------------------------------------------------------------*/
4457 /* AccLsh - left shift accumulator by known count                  */
4458 /*-----------------------------------------------------------------*/
4459 static void
4460 AccLsh (int shCount)
4461 {
4462   static const unsigned char SLMask[] =
4463     {
4464       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4465     };
4466
4467   if (shCount != 0)
4468     {
4469       if (shCount == 1)
4470         {
4471           emit2 ("add a,a");
4472         }
4473       else if (shCount == 2)
4474         {
4475           emit2 ("add a,a");
4476           emit2 ("add a,a");
4477         }
4478       else
4479         {
4480           /* rotate left accumulator */
4481           AccRol (shCount);
4482           /* and kill the lower order bits */
4483           emit2 ("and a,!immedbyte", SLMask[shCount]);
4484         }
4485     }
4486 }
4487
4488 /*-----------------------------------------------------------------*/
4489 /* shiftL1Left2Result - shift left one byte from left to result    */
4490 /*-----------------------------------------------------------------*/
4491 static void
4492 shiftL1Left2Result (operand * left, int offl,
4493                     operand * result, int offr, int shCount)
4494 {
4495   const char *l;
4496   l = aopGet (AOP (left), offl, FALSE);
4497   _moveA (l);
4498   /* shift left accumulator */
4499   AccLsh (shCount);
4500   aopPut (AOP (result), "a", offr);
4501 }
4502
4503
4504 /*-----------------------------------------------------------------*/
4505 /* genlshTwo - left shift two bytes by known amount != 0           */
4506 /*-----------------------------------------------------------------*/
4507 static void
4508 genlshTwo (operand * result, operand * left, int shCount)
4509 {
4510   int size = AOP_SIZE (result);
4511
4512   wassert (size == 2);
4513
4514   /* if shCount >= 8 */
4515   if (shCount >= 8)
4516     {
4517       shCount -= 8;
4518       if (size > 1)
4519         {
4520           if (shCount)
4521             {
4522               movLeft2Result (left, LSB, result, MSB16, 0);
4523               aopPut (AOP (result), "!zero", 0);
4524               shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4525             }
4526           else
4527             {
4528               movLeft2Result (left, LSB, result, MSB16, 0);
4529               aopPut (AOP (result), "!zero", 0);
4530             }
4531         }
4532       else
4533         {
4534           aopPut (AOP (result), "!zero", LSB);
4535         }
4536     }
4537   /*  1 <= shCount <= 7 */
4538   else
4539     {
4540       if (size == 1)
4541         {
4542           wassert (0);
4543         }
4544       else
4545         {
4546           shiftL2Left2Result (left, LSB, result, LSB, shCount);
4547         }
4548     }
4549 }
4550
4551 /*-----------------------------------------------------------------*/
4552 /* genlshOne - left shift a one byte quantity by known count       */
4553 /*-----------------------------------------------------------------*/
4554 static void
4555 genlshOne (operand * result, operand * left, int shCount)
4556 {
4557   shiftL1Left2Result (left, LSB, result, LSB, shCount);
4558 }
4559
4560 /*-----------------------------------------------------------------*/
4561 /* genLeftShiftLiteral - left shifting by known count              */
4562 /*-----------------------------------------------------------------*/
4563 static void
4564 genLeftShiftLiteral (operand * left,
4565                      operand * right,
4566                      operand * result,
4567                      iCode * ic)
4568 {
4569   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4570   int size;
4571
4572   freeAsmop (right, NULL, ic);
4573
4574   aopOp (left, ic, FALSE, FALSE);
4575   aopOp (result, ic, FALSE, FALSE);
4576
4577   size = getSize (operandType (result));
4578
4579 #if VIEW_SIZE
4580   emit2 ("; shift left  result %d, left %d", size,
4581             AOP_SIZE (left));
4582 #endif
4583
4584   /* I suppose that the left size >= result size */
4585   if (shCount == 0)
4586     {
4587       wassert (0);
4588     }
4589
4590   else if (shCount >= (size * 8)) 
4591     {
4592       while (size--)
4593         {
4594           aopPut (AOP (result), "!zero", size);
4595         }
4596     }
4597   else
4598     {
4599       switch (size)
4600         {
4601         case 1:
4602           genlshOne (result, left, shCount);
4603           break;
4604         case 2:
4605           genlshTwo (result, left, shCount);
4606           break;
4607         case 4:
4608           wassertl (0, "Shifting of longs is currently unsupported");
4609           break;
4610         default:
4611           wassert (0);
4612         }
4613     }
4614   freeAsmop (left, NULL, ic);
4615   freeAsmop (result, NULL, ic);
4616 }
4617
4618 /*-----------------------------------------------------------------*/
4619 /* genLeftShift - generates code for left shifting                 */
4620 /*-----------------------------------------------------------------*/
4621 static void
4622 genLeftShift (iCode * ic)
4623 {
4624   int size, offset;
4625   const char *l;
4626   symbol *tlbl, *tlbl1;
4627   operand *left, *right, *result;
4628
4629   right = IC_RIGHT (ic);
4630   left = IC_LEFT (ic);
4631   result = IC_RESULT (ic);
4632
4633   aopOp (right, ic, FALSE, FALSE);
4634
4635   /* if the shift count is known then do it
4636      as efficiently as possible */
4637   if (AOP_TYPE (right) == AOP_LIT)
4638     {
4639       genLeftShiftLiteral (left, right, result, ic);
4640       return;
4641     }
4642
4643   /* shift count is unknown then we have to form a loop get the loop
4644      count in B : Note: we take only the lower order byte since
4645      shifting more that 32 bits make no sense anyway, ( the largest
4646      size of an object can be only 32 bits ) */
4647   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4648   emit2 ("inc a");
4649   freeAsmop (right, NULL, ic);
4650   aopOp (left, ic, FALSE, FALSE);
4651   aopOp (result, ic, FALSE, FALSE);
4652
4653   /* now move the left to the result if they are not the
4654      same */
4655 #if 1
4656   if (!sameRegs (AOP (left), AOP (result)))
4657     {
4658
4659       size = AOP_SIZE (result);
4660       offset = 0;
4661       while (size--)
4662         {
4663           l = aopGet (AOP (left), offset, FALSE);
4664           aopPut (AOP (result), l, offset);
4665           offset++;
4666         }
4667     }
4668 #else
4669   size = AOP_SIZE (result);
4670   offset = 0;
4671   while (size--)
4672     {
4673       l = aopGet (AOP (left), offset, FALSE);
4674       aopPut (AOP (result), l, offset);
4675       offset++;
4676     }
4677 #endif
4678
4679
4680   tlbl = newiTempLabel (NULL);
4681   size = AOP_SIZE (result);
4682   offset = 0;
4683   tlbl1 = newiTempLabel (NULL);
4684
4685   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4686   emitLabel (tlbl->key + 100);
4687   l = aopGet (AOP (result), offset, FALSE);
4688
4689   emit2 ("or a,a");
4690
4691   while (size--)
4692     {
4693       l = aopGet (AOP (result), offset++, FALSE);
4694       emit2 ("rl %s", l);
4695     }
4696   emitLabel (tlbl1->key + 100);
4697   emit2 ("dec a");
4698   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4699
4700   freeAsmop (left, NULL, ic);
4701   freeAsmop (result, NULL, ic);
4702 }
4703
4704 /*-----------------------------------------------------------------*/
4705 /* genrshOne - left shift two bytes by known amount != 0           */
4706 /*-----------------------------------------------------------------*/
4707 static void
4708 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4709 {
4710   /* Errk */
4711   int size = AOP_SIZE (result);
4712   const char *l;
4713
4714   wassert (size == 1);
4715   wassert (shCount < 8);
4716
4717   l = aopGet (AOP (left), 0, FALSE);
4718
4719   emit2 ("or a,a");
4720
4721   if (AOP (result)->type == AOP_REG)
4722     {
4723       aopPut (AOP (result), l, 0);
4724       l = aopGet (AOP (result), 0, FALSE);
4725       while (shCount--)
4726         {
4727           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4728         }
4729     }
4730   else
4731     {
4732       _moveA (l);
4733       while (shCount--)
4734         {
4735           emit2 ("%s a", is_signed ? "sra" : "srl");
4736         }
4737       aopPut (AOP (result), "a", 0);
4738     }
4739 }
4740
4741 /*-----------------------------------------------------------------*/
4742 /* AccRsh - right shift accumulator by known count                 */
4743 /*-----------------------------------------------------------------*/
4744 static void
4745 AccRsh (int shCount)
4746 {
4747   static const unsigned char SRMask[] =
4748     {
4749       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4750     };
4751
4752   if (shCount != 0)
4753     {
4754       /* rotate right accumulator */
4755       AccRol (8 - shCount);
4756       /* and kill the higher order bits */
4757       emit2 ("and a,!immedbyte", SRMask[shCount]);
4758     }
4759 }
4760
4761 /*-----------------------------------------------------------------*/
4762 /* shiftR1Left2Result - shift right one byte from left to result   */
4763 /*-----------------------------------------------------------------*/
4764 static void
4765 shiftR1Left2Result (operand * left, int offl,
4766                     operand * result, int offr,
4767                     int shCount, int sign)
4768 {
4769   _moveA (aopGet (AOP (left), offl, FALSE));
4770   if (sign)
4771     {
4772       wassert (0);
4773     }
4774   else
4775     {
4776       AccRsh (shCount);
4777     }
4778   aopPut (AOP (result), "a", offr);
4779 }
4780
4781 /*-----------------------------------------------------------------*/
4782 /* genrshTwo - right shift two bytes by known amount != 0          */
4783 /*-----------------------------------------------------------------*/
4784 static void
4785 genrshTwo (operand * result, operand * left,
4786            int shCount, int sign)
4787 {
4788   /* if shCount >= 8 */
4789   if (shCount >= 8)
4790     {
4791       shCount -= 8;
4792       if (shCount)
4793         {
4794           shiftR1Left2Result (left, MSB16, result, LSB,
4795                               shCount, sign);
4796         }
4797       else
4798         {
4799           movLeft2Result (left, MSB16, result, LSB, sign);
4800         }
4801       aopPut (AOP (result), "!zero", 1);
4802     }
4803   /*  1 <= shCount <= 7 */
4804   else
4805     {
4806       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4807     }
4808 }
4809
4810 /*-----------------------------------------------------------------*/
4811 /* genRightShiftLiteral - left shifting by known count              */
4812 /*-----------------------------------------------------------------*/
4813 static void
4814 genRightShiftLiteral (operand * left,
4815                       operand * right,
4816                       operand * result,
4817                       iCode * ic,
4818                       int sign)
4819 {
4820   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4821   int size;
4822
4823   freeAsmop (right, NULL, ic);
4824
4825   aopOp (left, ic, FALSE, FALSE);
4826   aopOp (result, ic, FALSE, FALSE);
4827
4828   size = getSize (operandType (result));
4829
4830   emit2 ("; shift right  result %d, left %d", size,
4831             AOP_SIZE (left));
4832
4833   /* I suppose that the left size >= result size */
4834   if (shCount == 0)
4835     {
4836       wassert (0);
4837     }
4838
4839   else if (shCount >= (size * 8))
4840     while (size--)
4841       aopPut (AOP (result), "!zero", size);
4842   else
4843     {
4844       switch (size)
4845         {
4846         case 1:
4847           genrshOne (result, left, shCount, sign);
4848           break;
4849         case 2:
4850           /* PENDING: sign support */
4851           genrshTwo (result, left, shCount, sign);
4852           break;
4853         case 4:
4854           wassertl (0, "Asked to shift right a long which should be a function call");
4855           break;
4856         default:
4857           wassertl (0, "Entered default case in right shift delegate");
4858         }
4859     }
4860   freeAsmop (left, NULL, ic);
4861   freeAsmop (result, NULL, ic);
4862 }
4863
4864 /*-----------------------------------------------------------------*/
4865 /* genRightShift - generate code for right shifting                */
4866 /*-----------------------------------------------------------------*/
4867 static void
4868 genRightShift (iCode * ic)
4869 {
4870   operand *right, *left, *result;
4871   sym_link *retype;
4872   int size, offset, first = 1;
4873   const char *l;
4874   bool is_signed;
4875
4876   symbol *tlbl, *tlbl1;
4877
4878   /* if signed then we do it the hard way preserve the
4879      sign bit moving it inwards */
4880   retype = getSpec (operandType (IC_RESULT (ic)));
4881
4882   is_signed = !SPEC_USIGN (retype);
4883
4884   /* signed & unsigned types are treated the same : i.e. the
4885      signed is NOT propagated inwards : quoting from the
4886      ANSI - standard : "for E1 >> E2, is equivalent to division
4887      by 2**E2 if unsigned or if it has a non-negative value,
4888      otherwise the result is implementation defined ", MY definition
4889      is that the sign does not get propagated */
4890
4891   right = IC_RIGHT (ic);
4892   left = IC_LEFT (ic);
4893   result = IC_RESULT (ic);
4894
4895   aopOp (right, ic, FALSE, FALSE);
4896
4897   /* if the shift count is known then do it
4898      as efficiently as possible */
4899   if (AOP_TYPE (right) == AOP_LIT)
4900     {
4901       genRightShiftLiteral (left, right, result, ic, is_signed);
4902       return;
4903     }
4904
4905   aopOp (left, ic, FALSE, FALSE);
4906   aopOp (result, ic, FALSE, FALSE);
4907
4908   /* now move the left to the result if they are not the
4909      same */
4910   if (!sameRegs (AOP (left), AOP (result)) &&
4911       AOP_SIZE (result) > 1)
4912     {
4913
4914       size = AOP_SIZE (result);
4915       offset = 0;
4916       while (size--)
4917         {
4918           l = aopGet (AOP (left), offset, FALSE);
4919           aopPut (AOP (result), l, offset);
4920           offset++;
4921         }
4922     }
4923
4924   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4925   emit2 ("inc a");
4926   freeAsmop (right, NULL, ic);
4927
4928   tlbl = newiTempLabel (NULL);
4929   tlbl1 = newiTempLabel (NULL);
4930   size = AOP_SIZE (result);
4931   offset = size - 1;
4932
4933   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4934   emitLabel (tlbl->key + 100);
4935   while (size--)
4936     {
4937       l = aopGet (AOP (result), offset--, FALSE);
4938       if (first)
4939         {
4940           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4941           first = 0;
4942         }
4943       else
4944         {
4945           emit2 ("rr %s", l);
4946         }
4947     }
4948   emitLabel (tlbl1->key + 100);
4949   emit2 ("dec a");
4950   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4951
4952   freeAsmop (left, NULL, ic);
4953   freeAsmop (result, NULL, ic);
4954 }
4955
4956 /*-----------------------------------------------------------------*/
4957 /* genGenPointerGet -  get value from generic pointer space        */
4958 /*-----------------------------------------------------------------*/
4959 static void
4960 genGenPointerGet (operand * left,
4961                   operand * result, iCode * ic)
4962 {
4963   int size, offset;
4964   sym_link *retype = getSpec (operandType (result));
4965   int pair = PAIR_HL;
4966
4967   if (IS_GB)
4968     pair = PAIR_DE;
4969
4970   aopOp (left, ic, FALSE, FALSE);
4971   aopOp (result, ic, FALSE, FALSE);
4972
4973   if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
4974     {
4975       /* Just do it */
4976       if (isPtrPair (AOP (left)))
4977         {
4978           tsprintf (buffer, "!*pair", getPairName (AOP (left)));
4979           aopPut (AOP (result), buffer, 0);
4980         }
4981       else
4982         {
4983           emit2 ("ld a,!*pair", getPairName (AOP (left)));
4984           aopPut (AOP (result), "a", 0);
4985         }
4986       freeAsmop (left, NULL, ic);
4987       goto release;
4988     }
4989
4990   /* For now we always load into IY */
4991   /* if this is remateriazable */
4992   fetchPair (pair, AOP (left));
4993
4994   /* so iy now contains the address */
4995   freeAsmop (left, NULL, ic);
4996
4997   /* if bit then unpack */
4998   if (IS_BITVAR (retype))
4999     {
5000       wassert (0);
5001     }
5002   else
5003     {
5004       size = AOP_SIZE (result);
5005       offset = 0;
5006
5007       while (size--)
5008         {
5009           /* PENDING: make this better */
5010           if (!IS_GB && AOP (result)->type == AOP_REG)
5011             {
5012               aopPut (AOP (result), "!*hl", offset++);
5013             }
5014           else
5015             {
5016               emit2 ("ld a,!*pair", _pairs[pair].name);
5017               aopPut (AOP (result), "a", offset++);
5018             }
5019           if (size)
5020             {
5021               emit2 ("inc %s", _pairs[pair].name);
5022               _G.pairs[pair].offset++;
5023             }
5024         }
5025     }
5026
5027 release:
5028   freeAsmop (result, NULL, ic);
5029 }
5030
5031 /*-----------------------------------------------------------------*/
5032 /* genPointerGet - generate code for pointer get                   */
5033 /*-----------------------------------------------------------------*/
5034 static void
5035 genPointerGet (iCode * ic)
5036 {
5037   operand *left, *result;
5038   sym_link *type, *etype;
5039
5040   left = IC_LEFT (ic);
5041   result = IC_RESULT (ic);
5042
5043   /* depending on the type of pointer we need to
5044      move it to the correct pointer register */
5045   type = operandType (left);
5046   etype = getSpec (type);
5047
5048   genGenPointerGet (left, result, ic);
5049 }
5050
5051 bool
5052 isRegOrLit (asmop * aop)
5053 {
5054   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5055     return TRUE;
5056   return FALSE;
5057 }
5058
5059 /*-----------------------------------------------------------------*/
5060 /* genGenPointerSet - stores the value into a pointer location        */
5061 /*-----------------------------------------------------------------*/
5062 static void
5063 genGenPointerSet (operand * right,
5064                   operand * result, iCode * ic)
5065 {
5066   int size, offset;
5067   sym_link *retype = getSpec (operandType (right));
5068   PAIR_ID pairId = PAIR_HL;
5069
5070   aopOp (result, ic, FALSE, FALSE);
5071   aopOp (right, ic, FALSE, FALSE);
5072
5073   if (IS_GB)
5074     pairId = PAIR_DE;
5075
5076   /* Handle the exceptions first */
5077   if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5078     {
5079       /* Just do it */
5080       const char *l = aopGet (AOP (right), 0, FALSE);
5081       const char *pair = getPairName (AOP (result));
5082       if (canAssignToPtr (l) && isPtr (pair))
5083         {
5084           emit2 ("ld !*pair,%s", pair, l);
5085         }
5086       else
5087         {
5088           _moveA (l);
5089           emit2 ("ld !*pair,a", pair);
5090         }
5091       goto release;
5092     }
5093
5094   /* if the operand is already in dptr
5095      then we do nothing else we move the value to dptr */
5096   if (AOP_TYPE (result) != AOP_STR)
5097     {
5098       fetchPair (pairId, AOP (result));
5099     }
5100   /* so hl know contains the address */
5101   freeAsmop (result, NULL, ic);
5102
5103   /* if bit then unpack */
5104   if (IS_BITVAR (retype))
5105     {
5106       wassert (0);
5107     }
5108   else
5109     {
5110       size = AOP_SIZE (right);
5111       offset = 0;
5112
5113       while (size--)
5114         {
5115           const char *l = aopGet (AOP (right), offset, FALSE);
5116           if (isRegOrLit (AOP (right)) && !IS_GB)
5117             {
5118               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5119             }
5120           else
5121             {
5122               _moveA (l);
5123               emit2 ("ld !*pair,a", _pairs[pairId].name);
5124             }
5125           if (size)
5126             {
5127               emit2 ("inc %s", _pairs[pairId].name);
5128               _G.pairs[pairId].offset++;
5129             }
5130           offset++;
5131         }
5132     }
5133 release:
5134   freeAsmop (right, NULL, ic);
5135 }
5136
5137 /*-----------------------------------------------------------------*/
5138 /* genPointerSet - stores the value into a pointer location        */
5139 /*-----------------------------------------------------------------*/
5140 static void
5141 genPointerSet (iCode * ic)
5142 {
5143   operand *right, *result;
5144   sym_link *type, *etype;
5145
5146   right = IC_RIGHT (ic);
5147   result = IC_RESULT (ic);
5148
5149   /* depending on the type of pointer we need to
5150      move it to the correct pointer register */
5151   type = operandType (result);
5152   etype = getSpec (type);
5153
5154   genGenPointerSet (right, result, ic);
5155 }
5156
5157 /*-----------------------------------------------------------------*/
5158 /* genIfx - generate code for Ifx statement                        */
5159 /*-----------------------------------------------------------------*/
5160 static void
5161 genIfx (iCode * ic, iCode * popIc)
5162 {
5163   operand *cond = IC_COND (ic);
5164   int isbit = 0;
5165
5166   aopOp (cond, ic, FALSE, TRUE);
5167
5168   /* get the value into acc */
5169   if (AOP_TYPE (cond) != AOP_CRY)
5170     toBoolean (cond);
5171   else
5172     isbit = 1;
5173   /* the result is now in the accumulator */
5174   freeAsmop (cond, NULL, ic);
5175
5176   /* if there was something to be popped then do it */
5177   if (popIc)
5178     genIpop (popIc);
5179
5180   /* if the condition is  a bit variable */
5181   if (isbit && IS_ITEMP (cond) &&
5182       SPIL_LOC (cond))
5183     genIfxJump (ic, SPIL_LOC (cond)->rname);
5184   else if (isbit && !IS_ITEMP (cond))
5185     genIfxJump (ic, OP_SYMBOL (cond)->rname);
5186   else
5187     genIfxJump (ic, "a");
5188
5189   ic->generated = 1;
5190 }
5191
5192 /*-----------------------------------------------------------------*/
5193 /* genAddrOf - generates code for address of                       */
5194 /*-----------------------------------------------------------------*/
5195 static void
5196 genAddrOf (iCode * ic)
5197 {
5198   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5199
5200   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5201
5202   /* if the operand is on the stack then we
5203      need to get the stack offset of this
5204      variable */
5205   if (IS_GB)
5206     {
5207       if (sym->onStack)
5208         {
5209           spillCached ();
5210           if (sym->stack <= 0)
5211             {
5212               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5213             }
5214           else
5215             {
5216               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5217             }
5218           emit2 ("ld d,h");
5219           emit2 ("ld e,l");
5220         }
5221       else
5222         {
5223           emit2 ("ld de,!hashedstr", sym->rname);
5224         }
5225       aopPut (AOP (IC_RESULT (ic)), "e", 0);
5226       aopPut (AOP (IC_RESULT (ic)), "d", 1);
5227     }
5228   else
5229     {
5230       spillCached ();
5231       if (sym->onStack)
5232         {
5233           /* if it has an offset  then we need to compute it */
5234           if (sym->stack > 0)
5235             emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5236           else
5237             emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5238           emit2 ("add hl,sp");
5239         }
5240       else
5241         {
5242           emit2 ("ld hl,#%s", sym->rname);
5243         }
5244       aopPut (AOP (IC_RESULT (ic)), "l", 0);
5245       aopPut (AOP (IC_RESULT (ic)), "h", 1);
5246     }
5247   freeAsmop (IC_RESULT (ic), NULL, ic);
5248 }
5249
5250 /*-----------------------------------------------------------------*/
5251 /* genAssign - generate code for assignment                        */
5252 /*-----------------------------------------------------------------*/
5253 static void
5254 genAssign (iCode * ic)
5255 {
5256   operand *result, *right;
5257   int size, offset;
5258   unsigned long lit = 0L;
5259
5260   result = IC_RESULT (ic);
5261   right = IC_RIGHT (ic);
5262
5263 #if 1
5264   /* Dont bother assigning if they are the same */
5265   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5266     {
5267       emit2 ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5268       return;
5269     }
5270 #endif
5271
5272   aopOp (right, ic, FALSE, FALSE);
5273   aopOp (result, ic, TRUE, FALSE);
5274
5275   /* if they are the same registers */
5276   if (sameRegs (AOP (right), AOP (result)))
5277     {
5278       emit2 ("; (registers are the same)");
5279       goto release;
5280     }
5281
5282   /* if the result is a bit */
5283   if (AOP_TYPE (result) == AOP_CRY)
5284     {
5285       wassert (0);
5286     }
5287
5288   /* general case */
5289   size = AOP_SIZE (result);
5290   offset = 0;
5291
5292   if (AOP_TYPE (right) == AOP_LIT)
5293     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5294   if (isPair (AOP (result)))
5295     {
5296       fetchPair (getPairId (AOP (result)), AOP (right));
5297     }
5298   else if ((size > 1) &&
5299            (AOP_TYPE (result) != AOP_REG) &&
5300            (AOP_TYPE (right) == AOP_LIT) &&
5301            !IS_FLOAT (operandType (right)) &&
5302            (lit < 256L))
5303     {
5304       bool fXored = FALSE;
5305       offset = 0;
5306       /* Work from the top down.
5307          Done this way so that we can use the cached copy of 0
5308          in A for a fast clear */
5309       while (size--)
5310         {
5311           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5312             {
5313               if (!fXored && size > 1)
5314                 {
5315                   emit2 ("xor a,a");
5316                   fXored = TRUE;
5317                 }
5318               if (fXored)
5319                 {
5320                   aopPut (AOP (result), "a", offset);
5321                 }
5322               else
5323                 {
5324                   aopPut (AOP (result), "!zero", offset);
5325                 }
5326             }
5327           else
5328             aopPut (AOP (result),
5329                     aopGet (AOP (right), offset, FALSE),
5330                     offset);
5331           offset++;
5332         }
5333     }
5334   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5335     {
5336       /* Special case.  Load into a and d, then load out. */
5337       _moveA (aopGet (AOP (right), 0, FALSE));
5338       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5339       aopPut (AOP (result), "a", 0);
5340       aopPut (AOP (result), "e", 1);
5341     }
5342   else
5343     {
5344       while (size--)
5345         {
5346           /* PENDING: do this check better */
5347           if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5348             {
5349               _moveA (aopGet (AOP (right), offset, FALSE));
5350               aopPut (AOP (result), "a", offset);
5351             }
5352           else
5353             aopPut (AOP (result),
5354                     aopGet (AOP (right), offset, FALSE),
5355                     offset);
5356           offset++;
5357         }
5358     }
5359
5360 release:
5361   freeAsmop (right, NULL, ic);
5362   freeAsmop (result, NULL, ic);
5363 }
5364
5365 /*-----------------------------------------------------------------*/
5366 /* genJumpTab - genrates code for jump table                       */
5367 /*-----------------------------------------------------------------*/
5368 static void
5369 genJumpTab (iCode * ic)
5370 {
5371   symbol *jtab;
5372   const char *l;
5373
5374   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5375   /* get the condition into accumulator */
5376   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5377   if (!IS_GB)
5378     emit2 ("push de");
5379   emit2 ("ld e,%s", l);
5380   emit2 ("ld d,!zero");
5381   jtab = newiTempLabel (NULL);
5382   spillCached ();
5383   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5384   emit2 ("add hl,de");
5385   emit2 ("add hl,de");
5386   emit2 ("add hl,de");
5387   freeAsmop (IC_JTCOND (ic), NULL, ic);
5388   if (!IS_GB)
5389     emit2 ("pop de");
5390   emit2 ("jp !*hl");
5391   emitLabel (jtab->key + 100);
5392   /* now generate the jump labels */
5393   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5394        jtab = setNextItem (IC_JTLABELS (ic)))
5395     emit2 ("jp !tlabel", jtab->key + 100);
5396 }
5397
5398 /*-----------------------------------------------------------------*/
5399 /* genCast - gen code for casting                                  */
5400 /*-----------------------------------------------------------------*/
5401 static void
5402 genCast (iCode * ic)
5403 {
5404   operand *result = IC_RESULT (ic);
5405   sym_link *ctype = operandType (IC_LEFT (ic));
5406   operand *right = IC_RIGHT (ic);
5407   int size, offset;
5408
5409   /* if they are equivalent then do nothing */
5410   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5411     return;
5412
5413   aopOp (right, ic, FALSE, FALSE);
5414   aopOp (result, ic, FALSE, FALSE);
5415
5416   /* if the result is a bit */
5417   if (AOP_TYPE (result) == AOP_CRY)
5418     {
5419       wassert (0);
5420     }
5421
5422   /* if they are the same size : or less */
5423   if (AOP_SIZE (result) <= AOP_SIZE (right))
5424     {
5425
5426       /* if they are in the same place */
5427       if (sameRegs (AOP (right), AOP (result)))
5428         goto release;
5429
5430       /* if they in different places then copy */
5431       size = AOP_SIZE (result);
5432       offset = 0;
5433       while (size--)
5434         {
5435           aopPut (AOP (result),
5436                   aopGet (AOP (right), offset, FALSE),
5437                   offset);
5438           offset++;
5439         }
5440       goto release;
5441     }
5442
5443   /* PENDING: should be OK. */
5444 #if 0
5445   /* if the result is of type pointer */
5446   if (IS_PTR (ctype))
5447     {
5448       wassert (0);
5449     }
5450 #endif
5451
5452   /* so we now know that the size of destination is greater
5453      than the size of the source */
5454   /* we move to result for the size of source */
5455   size = AOP_SIZE (right);
5456   offset = 0;
5457   while (size--)
5458     {
5459       aopPut (AOP (result),
5460               aopGet (AOP (right), offset, FALSE),
5461               offset);
5462       offset++;
5463     }
5464
5465   /* now depending on the sign of the destination */
5466   size = AOP_SIZE (result) - AOP_SIZE (right);
5467   /* Unsigned or not an integral type - right fill with zeros */
5468   if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5469     {
5470       while (size--)
5471         aopPut (AOP (result), "!zero", offset++);
5472     }
5473   else
5474     {
5475       /* we need to extend the sign :{ */
5476         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5477                         FALSE);
5478       _moveA (l);
5479       emit2 ("; genCast: sign extend untested.");
5480       emit2 ("rla ");
5481       emit2 ("sbc a,a");
5482       while (size--)
5483         aopPut (AOP (result), "a", offset++);
5484     }
5485
5486 release:
5487   freeAsmop (right, NULL, ic);
5488   freeAsmop (result, NULL, ic);
5489 }
5490
5491 /*-----------------------------------------------------------------*/
5492 /* genReceive - generate code for a receive iCode                  */
5493 /*-----------------------------------------------------------------*/
5494 static void
5495 genReceive (iCode * ic)
5496 {
5497   if (isOperandInFarSpace (IC_RESULT (ic)) &&
5498       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5499        IS_TRUE_SYMOP (IC_RESULT (ic))))
5500     {
5501       wassert (0);
5502     }
5503   else
5504     {
5505         // PENDING: HACK
5506         int size;
5507         int i;
5508
5509         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5510         size = AOP_SIZE(IC_RESULT(ic));
5511
5512         for (i = 0; i < size; i++) {
5513             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5514         }
5515     }
5516
5517   freeAsmop (IC_RESULT (ic), NULL, ic);
5518 }
5519
5520 /*-----------------------------------------------------------------*/
5521 /* genZ80Code - generate code for Z80 based controllers            */
5522 /*-----------------------------------------------------------------*/
5523 void
5524 genZ80Code (iCode * lic)
5525 {
5526   iCode *ic;
5527   int cln = 0;
5528
5529   /* HACK */
5530   if (IS_GB)
5531     {
5532       _fReturn = _gbz80_return;
5533       _fTmp = _gbz80_return;
5534     }
5535   else
5536     {
5537       _fReturn = _z80_return;
5538       _fTmp = _z80_return;
5539     }
5540
5541   _G.lines.head = _G.lines.current = NULL;
5542
5543   for (ic = lic; ic; ic = ic->next)
5544     {
5545
5546       if (cln != ic->lineno)
5547         {
5548           emit2 ("; %s %d", ic->filename, ic->lineno);
5549           cln = ic->lineno;
5550         }
5551       /* if the result is marked as
5552          spilt and rematerializable or code for
5553          this has already been generated then
5554          do nothing */
5555       if (resultRemat (ic) || ic->generated)
5556         continue;
5557
5558       /* depending on the operation */
5559       switch (ic->op)
5560         {
5561         case '!':
5562           emit2 ("; genNot");
5563           genNot (ic);
5564           break;
5565
5566         case '~':
5567           emit2 ("; genCpl");
5568           genCpl (ic);
5569           break;
5570
5571         case UNARYMINUS:
5572           emit2 ("; genUminus");
5573           genUminus (ic);
5574           break;
5575
5576         case IPUSH:
5577           emit2 ("; genIpush");
5578           genIpush (ic);
5579           break;
5580
5581         case IPOP:
5582           /* IPOP happens only when trying to restore a
5583              spilt live range, if there is an ifx statement
5584              following this pop then the if statement might
5585              be using some of the registers being popped which
5586              would destory the contents of the register so
5587              we need to check for this condition and handle it */
5588           if (ic->next &&
5589               ic->next->op == IFX &&
5590               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5591             {
5592               emit2 ("; genIfx");
5593               genIfx (ic->next, ic);
5594             }
5595           else
5596             {
5597               emit2 ("; genIpop");
5598               genIpop (ic);
5599             }
5600           break;
5601
5602         case CALL:
5603           emit2 ("; genCall");
5604           genCall (ic);
5605           break;
5606
5607         case PCALL:
5608           emit2 ("; genPcall");
5609           genPcall (ic);
5610           break;
5611
5612         case FUNCTION:
5613           emit2 ("; genFunction");
5614           genFunction (ic);
5615           break;
5616
5617         case ENDFUNCTION:
5618           emit2 ("; genEndFunction");
5619           genEndFunction (ic);
5620           break;
5621
5622         case RETURN:
5623           emit2 ("; genRet");
5624           genRet (ic);
5625           break;
5626
5627         case LABEL:
5628           emit2 ("; genLabel");
5629           genLabel (ic);
5630           break;
5631
5632         case GOTO:
5633           emit2 ("; genGoto");
5634           genGoto (ic);
5635           break;
5636
5637         case '+':
5638           emit2 ("; genPlus");
5639           genPlus (ic);
5640           break;
5641
5642         case '-':
5643           emit2 ("; genMinus");
5644           genMinus (ic);
5645           break;
5646
5647         case '*':
5648           emit2 ("; genMult");
5649           genMult (ic);
5650           break;
5651
5652         case '/':
5653           emit2 ("; genDiv");
5654           genDiv (ic);
5655           break;
5656
5657         case '%':
5658           emit2 ("; genMod");
5659           genMod (ic);
5660           break;
5661
5662         case '>':
5663           emit2 ("; genCmpGt");
5664           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
5665           break;
5666
5667         case '<':
5668           emit2 ("; genCmpLt");
5669           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
5670           break;
5671
5672         case LE_OP:
5673         case GE_OP:
5674         case NE_OP:
5675
5676           /* note these two are xlated by algebraic equivalence
5677              during parsing SDCC.y */
5678           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5679                   "got '>=' or '<=' shouldn't have come here");
5680           break;
5681
5682         case EQ_OP:
5683           emit2 ("; genCmpEq");
5684           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
5685           break;
5686
5687         case AND_OP:
5688           emit2 ("; genAndOp");
5689           genAndOp (ic);
5690           break;
5691
5692         case OR_OP:
5693           emit2 ("; genOrOp");
5694           genOrOp (ic);
5695           break;
5696
5697         case '^':
5698           emit2 ("; genXor");
5699           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
5700           break;
5701
5702         case '|':
5703           emit2 ("; genOr");
5704           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
5705           break;
5706
5707         case BITWISEAND:
5708           emit2 ("; genAnd");
5709           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
5710           break;
5711
5712         case INLINEASM:
5713           emit2 ("; genInline");
5714           genInline (ic);
5715           break;
5716
5717         case RRC:
5718           emit2 ("; genRRC");
5719           genRRC (ic);
5720           break;
5721
5722         case RLC:
5723           emit2 ("; genRLC");
5724           genRLC (ic);
5725           break;
5726
5727         case GETHBIT:
5728           emit2 ("; genGetHBIT");
5729           genGetHbit (ic);
5730           break;
5731
5732         case LEFT_OP:
5733           emit2 ("; genLeftShift");
5734           genLeftShift (ic);
5735           break;
5736
5737         case RIGHT_OP:
5738           emit2 ("; genRightShift");
5739           genRightShift (ic);
5740           break;
5741
5742         case GET_VALUE_AT_ADDRESS:
5743           emit2 ("; genPointerGet");
5744           genPointerGet (ic);
5745           break;
5746
5747         case '=':
5748
5749           if (POINTER_SET (ic))
5750             {
5751               emit2 ("; genAssign (pointer)");
5752               genPointerSet (ic);
5753             }
5754           else
5755             {
5756               emit2 ("; genAssign");
5757               genAssign (ic);
5758             }
5759           break;
5760
5761         case IFX:
5762           emit2 ("; genIfx");
5763           genIfx (ic, NULL);
5764           break;
5765
5766         case ADDRESS_OF:
5767           emit2 ("; genAddrOf");
5768           genAddrOf (ic);
5769           break;
5770
5771         case JUMPTABLE:
5772           emit2 ("; genJumpTab");
5773           genJumpTab (ic);
5774           break;
5775
5776         case CAST:
5777           emit2 ("; genCast");
5778           genCast (ic);
5779           break;
5780
5781         case RECEIVE:
5782           emit2 ("; genReceive");
5783           genReceive (ic);
5784           break;
5785
5786         case SEND:
5787           emit2 ("; addSet");
5788           addSet (&_G.sendSet, ic);
5789           break;
5790
5791         default:
5792           ic = ic;
5793           /*      piCode(ic,stdout); */
5794
5795         }
5796     }
5797
5798
5799   /* now we are ready to call the
5800      peep hole optimizer */
5801   if (!options.nopeep)
5802     peepHole (&_G.lines.head);
5803
5804   /* This is unfortunate */
5805   /* now do the actual printing */
5806   {
5807     FILE *fp = codeOutFile;
5808     if (isInHome () && codeOutFile == code->oFile)
5809       codeOutFile = home->oFile;
5810     printLine (_G.lines.head, codeOutFile);
5811     if (_G.flushStatics)
5812       {
5813         flushStatics ();
5814         _G.flushStatics = 0;
5815       }
5816     codeOutFile = fp;
5817   }
5818 }
5819
5820 /*
5821   Attic
5822 static int
5823 _isPairUsed (iCode * ic, PAIR_ID pairId)
5824 {
5825   int ret = 0;
5826   switch (pairId)
5827     {
5828     case PAIR_DE:
5829       if (bitVectBitValue (ic->rMask, D_IDX))
5830         ret++;
5831       if (bitVectBitValue (ic->rMask, E_IDX))
5832         ret++;
5833       break;
5834     default:
5835       wassert (0);
5836     }
5837   return ret;
5838 }
5839
5840 */