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