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