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