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