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