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