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