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