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