Optimised mul, added asm string functions
[fw/sdcc] / src / z80 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - Z80 specific code generator.
3      
4   Michael Hope <michaelh@juju.net.nz> 2000
5   Based on the mcs51 generator -
6       Sandeep Dutta . sandeep.dutta@usa.net (1998)
7    and -  Jean-Louis VERN.jlvern@writeme.com (1999)
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24   In other words, you are welcome to use, share and improve this program.
25   You are forbidden to forbid anyone else to use, share and improve
26   what you give them.   Help stamp out software-hoarding!
27
28 -------------------------------------------------------------------------*/
29
30 /*
31   Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
32                                        ticks dhry  size
33   Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34   Improved WORD push                    22784 144 19AE
35   With label1 on                        22694 144 197E
36   With label2 on                        22743 144 198A
37   With label3 on                        22776 144 1999
38   With label4 on                        22776 144 1999
39   With all 'label' on                   22661 144 196F
40   With loopInvariant on                 20919 156 19AB
41   With loopInduction on                 Breaks    198B
42   With all working on                   20796 158 196C
43   Slightly better genCmp(signed)        20597 159 195B
44   Better reg packing, first peephole    20038 163 1873
45   With assign packing                   19281 165 1849
46   5/3/00                                17741 185 17B6
47   With reg params for mul and div       16234 202 162D
48
49   1. Starting again at 3 Aug 01         34965  93 219C
50    No asm strings
51    Includes long mul/div in code
52   2. Optimised memcpy for acc use       32102 102 226B
53   3. Optimised strcpy for acc use       27819 117 2237
54   3a Optimised memcpy fun
55   4. Optimised strcmp fun               21999 149 2294
56   5. Optimised strcmp further           21660 151 228C
57   6. Optimised memcpy by unroling       20885 157 2201
58   7. After turning loop induction on    19862 165 236D
59   8. Same as 7 but with more info       
60   9. With asm optimised strings         17030 192 2223
61
62   10 and below are with asm strings off.
63   
64   Apparent advantage of turning on regparams:
65   1.  Cost of push
66         Decent case is push of a constant 
67           - ld hl,#n; push hl: (10+11)*nargs
68   2.  Cost of pull from stack
69         Using asm with ld hl, etc
70           - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
71             10+11+(7+6+7+6)*nargs
72   3.  Cost of fixing stack
73           - pop hl*nargs
74             10*nargs
75   
76   So cost is (10+11+7+6+7+10)*nargs+10+11 
77       = 51*nargs+21
78       = 123 for mul, div, strcmp, strcpy
79   Saving of (98298+32766+32766+32766)*123 = 24181308
80   At 192 d/s for 682411768t, speed up to 199.  Hmm.
81 */
82
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <ctype.h>
87
88 #ifdef HAVE_SYS_ISA_DEFS_H
89 #include <sys/isa_defs.h>
90 #endif
91
92 #include "z80.h"
93 #include "SDCCglobl.h"
94 #include "SDCCpeeph.h"
95 #include "gen.h"
96 #include "SDCCglue.h"
97 #include "newalloc.h"
98
99 /* this is the down and dirty file with all kinds of kludgy & hacky
100    stuff. This is what it is all about CODE GENERATION for a specific MCU.
101    Some of the routines may be reusable, will have to see */
102
103 /* Z80 calling convention description.
104    Parameters are passed right to left.  As the stack grows downwards,
105    the parameters are arranged in left to right in memory.
106    Parameters may be passed in the HL and DE registers with one
107    parameter per pair.
108    PENDING: What if the parameter is a long?
109    Everything is caller saves. i.e. the caller must save any registers
110    that it wants to preserve over the call.
111    The return value is returned in DEHL.  DE is normally used as a
112    working register pair.  Caller saves allows it to be used for a
113    return value.
114    va args functions do not use register parameters.  All arguments
115    are passed on the stack.
116    IX is used as an index register to the top of the local variable
117    area.  ix-0 is the top most local variable.
118 */
119
120 enum {
121   DISABLE_DEBUG = 1
122 };
123
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129   { "c", "b", "e", "d" };
130
131 static char **_fReturn;
132 static char **_fTmp;
133
134 extern FILE *codeOutFile;
135
136 typedef enum
137   {
138     PAIR_INVALID,
139     PAIR_AF,
140     PAIR_BC,
141     PAIR_DE,
142     PAIR_HL,
143     PAIR_IY,
144     PAIR_IX,
145     NUM_PAIRS
146   } PAIR_ID;
147
148 static struct
149 {
150   const char *name;
151   const char *l;
152   const char *h;
153 } _pairs[NUM_PAIRS] = {
154   {    "??1", "?2", "?3" },
155   {    "af", "f", "a" },
156   {    "bc", "c", "b" },
157   {    "de", "e", "d" },
158   {    "hl", "l", "h" },
159   {    "iy", "iy.l?", "iy.h?" },
160   {    "ix", "ix.l?", "ix.h?" }
161 };
162
163 // PENDING
164 #define ACC_NAME        _pairs[PAIR_AF].h
165
166 #define RESULTONSTACK(x) \
167                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
168                          IC_RESULT(x)->aop->type == AOP_STK )
169
170 enum 
171   {
172     LSB,
173     MSB16,
174     MSB24,
175     MSB32
176   };
177
178 static struct 
179 {
180   struct 
181   {
182     AOP_TYPE last_type;
183     const char *lit;
184     int offset;
185   } pairs[NUM_PAIRS];
186   struct 
187   {
188     int last;
189     int pushed;
190     int param_offset;
191     int offset;
192     int pushedBC;
193     int pushedDE;
194   } stack;
195   int frameId;
196   int receiveOffset;
197   bool flushStatics;
198   bool in_home;
199   const char *lastFunctionName;
200
201   set *sendSet;
202
203   struct
204   {
205     /** TRUE if the registers have already been saved. */
206     bool saved;
207   } saves;
208
209   struct 
210   {
211     lineNode *head;
212     lineNode *current;
213     int isInline;
214   } lines;
215
216 } _G;
217
218 static const char *aopGet (asmop * aop, int offset, bool bit16);
219
220 static void
221 _tidyUp (char *buf)
222 {
223   /* Clean up the line so that it is 'prettier' */
224   if (strchr (buf, ':'))
225     {
226       /* Is a label - cant do anything */
227       return;
228     }
229   /* Change the first (and probably only) ' ' to a tab so
230      everything lines up.
231   */
232   while (*buf)
233     {
234       if (*buf == ' ')
235         {
236           *buf = '\t';
237           break;
238         }
239       buf++;
240     }
241 }
242
243 static void
244 _vemit2 (const char *szFormat, va_list ap)
245 {
246   char buffer[256];
247
248   tvsprintf (buffer, szFormat, ap);
249
250   _tidyUp (buffer);
251   _G.lines.current = (_G.lines.current ?
252               connectLine (_G.lines.current, newLineNode (buffer)) :
253               (_G.lines.head = newLineNode (buffer)));
254
255   _G.lines.current->isInline = _G.lines.isInline;
256 }
257
258 static void
259 emit2 (const char *szFormat,...)
260 {
261   va_list ap;
262
263   va_start (ap, szFormat);
264
265   _vemit2 (szFormat, ap);
266
267   va_end (ap);
268 }
269
270 static void
271 emitDebug (const char *szFormat,...)
272 {
273   if (!DISABLE_DEBUG)
274     {
275       va_list ap;
276       
277       va_start (ap, szFormat);
278       
279       _vemit2 (szFormat, ap);
280       
281       va_end (ap);
282     }
283 }
284
285 /*-----------------------------------------------------------------*/
286 /* emit2 - writes the code into a file : for now it is simple    */
287 /*-----------------------------------------------------------------*/
288 void
289 _emit2 (const char *inst, const char *fmt,...)
290 {
291   va_list ap;
292   char lb[INITIAL_INLINEASM];
293   char *lbp = lb;
294
295   va_start (ap, fmt);
296
297   if (*inst != '\0')
298     {
299       sprintf (lb, "%s\t", inst);
300       vsprintf (lb + (strlen (lb)), fmt, ap);
301     }
302   else
303     vsprintf (lb, fmt, ap);
304
305   while (isspace (*lbp))
306     lbp++;
307
308   if (lbp && *lbp)
309     {
310       _G.lines.current = (_G.lines.current ?
311                   connectLine (_G.lines.current, newLineNode (lb)) :
312                   (_G.lines.head = newLineNode (lb)));
313     }
314   _G.lines.current->isInline = _G.lines.isInline;
315   va_end (ap);
316 }
317
318 static void
319 _emitMove(const char *to, const char *from)
320 {
321   if (strcasecmp(to, from) != 0) 
322     {
323       emit2("ld %s,%s", to, from);
324     }
325   else 
326     {
327       // Optimise it out.
328       // Could leave this to the peephole, but sometimes the peephole is inhibited.
329     }
330 }
331
332 static void
333 _moveA(const char *moveFrom)
334 {
335     // Let the peephole optimiser take care of redundent loads
336     _emitMove(ACC_NAME, moveFrom);
337 }
338
339 static void
340 _clearCarry(void)
341 {
342     emit2("xor a,a");
343 }
344
345 const char *
346 getPairName (asmop * aop)
347 {
348   if (aop->type == AOP_REG)
349     {
350       switch (aop->aopu.aop_reg[0]->rIdx)
351         {
352         case C_IDX:
353           return "bc";
354           break;
355         case E_IDX:
356           return "de";
357           break;
358         case L_IDX:
359           return "hl";
360           break;
361         }
362     }
363   else if (aop->type == AOP_STR)
364     {
365       switch (*aop->aopu.aop_str[0])
366         {
367         case 'c':
368           return "bc";
369           break;
370         case 'e':
371           return "de";
372           break;
373         case 'l':
374           return "hl";
375           break;
376         }
377     }
378   wassert (0);
379   return NULL;
380 }
381
382 static PAIR_ID
383 getPairId (asmop * aop)
384 {
385   if (aop->size == 2)
386     {
387       if (aop->type == AOP_REG)
388         {
389           if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
390             {
391               return PAIR_BC;
392             }
393           if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
394             {
395               return PAIR_DE;
396             }
397           if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
398             {
399               return PAIR_HL;
400             }
401         }
402       if (aop->type == AOP_STR)
403         {
404           if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
405             {
406               return PAIR_BC;
407             }
408           if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
409             {
410               return PAIR_DE;
411             }
412           if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
413             {
414               return PAIR_HL;
415             }
416         }
417     }
418   return PAIR_INVALID;
419 }
420
421 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
422 bool
423 isPair (asmop * aop)
424 {
425   return (getPairId (aop) != PAIR_INVALID);
426 }
427
428 bool
429 isPtrPair (asmop * aop)
430 {
431   PAIR_ID pairId = getPairId (aop);
432   switch (pairId)
433     {
434     case PAIR_HL:
435     case PAIR_IY:
436     case PAIR_IX:
437       return TRUE;
438     default:
439       return FALSE;
440     }
441 }
442 /** Push a register pair onto the stack */
443 void
444 genPairPush (asmop * aop)
445 {
446   emit2 ("push %s", getPairName (aop));
447 }
448
449
450 /*-----------------------------------------------------------------*/
451 /* newAsmop - creates a new asmOp                                  */
452 /*-----------------------------------------------------------------*/
453 static asmop *
454 newAsmop (short type)
455 {
456   asmop *aop;
457
458   aop = Safe_calloc (1, sizeof (asmop));
459   aop->type = type;
460   return aop;
461 }
462
463 /*-----------------------------------------------------------------*/
464 /* aopForSym - for a true symbol                                   */
465 /*-----------------------------------------------------------------*/
466 static asmop *
467 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
468 {
469   asmop *aop;
470   memmap *space;
471
472   wassert (ic);
473   wassert (sym);
474   wassert (sym->etype);
475
476   space = SPEC_OCLS (sym->etype);
477
478   /* if already has one */
479   if (sym->aop)
480     return sym->aop;
481
482   /* Assign depending on the storage class */
483   if (sym->onStack || sym->iaccess)
484     {
485       emitDebug ("; AOP_STK for %s", sym->rname);
486       sym->aop = aop = newAsmop (AOP_STK);
487       aop->size = getSize (sym->type);
488       aop->aopu.aop_stk = sym->stack;
489       return aop;
490     }
491
492   /* special case for a function */
493   if (IS_FUNC (sym->type))
494     {
495       sym->aop = aop = newAsmop (AOP_IMMD);
496       aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
497       strcpy (aop->aopu.aop_immd, sym->rname);
498       aop->size = 2;
499       return aop;
500     }
501
502   if (IS_GB)
503     {
504       /* if it is in direct space */
505       if (IN_REGSP (space) && !requires_a)
506         {
507           sym->aop = aop = newAsmop (AOP_SFR);
508           aop->aopu.aop_dir = sym->rname;
509           aop->size = getSize (sym->type);
510           emitDebug ("; AOP_SFR for %s", sym->rname);
511           return aop;
512         }
513     }
514
515   /* only remaining is far space */
516   /* in which case DPTR gets the address */
517   if (IS_GB)
518     {
519       emitDebug ("; AOP_HL for %s", sym->rname);
520       sym->aop = aop = newAsmop (AOP_HL);
521     }
522   else
523     {
524       sym->aop = aop = newAsmop (AOP_IY);
525     }
526   aop->size = getSize (sym->type);
527   aop->aopu.aop_dir = sym->rname;
528
529   /* if it is in code space */
530   if (IN_CODESPACE (space))
531     aop->code = 1;
532
533   return aop;
534 }
535
536 /*-----------------------------------------------------------------*/
537 /* aopForRemat - rematerialzes an object                           */
538 /*-----------------------------------------------------------------*/
539 static asmop *
540 aopForRemat (symbol * sym)
541 {
542   char *s = buffer;
543   iCode *ic = sym->rematiCode;
544   asmop *aop = newAsmop (AOP_IMMD);
545
546   while (1)
547     {
548       /* if plus or minus print the right hand side */
549       if (ic->op == '+' || ic->op == '-')
550         {
551           /* PENDING: for re-target */
552           sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
553                    ic->op);
554           s += strlen (s);
555           ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
556           continue;
557         }
558       /* we reached the end */
559       sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
560       break;
561     }
562
563   aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
564   strcpy (aop->aopu.aop_immd, buffer);
565   return aop;
566 }
567
568 /*-----------------------------------------------------------------*/
569 /* regsInCommon - two operands have some registers in common       */
570 /*-----------------------------------------------------------------*/
571 bool
572 regsInCommon (operand * op1, operand * op2)
573 {
574   symbol *sym1, *sym2;
575   int i;
576
577   /* if they have registers in common */
578   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
579     return FALSE;
580
581   sym1 = OP_SYMBOL (op1);
582   sym2 = OP_SYMBOL (op2);
583
584   if (sym1->nRegs == 0 || sym2->nRegs == 0)
585     return FALSE;
586
587   for (i = 0; i < sym1->nRegs; i++)
588     {
589       int j;
590       if (!sym1->regs[i])
591         continue;
592
593       for (j = 0; j < sym2->nRegs; j++)
594         {
595           if (!sym2->regs[j])
596             continue;
597
598           if (sym2->regs[j] == sym1->regs[i])
599             return TRUE;
600         }
601     }
602
603   return FALSE;
604 }
605
606 /*-----------------------------------------------------------------*/
607 /* operandsEqu - equivalent                                        */
608 /*-----------------------------------------------------------------*/
609 bool
610 operandsEqu (operand * op1, operand * op2)
611 {
612   symbol *sym1, *sym2;
613
614   /* if they not symbols */
615   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
616     return FALSE;
617
618   sym1 = OP_SYMBOL (op1);
619   sym2 = OP_SYMBOL (op2);
620
621   /* if both are itemps & one is spilt
622      and the other is not then false */
623   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
624       sym1->isspilt != sym2->isspilt)
625     return FALSE;
626
627   /* if they are the same */
628   if (sym1 == sym2)
629     return 1;
630
631   if (strcmp (sym1->rname, sym2->rname) == 0)
632     return 2;
633
634
635   /* if left is a tmp & right is not */
636   if (IS_ITEMP (op1) &&
637       !IS_ITEMP (op2) &&
638       sym1->isspilt &&
639       (sym1->usl.spillLoc == sym2))
640     return 3;
641
642   if (IS_ITEMP (op2) &&
643       !IS_ITEMP (op1) &&
644       sym2->isspilt &&
645       sym1->level > 0 &&
646       (sym2->usl.spillLoc == sym1))
647     return 4;
648
649   return FALSE;
650 }
651
652 /*-----------------------------------------------------------------*/
653 /* sameRegs - two asmops have the same registers                   */
654 /*-----------------------------------------------------------------*/
655 bool
656 sameRegs (asmop * aop1, asmop * aop2)
657 {
658   int i;
659
660   if (aop1->type == AOP_SFR ||
661       aop2->type == AOP_SFR)
662     return FALSE;
663
664   if (aop1 == aop2)
665     return TRUE;
666
667   if (aop1->type != AOP_REG ||
668       aop2->type != AOP_REG)
669     return FALSE;
670
671   if (aop1->size != aop2->size)
672     return FALSE;
673
674   for (i = 0; i < aop1->size; i++)
675     if (aop1->aopu.aop_reg[i] !=
676         aop2->aopu.aop_reg[i])
677       return FALSE;
678
679   return TRUE;
680 }
681
682 /*-----------------------------------------------------------------*/
683 /* aopOp - allocates an asmop for an operand  :                    */
684 /*-----------------------------------------------------------------*/
685 static void
686 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
687 {
688   asmop *aop;
689   symbol *sym;
690   int i;
691
692   if (!op)
693     return;
694
695   /* if this a literal */
696   if (IS_OP_LITERAL (op))
697     {
698       op->aop = aop = newAsmop (AOP_LIT);
699       aop->aopu.aop_lit = op->operand.valOperand;
700       aop->size = getSize (operandType (op));
701       return;
702     }
703
704   /* if already has a asmop then continue */
705   if (op->aop)
706     return;
707
708   /* if the underlying symbol has a aop */
709   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
710     {
711       op->aop = OP_SYMBOL (op)->aop;
712       return;
713     }
714
715   /* if this is a true symbol */
716   if (IS_TRUE_SYMOP (op))
717     {
718       op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
719       return;
720     }
721
722   /* this is a temporary : this has
723      only four choices :
724      a) register
725      b) spillocation
726      c) rematerialize
727      d) conditional
728      e) can be a return use only */
729
730   sym = OP_SYMBOL (op);
731
732   /* if the type is a conditional */
733   if (sym->regType == REG_CND)
734     {
735       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
736       aop->size = 0;
737       return;
738     }
739
740   /* if it is spilt then two situations
741      a) is rematerialize
742      b) has a spill location */
743   if (sym->isspilt || sym->nRegs == 0)
744     {
745       /* rematerialize it NOW */
746       if (sym->remat)
747         {
748           sym->aop = op->aop = aop =
749             aopForRemat (sym);
750           aop->size = getSize (sym->type);
751           return;
752         }
753
754       if (sym->accuse)
755         {
756           if (sym->accuse == ACCUSE_A)
757             {
758               aop = op->aop = sym->aop = newAsmop (AOP_ACC);
759               aop->size = getSize (sym->type);
760               wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
761
762               aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
763             }
764           else if (sym->accuse == ACCUSE_HL)
765             {
766               wassert (!IS_GB);
767               aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
768               aop->size = getSize (sym->type);
769               wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
770               aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
771               aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
772             }
773           else 
774               {
775                   wassert (0);
776               }
777           return;
778         }
779
780       if (sym->ruonly)
781         {
782           int i;
783           aop = op->aop = sym->aop = newAsmop (AOP_STR);
784           aop->size = getSize (sym->type);
785           for (i = 0; i < 4; i++)
786             aop->aopu.aop_str[i] = _fReturn[i];
787           return;
788         }
789
790       /* else spill location  */
791       sym->aop = op->aop = aop =
792         aopForSym (ic, sym->usl.spillLoc, result, requires_a);
793       aop->size = getSize (sym->type);
794       return;
795     }
796
797   /* must be in a register */
798   sym->aop = op->aop = aop = newAsmop (AOP_REG);
799   aop->size = sym->nRegs;
800   for (i = 0; i < sym->nRegs; i++)
801     aop->aopu.aop_reg[i] = sym->regs[i];
802 }
803
804 /*-----------------------------------------------------------------*/
805 /* freeAsmop - free up the asmop given to an operand               */
806 /*----------------------------------------------------------------*/
807 static void
808 freeAsmop (operand * op, asmop * aaop, iCode * ic)
809 {
810   asmop *aop;
811
812   if (!op)
813     aop = aaop;
814   else
815     aop = op->aop;
816
817   if (!aop)
818     return;
819
820   if (aop->freed)
821     goto dealloc;
822
823   aop->freed = 1;
824
825 dealloc:
826   /* all other cases just dealloc */
827   if (op)
828     {
829       op->aop = NULL;
830       if (IS_SYMOP (op))
831         {
832           OP_SYMBOL (op)->aop = NULL;
833           /* if the symbol has a spill */
834           if (SPIL_LOC (op))
835             SPIL_LOC (op)->aop = NULL;
836         }
837     }
838 }
839
840 bool
841 isLitWord (asmop * aop)
842 {
843   /*    if (aop->size != 2)
844      return FALSE; */
845   switch (aop->type)
846     {
847     case AOP_IMMD:
848     case AOP_LIT:
849       return TRUE;
850     default:
851       return FALSE;
852     }
853 }
854
855 char *
856 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
857 {
858   char *s = buffer;
859   char *rs;
860
861   /* depending on type */
862   switch (aop->type)
863     {
864     case AOP_HL:
865     case AOP_IY:
866     case AOP_IMMD:
867       /* PENDING: for re-target */
868       if (with_hash)
869         tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
870       else
871         tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
872
873       return gc_strdup(s);
874
875     case AOP_LIT:
876       {
877         value *val = aop->aopu.aop_lit;
878         /* if it is a float then it gets tricky */
879         /* otherwise it is fairly simple */
880         if (!IS_FLOAT (val->type))
881           {
882             unsigned long v = (unsigned long) floatFromVal (val);
883
884             if (offset == 2)
885               {
886                 v >>= 16;
887               }
888             else if (offset == 0)
889               {
890                 // OK
891               }
892             else 
893               {
894                 wassertl(0, "Encountered an invalid offset while fetching a literal");
895               }
896
897             if (with_hash)
898               tsprintf (buffer, "!immedword", v);
899             else
900               tsprintf (buffer, "!constword", v);
901
902             return gc_strdup(buffer);
903           }
904         else
905           {
906             /* A float */
907             Z80_FLOAT f;
908             convertFloat (&f, floatFromVal (val));
909             if (with_hash)
910               tsprintf (buffer, "!immedword", f.w[offset / 2]);
911             else
912               tsprintf (buffer, "!constword", f.w[offset / 2]);
913             rs = Safe_calloc (1, strlen (buffer) + 1);
914             return strcpy (rs, buffer);
915           }
916       }
917     default:
918       return NULL;
919     }
920 }
921
922 char *
923 aopGetWord (asmop * aop, int offset)
924 {
925   return aopGetLitWordLong (aop, offset, TRUE);
926 }
927
928 bool
929 isPtr (const char *s)
930 {
931   if (!strcmp (s, "hl"))
932     return TRUE;
933   if (!strcmp (s, "ix"))
934     return TRUE;
935   if (!strcmp (s, "iy"))
936     return TRUE;
937   return FALSE;
938 }
939
940 static void
941 adjustPair (const char *pair, int *pold, int new)
942 {
943   wassert (pair);
944
945   while (*pold < new)
946     {
947       emit2 ("inc %s", pair);
948       (*pold)++;
949     }
950   while (*pold > new)
951     {
952       emit2 ("dec %s", pair);
953       (*pold)--;
954     }
955 }
956
957 static void
958 spillPair (PAIR_ID pairId)
959 {
960   _G.pairs[pairId].last_type = AOP_INVALID;
961   _G.pairs[pairId].lit = NULL;
962 }
963
964 static void
965 spillCached (void)
966 {
967   spillPair (PAIR_HL);
968   spillPair (PAIR_IY);
969 }
970
971 static bool
972 requiresHL (asmop * aop)
973 {
974   switch (aop->type)
975     {
976     case AOP_IY:
977     case AOP_HL:
978     case AOP_STK:
979       return TRUE;
980     default:
981       return FALSE;
982     }
983 }
984
985 static char *
986 fetchLitSpecial (asmop * aop, bool negate, bool xor)
987 {
988   unsigned long v;
989   value *val = aop->aopu.aop_lit;
990
991   wassert (aop->type == AOP_LIT);
992   wassert (!IS_FLOAT (val->type));
993
994   v = (unsigned long) floatFromVal (val);
995
996   if (xor)
997     v ^= 0x8000;
998   if (negate)
999     v = 0-v;
1000   v &= 0xFFFF;
1001
1002   tsprintf (buffer, "!immedword", v);
1003   return gc_strdup (buffer);
1004 }
1005
1006 static void
1007 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1008 {
1009   const char *l;
1010   const char *pair = _pairs[pairId].name;
1011   l = aopGetLitWordLong (left, offset, FALSE);
1012   wassert (l && pair);
1013
1014   if (isPtr (pair))
1015     {
1016       if (pairId == PAIR_HL || pairId == PAIR_IY)
1017         {
1018           if (_G.pairs[pairId].last_type == left->type)
1019             {
1020               if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1021                 {
1022                   if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1023                     {
1024                       adjustPair (pair, &_G.pairs[pairId].offset, offset);
1025                       return;
1026                     }
1027                   if (pairId == PAIR_IY && abs (offset) < 127)
1028                     {
1029                       return;
1030                     }
1031                 }
1032             }
1033         }
1034       _G.pairs[pairId].last_type = left->type;
1035       _G.pairs[pairId].lit = gc_strdup (l);
1036       _G.pairs[pairId].offset = offset;
1037     }
1038   if (IS_GB && pairId == PAIR_DE && 0)
1039     {
1040       if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1041         {
1042           if (abs (_G.pairs[pairId].offset - offset) < 3)
1043             {
1044               adjustPair (pair, &_G.pairs[pairId].offset, offset);
1045               return;
1046             }
1047         }
1048       _G.pairs[pairId].last_type = left->type;
1049       _G.pairs[pairId].lit = gc_strdup (l);
1050       _G.pairs[pairId].offset = offset;
1051     }
1052   /* Both a lit on the right and a true symbol on the left */
1053   emit2 ("ld %s,!hashedstr", pair, l);
1054 }
1055
1056 static void
1057 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1058 {
1059     /* if this is remateriazable */
1060     if (isLitWord (aop)) {
1061         fetchLitPair (pairId, aop, offset);
1062     }
1063     else {
1064         /* we need to get it byte by byte */
1065         if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1066             aopGet (aop, offset, FALSE);
1067             switch (aop->size) {
1068             case 1:
1069                 emit2 ("ld l,!*hl");
1070                 emit2 ("ld h,!immedbyte", 0);
1071                             break;
1072             case 2:
1073                 emit2 ("!ldahli");
1074                 emit2 ("ld h,!*hl");
1075                 emit2 ("ld l,a");
1076                 break;
1077             default:
1078                 emitDebug ("; WARNING: mlh woosed out.  This code is invalid.");
1079             }
1080         }
1081         else if (IS_Z80 && aop->type == AOP_IY) {
1082             /* Instead of fetching relative to IY, just grab directly
1083                from the address IY refers to */
1084             char *l = aopGetLitWordLong (aop, offset, FALSE);
1085             wassert (l);
1086             emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1087
1088             if (aop->size < 2) {
1089                 emit2("ld %s,!zero", _pairs[pairId].h);
1090             }
1091         }
1092         else {
1093             emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1094             emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1095         }
1096         /* PENDING: check? */
1097         if (pairId == PAIR_HL)
1098             spillPair (PAIR_HL);
1099     }
1100 }
1101
1102 static void
1103 fetchPair (PAIR_ID pairId, asmop * aop)
1104 {
1105   fetchPairLong (pairId, aop, 0);
1106 }
1107
1108 static void
1109 fetchHL (asmop * aop)
1110 {
1111   fetchPair (PAIR_HL, aop);
1112 }
1113
1114 static void
1115 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1116 {
1117   assert (pairId == PAIR_HL || pairId == PAIR_IY);
1118
1119   switch (aop->type)
1120     {
1121     case AOP_IY:
1122       fetchLitPair (pairId, aop, 0);
1123       break;
1124     case AOP_HL:
1125       fetchLitPair (pairId, aop, offset);
1126       _G.pairs[pairId].offset = offset;
1127       break;
1128     case AOP_STK:
1129       {
1130         /* Doesnt include _G.stack.pushed */
1131         int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1132         if (aop->aopu.aop_stk > 0)
1133           {
1134             abso += _G.stack.param_offset;
1135           }
1136         assert (pairId == PAIR_HL);
1137         /* In some cases we can still inc or dec hl */
1138         if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1139           {
1140             adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1141           }
1142         else
1143           {
1144             emit2 ("!ldahlsp", abso + _G.stack.pushed);
1145           }
1146         _G.pairs[pairId].offset = abso;
1147         break;
1148       }
1149     default:
1150       wassert (0);
1151     }
1152   _G.pairs[pairId].last_type = aop->type;
1153 }
1154
1155 static void
1156 emitLabel (int key)
1157 {
1158   emit2 ("!tlabeldef", key);
1159   spillCached ();
1160 }
1161
1162 /*-----------------------------------------------------------------*/
1163 /* aopGet - for fetching value of the aop                          */
1164 /*-----------------------------------------------------------------*/
1165 static const char *
1166 aopGet (asmop * aop, int offset, bool bit16)
1167 {
1168   char *s = buffer;
1169
1170   /* offset is greater than size then zero */
1171   /* PENDING: this seems a bit screwed in some pointer cases. */
1172   if (offset > (aop->size - 1) &&
1173       aop->type != AOP_LIT) 
1174     {
1175       tsprintf (s, "!zero");
1176       return gc_strdup(s);
1177     }
1178
1179   /* depending on type */
1180   switch (aop->type)
1181     {
1182     case AOP_IMMD:
1183       /* PENDING: re-target */
1184       if (bit16)
1185         tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1186       else
1187         switch (offset)
1188           {
1189           case 2:
1190             tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1191             break;
1192           case 1:
1193             tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1194             break;
1195           case 0:
1196             tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1197             break;
1198           default:
1199             wassert (0);
1200           }
1201
1202       return gc_strdup(s);
1203
1204     case AOP_DIR:
1205       wassert (IS_GB);
1206       emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1207       sprintf (s, "a");
1208
1209       return gc_strdup(s);
1210
1211     case AOP_SFR:
1212       wassert (IS_GB);
1213       emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1214       sprintf (s, "a");
1215
1216       return gc_strdup(s);
1217
1218     case AOP_REG:
1219       return aop->aopu.aop_reg[offset]->name;
1220
1221     case AOP_HL:
1222       wassert (IS_GB);
1223       setupPair (PAIR_HL, aop, offset);
1224       tsprintf (s, "!*hl");
1225
1226       return gc_strdup (s);
1227
1228     case AOP_IY:
1229       wassert (IS_Z80);
1230       setupPair (PAIR_IY, aop, offset);
1231       tsprintf (s, "!*iyx", offset);
1232
1233       return gc_strdup(s);
1234
1235     case AOP_STK:
1236       if (IS_GB)
1237         {
1238           setupPair (PAIR_HL, aop, offset);
1239           tsprintf (s, "!*hl");
1240         }
1241       else
1242         {
1243           if (aop->aopu.aop_stk >= 0)
1244             offset += _G.stack.param_offset;
1245           tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1246         }
1247
1248       return gc_strdup(s);
1249
1250     case AOP_CRY:
1251       wassert (0);
1252
1253     case AOP_ACC:
1254       if (!offset)
1255         {
1256           return "a";
1257         }
1258       else
1259         {
1260           tsprintf(s, "!zero");
1261           return gc_strdup(s);
1262         }
1263
1264     case AOP_HLREG:
1265       wassert (offset < 2);
1266       return aop->aopu.aop_str[offset];
1267
1268     case AOP_LIT:
1269       return aopLiteral (aop->aopu.aop_lit, offset);
1270
1271     case AOP_STR:
1272       aop->coff = offset;
1273       return aop->aopu.aop_str[offset];
1274
1275     default:
1276       break;
1277     }
1278   wassertl (0, "aopget got unsupported aop->type");
1279   exit (0);
1280 }
1281
1282 bool
1283 isRegString (const char *s)
1284 {
1285   if (!strcmp (s, "b") ||
1286       !strcmp (s, "c") ||
1287       !strcmp (s, "d") ||
1288       !strcmp (s, "e") ||
1289       !strcmp (s, "a") ||
1290       !strcmp (s, "h") ||
1291       !strcmp (s, "l"))
1292     return TRUE;
1293   return FALSE;
1294 }
1295
1296 bool
1297 isConstant (const char *s)
1298 {
1299   /* This is a bit of a hack... */
1300   return (*s == '#' || *s == '$');
1301 }
1302
1303 bool
1304 canAssignToPtr (const char *s)
1305 {
1306   if (isRegString (s))
1307     return TRUE;
1308   if (isConstant (s))
1309     return TRUE;
1310   return FALSE;
1311 }
1312
1313 /*-----------------------------------------------------------------*/
1314 /* aopPut - puts a string for a aop                                */
1315 /*-----------------------------------------------------------------*/
1316 static void
1317 aopPut (asmop * aop, const char *s, int offset)
1318 {
1319   char buffer2[256];
1320
1321   if (aop->size && offset > (aop->size - 1))
1322     {
1323       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1324               "aopPut got offset > aop->size");
1325       exit (0);
1326     }
1327
1328   // PENDING
1329   tsprintf(buffer2, s);
1330   s = buffer2;
1331
1332   /* will assign value to value */
1333   /* depending on where it is ofcourse */
1334   switch (aop->type)
1335     {
1336     case AOP_DIR:
1337       /* Direct.  Hmmm. */
1338       wassert (IS_GB);
1339       if (strcmp (s, "a"))
1340         emit2 ("ld a,%s", s);
1341       emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1342       break;
1343
1344     case AOP_SFR:
1345       wassert (IS_GB);
1346       if (strcmp (s, "a"))
1347         emit2 ("ld a,%s", s);
1348       emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1349       break;
1350
1351     case AOP_REG:
1352       if (!strcmp (s, "!*hl"))
1353         emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1354       else
1355         emit2 ("ld %s,%s",
1356                aop->aopu.aop_reg[offset]->name, s);
1357       break;
1358
1359     case AOP_IY:
1360       wassert (!IS_GB);
1361       setupPair (PAIR_IY, aop, offset);
1362       if (!canAssignToPtr (s))
1363         {
1364           emit2 ("ld a,%s", s);
1365           emit2 ("ld !*iyx,a", offset);
1366         }
1367       else
1368         emit2 ("ld !*iyx,%s", offset, s);
1369       break;
1370
1371     case AOP_HL:
1372       wassert (IS_GB);
1373       /* PENDING: for re-target */
1374       if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1375         {
1376           emit2 ("ld a,!*hl");
1377           s = "a";
1378         }
1379       setupPair (PAIR_HL, aop, offset);
1380
1381       emit2 ("ld !*hl,%s", s);
1382       break;
1383
1384     case AOP_STK:
1385       if (IS_GB)
1386         {
1387           /* PENDING: re-target */
1388           if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1389             {
1390               emit2 ("ld a,!*hl");
1391               s = "a";
1392             }
1393           setupPair (PAIR_HL, aop, offset);
1394           if (!canAssignToPtr (s))
1395             {
1396               emit2 ("ld a,%s", s);
1397               emit2 ("ld !*hl,a");
1398             }
1399           else
1400             emit2 ("ld !*hl,%s", s);
1401         }
1402       else
1403         {
1404           if (aop->aopu.aop_stk >= 0)
1405             offset += _G.stack.param_offset;
1406           if (!canAssignToPtr (s))
1407             {
1408               emit2 ("ld a,%s", s);
1409               emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1410             }
1411           else
1412             emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1413         }
1414       break;
1415
1416     case AOP_CRY:
1417       /* if bit variable */
1418       if (!aop->aopu.aop_dir)
1419         {
1420           emit2 ("ld a,#0");
1421           emit2 ("rla");
1422         }
1423       else
1424         {
1425           /* In bit space but not in C - cant happen */
1426           wassert (0);
1427         }
1428       break;
1429
1430     case AOP_STR:
1431       aop->coff = offset;
1432       if (strcmp (aop->aopu.aop_str[offset], s))
1433         {
1434           emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1435         }
1436       break;
1437
1438     case AOP_ACC:
1439       aop->coff = offset;
1440       if (!offset && (strcmp (s, "acc") == 0))
1441         break;
1442       if (offset > 0)
1443         {
1444
1445           emitDebug ("; Error aopPut AOP_ACC");
1446         }
1447       else
1448         {
1449           if (strcmp (aop->aopu.aop_str[offset], s))
1450             emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1451         }
1452       break;
1453
1454     case AOP_HLREG:
1455       wassert (offset < 2);
1456       emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1457       break;
1458
1459     default:
1460       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1461               "aopPut got unsupported aop->type");
1462       exit (0);
1463     }
1464 }
1465
1466 #define AOP(op) op->aop
1467 #define AOP_TYPE(op) AOP(op)->type
1468 #define AOP_SIZE(op) AOP(op)->size
1469 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1470
1471 static void
1472 commitPair (asmop * aop, PAIR_ID id)
1473 {
1474   if (id == PAIR_HL && requiresHL (aop))
1475     {
1476       emit2 ("ld a,l");
1477       emit2 ("ld d,h");
1478       aopPut (aop, "a", 0);
1479       aopPut (aop, "d", 1);
1480     }
1481   else
1482     {
1483       aopPut (aop, _pairs[id].l, 0);
1484       aopPut (aop, _pairs[id].h, 1);
1485     }
1486 }
1487
1488 /*-----------------------------------------------------------------*/
1489 /* getDataSize - get the operand data size                         */
1490 /*-----------------------------------------------------------------*/
1491 int
1492 getDataSize (operand * op)
1493 {
1494   int size;
1495   size = AOP_SIZE (op);
1496   if (size == 3)
1497     {
1498       /* pointer */
1499       wassert (0);
1500     }
1501   return size;
1502 }
1503
1504 /*-----------------------------------------------------------------*/
1505 /* movLeft2Result - move byte from left to result                  */
1506 /*-----------------------------------------------------------------*/
1507 static void
1508 movLeft2Result (operand * left, int offl,
1509                 operand * result, int offr, int sign)
1510 {
1511     const char *l;
1512   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1513     {
1514       l = aopGet (AOP (left), offl, FALSE);
1515
1516       if (!sign)
1517         {
1518           aopPut (AOP (result), l, offr);
1519         }
1520       else
1521         {
1522           wassert (0);
1523         }
1524     }
1525 }
1526
1527
1528 /** Put Acc into a register set
1529  */
1530 void
1531 outAcc (operand * result)
1532 {
1533   int size, offset;
1534   size = getDataSize (result);
1535   if (size)
1536     {
1537       aopPut (AOP (result), "a", 0);
1538       size--;
1539       offset = 1;
1540       /* unsigned or positive */
1541       while (size--)
1542         {
1543           aopPut (AOP (result), "!zero", offset++);
1544         }
1545     }
1546 }
1547
1548 /** Take the value in carry and put it into a register
1549  */
1550 void
1551 outBitCLong (operand * result, bool swap_sense)
1552 {
1553   /* if the result is bit */
1554   if (AOP_TYPE (result) == AOP_CRY)
1555     {
1556       emitDebug ("; Note: outBitC form 1");
1557       aopPut (AOP (result), "blah", 0);
1558     }
1559   else
1560     {
1561       emit2 ("ld a,!zero");
1562       emit2 ("rla");
1563       if (swap_sense)
1564         emit2 ("xor a,!immedbyte", 1);
1565       outAcc (result);
1566     }
1567 }
1568
1569 void
1570 outBitC (operand * result)
1571 {
1572   outBitCLong (result, FALSE);
1573 }
1574
1575 /*-----------------------------------------------------------------*/
1576 /* toBoolean - emit code for orl a,operator(sizeop)                */
1577 /*-----------------------------------------------------------------*/
1578 void
1579 _toBoolean (operand * oper)
1580 {
1581   int size = AOP_SIZE (oper);
1582   int offset = 0;
1583   if (size > 1)
1584     {
1585       emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1586       size--;
1587       while (size--)
1588         emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1589     }
1590   else
1591     {
1592       if (AOP (oper)->type != AOP_ACC)
1593         {
1594           _clearCarry();
1595           emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1596         }
1597     }
1598 }
1599
1600 /*-----------------------------------------------------------------*/
1601 /* genNot - generate code for ! operation                          */
1602 /*-----------------------------------------------------------------*/
1603 static void
1604 genNot (iCode * ic)
1605 {
1606   sym_link *optype = operandType (IC_LEFT (ic));
1607
1608   /* assign asmOps to operand & result */
1609   aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1610   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1611
1612   /* if in bit space then a special case */
1613   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1614     {
1615       wassert (0);
1616     }
1617
1618   /* if type float then do float */
1619   if (IS_FLOAT (optype))
1620     {
1621       wassert (0);
1622     }
1623
1624   _toBoolean (IC_LEFT (ic));
1625
1626   /* Not of A:
1627      If A == 0, !A = 1
1628      else A = 0
1629      So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1630   emit2 ("sub a,!one");
1631   outBitC (IC_RESULT (ic));
1632
1633   /* release the aops */
1634   freeAsmop (IC_LEFT (ic), NULL, ic);
1635   freeAsmop (IC_RESULT (ic), NULL, ic);
1636 }
1637
1638 /*-----------------------------------------------------------------*/
1639 /* genCpl - generate code for complement                           */
1640 /*-----------------------------------------------------------------*/
1641 static void
1642 genCpl (iCode * ic)
1643 {
1644   int offset = 0;
1645   int size;
1646
1647
1648   /* assign asmOps to operand & result */
1649   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1650   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1651
1652   /* if both are in bit space then
1653      a special case */
1654   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1655       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1656     {
1657       wassert (0);
1658     }
1659
1660   size = AOP_SIZE (IC_RESULT (ic));
1661   while (size--)
1662     {
1663       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1664       _moveA (l);
1665       emit2("cpl");
1666       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1667     }
1668
1669   /* release the aops */
1670   freeAsmop (IC_LEFT (ic), NULL, ic);
1671   freeAsmop (IC_RESULT (ic), NULL, ic);
1672 }
1673
1674 /*-----------------------------------------------------------------*/
1675 /* genUminus - unary minus code generation                         */
1676 /*-----------------------------------------------------------------*/
1677 static void
1678 genUminus (iCode * ic)
1679 {
1680   int offset, size;
1681   sym_link *optype, *rtype;
1682
1683   /* assign asmops */
1684   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1685   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1686
1687   /* if both in bit space then special
1688      case */
1689   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1690       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1691     {
1692       wassert (0);
1693       goto release;
1694     }
1695
1696   optype = operandType (IC_LEFT (ic));
1697   rtype = operandType (IC_RESULT (ic));
1698
1699   /* if float then do float stuff */
1700   if (IS_FLOAT (optype))
1701     {
1702       wassert (0);
1703       goto release;
1704     }
1705
1706   /* otherwise subtract from zero */
1707   size = AOP_SIZE (IC_LEFT (ic));
1708   offset = 0;
1709   _clearCarry();
1710   while (size--)
1711     {
1712       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1713       emit2 ("ld a,!zero");
1714       emit2 ("sbc a,%s", l);
1715       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1716     }
1717
1718   /* if any remaining bytes in the result */
1719   /* we just need to propagate the sign   */
1720   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1721     {
1722       emit2 ("rlc a");
1723       emit2 ("sbc a,a");
1724       while (size--)
1725         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1726     }
1727
1728 release:
1729   /* release the aops */
1730   freeAsmop (IC_LEFT (ic), NULL, ic);
1731   freeAsmop (IC_RESULT (ic), NULL, ic);
1732 }
1733
1734 static void
1735 _push (PAIR_ID pairId)
1736 {
1737   emit2 ("push %s", _pairs[pairId].name);
1738   _G.stack.pushed += 2;
1739 }
1740
1741 static void
1742 _pop (PAIR_ID pairId)
1743 {
1744   emit2 ("pop %s", _pairs[pairId].name);
1745   _G.stack.pushed -= 2;
1746 }
1747
1748
1749 /*-----------------------------------------------------------------*/
1750 /* assignResultValue -               */
1751 /*-----------------------------------------------------------------*/
1752 void
1753 assignResultValue (operand * oper)
1754 {
1755   int size = AOP_SIZE (oper);
1756   bool topInA = 0;
1757
1758   wassert (size <= 4);
1759   topInA = requiresHL (AOP (oper));
1760
1761 #if 0
1762   if (!IS_GB)
1763     wassert (size <= 2);
1764 #endif
1765   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1766     {
1767       /* We do it the hard way here. */
1768       _push (PAIR_HL);
1769       aopPut (AOP (oper), _fReturn[0], 0);
1770       aopPut (AOP (oper), _fReturn[1], 1);
1771       emit2 ("pop de");
1772       _G.stack.pushed -= 2;
1773       aopPut (AOP (oper), _fReturn[0], 2);
1774       aopPut (AOP (oper), _fReturn[1], 3);
1775     }
1776   else
1777     {
1778       while (size--)
1779         {
1780           aopPut (AOP (oper), _fReturn[size], size);
1781         }
1782     }
1783 }
1784
1785 static void
1786 _saveRegsForCall(iCode *ic, int sendSetSize)
1787 {
1788   /* Rules:
1789       o Stack parameters are pushed before this function enters
1790       o DE and BC may be used in this function.
1791       o HL and DE may be used to return the result.
1792       o HL and DE may be used to send variables.
1793       o DE and BC may be used to store the result value.
1794       o HL may be used in computing the sent value of DE
1795       o The iPushes for other parameters occur before any addSets
1796
1797      Logic: (to be run inside the first iPush or if none, before sending)
1798       o Compute if DE and/or BC are in use over the call
1799       o Compute if DE is used in the send set
1800       o Compute if DE and/or BC are used to hold the result value
1801       o If (DE is used, or in the send set) and is not used in the result, push.
1802       o If BC is used and is not in the result, push
1803       o 
1804       o If DE is used in the send set, fetch
1805       o If HL is used in the send set, fetch
1806       o Call
1807       o ...
1808   */
1809   if (_G.saves.saved == FALSE) {
1810     bool deInUse, bcInUse;
1811     bool deSending;
1812     bool bcInRet = FALSE, deInRet = FALSE;
1813     bitVect *rInUse;
1814
1815 #if 1
1816     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1817 #else
1818     if (IC_RESULT(ic))
1819       {
1820         rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
1821       }
1822     else 
1823       {
1824         /* Has no result, so in use is all of in use */
1825         rInUse = ic->rMask;
1826       }
1827 #endif
1828
1829     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1830     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1831
1832     deSending = (sendSetSize > 1);
1833
1834     emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1835
1836     if (bcInUse && bcInRet == FALSE) {
1837       _push(PAIR_BC);
1838       _G.stack.pushedBC = TRUE;
1839     }
1840     if (deInUse && deInRet == FALSE) {
1841       _push(PAIR_DE);
1842       _G.stack.pushedDE = TRUE;
1843     }
1844
1845     _G.saves.saved = TRUE;
1846   }
1847   else {
1848     /* Already saved. */
1849   }
1850 }
1851
1852 /*-----------------------------------------------------------------*/
1853 /* genIpush - genrate code for pushing this gets a little complex  */
1854 /*-----------------------------------------------------------------*/
1855 static void
1856 genIpush (iCode * ic)
1857 {
1858   int size, offset = 0;
1859   const char *l;
1860
1861   /* if this is not a parm push : ie. it is spill push
1862      and spill push is always done on the local stack */
1863   if (!ic->parmPush)
1864     {
1865       wassertl(0, "Encountered an unsupported spill push.");
1866       return;
1867     }
1868
1869   if (_G.saves.saved == FALSE) {
1870     /* Caller saves, and this is the first iPush. */
1871     /* Scan ahead until we find the function that we are pushing parameters to.
1872        Count the number of addSets on the way to figure out what registers
1873        are used in the send set.
1874     */
1875     int nAddSets = 0;
1876     iCode *walk = ic->next;
1877     
1878     while (walk) {
1879       if (walk->op == SEND) {
1880         nAddSets++;
1881       }
1882       else if (walk->op == CALL || walk->op == PCALL) {
1883         /* Found it. */
1884         break;
1885       }
1886       else {
1887         /* Keep looking. */
1888       }
1889       walk = walk->next;
1890     }
1891     _saveRegsForCall(walk, nAddSets);
1892   }
1893   else {
1894     /* Already saved by another iPush. */
1895   }
1896
1897   /* then do the push */
1898   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1899
1900   size = AOP_SIZE (IC_LEFT (ic));
1901
1902   if (isPair (AOP (IC_LEFT (ic))))
1903     {
1904       _G.stack.pushed += 2;
1905       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1906     }
1907   else
1908     {
1909       if (size == 2)
1910         {
1911           fetchHL (AOP (IC_LEFT (ic)));
1912           emit2 ("push hl");
1913           spillPair (PAIR_HL);
1914           _G.stack.pushed += 2;
1915           goto release;
1916         }
1917       if (size == 4)
1918         {
1919           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
1920           emit2 ("push hl");
1921           spillPair (PAIR_HL);
1922           _G.stack.pushed += 2;
1923           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
1924           emit2 ("push hl");
1925           spillPair (PAIR_HL);
1926           _G.stack.pushed += 2;
1927           goto release;
1928         }
1929       offset = size;
1930       while (size--)
1931         {
1932           if (AOP (IC_LEFT (ic))->type == AOP_IY)
1933             {
1934               char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
1935               wassert (l);
1936               emit2 ("ld a,(%s)", l);
1937             }
1938           else
1939             {
1940               l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
1941               emit2 ("ld a,%s", l);
1942             }
1943           emit2 ("push af");
1944           emit2 ("inc sp");
1945           _G.stack.pushed++;
1946         }
1947     }
1948 release:
1949   freeAsmop (IC_LEFT (ic), NULL, ic);
1950 }
1951
1952 /*-----------------------------------------------------------------*/
1953 /* genIpop - recover the registers: can happen only for spilling   */
1954 /*-----------------------------------------------------------------*/
1955 static void
1956 genIpop (iCode * ic)
1957 {
1958   int size, offset;
1959
1960
1961   /* if the temp was not pushed then */
1962   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
1963     return;
1964
1965   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1966   size = AOP_SIZE (IC_LEFT (ic));
1967   offset = (size - 1);
1968   if (isPair (AOP (IC_LEFT (ic))))
1969     {
1970       emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
1971     }
1972   else
1973     {
1974       while (size--)
1975         {
1976           emit2 ("dec sp");
1977           emit2 ("pop hl");
1978           spillPair (PAIR_HL);
1979           aopPut (AOP (IC_LEFT (ic)), "l", offset--);
1980         }
1981     }
1982
1983   freeAsmop (IC_LEFT (ic), NULL, ic);
1984 }
1985
1986 /* This is quite unfortunate */
1987 static void
1988 setArea (int inHome)
1989 {
1990   /*
1991     static int lastArea = 0;
1992
1993      if (_G.in_home != inHome) {
1994      if (inHome) {
1995      const char *sz = port->mem.code_name;
1996      port->mem.code_name = "HOME";
1997      emit2("!area", CODE_NAME);
1998      port->mem.code_name = sz;
1999      }
2000      else
2001      emit2("!area", CODE_NAME); */
2002   _G.in_home = inHome;
2003   //    }
2004 }
2005
2006 static bool
2007 isInHome (void)
2008 {
2009   return _G.in_home;
2010 }
2011
2012 static int
2013 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2014 {
2015   int ret = 0;
2016   asmop *aop;
2017   symbol *sym = OP_SYMBOL (op);
2018
2019   if (sym->isspilt || sym->nRegs == 0)
2020     return 0;
2021
2022   aopOp (op, ic, FALSE, FALSE);
2023
2024   aop = AOP (op);
2025   if (aop->type == AOP_REG)
2026     {
2027       int i;
2028       for (i = 0; i < aop->size; i++)
2029         {
2030           if (pairId == PAIR_DE)
2031             {
2032               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2033               if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2034                 ret++;
2035               if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2036                 ret++;
2037             }
2038           else if (pairId == PAIR_BC)
2039             {
2040               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2041               if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2042                 ret++;
2043               if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2044                 ret++;
2045             }
2046           else
2047             {
2048               wassert (0);
2049             }
2050         }
2051     }
2052
2053   freeAsmop (IC_LEFT (ic), NULL, ic);
2054   return ret;
2055 }
2056
2057 /** Emit the code for a call statement
2058  */
2059 static void
2060 emitCall (iCode * ic, bool ispcall)
2061 {
2062   sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2063
2064   bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2065
2066   /* if caller saves & we have not saved then */
2067   if (!ic->regsSaved)
2068     {
2069       /* PENDING */
2070     }
2071
2072   _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2073
2074   /* if send set is not empty then assign */
2075   if (_G.sendSet)
2076     {
2077       iCode *sic;
2078       int send = 0;
2079       int nSend = elementsInSet(_G.sendSet);
2080       bool swapped = FALSE;
2081
2082       int _z80_sendOrder[] = {
2083         PAIR_BC, PAIR_DE
2084       };
2085
2086       if (nSend > 1) {
2087         /* Check if the parameters are swapped.  If so route through hl instead. */
2088         wassertl (nSend == 2, "Pedantic check.  Code only checks for the two send items case.");
2089
2090         sic = setFirstItem(_G.sendSet);
2091         sic = setNextItem(_G.sendSet);
2092
2093         if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2094           /* The second send value is loaded from one the one that holds the first
2095              send, i.e. it is overwritten. */
2096           /* Cache the first in HL, and load the second from HL instead. */
2097           emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2098           emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2099
2100           swapped = TRUE;
2101         }
2102       }
2103
2104       for (sic = setFirstItem (_G.sendSet); sic;
2105            sic = setNextItem (_G.sendSet))
2106         {
2107           int size;
2108           aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2109
2110           size = AOP_SIZE (IC_LEFT (sic));
2111           wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2112           wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2113
2114           // PENDING: Mild hack
2115           if (swapped == TRUE && send == 1) {
2116             if (size > 1) {
2117               emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2118             }
2119             else {
2120               emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2121             }
2122             emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2123           }
2124           else {
2125             fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2126           }
2127
2128           send++;
2129           freeAsmop (IC_LEFT (sic), NULL, sic);
2130         }
2131       _G.sendSet = NULL;
2132     }
2133
2134   if (ispcall)
2135     {
2136       if (IS_BANKEDCALL (detype))
2137         {
2138           werror (W_INDIR_BANKED);
2139         }
2140       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2141
2142       if (isLitWord (AOP (IC_LEFT (ic))))
2143         {
2144           emitDebug ("; Special case where the pCall is to a constant");
2145           emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2146         }
2147       else
2148         {
2149           symbol *rlbl = newiTempLabel (NULL);
2150           spillPair (PAIR_HL);
2151           emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2152           emit2 ("push hl");
2153           _G.stack.pushed += 2;
2154
2155           fetchHL (AOP (IC_LEFT (ic)));
2156           emit2 ("jp !*hl");
2157           emit2 ("!tlabeldef", (rlbl->key + 100));
2158           _G.stack.pushed -= 2;
2159         }
2160       freeAsmop (IC_LEFT (ic), NULL, ic);
2161     }
2162   else
2163     {
2164       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2165       OP_SYMBOL (IC_LEFT (ic))->rname :
2166       OP_SYMBOL (IC_LEFT (ic))->name;
2167       if (IS_BANKEDCALL (detype))
2168         {
2169           emit2 ("call banked_call");
2170           emit2 ("!dws", name);
2171           emit2 ("!dw !bankimmeds", name);
2172         }
2173       else
2174         {
2175           /* make the call */
2176           emit2 ("call %s", name);
2177         }
2178     }
2179   spillCached ();
2180
2181   /* Mark the regsiters as restored. */
2182   _G.saves.saved = FALSE;
2183
2184   /* if we need assign a result value */
2185   if ((IS_ITEMP (IC_RESULT (ic)) &&
2186        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2187         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2188       IS_TRUE_SYMOP (IC_RESULT (ic)))
2189     {
2190
2191       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2192
2193       assignResultValue (IC_RESULT (ic));
2194
2195       freeAsmop (IC_RESULT (ic), NULL, ic);
2196     }
2197
2198   /* adjust the stack for parameters if required */
2199   if (ic->parmBytes)
2200     {
2201       int i = ic->parmBytes;
2202
2203       _G.stack.pushed -= i;
2204       if (IS_GB)
2205         {
2206           emit2 ("!ldaspsp", i);
2207         }
2208       else
2209         {
2210           spillCached ();
2211           if (i > 6)
2212             {
2213               emit2 ("ld hl,#%d", i);
2214               emit2 ("add hl,sp");
2215               emit2 ("ld sp,hl");
2216             }
2217           else
2218             {
2219               while (i > 1)
2220                 {
2221                   emit2 ("pop hl");
2222                   i -= 2;
2223                 }
2224               if (i)
2225                 emit2 ("inc sp");
2226             }
2227           spillCached ();
2228         }
2229     }
2230
2231   if (_G.stack.pushedDE) 
2232     {
2233       bool dInUse = bitVectBitValue(rInUse, D_IDX);
2234       bool eInUse = bitVectBitValue(rInUse, E_IDX);
2235
2236       if (dInUse && eInUse) 
2237         {
2238           _pop (PAIR_DE);
2239         }
2240       else if (dInUse)
2241         {
2242           _pop(PAIR_HL);
2243           emit2 ("ld d,h");
2244         }
2245       else if (eInUse)
2246         {
2247           _pop(PAIR_HL);
2248           emit2 ("ld e,l");
2249         }
2250       else
2251         {
2252           wassertl (0, "Neither D or E were in use but it was pushed.");
2253         }
2254       _G.stack.pushedDE = FALSE;
2255     }
2256   
2257   if (_G.stack.pushedBC) 
2258     {
2259       bool bInUse = bitVectBitValue(rInUse, B_IDX);
2260       bool cInUse = bitVectBitValue(rInUse, C_IDX);
2261
2262       // If both B and C are used in the return value, then we won't get
2263       // here.
2264       if (bInUse && cInUse) 
2265         {
2266           _pop (PAIR_BC);
2267         }
2268       else if (bInUse)
2269         {
2270           _pop(PAIR_HL);
2271           emit2 ("ld b,h");
2272         }
2273       else if (cInUse)
2274         {
2275           _pop(PAIR_HL);
2276           emit2 ("ld c,l");
2277         }
2278       else
2279         {
2280           wassertl (0, "Neither B or C were in use but it was pushed.");
2281         }
2282       _G.stack.pushedBC = FALSE;
2283     }
2284 }
2285
2286 /*-----------------------------------------------------------------*/
2287 /* genCall - generates a call statement                            */
2288 /*-----------------------------------------------------------------*/
2289 static void
2290 genCall (iCode * ic)
2291 {
2292   emitCall (ic, FALSE);
2293 }
2294
2295 /*-----------------------------------------------------------------*/
2296 /* genPcall - generates a call by pointer statement                */
2297 /*-----------------------------------------------------------------*/
2298 static void
2299 genPcall (iCode * ic)
2300 {
2301   emitCall (ic, TRUE);
2302 }
2303
2304 /*-----------------------------------------------------------------*/
2305 /* resultRemat - result  is rematerializable                       */
2306 /*-----------------------------------------------------------------*/
2307 static int
2308 resultRemat (iCode * ic)
2309 {
2310   if (SKIP_IC (ic) || ic->op == IFX)
2311     return 0;
2312
2313   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2314     {
2315       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2316       if (sym->remat && !POINTER_SET (ic))
2317         return 1;
2318     }
2319
2320   return 0;
2321 }
2322
2323 extern set *publics;
2324
2325 /*-----------------------------------------------------------------*/
2326 /* genFunction - generated code for function entry                 */
2327 /*-----------------------------------------------------------------*/
2328 static void
2329 genFunction (iCode * ic)
2330 {
2331   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2332   sym_link *fetype;
2333
2334 #if CALLEE_SAVES
2335   bool bcInUse = FALSE;
2336   bool deInUse = FALSE;
2337 #endif
2338
2339   setArea (IS_NONBANKED (sym->etype));
2340
2341   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2342      else.
2343   */
2344   _G.receiveOffset = 0;
2345
2346 #if 0
2347   /* PENDING: hack */
2348   if (!IS_STATIC (sym->etype))
2349     {
2350       addSetIfnotP (&publics, sym);
2351     }
2352 #endif
2353
2354   /* Record the last function name for debugging. */
2355   _G.lastFunctionName = sym->rname;
2356   
2357   /* Create the function header */
2358   emit2 ("!functionheader", sym->name);
2359   /* PENDING: portability. */
2360   emit2 ("__%s_start:", sym->rname);
2361   emit2 ("!functionlabeldef", sym->rname);
2362
2363   if (options.profile) 
2364     {
2365       emit2 ("!profileenter");
2366     }
2367
2368   fetype = getSpec (operandType (IC_LEFT (ic)));
2369
2370   /* if critical function then turn interrupts off */
2371   if (SPEC_CRTCL (fetype))
2372     emit2 ("!di");
2373
2374   /* if this is an interrupt service routine then save all potentially used registers. */
2375   if (IS_ISR (sym->etype))
2376     {
2377       emit2 ("!pusha");
2378     }
2379
2380   /* PENDING: callee-save etc */
2381
2382   _G.stack.param_offset = 0;
2383
2384 #if CALLEE_SAVES
2385   /* Detect which registers are used. */
2386   if (sym->regsUsed)
2387     {
2388       int i;
2389       for (i = 0; i < sym->regsUsed->size; i++)
2390         {
2391           if (bitVectBitValue (sym->regsUsed, i))
2392             {
2393               switch (i)
2394                 {
2395                 case C_IDX:
2396                 case B_IDX:
2397                   bcInUse = TRUE;
2398                   break;
2399                 case D_IDX:
2400                 case E_IDX:
2401                   if (IS_Z80) {
2402                     deInUse = TRUE;
2403                   }
2404                   else {
2405                     /* Other systems use DE as a temporary. */
2406                   }
2407                   break;
2408                 }
2409             }
2410         }
2411     }
2412
2413   if (bcInUse) 
2414     {
2415       emit2 ("push bc");
2416       _G.stack.param_offset += 2;
2417     }
2418
2419   _G.stack.pushedBC = bcInUse;
2420
2421   if (deInUse)
2422     {
2423       emit2 ("push de");
2424       _G.stack.param_offset += 2;
2425     }
2426
2427   _G.stack.pushedDE = deInUse;
2428 #endif
2429
2430   /* adjust the stack for the function */
2431   _G.stack.last = sym->stack;
2432
2433   if (sym->stack)
2434     emit2 ("!enterx", sym->stack);
2435   else
2436     emit2 ("!enter");
2437   _G.stack.offset = sym->stack;
2438 }
2439
2440 /*-----------------------------------------------------------------*/
2441 /* genEndFunction - generates epilogue for functions               */
2442 /*-----------------------------------------------------------------*/
2443 static void
2444 genEndFunction (iCode * ic)
2445 {
2446   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2447
2448   if (IS_ISR (sym->etype))
2449     {
2450       wassert (0);
2451     }
2452   else
2453     {
2454       if (SPEC_CRTCL (sym->etype))
2455         emit2 ("!ei");
2456
2457       /* PENDING: calleeSave */
2458
2459       if (_G.stack.offset)
2460         {
2461           emit2 ("!leavex", _G.stack.offset);
2462         }
2463       else
2464         {
2465           emit2 ("!leave");
2466         }
2467
2468 #if CALLEE_SAVES
2469       if (_G.stack.pushedDE) 
2470         {
2471           emit2 ("pop de");
2472           _G.stack.pushedDE = FALSE;
2473         }
2474
2475       if (_G.stack.pushedDE) 
2476         {
2477           emit2 ("pop bc");
2478           _G.stack.pushedDE = FALSE;
2479         }
2480 #endif
2481
2482       if (options.profile) 
2483         {
2484           emit2 ("!profileexit");
2485         }
2486
2487
2488       /* Both baned and non-banked just ret */
2489       emit2 ("ret");
2490
2491       /* PENDING: portability. */
2492       emit2 ("__%s_end:", sym->rname);
2493     }
2494   _G.flushStatics = 1;
2495   _G.stack.pushed = 0;
2496   _G.stack.offset = 0;
2497 }
2498
2499 /*-----------------------------------------------------------------*/
2500 /* genRet - generate code for return statement                     */
2501 /*-----------------------------------------------------------------*/
2502 static void
2503 genRet (iCode * ic)
2504 {
2505     const char *l;
2506   /* Errk.  This is a hack until I can figure out how
2507      to cause dehl to spill on a call */
2508   int size, offset = 0;
2509
2510   /* if we have no return value then
2511      just generate the "ret" */
2512   if (!IC_LEFT (ic))
2513     goto jumpret;
2514
2515   /* we have something to return then
2516      move the return value into place */
2517   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2518   size = AOP_SIZE (IC_LEFT (ic));
2519
2520   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2521     {
2522       if (IS_GB)
2523         {
2524           emit2 ("ld de,%s", l);
2525         }
2526       else
2527         {
2528           emit2 ("ld hl,%s", l);
2529         }
2530     }
2531   else
2532     {
2533       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2534         {
2535           fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2536           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2537         }
2538       else
2539         {
2540           while (size--)
2541             {
2542               l = aopGet (AOP (IC_LEFT (ic)), offset,
2543                           FALSE);
2544               if (strcmp (_fReturn[offset], l))
2545                 emit2 ("ld %s,%s", _fReturn[offset++], l);
2546             }
2547         }
2548     }
2549   freeAsmop (IC_LEFT (ic), NULL, ic);
2550
2551 jumpret:
2552   /* generate a jump to the return label
2553      if the next is not the return statement */
2554   if (!(ic->next && ic->next->op == LABEL &&
2555         IC_LABEL (ic->next) == returnLabel))
2556
2557     emit2 ("jp !tlabel", returnLabel->key + 100);
2558 }
2559
2560 /*-----------------------------------------------------------------*/
2561 /* genLabel - generates a label                                    */
2562 /*-----------------------------------------------------------------*/
2563 static void
2564 genLabel (iCode * ic)
2565 {
2566   /* special case never generate */
2567   if (IC_LABEL (ic) == entryLabel)
2568     return;
2569
2570   emitLabel (IC_LABEL (ic)->key + 100);
2571 }
2572
2573 /*-----------------------------------------------------------------*/
2574 /* genGoto - generates a ljmp                                      */
2575 /*-----------------------------------------------------------------*/
2576 static void
2577 genGoto (iCode * ic)
2578 {
2579   emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2580 }
2581
2582 /*-----------------------------------------------------------------*/
2583 /* genPlusIncr :- does addition with increment if possible         */
2584 /*-----------------------------------------------------------------*/
2585 static bool
2586 genPlusIncr (iCode * ic)
2587 {
2588   unsigned int icount;
2589   unsigned int size = getDataSize (IC_RESULT (ic));
2590   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2591
2592   /* will try to generate an increment */
2593   /* if the right side is not a literal
2594      we cannot */
2595   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2596     return FALSE;
2597
2598   emitDebug ("; genPlusIncr");
2599
2600   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2601
2602   /* If result is a pair */
2603   if (resultId != PAIR_INVALID)
2604     {
2605       if (isLitWord (AOP (IC_LEFT (ic))))
2606         {
2607           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2608           return TRUE;
2609         }
2610       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2611         {
2612           fetchPair (resultId, AOP (IC_RIGHT (ic)));
2613           emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2614           return TRUE;
2615         }
2616       if (icount > 5)
2617         return FALSE;
2618       /* Inc a pair */
2619       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2620         {
2621           if (icount > 2)
2622             return FALSE;
2623           movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2624           movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2625         }
2626       while (icount--)
2627         {
2628           emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2629         }
2630       return TRUE;
2631     }
2632
2633   /* if the literal value of the right hand side
2634      is greater than 4 then it is not worth it */
2635   if (icount > 4)
2636     return FALSE;
2637
2638   /* if increment 16 bits in register */
2639   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2640       size > 1 &&
2641       icount == 1
2642     )
2643     {
2644       int offset = 0;
2645       symbol *tlbl = NULL;
2646       tlbl = newiTempLabel (NULL);
2647       while (size--)
2648         {
2649           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2650           if (size)
2651             {
2652               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2653             }
2654         }
2655       emitLabel (tlbl->key + 100);
2656       return TRUE;
2657     }
2658
2659   /* if the sizes are greater than 1 then we cannot */
2660   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2661       AOP_SIZE (IC_LEFT (ic)) > 1)
2662     return FALSE;
2663
2664   /* we can if the aops of the left & result match or
2665      if they are in registers and the registers are the
2666      same */
2667   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2668     {
2669       while (icount--)
2670         {
2671           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2672         }
2673       return TRUE;
2674     }
2675
2676   return FALSE;
2677 }
2678
2679 /*-----------------------------------------------------------------*/
2680 /* outBitAcc - output a bit in acc                                 */
2681 /*-----------------------------------------------------------------*/
2682 void
2683 outBitAcc (operand * result)
2684 {
2685   symbol *tlbl = newiTempLabel (NULL);
2686   /* if the result is a bit */
2687   if (AOP_TYPE (result) == AOP_CRY)
2688     {
2689       wassert (0);
2690     }
2691   else
2692     {
2693       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2694       emit2 ("ld a,!one");
2695       emitLabel (tlbl->key + 100);
2696       outAcc (result);
2697     }
2698 }
2699
2700 /*-----------------------------------------------------------------*/
2701 /* genPlus - generates code for addition                           */
2702 /*-----------------------------------------------------------------*/
2703 static void
2704 genPlus (iCode * ic)
2705 {
2706   int size, offset = 0;
2707
2708   /* special cases :- */
2709
2710   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2711   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2712   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2713
2714   /* Swap the left and right operands if:
2715
2716      if literal, literal on the right or
2717      if left requires ACC or right is already
2718      in ACC */
2719
2720   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2721       (AOP_NEEDSACC (IC_LEFT (ic))) ||
2722       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2723     {
2724       operand *t = IC_RIGHT (ic);
2725       IC_RIGHT (ic) = IC_LEFT (ic);
2726       IC_LEFT (ic) = t;
2727     }
2728
2729   /* if both left & right are in bit
2730      space */
2731   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2732       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2733     {
2734       /* Cant happen */
2735       wassert (0);
2736     }
2737
2738   /* if left in bit space & right literal */
2739   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2740       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2741     {
2742       /* Can happen I guess */
2743       wassert (0);
2744     }
2745
2746   /* if I can do an increment instead
2747      of add then GOOD for ME */
2748   if (genPlusIncr (ic) == TRUE)
2749     goto release;
2750
2751   emitDebug ("; genPlusIncr failed");
2752
2753   size = getDataSize (IC_RESULT (ic));
2754
2755   /* Special case when left and right are constant */
2756   if (isPair (AOP (IC_RESULT (ic))))
2757     {
2758       char *left, *right;
2759
2760       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2761       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2762       if (left && right)
2763         {
2764           /* It's a pair */
2765           /* PENDING: fix */
2766           char buffer[100];
2767           sprintf (buffer, "#(%s + %s)", left, right);
2768           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2769           goto release;
2770         }
2771     }
2772
2773   if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2774     {
2775       /* Fetch into HL then do the add */
2776       spillPair (PAIR_HL);
2777       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2778       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2779       goto release;
2780     }
2781
2782   /* Special case:
2783      ld hl,sp+n trashes C so we cant afford to do it during an
2784      add with stack based varibles.  Worst case is:
2785      ld  hl,sp+left
2786      ld  a,(hl)
2787      ld  hl,sp+right
2788      add (hl)
2789      ld  hl,sp+result
2790      ld  (hl),a
2791      ld  hl,sp+left+1
2792      ld  a,(hl)
2793      ld  hl,sp+right+1
2794      adc (hl)
2795      ld  hl,sp+result+1
2796      ld  (hl),a
2797      So you cant afford to load up hl if either left, right, or result
2798      is on the stack (*sigh*)  The alt is:
2799      ld  hl,sp+left
2800      ld  de,(hl)
2801      ld  hl,sp+right
2802      ld  hl,(hl)
2803      add hl,de
2804      ld  hl,sp+result
2805      ld  (hl),hl
2806      Combinations in here are:
2807      * If left or right are in bc then the loss is small - trap later
2808      * If the result is in bc then the loss is also small
2809    */
2810   if (IS_GB)
2811     {
2812       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2813           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2814           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2815         {
2816           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2817                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2818               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2819                AOP_SIZE (IC_RIGHT (ic)) <= 2))
2820             {
2821               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2822                 {
2823                   /* Swap left and right */
2824                   operand *t = IC_RIGHT (ic);
2825                   IC_RIGHT (ic) = IC_LEFT (ic);
2826                   IC_LEFT (ic) = t;
2827                 }
2828               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2829                 {
2830                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2831                   emit2 ("add hl,bc");
2832                 }
2833               else
2834                 {
2835                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2836                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2837                   emit2 ("add hl,de");
2838                 }
2839               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2840               goto release;
2841             }
2842           else if (size == 4)
2843             {
2844               emitDebug ("; WARNING: This add is probably broken.\n");
2845             }
2846         }
2847     }
2848
2849   while (size--)
2850     {
2851       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2852         {
2853           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2854           if (offset == 0)
2855             emit2 ("add a,%s",
2856                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2857           else
2858             emit2 ("adc a,%s",
2859                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2860         }
2861       else
2862         {
2863           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2864           if (offset == 0)
2865             emit2 ("add a,%s",
2866                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2867           else
2868             emit2 ("adc a,%s",
2869                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2870         }
2871       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2872     }
2873
2874 release:
2875   freeAsmop (IC_LEFT (ic), NULL, ic);
2876   freeAsmop (IC_RIGHT (ic), NULL, ic);
2877   freeAsmop (IC_RESULT (ic), NULL, ic);
2878
2879 }
2880
2881 /*-----------------------------------------------------------------*/
2882 /* genMinusDec :- does subtraction with deccrement if possible     */
2883 /*-----------------------------------------------------------------*/
2884 static bool
2885 genMinusDec (iCode * ic)
2886 {
2887   unsigned int icount;
2888   unsigned int size = getDataSize (IC_RESULT (ic));
2889
2890   /* will try to generate an increment */
2891   /* if the right side is not a literal we cannot */
2892   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2893     return FALSE;
2894
2895   /* if the literal value of the right hand side
2896      is greater than 4 then it is not worth it */
2897   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2898     return FALSE;
2899
2900   size = getDataSize (IC_RESULT (ic));
2901
2902   /* if decrement 16 bits in register */
2903   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2904       (size > 1) && isPair (AOP (IC_RESULT (ic))))
2905     {
2906       while (icount--)
2907         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2908       return TRUE;
2909     }
2910
2911   /* If result is a pair */
2912   if (isPair (AOP (IC_RESULT (ic))))
2913     {
2914       movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2915       movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2916       while (icount--)
2917         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2918       return TRUE;
2919     }
2920
2921   /* if increment 16 bits in register */
2922   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2923       (size == 2))
2924     {
2925       fetchPair (PAIR_HL, AOP (IC_RESULT (ic)));
2926
2927       while (icount--) {
2928         emit2 ("dec hl");
2929       }
2930       aopPut (AOP (IC_RESULT (ic)), "l", LSB);
2931       aopPut (AOP (IC_RESULT (ic)), "h", MSB16);
2932
2933       return TRUE;
2934     }
2935
2936
2937   /* if the sizes are greater than 1 then we cannot */
2938   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2939       AOP_SIZE (IC_LEFT (ic)) > 1)
2940     return FALSE;
2941
2942   /* we can if the aops of the left & result match or if they are in
2943      registers and the registers are the same */
2944   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2945     {
2946       while (icount--)
2947         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
2948       return TRUE;
2949     }
2950
2951   return FALSE;
2952 }
2953
2954 /*-----------------------------------------------------------------*/
2955 /* genMinus - generates code for subtraction                       */
2956 /*-----------------------------------------------------------------*/
2957 static void
2958 genMinus (iCode * ic)
2959 {
2960   int size, offset = 0;
2961   unsigned long lit = 0L;
2962
2963   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2964   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2965   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2966
2967   /* special cases :- */
2968   /* if both left & right are in bit space */
2969   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2970       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2971     {
2972       wassert (0);
2973       goto release;
2974     }
2975
2976   /* if I can do an decrement instead of subtract then GOOD for ME */
2977   if (genMinusDec (ic) == TRUE)
2978     goto release;
2979
2980   size = getDataSize (IC_RESULT (ic));
2981
2982   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2983     {
2984     }
2985   else
2986     {
2987       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2988       lit = -(long) lit;
2989     }
2990
2991   /* Same logic as genPlus */
2992   if (IS_GB)
2993     {
2994       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2995           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2996           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2997         {
2998           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2999                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3000               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3001                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3002             {
3003               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3004               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3005
3006               if (left == PAIR_INVALID && right == PAIR_INVALID)
3007                 {
3008                   left = PAIR_DE;
3009                   right = PAIR_HL;
3010                 }
3011               else if (right == PAIR_INVALID)
3012                 right = PAIR_DE;
3013               else if (left == PAIR_INVALID)
3014                 left = PAIR_DE;
3015
3016               fetchPair (left, AOP (IC_LEFT (ic)));
3017               /* Order is important.  Right may be HL */
3018               fetchPair (right, AOP (IC_RIGHT (ic)));
3019
3020               emit2 ("ld a,%s", _pairs[left].l);
3021               emit2 ("sub a,%s", _pairs[right].l);
3022               emit2 ("ld e,a");
3023               emit2 ("ld a,%s", _pairs[left].h);
3024               emit2 ("sbc a,%s", _pairs[right].h);
3025
3026               aopPut (AOP (IC_RESULT (ic)), "a", 1);
3027               aopPut (AOP (IC_RESULT (ic)), "e", 0);
3028               goto release;
3029             }
3030           else if (size == 4)
3031             {
3032               emitDebug ("; WARNING: This sub is probably broken.\n");
3033             }
3034         }
3035     }
3036
3037   /* if literal, add a,#-lit, else normal subb */
3038   while (size--)
3039     {
3040       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3041       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3042         {
3043           if (!offset)
3044             emit2 ("sub a,%s",
3045                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3046           else
3047             emit2 ("sbc a,%s",
3048                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3049         }
3050       else
3051         {
3052           /* first add without previous c */
3053           if (!offset)
3054             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3055           else
3056             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3057         }
3058       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3059     }
3060
3061   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3062       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3063       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3064     wassert (0);
3065
3066 release:
3067   freeAsmop (IC_LEFT (ic), NULL, ic);
3068   freeAsmop (IC_RIGHT (ic), NULL, ic);
3069   freeAsmop (IC_RESULT (ic), NULL, ic);
3070 }
3071
3072 /*-----------------------------------------------------------------*/
3073 /* genMult - generates code for multiplication                     */
3074 /*-----------------------------------------------------------------*/
3075 static void
3076 genMult (iCode * ic)
3077 {
3078   /* Shouldn't occur - all done through function calls */
3079   wassert (0);
3080 }
3081
3082 /*-----------------------------------------------------------------*/
3083 /* genDiv - generates code for division                            */
3084 /*-----------------------------------------------------------------*/
3085 static void
3086 genDiv (iCode * ic)
3087 {
3088   /* Shouldn't occur - all done through function calls */
3089   wassert (0);
3090 }
3091
3092 /*-----------------------------------------------------------------*/
3093 /* genMod - generates code for division                            */
3094 /*-----------------------------------------------------------------*/
3095 static void
3096 genMod (iCode * ic)
3097 {
3098   /* Shouldn't occur - all done through function calls */
3099   wassert (0);
3100 }
3101
3102 /*-----------------------------------------------------------------*/
3103 /* genIfxJump :- will create a jump depending on the ifx           */
3104 /*-----------------------------------------------------------------*/
3105 static void
3106 genIfxJump (iCode * ic, char *jval)
3107 {
3108   symbol *jlbl;
3109   const char *inst;
3110
3111   /* if true label then we jump if condition
3112      supplied is true */
3113   if (IC_TRUE (ic))
3114     {
3115       jlbl = IC_TRUE (ic);
3116       if (!strcmp (jval, "a"))
3117         {
3118           inst = "nz";
3119         }
3120       else if (!strcmp (jval, "c"))
3121         {
3122           inst = "c";
3123         }
3124       else if (!strcmp (jval, "nc"))
3125         {
3126           inst = "nc";
3127         }
3128       else
3129         {
3130           /* The buffer contains the bit on A that we should test */
3131           inst = "nz";
3132         }
3133     }
3134   else
3135     {
3136       /* false label is present */
3137       jlbl = IC_FALSE (ic);
3138       if (!strcmp (jval, "a"))
3139         {
3140           inst = "z";
3141         }
3142       else if (!strcmp (jval, "c"))
3143         {
3144           inst = "nc";
3145         }
3146       else if (!strcmp (jval, "nc"))
3147         {
3148           inst = "c";
3149         }
3150       else
3151         {
3152           /* The buffer contains the bit on A that we should test */
3153           inst = "z";
3154         }
3155     }
3156   /* Z80 can do a conditional long jump */
3157   if (!strcmp (jval, "a"))
3158     {
3159       emit2 ("or a,a");
3160     }
3161   else if (!strcmp (jval, "c"))
3162     {
3163     }
3164   else if (!strcmp (jval, "nc"))
3165     {
3166     }
3167   else
3168     {
3169       emit2 ("bit %s,a", jval);
3170     }
3171   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3172
3173   /* mark the icode as generated */
3174   ic->generated = 1;
3175 }
3176
3177 static const char *
3178 _getPairIdName (PAIR_ID id)
3179 {
3180   return _pairs[id].name;
3181 }
3182
3183 /** Generic compare for > or <
3184  */
3185 static void
3186 genCmp (operand * left, operand * right,
3187         operand * result, iCode * ifx, int sign)
3188 {
3189   int size, offset = 0;
3190   unsigned long lit = 0L;
3191   bool swap_sense = FALSE;
3192
3193   /* if left & right are bit variables */
3194   if (AOP_TYPE (left) == AOP_CRY &&
3195       AOP_TYPE (right) == AOP_CRY)
3196     {
3197       /* Cant happen on the Z80 */
3198       wassert (0);
3199     }
3200   else
3201     {
3202       /* subtract right from left if at the
3203          end the carry flag is set then we know that
3204          left is greater than right */
3205       size = max (AOP_SIZE (left), AOP_SIZE (right));
3206
3207       /* if unsigned char cmp with lit, just compare */
3208       if ((size == 1) &&
3209           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3210         {
3211           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3212           if (sign)
3213             {
3214               emit2 ("xor a,!immedbyte", 0x80);
3215               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3216             }
3217           else
3218             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3219         }
3220       else
3221         {
3222           /* Special cases:
3223              On the GB:
3224              If the left or the right is a lit:
3225              Load -lit into HL, add to right via, check sense.
3226            */
3227           if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3228             {
3229               PAIR_ID id = PAIR_DE;
3230               asmop *lit = AOP (right);
3231               asmop *op = AOP (left);
3232               swap_sense = TRUE;
3233
3234               if (AOP_TYPE (left) == AOP_LIT)
3235                 {
3236                   swap_sense = FALSE;
3237                   lit = AOP (left);
3238                   op = AOP (right);
3239                 }
3240               if (sign)
3241                 {
3242                   emit2 ("ld e,%s", aopGet (op, 0, 0));
3243                   emit2 ("ld a,%s", aopGet (op, 1, 0));
3244                   emit2 ("xor a,!immedbyte", 0x80);
3245                   emit2 ("ld d,a");
3246                 }
3247               else
3248                 {
3249                   id = getPairId (op);
3250                   if (id == PAIR_INVALID)
3251                     {
3252                       fetchPair (PAIR_DE, op);
3253                       id = PAIR_DE;
3254                     }
3255                 }
3256               spillPair (PAIR_HL);
3257               emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3258               emit2 ("add hl,%s", _getPairIdName (id));
3259               goto release;
3260             }
3261           if (AOP_TYPE (right) == AOP_LIT)
3262             {
3263               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3264               /* optimize if(x < 0) or if(x >= 0) */
3265               if (lit == 0L)
3266                 {
3267                   if (!sign)
3268                     {
3269                       /* No sign so it's always false */
3270                       _clearCarry();
3271                     }
3272                   else
3273                     {
3274                       /* Just load in the top most bit */
3275                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3276                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3277                         {
3278                           genIfxJump (ifx, "7");
3279                           return;
3280                         }
3281                       else
3282                         emit2 ("rlc a");
3283                     }
3284                   goto release;
3285                 }
3286             }
3287           if (sign)
3288             {
3289               /* First setup h and l contaning the top most bytes XORed */
3290               bool fDidXor = FALSE;
3291               if (AOP_TYPE (left) == AOP_LIT)
3292                 {
3293                   unsigned long lit = (unsigned long)
3294                   floatFromVal (AOP (left)->aopu.aop_lit);
3295                   emit2 ("ld %s,!immedbyte", _fTmp[0],
3296                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3297                 }
3298               else
3299                 {
3300                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3301                   emit2 ("xor a,!immedbyte", 0x80);
3302                   emit2 ("ld %s,a", _fTmp[0]);
3303                   fDidXor = TRUE;
3304                 }
3305               if (AOP_TYPE (right) == AOP_LIT)
3306                 {
3307                   unsigned long lit = (unsigned long)
3308                   floatFromVal (AOP (right)->aopu.aop_lit);
3309                   emit2 ("ld %s,!immedbyte", _fTmp[1],
3310                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3311                 }
3312               else
3313                 {
3314                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3315                   emit2 ("xor a,!immedbyte", 0x80);
3316                   emit2 ("ld %s,a", _fTmp[1]);
3317                   fDidXor = TRUE;
3318                 }
3319               if (!fDidXor)
3320                 _clearCarry();
3321             }
3322           else
3323             {
3324               _clearCarry();
3325             }
3326           while (size--)
3327             {
3328               /* Do a long subtract */
3329               if (!sign || size)
3330                 {
3331                   _moveA (aopGet (AOP (left), offset, FALSE));
3332                 }
3333               if (sign && size == 0)
3334                 {
3335                   emit2 ("ld a,%s", _fTmp[0]);
3336                   emit2 ("sbc a,%s", _fTmp[1]);
3337                 }
3338               else
3339                 {
3340                   /* Subtract through, propagating the carry */
3341                   emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
3342                 }
3343             }
3344         }
3345     }
3346
3347 release:
3348   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3349     {
3350       outBitCLong (result, swap_sense);
3351     }
3352   else
3353     {
3354       /* if the result is used in the next
3355          ifx conditional branch then generate
3356          code a little differently */
3357       if (ifx)
3358         genIfxJump (ifx, swap_sense ? "nc" : "c");
3359       else
3360         outBitCLong (result, swap_sense);
3361       /* leave the result in acc */
3362     }
3363 }
3364
3365 /*-----------------------------------------------------------------*/
3366 /* genCmpGt :- greater than comparison                             */
3367 /*-----------------------------------------------------------------*/
3368 static void
3369 genCmpGt (iCode * ic, iCode * ifx)
3370 {
3371   operand *left, *right, *result;
3372   sym_link *letype, *retype;
3373   int sign;
3374
3375   left = IC_LEFT (ic);
3376   right = IC_RIGHT (ic);
3377   result = IC_RESULT (ic);
3378
3379   letype = getSpec (operandType (left));
3380   retype = getSpec (operandType (right));
3381   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3382   /* assign the amsops */
3383   aopOp (left, ic, FALSE, FALSE);
3384   aopOp (right, ic, FALSE, FALSE);
3385   aopOp (result, ic, TRUE, FALSE);
3386
3387   genCmp (right, left, result, ifx, sign);
3388
3389   freeAsmop (left, NULL, ic);
3390   freeAsmop (right, NULL, ic);
3391   freeAsmop (result, NULL, ic);
3392 }
3393
3394 /*-----------------------------------------------------------------*/
3395 /* genCmpLt - less than comparisons                                */
3396 /*-----------------------------------------------------------------*/
3397 static void
3398 genCmpLt (iCode * ic, iCode * ifx)
3399 {
3400   operand *left, *right, *result;
3401   sym_link *letype, *retype;
3402   int sign;
3403
3404   left = IC_LEFT (ic);
3405   right = IC_RIGHT (ic);
3406   result = IC_RESULT (ic);
3407
3408   letype = getSpec (operandType (left));
3409   retype = getSpec (operandType (right));
3410   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3411
3412   /* assign the amsops */
3413   aopOp (left, ic, FALSE, FALSE);
3414   aopOp (right, ic, FALSE, FALSE);
3415   aopOp (result, ic, TRUE, FALSE);
3416
3417   genCmp (left, right, result, ifx, sign);
3418
3419   freeAsmop (left, NULL, ic);
3420   freeAsmop (right, NULL, ic);
3421   freeAsmop (result, NULL, ic);
3422 }
3423
3424 /*-----------------------------------------------------------------*/
3425 /* gencjneshort - compare and jump if not equal                    */
3426 /*-----------------------------------------------------------------*/
3427 static void
3428 gencjneshort (operand * left, operand * right, symbol * lbl)
3429 {
3430   int size = max (AOP_SIZE (left), AOP_SIZE (right));
3431   int offset = 0;
3432   unsigned long lit = 0L;
3433
3434   /* Swap the left and right if it makes the computation easier */
3435   if (AOP_TYPE (left) == AOP_LIT)
3436     {
3437       operand *t = right;
3438       right = left;
3439       left = t;
3440     }
3441
3442   if (AOP_TYPE (right) == AOP_LIT)
3443     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3444
3445   /* if the right side is a literal then anything goes */
3446   if (AOP_TYPE (right) == AOP_LIT &&
3447       AOP_TYPE (left) != AOP_DIR)
3448     {
3449       if (lit == 0)
3450         {
3451           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3452           if (size > 1)
3453             {
3454               size--;
3455               offset++;
3456               while (size--)
3457                 {
3458                   emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3459                 }
3460             }
3461           else
3462             {
3463               emit2 ("or a,a");
3464             }
3465           emit2 ("jp nz,!tlabel", lbl->key + 100);
3466         }
3467       else
3468         {
3469           while (size--)
3470             {
3471               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3472               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3473                 emit2 ("or a,a");
3474               else
3475                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3476               emit2 ("jp nz,!tlabel", lbl->key + 100);
3477               offset++;
3478             }
3479         }
3480     }
3481   /* if the right side is in a register or in direct space or
3482      if the left is a pointer register & right is not */
3483   else if (AOP_TYPE (right) == AOP_REG ||
3484            AOP_TYPE (right) == AOP_DIR ||
3485            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3486     {
3487       while (size--)
3488         {
3489           _moveA (aopGet (AOP (left), offset, FALSE));
3490           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3491               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3492             /* PENDING */
3493             emit2 ("jp nz,!tlabel", lbl->key + 100);
3494           else
3495             {
3496               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3497               emit2 ("jp nz,!tlabel", lbl->key + 100);
3498             }
3499           offset++;
3500         }
3501     }
3502   else
3503     {
3504       /* right is a pointer reg need both a & b */
3505       /* PENDING: is this required? */
3506       while (size--)
3507         {
3508           _moveA (aopGet (AOP (right), offset, FALSE));
3509           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3510           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3511           offset++;
3512         }
3513     }
3514 }
3515
3516 /*-----------------------------------------------------------------*/
3517 /* gencjne - compare and jump if not equal                         */
3518 /*-----------------------------------------------------------------*/
3519 static void
3520 gencjne (operand * left, operand * right, symbol * lbl)
3521 {
3522   symbol *tlbl = newiTempLabel (NULL);
3523
3524   gencjneshort (left, right, lbl);
3525
3526   /* PENDING: ?? */
3527   emit2 ("ld a,!one");
3528   emit2 ("!shortjp !tlabel", tlbl->key + 100);
3529   emitLabel (lbl->key + 100);
3530   emit2 ("xor a,a");
3531   emitLabel (tlbl->key + 100);
3532 }
3533
3534 /*-----------------------------------------------------------------*/
3535 /* genCmpEq - generates code for equal to                          */
3536 /*-----------------------------------------------------------------*/
3537 static void
3538 genCmpEq (iCode * ic, iCode * ifx)
3539 {
3540   operand *left, *right, *result;
3541
3542   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3543   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3544   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3545
3546   emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3547
3548   /* Swap operands if it makes the operation easier. ie if:
3549      1.  Left is a literal.
3550    */
3551   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3552     {
3553       operand *t = IC_RIGHT (ic);
3554       IC_RIGHT (ic) = IC_LEFT (ic);
3555       IC_LEFT (ic) = t;
3556     }
3557
3558   if (ifx && !AOP_SIZE (result))
3559     {
3560       symbol *tlbl;
3561       /* if they are both bit variables */
3562       if (AOP_TYPE (left) == AOP_CRY &&
3563           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3564         {
3565           wassert (0);
3566         }
3567       else
3568         {
3569           tlbl = newiTempLabel (NULL);
3570           gencjneshort (left, right, tlbl);
3571           if (IC_TRUE (ifx))
3572             {
3573               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3574               emitLabel (tlbl->key + 100);
3575             }
3576           else
3577             {
3578               /* PENDING: do this better */
3579               symbol *lbl = newiTempLabel (NULL);
3580               emit2 ("!shortjp !tlabel", lbl->key + 100);
3581               emitLabel (tlbl->key + 100);
3582               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3583               emitLabel (lbl->key + 100);
3584             }
3585         }
3586       /* mark the icode as generated */
3587       ifx->generated = 1;
3588       goto release;
3589     }
3590
3591   /* if they are both bit variables */
3592   if (AOP_TYPE (left) == AOP_CRY &&
3593       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3594     {
3595       wassert (0);
3596     }
3597   else
3598     {
3599       gencjne (left, right, newiTempLabel (NULL));
3600       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3601         {
3602           wassert (0);
3603         }
3604       if (ifx)
3605         {
3606           genIfxJump (ifx, "a");
3607           goto release;
3608         }
3609       /* if the result is used in an arithmetic operation
3610          then put the result in place */
3611       if (AOP_TYPE (result) != AOP_CRY)
3612         {
3613           outAcc (result);
3614         }
3615       /* leave the result in acc */
3616     }
3617
3618 release:
3619   freeAsmop (left, NULL, ic);
3620   freeAsmop (right, NULL, ic);
3621   freeAsmop (result, NULL, ic);
3622 }
3623
3624 /*-----------------------------------------------------------------*/
3625 /* ifxForOp - returns the icode containing the ifx for operand     */
3626 /*-----------------------------------------------------------------*/
3627 static iCode *
3628 ifxForOp (operand * op, iCode * ic)
3629 {
3630   /* if true symbol then needs to be assigned */
3631   if (IS_TRUE_SYMOP (op))
3632     return NULL;
3633
3634   /* if this has register type condition and
3635      the next instruction is ifx with the same operand
3636      and live to of the operand is upto the ifx only then */
3637   if (ic->next &&
3638       ic->next->op == IFX &&
3639       IC_COND (ic->next)->key == op->key &&
3640       OP_SYMBOL (op)->liveTo <= ic->next->seq)
3641     return ic->next;
3642
3643   return NULL;
3644 }
3645
3646 /*-----------------------------------------------------------------*/
3647 /* genAndOp - for && operation                                     */
3648 /*-----------------------------------------------------------------*/
3649 static void
3650 genAndOp (iCode * ic)
3651 {
3652   operand *left, *right, *result;
3653   symbol *tlbl;
3654
3655   /* note here that && operations that are in an if statement are
3656      taken away by backPatchLabels only those used in arthmetic
3657      operations remain */
3658   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3659   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3660   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3661
3662   /* if both are bit variables */
3663   if (AOP_TYPE (left) == AOP_CRY &&
3664       AOP_TYPE (right) == AOP_CRY)
3665     {
3666       wassert (0);
3667     }
3668   else
3669     {
3670       tlbl = newiTempLabel (NULL);
3671       _toBoolean (left);
3672       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3673       _toBoolean (right);
3674       emitLabel (tlbl->key + 100);
3675       outBitAcc (result);
3676     }
3677
3678   freeAsmop (left, NULL, ic);
3679   freeAsmop (right, NULL, ic);
3680   freeAsmop (result, NULL, ic);
3681 }
3682
3683 /*-----------------------------------------------------------------*/
3684 /* genOrOp - for || operation                                      */
3685 /*-----------------------------------------------------------------*/
3686 static void
3687 genOrOp (iCode * ic)
3688 {
3689   operand *left, *right, *result;
3690   symbol *tlbl;
3691
3692   /* note here that || operations that are in an
3693      if statement are taken away by backPatchLabels
3694      only those used in arthmetic operations remain */
3695   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3696   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3697   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3698
3699   /* if both are bit variables */
3700   if (AOP_TYPE (left) == AOP_CRY &&
3701       AOP_TYPE (right) == AOP_CRY)
3702     {
3703       wassert (0);
3704     }
3705   else
3706     {
3707       tlbl = newiTempLabel (NULL);
3708       _toBoolean (left);
3709       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3710       _toBoolean (right);
3711       emitLabel (tlbl->key + 100);
3712       outBitAcc (result);
3713     }
3714
3715   freeAsmop (left, NULL, ic);
3716   freeAsmop (right, NULL, ic);
3717   freeAsmop (result, NULL, ic);
3718 }
3719
3720 /*-----------------------------------------------------------------*/
3721 /* isLiteralBit - test if lit == 2^n                               */
3722 /*-----------------------------------------------------------------*/
3723 int
3724 isLiteralBit (unsigned long lit)
3725 {
3726   unsigned long pw[32] =
3727   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3728    0x100L, 0x200L, 0x400L, 0x800L,
3729    0x1000L, 0x2000L, 0x4000L, 0x8000L,
3730    0x10000L, 0x20000L, 0x40000L, 0x80000L,
3731    0x100000L, 0x200000L, 0x400000L, 0x800000L,
3732    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3733    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3734   int idx;
3735
3736   for (idx = 0; idx < 32; idx++)
3737     if (lit == pw[idx])
3738       return idx + 1;
3739   return 0;
3740 }
3741
3742 /*-----------------------------------------------------------------*/
3743 /* jmpTrueOrFalse -                                                */
3744 /*-----------------------------------------------------------------*/
3745 static void
3746 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3747 {
3748   // ugly but optimized by peephole
3749   if (IC_TRUE (ic))
3750     {
3751       symbol *nlbl = newiTempLabel (NULL);
3752       emit2 ("jp !tlabel", nlbl->key + 100);
3753       emitLabel (tlbl->key + 100);
3754       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3755       emitLabel (nlbl->key + 100);
3756     }
3757   else
3758     {
3759       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3760       emitLabel (tlbl->key + 100);
3761     }
3762   ic->generated = 1;
3763 }
3764
3765 /*-----------------------------------------------------------------*/
3766 /* genAnd  - code for and                                          */
3767 /*-----------------------------------------------------------------*/
3768 static void
3769 genAnd (iCode * ic, iCode * ifx)
3770 {
3771   operand *left, *right, *result;
3772   int size, offset = 0;
3773   unsigned long lit = 0L;
3774   int bytelit = 0;
3775
3776   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3777   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3778   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3779
3780 #ifdef DEBUG_TYPE
3781   emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3782             AOP_TYPE (result),
3783             AOP_TYPE (left), AOP_TYPE (right));
3784   emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3785             AOP_SIZE (result),
3786             AOP_SIZE (left), AOP_SIZE (right));
3787 #endif
3788
3789   /* if left is a literal & right is not then exchange them */
3790   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3791       AOP_NEEDSACC (left))
3792     {
3793       operand *tmp = right;
3794       right = left;
3795       left = tmp;
3796     }
3797
3798   /* if result = right then exchange them */
3799   if (sameRegs (AOP (result), AOP (right)))
3800     {
3801       operand *tmp = right;
3802       right = left;
3803       left = tmp;
3804     }
3805
3806   /* if right is bit then exchange them */
3807   if (AOP_TYPE (right) == AOP_CRY &&
3808       AOP_TYPE (left) != AOP_CRY)
3809     {
3810       operand *tmp = right;
3811       right = left;
3812       left = tmp;
3813     }
3814   if (AOP_TYPE (right) == AOP_LIT)
3815     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3816
3817   size = AOP_SIZE (result);
3818
3819   if (AOP_TYPE (left) == AOP_CRY)
3820     {
3821       wassert (0);
3822       goto release;
3823     }
3824
3825   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
3826   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
3827   if ((AOP_TYPE (right) == AOP_LIT) &&
3828       (AOP_TYPE (result) == AOP_CRY) &&
3829       (AOP_TYPE (left) != AOP_CRY))
3830     {
3831       int posbit = isLiteralBit (lit);
3832       /* left &  2^n */
3833       if (posbit)
3834         {
3835           posbit--;
3836           _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3837           // bit = left & 2^n
3838           if (size)
3839             {
3840               wassert (0);
3841               emit2 ("mov c,acc.%d", posbit & 0x07);
3842             }
3843           // if(left &  2^n)
3844           else
3845             {
3846               if (ifx)
3847                 {
3848                   sprintf (buffer, "%d", posbit & 0x07);
3849                   genIfxJump (ifx, buffer);
3850                 }
3851               else
3852                 {
3853                   wassert (0);
3854                 }
3855               goto release;
3856             }
3857         }
3858       else
3859         {
3860           symbol *tlbl = newiTempLabel (NULL);
3861           int sizel = AOP_SIZE (left);
3862           if (size)
3863             {
3864               wassert (0);
3865               emit2 ("setb c");
3866             }
3867           while (sizel--)
3868             {
3869               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3870                 {
3871                   _moveA (aopGet (AOP (left), offset, FALSE));
3872                   // byte ==  2^n ?
3873                   if ((posbit = isLiteralBit (bytelit)) != 0)
3874                     {
3875                       wassert (0);
3876                       emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
3877                     }
3878                   else
3879                     {
3880                       if (bytelit != 0x0FFL)
3881                         emit2 ("and a,%s",
3882                                   aopGet (AOP (right), offset, FALSE));
3883                       else
3884                         /* For the flags */
3885                         emit2 ("or a,a");
3886                       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3887                     }
3888                 }
3889               offset++;
3890             }
3891           // bit = left & literal
3892           if (size)
3893             {
3894               emit2 ("clr c");
3895               emit2 ("!tlabeldef", tlbl->key + 100);
3896             }
3897           // if(left & literal)
3898           else
3899             {
3900               if (ifx)
3901                 jmpTrueOrFalse (ifx, tlbl);
3902               goto release;
3903             }
3904         }
3905       outBitC (result);
3906       goto release;
3907     }
3908
3909   /* if left is same as result */
3910   if (sameRegs (AOP (result), AOP (left)))
3911     {
3912       for (; size--; offset++)
3913         {
3914           if (AOP_TYPE (right) == AOP_LIT)
3915             {
3916               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3917                 continue;
3918               else
3919                 {
3920                   if (bytelit == 0)
3921                     aopPut (AOP (result), "!zero", offset);
3922                   else
3923                     {
3924                       _moveA (aopGet (AOP (left), offset, FALSE));
3925                       emit2 ("and a,%s",
3926                                 aopGet (AOP (right), offset, FALSE));
3927                       aopPut (AOP (left), "a", offset);
3928                     }
3929                 }
3930
3931             }
3932           else
3933             {
3934               if (AOP_TYPE (left) == AOP_ACC)
3935                 {
3936                   wassert (0);
3937                 }
3938               else
3939                 {
3940                   _moveA (aopGet (AOP (left), offset, FALSE));
3941                   emit2 ("and a,%s",
3942                             aopGet (AOP (right), offset, FALSE));
3943                   aopPut (AOP (left), "a", offset);
3944                 }
3945             }
3946         }
3947     }
3948   else
3949     {
3950       // left & result in different registers
3951       if (AOP_TYPE (result) == AOP_CRY)
3952         {
3953           wassert (0);
3954         }
3955       else
3956         {
3957           for (; (size--); offset++)
3958             {
3959               // normal case
3960               // result = left & right
3961               if (AOP_TYPE (right) == AOP_LIT)
3962                 {
3963                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3964                     {
3965                       aopPut (AOP (result),
3966                               aopGet (AOP (left), offset, FALSE),
3967                               offset);
3968                       continue;
3969                     }
3970                   else if (bytelit == 0)
3971                     {
3972                       aopPut (AOP (result), "!zero", offset);
3973                       continue;
3974                     }
3975                 }
3976               // faster than result <- left, anl result,right
3977               // and better if result is SFR
3978               if (AOP_TYPE (left) == AOP_ACC)
3979                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
3980               else
3981                 {
3982                   _moveA (aopGet (AOP (left), offset, FALSE));
3983                   emit2 ("and a,%s",
3984                             aopGet (AOP (right), offset, FALSE));
3985                 }
3986               aopPut (AOP (result), "a", offset);
3987             }
3988         }
3989
3990     }
3991
3992 release:
3993   freeAsmop (left, NULL, ic);
3994   freeAsmop (right, NULL, ic);
3995   freeAsmop (result, NULL, ic);
3996 }
3997
3998 /*-----------------------------------------------------------------*/
3999 /* genOr  - code for or                                            */
4000 /*-----------------------------------------------------------------*/
4001 static void
4002 genOr (iCode * ic, iCode * ifx)
4003 {
4004   operand *left, *right, *result;
4005   int size, offset = 0;
4006   unsigned long lit = 0L;
4007
4008   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4009   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4010   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4011
4012 #if 1
4013   emitDebug ("; Type res[%d] = l[%d]&r[%d]",
4014             AOP_TYPE (result),
4015             AOP_TYPE (left), AOP_TYPE (right));
4016   emitDebug ("; Size res[%d] = l[%d]&r[%d]",
4017             AOP_SIZE (result),
4018             AOP_SIZE (left), AOP_SIZE (right));
4019 #endif
4020
4021   /* if left is a literal & right is not then exchange them */
4022   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4023       AOP_NEEDSACC (left))
4024     {
4025       operand *tmp = right;
4026       right = left;
4027       left = tmp;
4028     }
4029
4030   /* if result = right then exchange them */
4031   if (sameRegs (AOP (result), AOP (right)))
4032     {
4033       operand *tmp = right;
4034       right = left;
4035       left = tmp;
4036     }
4037
4038   /* if right is bit then exchange them */
4039   if (AOP_TYPE (right) == AOP_CRY &&
4040       AOP_TYPE (left) != AOP_CRY)
4041     {
4042       operand *tmp = right;
4043       right = left;
4044       left = tmp;
4045     }
4046   if (AOP_TYPE (right) == AOP_LIT)
4047     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4048
4049   size = AOP_SIZE (result);
4050
4051   if (AOP_TYPE (left) == AOP_CRY)
4052     {
4053       wassert (0);
4054       goto release;
4055     }
4056
4057   if ((AOP_TYPE (right) == AOP_LIT) &&
4058       (AOP_TYPE (result) == AOP_CRY) &&
4059       (AOP_TYPE (left) != AOP_CRY))
4060     {
4061       wassert (0);
4062       goto release;
4063     }
4064
4065   /* if left is same as result */
4066   if (sameRegs (AOP (result), AOP (left)))
4067     {
4068       for (; size--; offset++)
4069         {
4070           if (AOP_TYPE (right) == AOP_LIT)
4071             {
4072               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4073                 continue;
4074               else
4075                 {
4076                   _moveA (aopGet (AOP (left), offset, FALSE));
4077                   emit2 ("or a,%s",
4078                             aopGet (AOP (right), offset, FALSE));
4079                   aopPut (AOP (result), "a", offset);
4080                 }
4081             }
4082           else
4083             {
4084               if (AOP_TYPE (left) == AOP_ACC)
4085                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4086               else
4087                 {
4088                   _moveA (aopGet (AOP (left), offset, FALSE));
4089                   emit2 ("or a,%s",
4090                             aopGet (AOP (right), offset, FALSE));
4091                   aopPut (AOP (result), "a", offset);
4092                 }
4093             }
4094         }
4095     }
4096   else
4097     {
4098       // left & result in different registers
4099       if (AOP_TYPE (result) == AOP_CRY)
4100         {
4101           wassert (0);
4102         }
4103       else
4104         for (; (size--); offset++)
4105           {
4106             // normal case
4107             // result = left & right
4108             if (AOP_TYPE (right) == AOP_LIT)
4109               {
4110                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4111                   {
4112                     aopPut (AOP (result),
4113                             aopGet (AOP (left), offset, FALSE),
4114                             offset);
4115                     continue;
4116                   }
4117               }
4118             // faster than result <- left, anl result,right
4119             // and better if result is SFR
4120             if (AOP_TYPE (left) == AOP_ACC)
4121               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4122             else
4123               {
4124                 _moveA (aopGet (AOP (left), offset, FALSE));
4125                 emit2 ("or a,%s",
4126                           aopGet (AOP (right), offset, FALSE));
4127               }
4128             aopPut (AOP (result), "a", offset);
4129             /* PENDING: something weird is going on here.  Add exception. */
4130             if (AOP_TYPE (result) == AOP_ACC)
4131               break;
4132           }
4133     }
4134
4135 release:
4136   freeAsmop (left, NULL, ic);
4137   freeAsmop (right, NULL, ic);
4138   freeAsmop (result, NULL, ic);
4139 }
4140
4141 /*-----------------------------------------------------------------*/
4142 /* genXor - code for xclusive or                                   */
4143 /*-----------------------------------------------------------------*/
4144 static void
4145 genXor (iCode * ic, iCode * ifx)
4146 {
4147   operand *left, *right, *result;
4148   int size, offset = 0;
4149   unsigned long lit = 0L;
4150
4151   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4152   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4153   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4154
4155   /* if left is a literal & right is not then exchange them */
4156   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4157       AOP_NEEDSACC (left))
4158     {
4159       operand *tmp = right;
4160       right = left;
4161       left = tmp;
4162     }
4163
4164   /* if result = right then exchange them */
4165   if (sameRegs (AOP (result), AOP (right)))
4166     {
4167       operand *tmp = right;
4168       right = left;
4169       left = tmp;
4170     }
4171
4172   /* if right is bit then exchange them */
4173   if (AOP_TYPE (right) == AOP_CRY &&
4174       AOP_TYPE (left) != AOP_CRY)
4175     {
4176       operand *tmp = right;
4177       right = left;
4178       left = tmp;
4179     }
4180   if (AOP_TYPE (right) == AOP_LIT)
4181     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4182
4183   size = AOP_SIZE (result);
4184
4185   if (AOP_TYPE (left) == AOP_CRY)
4186     {
4187       wassert (0);
4188       goto release;
4189     }
4190
4191   if ((AOP_TYPE (right) == AOP_LIT) &&
4192       (AOP_TYPE (result) == AOP_CRY) &&
4193       (AOP_TYPE (left) != AOP_CRY))
4194     {
4195       wassert (0);
4196       goto release;
4197     }
4198
4199   /* if left is same as result */
4200   if (sameRegs (AOP (result), AOP (left)))
4201     {
4202       for (; size--; offset++)
4203         {
4204           if (AOP_TYPE (right) == AOP_LIT)
4205             {
4206               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4207                 continue;
4208               else
4209                 {
4210                   _moveA (aopGet (AOP (right), offset, FALSE));
4211                   emit2 ("xor a,%s",
4212                             aopGet (AOP (left), offset, FALSE));
4213                   aopPut (AOP (result), "a", offset);
4214                 }
4215             }
4216           else
4217             {
4218               if (AOP_TYPE (left) == AOP_ACC)
4219                 {
4220                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4221                 }
4222               else
4223                 {
4224                   _moveA (aopGet (AOP (right), offset, FALSE));
4225                   emit2 ("xor a,%s",
4226                             aopGet (AOP (left), offset, FALSE));
4227                   aopPut (AOP (result), "a", 0);
4228                 }
4229             }
4230         }
4231     }
4232   else
4233     {
4234       // left & result in different registers
4235       if (AOP_TYPE (result) == AOP_CRY)
4236         {
4237           wassert (0);
4238         }
4239       else
4240         for (; (size--); offset++)
4241           {
4242             // normal case
4243             // result = left & right
4244             if (AOP_TYPE (right) == AOP_LIT)
4245               {
4246                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4247                   {
4248                     aopPut (AOP (result),
4249                             aopGet (AOP (left), offset, FALSE),
4250                             offset);
4251                     continue;
4252                   }
4253               }
4254             // faster than result <- left, anl result,right
4255             // and better if result is SFR
4256             if (AOP_TYPE (left) == AOP_ACC) 
4257               {
4258                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4259               }
4260             else
4261               {
4262                 _moveA (aopGet (AOP (right), offset, FALSE));
4263                 emit2 ("xor a,%s",
4264                           aopGet (AOP (left), offset, FALSE));
4265               }
4266             aopPut (AOP (result), "a", offset);
4267           }
4268     }
4269
4270 release:
4271   freeAsmop (left, NULL, ic);
4272   freeAsmop (right, NULL, ic);
4273   freeAsmop (result, NULL, ic);
4274 }
4275
4276 /*-----------------------------------------------------------------*/
4277 /* genInline - write the inline code out                           */
4278 /*-----------------------------------------------------------------*/
4279 static void
4280 genInline (iCode * ic)
4281 {
4282   char *buffer, *bp, *bp1;
4283
4284   _G.lines.isInline += (!options.asmpeep);
4285
4286   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4287   strcpy (buffer, IC_INLINE (ic));
4288
4289   /* emit each line as a code */
4290   while (*bp)
4291     {
4292       if (*bp == '\n')
4293         {
4294           *bp++ = '\0';
4295           emit2 (bp1);
4296           bp1 = bp;
4297         }
4298       else
4299         {
4300           if (*bp == ':')
4301             {
4302               bp++;
4303               *bp = '\0';
4304               bp++;
4305               emit2 (bp1);
4306               bp1 = bp;
4307             }
4308           else
4309             bp++;
4310         }
4311     }
4312   if (bp1 != bp)
4313     emit2 (bp1);
4314   _G.lines.isInline -= (!options.asmpeep);
4315
4316 }
4317
4318 /*-----------------------------------------------------------------*/
4319 /* genRRC - rotate right with carry                                */
4320 /*-----------------------------------------------------------------*/
4321 static void
4322 genRRC (iCode * ic)
4323 {
4324   wassert (0);
4325 }
4326
4327 /*-----------------------------------------------------------------*/
4328 /* genRLC - generate code for rotate left with carry               */
4329 /*-----------------------------------------------------------------*/
4330 static void
4331 genRLC (iCode * ic)
4332 {
4333   wassert (0);
4334 }
4335
4336 /*-----------------------------------------------------------------*/
4337 /* genGetHbit - generates code get highest order bit               */
4338 /*-----------------------------------------------------------------*/
4339 static void
4340 genGetHbit (iCode * ic)
4341 {
4342   operand *left, *result;
4343   left = IC_LEFT (ic);
4344   result = IC_RESULT (ic);
4345   aopOp (left, ic, FALSE, FALSE);
4346   aopOp (result, ic, FALSE, FALSE);
4347
4348   /* get the highest order byte into a */
4349   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4350
4351   if (AOP_TYPE (result) == AOP_CRY)
4352     {
4353       emit2 ("rl a");
4354       outBitC (result);
4355     }
4356   else
4357     {
4358       emit2 ("rlc a");
4359       /* PENDING: For re-target. */
4360       emit2 ("and a,#1");
4361       outAcc (result);
4362     }
4363
4364
4365   freeAsmop (left, NULL, ic);
4366   freeAsmop (result, NULL, ic);
4367 }
4368
4369 static void
4370 emitRsh2 (asmop *aop, int size, int is_signed)
4371 {
4372   int offset = 0;
4373
4374   while (size--)
4375     {
4376       const char *l = aopGet (aop, size, FALSE);
4377       if (offset == 0)
4378         {
4379           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4380         }
4381       else
4382         {
4383           emit2 ("rr %s", l);
4384         }
4385       offset++;
4386     }
4387 }
4388
4389 /*-----------------------------------------------------------------*/
4390 /* shiftR2Left2Result - shift right two bytes from left to result  */
4391 /*-----------------------------------------------------------------*/
4392 static void
4393 shiftR2Left2Result (operand * left, int offl,
4394                     operand * result, int offr,
4395                     int shCount, int is_signed)
4396 {
4397   int size = 2;
4398   symbol *tlbl, *tlbl1;
4399
4400   movLeft2Result (left, offl, result, offr, 0);
4401   movLeft2Result (left, offl + 1, result, offr + 1, 0);
4402
4403   /*  if (AOP(result)->type == AOP_REG) { */
4404   
4405   tlbl = newiTempLabel (NULL);
4406   tlbl1 = newiTempLabel (NULL);
4407
4408   /* Left is already in result - so now do the shift */
4409   if (shCount <= 2)
4410     {
4411       while (shCount--)
4412         {
4413           emitRsh2 (AOP (result), size, is_signed);
4414         }
4415     }
4416   else
4417     {
4418       emit2 ("ld a,!immedbyte+1", shCount);
4419       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4420       emitLabel (tlbl->key + 100);
4421
4422       emitRsh2 (AOP (result), size, is_signed);
4423
4424       emitLabel (tlbl1->key + 100);
4425       emit2 ("dec a");
4426       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4427     }
4428 }
4429
4430 /*-----------------------------------------------------------------*/
4431 /* shiftL2Left2Result - shift left two bytes from left to result   */
4432 /*-----------------------------------------------------------------*/
4433 static void
4434 shiftL2Left2Result (operand * left, int offl,
4435                     operand * result, int offr, int shCount)
4436 {
4437   if (sameRegs (AOP (result), AOP (left)) &&
4438       ((offl + MSB16) == offr))
4439     {
4440       wassert (0);
4441     }
4442   else
4443     {
4444       /* Copy left into result */
4445       movLeft2Result (left, offl, result, offr, 0);
4446       movLeft2Result (left, offl + 1, result, offr + 1, 0);
4447     }
4448   /* PENDING: for now just see if it'll work. */
4449   /*if (AOP(result)->type == AOP_REG) { */
4450   {
4451     int size = 2;
4452     int offset = 0;
4453     symbol *tlbl, *tlbl1;
4454     const char *l;
4455
4456     tlbl = newiTempLabel (NULL);
4457     tlbl1 = newiTempLabel (NULL);
4458
4459     /* Left is already in result - so now do the shift */
4460     if (shCount > 1)
4461       {
4462         emit2 ("ld a,!immedbyte+1", shCount);
4463         emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4464         emitLabel (tlbl->key + 100);
4465       }
4466
4467     emit2 ("or a,a");
4468     while (size--)
4469       {
4470         l = aopGet (AOP (result), offset, FALSE);
4471
4472         emit2 ("rl %s", l);
4473
4474         offset++;
4475       }
4476     if (shCount > 1)
4477       {
4478         emitLabel (tlbl1->key + 100);
4479         emit2 ("dec a");
4480         emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4481       }
4482   }
4483 }
4484
4485 /*-----------------------------------------------------------------*/
4486 /* AccRol - rotate left accumulator by known count                 */
4487 /*-----------------------------------------------------------------*/
4488 static void
4489 AccRol (int shCount)
4490 {
4491   shCount &= 0x0007;            // shCount : 0..7
4492
4493   switch (shCount)
4494     {
4495     case 0:
4496       break;
4497     case 1:
4498       emit2 ("rl a");
4499       break;
4500     case 2:
4501       emit2 ("rl a");
4502       emit2 ("rl a");
4503       break;
4504     case 3:
4505       emit2 ("rl a");
4506       emit2 ("rl a");
4507       emit2 ("rl a");
4508       break;
4509     case 4:
4510       emit2 ("rl a");
4511       emit2 ("rl a");
4512       emit2 ("rl a");
4513       emit2 ("rl a");
4514       break;
4515     case 5:
4516       emit2 ("rr a");
4517       emit2 ("rr a");
4518       emit2 ("rr a");
4519       break;
4520     case 6:
4521       emit2 ("rr a");
4522       emit2 ("rr a");
4523       break;
4524     case 7:
4525       emit2 ("rr a");
4526       break;
4527     }
4528 }
4529
4530 /*-----------------------------------------------------------------*/
4531 /* AccLsh - left shift accumulator by known count                  */
4532 /*-----------------------------------------------------------------*/
4533 static void
4534 AccLsh (int shCount)
4535 {
4536   static const unsigned char SLMask[] =
4537     {
4538       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4539     };
4540
4541   if (shCount != 0)
4542     {
4543       if (shCount == 1)
4544         {
4545           emit2 ("add a,a");
4546         }
4547       else if (shCount == 2)
4548         {
4549           emit2 ("add a,a");
4550           emit2 ("add a,a");
4551         }
4552       else
4553         {
4554           /* rotate left accumulator */
4555           AccRol (shCount);
4556           /* and kill the lower order bits */
4557           emit2 ("and a,!immedbyte", SLMask[shCount]);
4558         }
4559     }
4560 }
4561
4562 /*-----------------------------------------------------------------*/
4563 /* shiftL1Left2Result - shift left one byte from left to result    */
4564 /*-----------------------------------------------------------------*/
4565 static void
4566 shiftL1Left2Result (operand * left, int offl,
4567                     operand * result, int offr, int shCount)
4568 {
4569   const char *l;
4570   l = aopGet (AOP (left), offl, FALSE);
4571   _moveA (l);
4572   /* shift left accumulator */
4573   AccLsh (shCount);
4574   aopPut (AOP (result), "a", offr);
4575 }
4576
4577
4578 /*-----------------------------------------------------------------*/
4579 /* genlshTwo - left shift two bytes by known amount != 0           */
4580 /*-----------------------------------------------------------------*/
4581 static void
4582 genlshTwo (operand * result, operand * left, int shCount)
4583 {
4584   int size = AOP_SIZE (result);
4585
4586   wassert (size == 2);
4587
4588   /* if shCount >= 8 */
4589   if (shCount >= 8)
4590     {
4591       shCount -= 8;
4592       if (size > 1)
4593         {
4594           if (shCount)
4595             {
4596               movLeft2Result (left, LSB, result, MSB16, 0);
4597               aopPut (AOP (result), "!zero", 0);
4598               shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4599             }
4600           else
4601             {
4602               movLeft2Result (left, LSB, result, MSB16, 0);
4603               aopPut (AOP (result), "!zero", 0);
4604             }
4605         }
4606       else
4607         {
4608           aopPut (AOP (result), "!zero", LSB);
4609         }
4610     }
4611   /*  1 <= shCount <= 7 */
4612   else
4613     {
4614       if (size == 1)
4615         {
4616           wassert (0);
4617         }
4618       else
4619         {
4620           shiftL2Left2Result (left, LSB, result, LSB, shCount);
4621         }
4622     }
4623 }
4624
4625 /*-----------------------------------------------------------------*/
4626 /* genlshOne - left shift a one byte quantity by known count       */
4627 /*-----------------------------------------------------------------*/
4628 static void
4629 genlshOne (operand * result, operand * left, int shCount)
4630 {
4631   shiftL1Left2Result (left, LSB, result, LSB, shCount);
4632 }
4633
4634 /*-----------------------------------------------------------------*/
4635 /* genLeftShiftLiteral - left shifting by known count              */
4636 /*-----------------------------------------------------------------*/
4637 static void
4638 genLeftShiftLiteral (operand * left,
4639                      operand * right,
4640                      operand * result,
4641                      iCode * ic)
4642 {
4643   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4644   int size;
4645
4646   freeAsmop (right, NULL, ic);
4647
4648   aopOp (left, ic, FALSE, FALSE);
4649   aopOp (result, ic, FALSE, FALSE);
4650
4651   size = getSize (operandType (result));
4652
4653 #if VIEW_SIZE
4654   emitDebug ("; shift left  result %d, left %d", size,
4655             AOP_SIZE (left));
4656 #endif
4657
4658   /* I suppose that the left size >= result size */
4659   if (shCount == 0)
4660     {
4661       wassert (0);
4662     }
4663
4664   else if (shCount >= (size * 8)) 
4665     {
4666       while (size--)
4667         {
4668           aopPut (AOP (result), "!zero", size);
4669         }
4670     }
4671   else
4672     {
4673       switch (size)
4674         {
4675         case 1:
4676           genlshOne (result, left, shCount);
4677           break;
4678         case 2:
4679           genlshTwo (result, left, shCount);
4680           break;
4681         case 4:
4682           wassertl (0, "Shifting of longs is currently unsupported");
4683           break;
4684         default:
4685           wassert (0);
4686         }
4687     }
4688   freeAsmop (left, NULL, ic);
4689   freeAsmop (result, NULL, ic);
4690 }
4691
4692 /*-----------------------------------------------------------------*/
4693 /* genLeftShift - generates code for left shifting                 */
4694 /*-----------------------------------------------------------------*/
4695 static void
4696 genLeftShift (iCode * ic)
4697 {
4698   int size, offset;
4699   const char *l;
4700   symbol *tlbl, *tlbl1;
4701   operand *left, *right, *result;
4702
4703   right = IC_RIGHT (ic);
4704   left = IC_LEFT (ic);
4705   result = IC_RESULT (ic);
4706
4707   aopOp (right, ic, FALSE, FALSE);
4708
4709   /* if the shift count is known then do it
4710      as efficiently as possible */
4711   if (AOP_TYPE (right) == AOP_LIT)
4712     {
4713       genLeftShiftLiteral (left, right, result, ic);
4714       return;
4715     }
4716
4717   /* shift count is unknown then we have to form a loop get the loop
4718      count in B : Note: we take only the lower order byte since
4719      shifting more that 32 bits make no sense anyway, ( the largest
4720      size of an object can be only 32 bits ) */
4721   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4722   emit2 ("inc a");
4723   freeAsmop (right, NULL, ic);
4724   aopOp (left, ic, FALSE, FALSE);
4725   aopOp (result, ic, FALSE, FALSE);
4726
4727   /* now move the left to the result if they are not the
4728      same */
4729 #if 1
4730   if (!sameRegs (AOP (left), AOP (result)))
4731     {
4732
4733       size = AOP_SIZE (result);
4734       offset = 0;
4735       while (size--)
4736         {
4737           l = aopGet (AOP (left), offset, FALSE);
4738           aopPut (AOP (result), l, offset);
4739           offset++;
4740         }
4741     }
4742 #else
4743   size = AOP_SIZE (result);
4744   offset = 0;
4745   while (size--)
4746     {
4747       l = aopGet (AOP (left), offset, FALSE);
4748       aopPut (AOP (result), l, offset);
4749       offset++;
4750     }
4751 #endif
4752
4753
4754   tlbl = newiTempLabel (NULL);
4755   size = AOP_SIZE (result);
4756   offset = 0;
4757   tlbl1 = newiTempLabel (NULL);
4758
4759   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4760   emitLabel (tlbl->key + 100);
4761   l = aopGet (AOP (result), offset, FALSE);
4762
4763   emit2 ("or a,a");
4764
4765   while (size--)
4766     {
4767       l = aopGet (AOP (result), offset++, FALSE);
4768       emit2 ("rl %s", l);
4769     }
4770   emitLabel (tlbl1->key + 100);
4771   emit2 ("dec a");
4772   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4773
4774   freeAsmop (left, NULL, ic);
4775   freeAsmop (result, NULL, ic);
4776 }
4777
4778 /*-----------------------------------------------------------------*/
4779 /* genrshOne - left shift two bytes by known amount != 0           */
4780 /*-----------------------------------------------------------------*/
4781 static void
4782 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4783 {
4784   /* Errk */
4785   int size = AOP_SIZE (result);
4786   const char *l;
4787
4788   wassert (size == 1);
4789   wassert (shCount < 8);
4790
4791   l = aopGet (AOP (left), 0, FALSE);
4792
4793   emit2 ("or a,a");
4794
4795   if (AOP (result)->type == AOP_REG)
4796     {
4797       aopPut (AOP (result), l, 0);
4798       l = aopGet (AOP (result), 0, FALSE);
4799       while (shCount--)
4800         {
4801           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4802         }
4803     }
4804   else
4805     {
4806       _moveA (l);
4807       while (shCount--)
4808         {
4809           emit2 ("%s a", is_signed ? "sra" : "srl");
4810         }
4811       aopPut (AOP (result), "a", 0);
4812     }
4813 }
4814
4815 /*-----------------------------------------------------------------*/
4816 /* AccRsh - right shift accumulator by known count                 */
4817 /*-----------------------------------------------------------------*/
4818 static void
4819 AccRsh (int shCount)
4820 {
4821   static const unsigned char SRMask[] =
4822     {
4823       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4824     };
4825
4826   if (shCount != 0)
4827     {
4828       /* rotate right accumulator */
4829       AccRol (8 - shCount);
4830       /* and kill the higher order bits */
4831       emit2 ("and a,!immedbyte", SRMask[shCount]);
4832     }
4833 }
4834
4835 /*-----------------------------------------------------------------*/
4836 /* shiftR1Left2Result - shift right one byte from left to result   */
4837 /*-----------------------------------------------------------------*/
4838 static void
4839 shiftR1Left2Result (operand * left, int offl,
4840                     operand * result, int offr,
4841                     int shCount, int sign)
4842 {
4843   _moveA (aopGet (AOP (left), offl, FALSE));
4844   if (sign)
4845     {
4846       wassert (0);
4847     }
4848   else
4849     {
4850       AccRsh (shCount);
4851     }
4852   aopPut (AOP (result), "a", offr);
4853 }
4854
4855 /*-----------------------------------------------------------------*/
4856 /* genrshTwo - right shift two bytes by known amount != 0          */
4857 /*-----------------------------------------------------------------*/
4858 static void
4859 genrshTwo (operand * result, operand * left,
4860            int shCount, int sign)
4861 {
4862   /* if shCount >= 8 */
4863   if (shCount >= 8)
4864     {
4865       shCount -= 8;
4866       if (shCount)
4867         {
4868           shiftR1Left2Result (left, MSB16, result, LSB,
4869                               shCount, sign);
4870         }
4871       else
4872         {
4873           movLeft2Result (left, MSB16, result, LSB, sign);
4874         }
4875       aopPut (AOP (result), "!zero", 1);
4876     }
4877   /*  1 <= shCount <= 7 */
4878   else
4879     {
4880       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4881     }
4882 }
4883
4884 /*-----------------------------------------------------------------*/
4885 /* genRightShiftLiteral - left shifting by known count              */
4886 /*-----------------------------------------------------------------*/
4887 static void
4888 genRightShiftLiteral (operand * left,
4889                       operand * right,
4890                       operand * result,
4891                       iCode * ic,
4892                       int sign)
4893 {
4894   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4895   int size;
4896
4897   freeAsmop (right, NULL, ic);
4898
4899   aopOp (left, ic, FALSE, FALSE);
4900   aopOp (result, ic, FALSE, FALSE);
4901
4902   size = getSize (operandType (result));
4903
4904   emitDebug ("; shift right  result %d, left %d", size,
4905             AOP_SIZE (left));
4906
4907   /* I suppose that the left size >= result size */
4908   if (shCount == 0)
4909     {
4910       wassert (0);
4911     }
4912
4913   else if (shCount >= (size * 8))
4914     while (size--)
4915       aopPut (AOP (result), "!zero", size);
4916   else
4917     {
4918       switch (size)
4919         {
4920         case 1:
4921           genrshOne (result, left, shCount, sign);
4922           break;
4923         case 2:
4924           /* PENDING: sign support */
4925           genrshTwo (result, left, shCount, sign);
4926           break;
4927         case 4:
4928           wassertl (0, "Asked to shift right a long which should be a function call");
4929           break;
4930         default:
4931           wassertl (0, "Entered default case in right shift delegate");
4932         }
4933     }
4934   freeAsmop (left, NULL, ic);
4935   freeAsmop (result, NULL, ic);
4936 }
4937
4938 /*-----------------------------------------------------------------*/
4939 /* genRightShift - generate code for right shifting                */
4940 /*-----------------------------------------------------------------*/
4941 static void
4942 genRightShift (iCode * ic)
4943 {
4944   operand *right, *left, *result;
4945   sym_link *retype;
4946   int size, offset, first = 1;
4947   const char *l;
4948   bool is_signed;
4949
4950   symbol *tlbl, *tlbl1;
4951
4952   /* if signed then we do it the hard way preserve the
4953      sign bit moving it inwards */
4954   retype = getSpec (operandType (IC_RESULT (ic)));
4955
4956   is_signed = !SPEC_USIGN (retype);
4957
4958   /* signed & unsigned types are treated the same : i.e. the
4959      signed is NOT propagated inwards : quoting from the
4960      ANSI - standard : "for E1 >> E2, is equivalent to division
4961      by 2**E2 if unsigned or if it has a non-negative value,
4962      otherwise the result is implementation defined ", MY definition
4963      is that the sign does not get propagated */
4964
4965   right = IC_RIGHT (ic);
4966   left = IC_LEFT (ic);
4967   result = IC_RESULT (ic);
4968
4969   aopOp (right, ic, FALSE, FALSE);
4970
4971   /* if the shift count is known then do it
4972      as efficiently as possible */
4973   if (AOP_TYPE (right) == AOP_LIT)
4974     {
4975       genRightShiftLiteral (left, right, result, ic, is_signed);
4976       return;
4977     }
4978
4979   aopOp (left, ic, FALSE, FALSE);
4980   aopOp (result, ic, FALSE, FALSE);
4981
4982   /* now move the left to the result if they are not the
4983      same */
4984   if (!sameRegs (AOP (left), AOP (result)) &&
4985       AOP_SIZE (result) > 1)
4986     {
4987
4988       size = AOP_SIZE (result);
4989       offset = 0;
4990       while (size--)
4991         {
4992           l = aopGet (AOP (left), offset, FALSE);
4993           aopPut (AOP (result), l, offset);
4994           offset++;
4995         }
4996     }
4997
4998   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4999   emit2 ("inc a");
5000   freeAsmop (right, NULL, ic);
5001
5002   tlbl = newiTempLabel (NULL);
5003   tlbl1 = newiTempLabel (NULL);
5004   size = AOP_SIZE (result);
5005   offset = size - 1;
5006
5007   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5008   emitLabel (tlbl->key + 100);
5009   while (size--)
5010     {
5011       l = aopGet (AOP (result), offset--, FALSE);
5012       if (first)
5013         {
5014           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5015           first = 0;
5016         }
5017       else
5018         {
5019           emit2 ("rr %s", l);
5020         }
5021     }
5022   emitLabel (tlbl1->key + 100);
5023   emit2 ("dec a");
5024   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5025
5026   freeAsmop (left, NULL, ic);
5027   freeAsmop (result, NULL, ic);
5028 }
5029
5030 /*-----------------------------------------------------------------*/
5031 /* genGenPointerGet -  get value from generic pointer space        */
5032 /*-----------------------------------------------------------------*/
5033 static void
5034 genGenPointerGet (operand * left,
5035                   operand * result, iCode * ic)
5036 {
5037   int size, offset;
5038   sym_link *retype = getSpec (operandType (result));
5039   int pair = PAIR_HL;
5040
5041   if (IS_GB)
5042     pair = PAIR_DE;
5043
5044   aopOp (left, ic, FALSE, FALSE);
5045   aopOp (result, ic, FALSE, FALSE);
5046
5047   if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5048     {
5049       /* Just do it */
5050       if (isPtrPair (AOP (left)))
5051         {
5052           tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5053           aopPut (AOP (result), buffer, 0);
5054         }
5055       else
5056         {
5057           emit2 ("ld a,!*pair", getPairName (AOP (left)));
5058           aopPut (AOP (result), "a", 0);
5059         }
5060       freeAsmop (left, NULL, ic);
5061       goto release;
5062     }
5063
5064   /* For now we always load into IY */
5065   /* if this is remateriazable */
5066   fetchPair (pair, AOP (left));
5067
5068   /* so iy now contains the address */
5069   freeAsmop (left, NULL, ic);
5070
5071   /* if bit then unpack */
5072   if (IS_BITVAR (retype))
5073     {
5074       wassert (0);
5075     }
5076   else
5077     {
5078       size = AOP_SIZE (result);
5079       offset = 0;
5080
5081       while (size--)
5082         {
5083           /* PENDING: make this better */
5084           if (!IS_GB && AOP (result)->type == AOP_REG)
5085             {
5086               aopPut (AOP (result), "!*hl", offset++);
5087             }
5088           else
5089             {
5090               emit2 ("ld a,!*pair", _pairs[pair].name);
5091               aopPut (AOP (result), "a", offset++);
5092             }
5093           if (size)
5094             {
5095               emit2 ("inc %s", _pairs[pair].name);
5096               _G.pairs[pair].offset++;
5097             }
5098         }
5099     }
5100
5101 release:
5102   freeAsmop (result, NULL, ic);
5103 }
5104
5105 /*-----------------------------------------------------------------*/
5106 /* genPointerGet - generate code for pointer get                   */
5107 /*-----------------------------------------------------------------*/
5108 static void
5109 genPointerGet (iCode * ic)
5110 {
5111   operand *left, *result;
5112   sym_link *type, *etype;
5113
5114   left = IC_LEFT (ic);
5115   result = IC_RESULT (ic);
5116
5117   /* depending on the type of pointer we need to
5118      move it to the correct pointer register */
5119   type = operandType (left);
5120   etype = getSpec (type);
5121
5122   genGenPointerGet (left, result, ic);
5123 }
5124
5125 bool
5126 isRegOrLit (asmop * aop)
5127 {
5128   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5129     return TRUE;
5130   return FALSE;
5131 }
5132
5133 /*-----------------------------------------------------------------*/
5134 /* genGenPointerSet - stores the value into a pointer location        */
5135 /*-----------------------------------------------------------------*/
5136 static void
5137 genGenPointerSet (operand * right,
5138                   operand * result, iCode * ic)
5139 {
5140   int size, offset;
5141   sym_link *retype = getSpec (operandType (right));
5142   PAIR_ID pairId = PAIR_HL;
5143
5144   aopOp (result, ic, FALSE, FALSE);
5145   aopOp (right, ic, FALSE, FALSE);
5146
5147   if (IS_GB)
5148     pairId = PAIR_DE;
5149
5150   /* Handle the exceptions first */
5151   if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5152     {
5153       /* Just do it */
5154       const char *l = aopGet (AOP (right), 0, FALSE);
5155       const char *pair = getPairName (AOP (result));
5156       if (canAssignToPtr (l) && isPtr (pair))
5157         {
5158           emit2 ("ld !*pair,%s", pair, l);
5159         }
5160       else
5161         {
5162           _moveA (l);
5163           emit2 ("ld !*pair,a", pair);
5164         }
5165       goto release;
5166     }
5167
5168   /* if the operand is already in dptr
5169      then we do nothing else we move the value to dptr */
5170   if (AOP_TYPE (result) != AOP_STR)
5171     {
5172       fetchPair (pairId, AOP (result));
5173     }
5174   /* so hl know contains the address */
5175   freeAsmop (result, NULL, ic);
5176
5177   /* if bit then unpack */
5178   if (IS_BITVAR (retype))
5179     {
5180       wassert (0);
5181     }
5182   else
5183     {
5184       size = AOP_SIZE (right);
5185       offset = 0;
5186
5187       while (size--)
5188         {
5189           const char *l = aopGet (AOP (right), offset, FALSE);
5190           if (isRegOrLit (AOP (right)) && !IS_GB)
5191             {
5192               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5193             }
5194           else
5195             {
5196               _moveA (l);
5197               emit2 ("ld !*pair,a", _pairs[pairId].name);
5198             }
5199           if (size)
5200             {
5201               emit2 ("inc %s", _pairs[pairId].name);
5202               _G.pairs[pairId].offset++;
5203             }
5204           offset++;
5205         }
5206     }
5207 release:
5208   freeAsmop (right, NULL, ic);
5209 }
5210
5211 /*-----------------------------------------------------------------*/
5212 /* genPointerSet - stores the value into a pointer location        */
5213 /*-----------------------------------------------------------------*/
5214 static void
5215 genPointerSet (iCode * ic)
5216 {
5217   operand *right, *result;
5218   sym_link *type, *etype;
5219
5220   right = IC_RIGHT (ic);
5221   result = IC_RESULT (ic);
5222
5223   /* depending on the type of pointer we need to
5224      move it to the correct pointer register */
5225   type = operandType (result);
5226   etype = getSpec (type);
5227
5228   genGenPointerSet (right, result, ic);
5229 }
5230
5231 /*-----------------------------------------------------------------*/
5232 /* genIfx - generate code for Ifx statement                        */
5233 /*-----------------------------------------------------------------*/
5234 static void
5235 genIfx (iCode * ic, iCode * popIc)
5236 {
5237   operand *cond = IC_COND (ic);
5238   int isbit = 0;
5239
5240   aopOp (cond, ic, FALSE, TRUE);
5241
5242   /* get the value into acc */
5243   if (AOP_TYPE (cond) != AOP_CRY)
5244     _toBoolean (cond);
5245   else
5246     isbit = 1;
5247   /* the result is now in the accumulator */
5248   freeAsmop (cond, NULL, ic);
5249
5250   /* if there was something to be popped then do it */
5251   if (popIc)
5252     genIpop (popIc);
5253
5254   /* if the condition is  a bit variable */
5255   if (isbit && IS_ITEMP (cond) &&
5256       SPIL_LOC (cond))
5257     genIfxJump (ic, SPIL_LOC (cond)->rname);
5258   else if (isbit && !IS_ITEMP (cond))
5259     genIfxJump (ic, OP_SYMBOL (cond)->rname);
5260   else
5261     genIfxJump (ic, "a");
5262
5263   ic->generated = 1;
5264 }
5265
5266 /*-----------------------------------------------------------------*/
5267 /* genAddrOf - generates code for address of                       */
5268 /*-----------------------------------------------------------------*/
5269 static void
5270 genAddrOf (iCode * ic)
5271 {
5272   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5273
5274   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5275
5276   /* if the operand is on the stack then we
5277      need to get the stack offset of this
5278      variable */
5279   if (IS_GB)
5280     {
5281       if (sym->onStack)
5282         {
5283           spillCached ();
5284           if (sym->stack <= 0)
5285             {
5286               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5287             }
5288           else
5289             {
5290               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5291             }
5292           emit2 ("ld d,h");
5293           emit2 ("ld e,l");
5294         }
5295       else
5296         {
5297           emit2 ("ld de,!hashedstr", sym->rname);
5298         }
5299       aopPut (AOP (IC_RESULT (ic)), "e", 0);
5300       aopPut (AOP (IC_RESULT (ic)), "d", 1);
5301     }
5302   else
5303     {
5304       spillCached ();
5305       if (sym->onStack)
5306         {
5307           /* if it has an offset  then we need to compute it */
5308           if (sym->stack > 0)
5309             emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5310           else
5311             emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5312           emit2 ("add hl,sp");
5313         }
5314       else
5315         {
5316           emit2 ("ld hl,#%s", sym->rname);
5317         }
5318       aopPut (AOP (IC_RESULT (ic)), "l", 0);
5319       aopPut (AOP (IC_RESULT (ic)), "h", 1);
5320     }
5321   freeAsmop (IC_RESULT (ic), NULL, ic);
5322 }
5323
5324 /*-----------------------------------------------------------------*/
5325 /* genAssign - generate code for assignment                        */
5326 /*-----------------------------------------------------------------*/
5327 static void
5328 genAssign (iCode * ic)
5329 {
5330   operand *result, *right;
5331   int size, offset;
5332   unsigned long lit = 0L;
5333
5334   result = IC_RESULT (ic);
5335   right = IC_RIGHT (ic);
5336
5337 #if 1
5338   /* Dont bother assigning if they are the same */
5339   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5340     {
5341       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5342       return;
5343     }
5344 #endif
5345
5346   aopOp (right, ic, FALSE, FALSE);
5347   aopOp (result, ic, TRUE, FALSE);
5348
5349   /* if they are the same registers */
5350   if (sameRegs (AOP (right), AOP (result)))
5351     {
5352       emitDebug ("; (registers are the same)");
5353       goto release;
5354     }
5355
5356   /* if the result is a bit */
5357   if (AOP_TYPE (result) == AOP_CRY)
5358     {
5359       wassert (0);
5360     }
5361
5362   /* general case */
5363   size = AOP_SIZE (result);
5364   offset = 0;
5365
5366   if (AOP_TYPE (right) == AOP_LIT)
5367     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5368   if (isPair (AOP (result)))
5369     {
5370       fetchPair (getPairId (AOP (result)), AOP (right));
5371     }
5372   else if ((size > 1) &&
5373            (AOP_TYPE (result) != AOP_REG) &&
5374            (AOP_TYPE (right) == AOP_LIT) &&
5375            !IS_FLOAT (operandType (right)) &&
5376            (lit < 256L))
5377     {
5378       bool fXored = FALSE;
5379       offset = 0;
5380       /* Work from the top down.
5381          Done this way so that we can use the cached copy of 0
5382          in A for a fast clear */
5383       while (size--)
5384         {
5385           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5386             {
5387               if (!fXored && size > 1)
5388                 {
5389                   emit2 ("xor a,a");
5390                   fXored = TRUE;
5391                 }
5392               if (fXored)
5393                 {
5394                   aopPut (AOP (result), "a", offset);
5395                 }
5396               else
5397                 {
5398                   aopPut (AOP (result), "!zero", offset);
5399                 }
5400             }
5401           else
5402             aopPut (AOP (result),
5403                     aopGet (AOP (right), offset, FALSE),
5404                     offset);
5405           offset++;
5406         }
5407     }
5408   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5409     {
5410       /* Special case.  Load into a and d, then load out. */
5411       _moveA (aopGet (AOP (right), 0, FALSE));
5412       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5413       aopPut (AOP (result), "a", 0);
5414       aopPut (AOP (result), "e", 1);
5415     }
5416   else
5417     {
5418       while (size--)
5419         {
5420           /* PENDING: do this check better */
5421           if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5422             {
5423               _moveA (aopGet (AOP (right), offset, FALSE));
5424               aopPut (AOP (result), "a", offset);
5425             }
5426           else
5427             aopPut (AOP (result),
5428                     aopGet (AOP (right), offset, FALSE),
5429                     offset);
5430           offset++;
5431         }
5432     }
5433
5434 release:
5435   freeAsmop (right, NULL, ic);
5436   freeAsmop (result, NULL, ic);
5437 }
5438
5439 /*-----------------------------------------------------------------*/
5440 /* genJumpTab - genrates code for jump table                       */
5441 /*-----------------------------------------------------------------*/
5442 static void
5443 genJumpTab (iCode * ic)
5444 {
5445   symbol *jtab;
5446   const char *l;
5447
5448   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5449   /* get the condition into accumulator */
5450   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5451   if (!IS_GB)
5452     emit2 ("push de");
5453   emit2 ("ld e,%s", l);
5454   emit2 ("ld d,!zero");
5455   jtab = newiTempLabel (NULL);
5456   spillCached ();
5457   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5458   emit2 ("add hl,de");
5459   emit2 ("add hl,de");
5460   emit2 ("add hl,de");
5461   freeAsmop (IC_JTCOND (ic), NULL, ic);
5462   if (!IS_GB)
5463     emit2 ("pop de");
5464   emit2 ("jp !*hl");
5465   emitLabel (jtab->key + 100);
5466   /* now generate the jump labels */
5467   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5468        jtab = setNextItem (IC_JTLABELS (ic)))
5469     emit2 ("jp !tlabel", jtab->key + 100);
5470 }
5471
5472 /*-----------------------------------------------------------------*/
5473 /* genCast - gen code for casting                                  */
5474 /*-----------------------------------------------------------------*/
5475 static void
5476 genCast (iCode * ic)
5477 {
5478   operand *result = IC_RESULT (ic);
5479   sym_link *ctype = operandType (IC_LEFT (ic));
5480   operand *right = IC_RIGHT (ic);
5481   int size, offset;
5482
5483   /* if they are equivalent then do nothing */
5484   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5485     return;
5486
5487   aopOp (right, ic, FALSE, FALSE);
5488   aopOp (result, ic, FALSE, FALSE);
5489
5490   /* if the result is a bit */
5491   if (AOP_TYPE (result) == AOP_CRY)
5492     {
5493       wassert (0);
5494     }
5495
5496   /* if they are the same size : or less */
5497   if (AOP_SIZE (result) <= AOP_SIZE (right))
5498     {
5499
5500       /* if they are in the same place */
5501       if (sameRegs (AOP (right), AOP (result)))
5502         goto release;
5503
5504       /* if they in different places then copy */
5505       size = AOP_SIZE (result);
5506       offset = 0;
5507       while (size--)
5508         {
5509           aopPut (AOP (result),
5510                   aopGet (AOP (right), offset, FALSE),
5511                   offset);
5512           offset++;
5513         }
5514       goto release;
5515     }
5516
5517   /* PENDING: should be OK. */
5518 #if 0
5519   /* if the result is of type pointer */
5520   if (IS_PTR (ctype))
5521     {
5522       wassert (0);
5523     }
5524 #endif
5525
5526   /* so we now know that the size of destination is greater
5527      than the size of the source */
5528   /* we move to result for the size of source */
5529   size = AOP_SIZE (right);
5530   offset = 0;
5531   while (size--)
5532     {
5533       aopPut (AOP (result),
5534               aopGet (AOP (right), offset, FALSE),
5535               offset);
5536       offset++;
5537     }
5538
5539   /* now depending on the sign of the destination */
5540   size = AOP_SIZE (result) - AOP_SIZE (right);
5541   /* Unsigned or not an integral type - right fill with zeros */
5542   if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5543     {
5544       while (size--)
5545         aopPut (AOP (result), "!zero", offset++);
5546     }
5547   else
5548     {
5549       /* we need to extend the sign :{ */
5550         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5551                         FALSE);
5552       _moveA (l);
5553       emitDebug ("; genCast: sign extend untested.");
5554       emit2 ("rla ");
5555       emit2 ("sbc a,a");
5556       while (size--)
5557         aopPut (AOP (result), "a", offset++);
5558     }
5559
5560 release:
5561   freeAsmop (right, NULL, ic);
5562   freeAsmop (result, NULL, ic);
5563 }
5564
5565 /*-----------------------------------------------------------------*/
5566 /* genReceive - generate code for a receive iCode                  */
5567 /*-----------------------------------------------------------------*/
5568 static void
5569 genReceive (iCode * ic)
5570 {
5571   if (isOperandInFarSpace (IC_RESULT (ic)) &&
5572       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5573        IS_TRUE_SYMOP (IC_RESULT (ic))))
5574     {
5575       wassert (0);
5576     }
5577   else
5578     {
5579         // PENDING: HACK
5580         int size;
5581         int i;
5582
5583         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5584         size = AOP_SIZE(IC_RESULT(ic));
5585
5586         for (i = 0; i < size; i++) {
5587             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5588         }
5589     }
5590
5591   freeAsmop (IC_RESULT (ic), NULL, ic);
5592 }
5593
5594 enum
5595   {
5596     /** Maximum number of bytes to emit per line. */
5597     DBEMIT_MAX_RUN = 8
5598   };
5599
5600 /** Context for the byte output chunker. */
5601 typedef struct
5602 {
5603   unsigned char buffer[DBEMIT_MAX_RUN];
5604   int pos;
5605 } DBEMITCTX;
5606
5607
5608 /** Flushes a byte chunker by writing out all in the buffer and
5609     reseting. 
5610 */
5611 static void
5612 _dbFlush(DBEMITCTX *self)
5613 {
5614   char line[256];
5615
5616   if (self->pos > 0)
5617     {
5618       int i;
5619       sprintf(line, ".db 0x%02X", self->buffer[0]);
5620
5621       for (i = 1; i < self->pos; i++)
5622         {
5623           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5624         }
5625       emit2(line);
5626     }
5627   self->pos = 0;
5628 }
5629
5630 /** Write out another byte, buffering until a decent line is
5631     generated.
5632 */
5633 static void
5634 _dbEmit(DBEMITCTX *self, int c)
5635 {
5636   if (self->pos == DBEMIT_MAX_RUN)
5637     {
5638       _dbFlush(self);
5639     }
5640   self->buffer[self->pos++] = c;
5641 }
5642
5643 /** Context for a simple run length encoder. */
5644 typedef struct
5645 {
5646   unsigned last;
5647   unsigned char buffer[128];
5648   int pos;
5649   /** runLen may be equivalent to pos. */
5650   int runLen;
5651 } RLECTX;
5652
5653 enum
5654   {
5655     RLE_CHANGE_COST = 4,
5656     RLE_MAX_BLOCK = 127
5657   };
5658
5659 /** Flush the buffer of a run length encoder by writing out the run or
5660     data that it currently contains.
5661 */
5662 static void
5663 _rleCommit(RLECTX *self)
5664 {
5665   int i;
5666   if (self->pos != 0)
5667     {
5668       DBEMITCTX db;
5669       memset(&db, 0, sizeof(db));
5670           
5671       emit2(".db %u", self->pos);
5672       
5673       for (i = 0; i < self->pos; i++)
5674         {
5675           _dbEmit(&db, self->buffer[i]);
5676         }
5677       _dbFlush(&db);
5678     }
5679   /* Reset */
5680   self->pos = 0;
5681 }
5682
5683 /* Encoder design:
5684    Can get either a run or a block of random stuff.
5685    Only want to change state if a good run comes in or a run ends.
5686    Detecting run end is easy.
5687    Initial state?
5688
5689    Say initial state is in run, len zero, last zero.  Then if you get a
5690    few zeros then something else then a short run will be output.
5691    Seems OK.  While in run mode, keep counting.  While in random mode,
5692    keep a count of the run.  If run hits margin, output all up to run,
5693    restart, enter run mode.
5694 */
5695
5696 /** Add another byte into the run length encoder, flushing as
5697     required.  The run length encoder uses the Amiga IFF style, where
5698     a block is prefixed by its run length.  A positive length means
5699     the next n bytes pass straight through.  A negative length means
5700     that the next byte is repeated -n times.  A zero terminates the
5701     chunks.
5702 */
5703 static void
5704 _rleAppend(RLECTX *self, int c)
5705 {
5706   int i;
5707
5708   if (c != self->last)
5709     {
5710       /* The run has stopped.  See if it is worthwhile writing it out
5711          as a run.  Note that the random data comes in as runs of
5712          length one.
5713       */
5714       if (self->runLen > RLE_CHANGE_COST)
5715         {
5716           /* Yes, worthwhile. */
5717           /* Commit whatever was in the buffer. */
5718           _rleCommit(self);
5719           emit2(".db -%u,0x%02X", self->runLen, self->last);
5720         }
5721       else
5722         {
5723           /* Not worthwhile.  Append to the end of the random list. */
5724           for (i = 0; i < self->runLen; i++)
5725             {
5726               if (self->pos >= RLE_MAX_BLOCK)
5727                 {
5728                   /* Commit. */
5729                   _rleCommit(self);
5730                 }
5731               self->buffer[self->pos++] = self->last;
5732             }
5733         }
5734       self->runLen = 1;
5735       self->last = c;
5736     }
5737   else
5738     {
5739       if (self->runLen >= RLE_MAX_BLOCK)
5740         {
5741           /* Commit whatever was in the buffer. */
5742           _rleCommit(self);
5743
5744           emit2 (".db -%u,0x%02X", self->runLen, self->last);
5745           self->runLen = 0;
5746         }
5747       self->runLen++;
5748     }
5749 }
5750
5751 static void
5752 _rleFlush(RLECTX *self)
5753 {
5754   _rleAppend(self, -1);
5755   _rleCommit(self);
5756   self->pos = 0;
5757   self->last = 0;
5758   self->runLen = 0;
5759 }
5760
5761 /** genArrayInit - Special code for initialising an array with constant
5762    data.
5763 */
5764 static void
5765 genArrayInit (iCode * ic)
5766 {
5767   literalList *iLoop;
5768   int         ix;
5769   int         elementSize = 0, eIndex, i;
5770   unsigned    val, lastVal;
5771   sym_link    *type;
5772   RLECTX      rle;
5773
5774   memset(&rle, 0, sizeof(rle));
5775
5776   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5777
5778   if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5779     {
5780       /* Emit the support function call and the destination address. */
5781       emit2("call __initrleblock");
5782       emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5783     }
5784   else
5785     {
5786       wassertl (0, "Unexpected operand to genArrayInit.\n");
5787     }
5788     
5789   type = operandType(IC_LEFT(ic));
5790     
5791   if (type && type->next)
5792     {
5793       elementSize = getSize(type->next);
5794     }
5795   else
5796     {
5797       wassertl (0, "Can't determine element size in genArrayInit.");
5798     }
5799
5800   iLoop = IC_ARRAYILIST(ic);
5801   lastVal = (unsigned)-1;
5802
5803   /* Feed all the bytes into the run length encoder which will handle
5804      the actual output.
5805      This works well for mixed char data, and for random int and long
5806      data.
5807   */
5808   while (iLoop)
5809     {
5810       ix = iLoop->count;
5811
5812       if (ix != 0)
5813         {
5814           for (i = 0; i < ix; i++)
5815             {
5816               for (eIndex = 0; eIndex < elementSize; eIndex++)
5817                 {
5818                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5819                   _rleAppend(&rle, val);
5820                 }
5821             }
5822         }
5823         
5824       iLoop = iLoop->next;
5825     }
5826
5827   _rleFlush(&rle);
5828   /* Mark the end of the run. */
5829   emit2(".db 0");
5830
5831   freeAsmop (IC_LEFT(ic), NULL, ic);
5832 }
5833
5834 /*-----------------------------------------------------------------*/
5835 /* genZ80Code - generate code for Z80 based controllers            */
5836 /*-----------------------------------------------------------------*/
5837 void
5838 genZ80Code (iCode * lic)
5839 {
5840   iCode *ic;
5841   int cln = 0;
5842
5843   /* HACK */
5844   if (IS_GB)
5845     {
5846       _fReturn = _gbz80_return;
5847       _fTmp = _gbz80_return;
5848     }
5849   else
5850     {
5851       _fReturn = _z80_return;
5852       _fTmp = _z80_return;
5853     }
5854
5855   _G.lines.head = _G.lines.current = NULL;
5856
5857   for (ic = lic; ic; ic = ic->next)
5858     {
5859
5860       if (cln != ic->lineno)
5861         {
5862           emit2 ("; %s %d", ic->filename, ic->lineno);
5863           cln = ic->lineno;
5864         }
5865       /* if the result is marked as
5866          spilt and rematerializable or code for
5867          this has already been generated then
5868          do nothing */
5869       if (resultRemat (ic) || ic->generated)
5870         continue;
5871
5872       /* depending on the operation */
5873       switch (ic->op)
5874         {
5875         case '!':
5876           emitDebug ("; genNot");
5877           genNot (ic);
5878           break;
5879
5880         case '~':
5881           emitDebug ("; genCpl");
5882           genCpl (ic);
5883           break;
5884
5885         case UNARYMINUS:
5886           emitDebug ("; genUminus");
5887           genUminus (ic);
5888           break;
5889
5890         case IPUSH:
5891           emitDebug ("; genIpush");
5892           genIpush (ic);
5893           break;
5894
5895         case IPOP:
5896           /* IPOP happens only when trying to restore a
5897              spilt live range, if there is an ifx statement
5898              following this pop then the if statement might
5899              be using some of the registers being popped which
5900              would destory the contents of the register so
5901              we need to check for this condition and handle it */
5902           if (ic->next &&
5903               ic->next->op == IFX &&
5904               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5905             {
5906               emitDebug ("; genIfx");
5907               genIfx (ic->next, ic);
5908             }
5909           else
5910             {
5911               emitDebug ("; genIpop");
5912               genIpop (ic);
5913             }
5914           break;
5915
5916         case CALL:
5917           emitDebug ("; genCall");
5918           genCall (ic);
5919           break;
5920
5921         case PCALL:
5922           emitDebug ("; genPcall");
5923           genPcall (ic);
5924           break;
5925
5926         case FUNCTION:
5927           emitDebug ("; genFunction");
5928           genFunction (ic);
5929           break;
5930
5931         case ENDFUNCTION:
5932           emitDebug ("; genEndFunction");
5933           genEndFunction (ic);
5934           break;
5935
5936         case RETURN:
5937           emitDebug ("; genRet");
5938           genRet (ic);
5939           break;
5940
5941         case LABEL:
5942           emitDebug ("; genLabel");
5943           genLabel (ic);
5944           break;
5945
5946         case GOTO:
5947           emitDebug ("; genGoto");
5948           genGoto (ic);
5949           break;
5950
5951         case '+':
5952           emitDebug ("; genPlus");
5953           genPlus (ic);
5954           break;
5955
5956         case '-':
5957           emitDebug ("; genMinus");
5958           genMinus (ic);
5959           break;
5960
5961         case '*':
5962           emitDebug ("; genMult");
5963           genMult (ic);
5964           break;
5965
5966         case '/':
5967           emitDebug ("; genDiv");
5968           genDiv (ic);
5969           break;
5970
5971         case '%':
5972           emitDebug ("; genMod");
5973           genMod (ic);
5974           break;
5975
5976         case '>':
5977           emitDebug ("; genCmpGt");
5978           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
5979           break;
5980
5981         case '<':
5982           emitDebug ("; genCmpLt");
5983           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
5984           break;
5985
5986         case LE_OP:
5987         case GE_OP:
5988         case NE_OP:
5989
5990           /* note these two are xlated by algebraic equivalence
5991              during parsing SDCC.y */
5992           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5993                   "got '>=' or '<=' shouldn't have come here");
5994           break;
5995
5996         case EQ_OP:
5997           emitDebug ("; genCmpEq");
5998           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
5999           break;
6000
6001         case AND_OP:
6002           emitDebug ("; genAndOp");
6003           genAndOp (ic);
6004           break;
6005
6006         case OR_OP:
6007           emitDebug ("; genOrOp");
6008           genOrOp (ic);
6009           break;
6010
6011         case '^':
6012           emitDebug ("; genXor");
6013           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6014           break;
6015
6016         case '|':
6017           emitDebug ("; genOr");
6018           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6019           break;
6020
6021         case BITWISEAND:
6022           emitDebug ("; genAnd");
6023           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6024           break;
6025
6026         case INLINEASM:
6027           emitDebug ("; genInline");
6028           genInline (ic);
6029           break;
6030
6031         case RRC:
6032           emitDebug ("; genRRC");
6033           genRRC (ic);
6034           break;
6035
6036         case RLC:
6037           emitDebug ("; genRLC");
6038           genRLC (ic);
6039           break;
6040
6041         case GETHBIT:
6042           emitDebug ("; genGetHBIT");
6043           genGetHbit (ic);
6044           break;
6045
6046         case LEFT_OP:
6047           emitDebug ("; genLeftShift");
6048           genLeftShift (ic);
6049           break;
6050
6051         case RIGHT_OP:
6052           emitDebug ("; genRightShift");
6053           genRightShift (ic);
6054           break;
6055
6056         case GET_VALUE_AT_ADDRESS:
6057           emitDebug ("; genPointerGet");
6058           genPointerGet (ic);
6059           break;
6060
6061         case '=':
6062
6063           if (POINTER_SET (ic))
6064             {
6065               emitDebug ("; genAssign (pointer)");
6066               genPointerSet (ic);
6067             }
6068           else
6069             {
6070               emitDebug ("; genAssign");
6071               genAssign (ic);
6072             }
6073           break;
6074
6075         case IFX:
6076           emitDebug ("; genIfx");
6077           genIfx (ic, NULL);
6078           break;
6079
6080         case ADDRESS_OF:
6081           emitDebug ("; genAddrOf");
6082           genAddrOf (ic);
6083           break;
6084
6085         case JUMPTABLE:
6086           emitDebug ("; genJumpTab");
6087           genJumpTab (ic);
6088           break;
6089
6090         case CAST:
6091           emitDebug ("; genCast");
6092           genCast (ic);
6093           break;
6094
6095         case RECEIVE:
6096           emitDebug ("; genReceive");
6097           genReceive (ic);
6098           break;
6099
6100         case SEND:
6101           emitDebug ("; addSet");
6102           addSet (&_G.sendSet, ic);
6103           break;
6104
6105         case ARRAYINIT:
6106             genArrayInit(ic);
6107             break;
6108             
6109         default:
6110           ic = ic;
6111           /*      piCode(ic,stdout); */
6112
6113         }
6114     }
6115
6116
6117   /* now we are ready to call the
6118      peep hole optimizer */
6119   if (!options.nopeep)
6120     peepHole (&_G.lines.head);
6121
6122   /* This is unfortunate */
6123   /* now do the actual printing */
6124   {
6125     FILE *fp = codeOutFile;
6126     if (isInHome () && codeOutFile == code->oFile)
6127       codeOutFile = home->oFile;
6128     printLine (_G.lines.head, codeOutFile);
6129     if (_G.flushStatics)
6130       {
6131         flushStatics ();
6132         _G.flushStatics = 0;
6133       }
6134     codeOutFile = fp;
6135   }
6136 }
6137
6138 /*
6139   Attic
6140 static int
6141 _isPairUsed (iCode * ic, PAIR_ID pairId)
6142 {
6143   int ret = 0;
6144   switch (pairId)
6145     {
6146     case PAIR_DE:
6147       if (bitVectBitValue (ic->rMask, D_IDX))
6148         ret++;
6149       if (bitVectBitValue (ic->rMask, E_IDX))
6150         ret++;
6151       break;
6152     default:
6153       wassert (0);
6154     }
6155   return ret;
6156 }
6157
6158 */