6c5d5ae74ab3eecd5fd7db2e6b1e0692a6fced03
[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   /* If the result is in a register then we can load then increment.
2891    */
2892   if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
2893     {
2894       aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
2895       while (icount--)
2896         {
2897           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
2898         }
2899       return TRUE;
2900     }
2901
2902   /* we can if the aops of the left & result match or
2903      if they are in registers and the registers are the
2904      same */
2905   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2906     {
2907       while (icount--)
2908         {
2909           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2910         }
2911       return TRUE;
2912     }
2913
2914   return FALSE;
2915 }
2916
2917 /*-----------------------------------------------------------------*/
2918 /* outBitAcc - output a bit in acc                                 */
2919 /*-----------------------------------------------------------------*/
2920 void
2921 outBitAcc (operand * result)
2922 {
2923   symbol *tlbl = newiTempLabel (NULL);
2924   /* if the result is a bit */
2925   if (AOP_TYPE (result) == AOP_CRY)
2926     {
2927       wassertl (0, "Tried to write A into a bit");
2928     }
2929   else
2930     {
2931       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2932       emit2 ("ld a,!one");
2933       emitLabel (tlbl->key + 100);
2934       outAcc (result);
2935     }
2936 }
2937
2938 bool
2939 couldDestroyCarry (asmop *aop)
2940 {
2941   if (aop)
2942     {
2943       if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
2944         {
2945           return TRUE;
2946         }
2947     }
2948   return FALSE;
2949 }
2950
2951 static void
2952 shiftIntoPair (int idx, asmop *aop)
2953 {
2954   PAIR_ID id = PAIR_INVALID;
2955
2956   wassertl (IS_Z80, "Only implemented for the Z80");
2957   //  wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
2958
2959   switch (idx) 
2960     {
2961     case 0:
2962       id = PAIR_HL;
2963       break;
2964     case 1:
2965       id = PAIR_DE;
2966       _push (PAIR_DE);
2967       break;
2968     default:
2969       wassertl (0, "Internal error - hit default case");
2970     }
2971
2972   emitDebug ("; Shift into pair idx %u", idx);
2973
2974   if (id == PAIR_HL)
2975     {
2976       setupPair (PAIR_HL, aop, 0);
2977     }
2978   else
2979     {
2980       setupPair (PAIR_IY, aop, 0);
2981       emit2 ("push iy");
2982       emit2 ("pop %s", _pairs[id].name);
2983     }
2984
2985   aop->type = AOP_PAIRPTR;
2986   aop->aopu.aop_pairId = id;
2987   _G.pairs[id].offset = 0;
2988   _G.pairs[id].last_type = aop->type;
2989 }
2990
2991 static void 
2992 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
2993 {
2994   wassert (left && right);
2995
2996   if (IS_Z80)
2997     {
2998       if (couldDestroyCarry (right) && couldDestroyCarry (result))
2999         {
3000           shiftIntoPair (0, right);
3001           shiftIntoPair (1, result);
3002         }
3003       else if (couldDestroyCarry (right))
3004         {
3005           shiftIntoPair (0, right);
3006         }
3007       else if (couldDestroyCarry (result))
3008         {
3009           shiftIntoPair (0, result);
3010         }
3011       else
3012         {
3013           /* Fine */
3014         }
3015     }
3016 }
3017
3018 /*-----------------------------------------------------------------*/
3019 /* genPlus - generates code for addition                           */
3020 /*-----------------------------------------------------------------*/
3021 static void
3022 genPlus (iCode * ic)
3023 {
3024   int size, offset = 0;
3025
3026   /* special cases :- */
3027
3028   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3029   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3030   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3031
3032   /* Swap the left and right operands if:
3033
3034      if literal, literal on the right or
3035      if left requires ACC or right is already
3036      in ACC */
3037
3038   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3039       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3040       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3041     {
3042       operand *t = IC_RIGHT (ic);
3043       IC_RIGHT (ic) = IC_LEFT (ic);
3044       IC_LEFT (ic) = t;
3045     }
3046
3047   /* if both left & right are in bit
3048      space */
3049   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3050       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3051     {
3052       /* Cant happen */
3053       wassertl (0, "Tried to add two bits");
3054     }
3055
3056   /* if left in bit space & right literal */
3057   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3058       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3059     {
3060       /* Can happen I guess */
3061       wassertl (0, "Tried to add a bit to a literal");
3062     }
3063
3064   /* if I can do an increment instead
3065      of add then GOOD for ME */
3066   if (genPlusIncr (ic) == TRUE)
3067     goto release;
3068
3069   emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3070
3071   size = getDataSize (IC_RESULT (ic));
3072
3073   /* Special case when left and right are constant */
3074   if (isPair (AOP (IC_RESULT (ic))))
3075     {
3076       char *left, *right;
3077       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3078       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3079
3080       if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3081           left && right)
3082         {
3083           /* It's a pair */
3084           /* PENDING: fix */
3085           char buffer[100];
3086           sprintf (buffer, "#(%s + %s)", left, right);
3087           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3088           goto release;
3089         }
3090     }
3091
3092   if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3093     {
3094       /* Fetch into HL then do the add */
3095       spillPair (PAIR_HL);
3096       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3097       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3098       goto release;
3099     }
3100
3101   if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD)
3102     {
3103       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3104       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3105       spillCached();
3106       commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3107       goto release;
3108     }
3109
3110   /* Special case:
3111      ld hl,sp+n trashes C so we cant afford to do it during an
3112      add with stack based varibles.  Worst case is:
3113      ld  hl,sp+left
3114      ld  a,(hl)
3115      ld  hl,sp+right
3116      add (hl)
3117      ld  hl,sp+result
3118      ld  (hl),a
3119      ld  hl,sp+left+1
3120      ld  a,(hl)
3121      ld  hl,sp+right+1
3122      adc (hl)
3123      ld  hl,sp+result+1
3124      ld  (hl),a
3125      So you cant afford to load up hl if either left, right, or result
3126      is on the stack (*sigh*)  The alt is:
3127      ld  hl,sp+left
3128      ld  de,(hl)
3129      ld  hl,sp+right
3130      ld  hl,(hl)
3131      add hl,de
3132      ld  hl,sp+result
3133      ld  (hl),hl
3134      Combinations in here are:
3135      * If left or right are in bc then the loss is small - trap later
3136      * If the result is in bc then the loss is also small
3137    */
3138   if (IS_GB)
3139     {
3140       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3141           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3142           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3143         {
3144           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3145                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3146               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3147                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3148             {
3149               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3150                 {
3151                   /* Swap left and right */
3152                   operand *t = IC_RIGHT (ic);
3153                   IC_RIGHT (ic) = IC_LEFT (ic);
3154                   IC_LEFT (ic) = t;
3155                 }
3156               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3157                 {
3158                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3159                   emit2 ("add hl,bc");
3160                 }
3161               else
3162                 {
3163                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3164                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3165                   emit2 ("add hl,de");
3166                 }
3167               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3168               goto release;
3169             }
3170         }
3171       if (size == 4)
3172         {
3173           /* Be paranoid on the GB with 4 byte variables due to how C
3174              can be trashed by lda hl,n(sp).
3175           */
3176           _gbz80_emitAddSubLong (ic, TRUE);
3177           goto release;
3178         }
3179     }
3180
3181   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3182
3183   while (size--)
3184     {
3185       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3186         {
3187           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3188           if (offset == 0)
3189             emit2 ("add a,%s",
3190                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3191           else
3192             emit2 ("adc a,%s",
3193                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3194         }
3195       else
3196         {
3197           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3198           if (offset == 0)
3199             emit2 ("add a,%s",
3200                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3201           else
3202             emit2 ("adc a,%s",
3203                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3204         }
3205       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3206     }
3207
3208 release:
3209   freeAsmop (IC_LEFT (ic), NULL, ic);
3210   freeAsmop (IC_RIGHT (ic), NULL, ic);
3211   freeAsmop (IC_RESULT (ic), NULL, ic);
3212
3213 }
3214
3215 /*-----------------------------------------------------------------*/
3216 /* genMinusDec :- does subtraction with deccrement if possible     */
3217 /*-----------------------------------------------------------------*/
3218 static bool
3219 genMinusDec (iCode * ic)
3220 {
3221   unsigned int icount;
3222   unsigned int size = getDataSize (IC_RESULT (ic));
3223
3224   /* will try to generate an increment */
3225   /* if the right side is not a literal we cannot */
3226   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3227     return FALSE;
3228
3229   /* if the literal value of the right hand side
3230      is greater than 4 then it is not worth it */
3231   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3232     return FALSE;
3233
3234   size = getDataSize (IC_RESULT (ic));
3235
3236   /* if decrement 16 bits in register */
3237   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3238       (size > 1) && isPair (AOP (IC_RESULT (ic))))
3239     {
3240       while (icount--)
3241         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3242       return TRUE;
3243     }
3244
3245   /* If result is a pair */
3246   if (isPair (AOP (IC_RESULT (ic))))
3247     {
3248       movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3249       while (icount--)
3250         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3251       return TRUE;
3252     }
3253
3254   /* if increment 16 bits in register */
3255   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3256       (size == 2)
3257       )
3258     {
3259       fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3260
3261       while (icount--) {
3262         emit2 ("dec %s", _getTempPairName());
3263       }
3264
3265       commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3266
3267       return TRUE;
3268     }
3269
3270
3271   /* if the sizes are greater than 1 then we cannot */
3272   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3273       AOP_SIZE (IC_LEFT (ic)) > 1)
3274     return FALSE;
3275
3276   /* we can if the aops of the left & result match or if they are in
3277      registers and the registers are the same */
3278   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3279     {
3280       while (icount--)
3281         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3282       return TRUE;
3283     }
3284
3285   return FALSE;
3286 }
3287
3288 /*-----------------------------------------------------------------*/
3289 /* genMinus - generates code for subtraction                       */
3290 /*-----------------------------------------------------------------*/
3291 static void
3292 genMinus (iCode * ic)
3293 {
3294   int size, offset = 0;
3295   unsigned long lit = 0L;
3296
3297   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3298   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3299   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3300
3301   /* special cases :- */
3302   /* if both left & right are in bit space */
3303   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3304       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3305     {
3306       wassertl (0, "Tried to subtract two bits");
3307       goto release;
3308     }
3309
3310   /* if I can do an decrement instead of subtract then GOOD for ME */
3311   if (genMinusDec (ic) == TRUE)
3312     goto release;
3313
3314   size = getDataSize (IC_RESULT (ic));
3315
3316   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3317     {
3318     }
3319   else
3320     {
3321       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3322       lit = -(long) lit;
3323     }
3324
3325   /* Same logic as genPlus */
3326   if (IS_GB)
3327     {
3328       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3329           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3330           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3331         {
3332           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3333                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3334               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3335                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3336             {
3337               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3338               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3339
3340               if (left == PAIR_INVALID && right == PAIR_INVALID)
3341                 {
3342                   left = PAIR_DE;
3343                   right = PAIR_HL;
3344                 }
3345               else if (right == PAIR_INVALID)
3346                 right = PAIR_DE;
3347               else if (left == PAIR_INVALID)
3348                 left = PAIR_DE;
3349
3350               fetchPair (left, AOP (IC_LEFT (ic)));
3351               /* Order is important.  Right may be HL */
3352               fetchPair (right, AOP (IC_RIGHT (ic)));
3353
3354               emit2 ("ld a,%s", _pairs[left].l);
3355               emit2 ("sub a,%s", _pairs[right].l);
3356               emit2 ("ld e,a");
3357               emit2 ("ld a,%s", _pairs[left].h);
3358               emit2 ("sbc a,%s", _pairs[right].h);
3359
3360               if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3361                 {
3362                   aopPut (AOP (IC_RESULT (ic)), "a", 1);
3363                 }
3364               aopPut (AOP (IC_RESULT (ic)), "e", 0);
3365               goto release;
3366             }
3367         }
3368       if (size == 4)
3369         {
3370           /* Be paranoid on the GB with 4 byte variables due to how C
3371              can be trashed by lda hl,n(sp).
3372           */
3373           _gbz80_emitAddSubLong (ic, FALSE);
3374           goto release;
3375         }
3376     }
3377
3378   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3379
3380   /* if literal, add a,#-lit, else normal subb */
3381   while (size--)
3382     {
3383       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3384       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3385         {
3386           if (!offset)
3387             emit2 ("sub a,%s",
3388                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3389           else
3390             emit2 ("sbc a,%s",
3391                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3392         }
3393       else
3394         {
3395           /* first add without previous c */
3396           if (!offset)
3397             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3398           else
3399             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3400         }
3401       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3402     }
3403
3404   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3405       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3406       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3407     {
3408       wassertl (0, "Tried to subtract on a long pointer");
3409     }
3410
3411 release:
3412   freeAsmop (IC_LEFT (ic), NULL, ic);
3413   freeAsmop (IC_RIGHT (ic), NULL, ic);
3414   freeAsmop (IC_RESULT (ic), NULL, ic);
3415 }
3416
3417 /*-----------------------------------------------------------------*/
3418 /* genMult - generates code for multiplication                     */
3419 /*-----------------------------------------------------------------*/
3420 static void
3421 genMult (iCode * ic)
3422 {
3423   int val;
3424   int count, i;
3425   /* If true then the final operation should be a subtract */
3426   bool active = FALSE;
3427
3428   /* Shouldn't occur - all done through function calls */
3429   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3430   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3431   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3432
3433   if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3434       AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3435       AOP_SIZE (IC_RESULT (ic)) > 2)
3436     {
3437       wassertl (0, "Multiplication is handled through support function calls");
3438     }
3439
3440   /* Swap left and right such that right is a literal */
3441   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3442     {
3443       operand *t = IC_RIGHT (ic);
3444       IC_RIGHT (ic) = IC_LEFT (ic);
3445       IC_LEFT (ic) = t;
3446     }
3447
3448   wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3449
3450   val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3451   //  wassertl (val > 0, "Multiply must be positive");
3452   wassertl (val != 1, "Can't multiply by 1");
3453
3454   if (IS_Z80) {
3455     _push (PAIR_DE);
3456   }
3457
3458   if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3459     {
3460       emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3461       emit2 ("ld a,e");
3462       emit2 ("rlc a");
3463       emit2 ("sbc a,a");
3464       emit2 ("ld d,a");
3465     }
3466   else
3467     {
3468       fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3469     }
3470
3471   i = val;
3472
3473   /* Fully unroled version of mul.s.  Not the most efficient.
3474    */
3475   for (count = 0; count < 16; count++)
3476     {
3477       if (count != 0 && active)
3478         {
3479           emit2 ("add hl,hl");
3480         }
3481       if (i & 0x8000U)
3482         {
3483           if (active == FALSE)
3484             {
3485               emit2 ("ld l,e");
3486               emit2 ("ld h,d");
3487             }
3488           else
3489             {
3490               emit2 ("add hl,de");
3491             }
3492           active = TRUE;
3493         }
3494       i <<= 1;
3495     }
3496
3497   spillCached();
3498
3499   if (IS_Z80)
3500     {
3501       _pop (PAIR_DE);
3502     }
3503
3504   commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3505
3506   freeAsmop (IC_LEFT (ic), NULL, ic);
3507   freeAsmop (IC_RIGHT (ic), NULL, ic);
3508   freeAsmop (IC_RESULT (ic), NULL, ic);
3509 }
3510
3511 /*-----------------------------------------------------------------*/
3512 /* genDiv - generates code for division                            */
3513 /*-----------------------------------------------------------------*/
3514 static void
3515 genDiv (iCode * ic)
3516 {
3517   /* Shouldn't occur - all done through function calls */
3518   wassertl (0, "Division is handled through support function calls");
3519 }
3520
3521 /*-----------------------------------------------------------------*/
3522 /* genMod - generates code for division                            */
3523 /*-----------------------------------------------------------------*/
3524 static void
3525 genMod (iCode * ic)
3526 {
3527   /* Shouldn't occur - all done through function calls */
3528   wassert (0);
3529 }
3530
3531 /*-----------------------------------------------------------------*/
3532 /* genIfxJump :- will create a jump depending on the ifx           */
3533 /*-----------------------------------------------------------------*/
3534 static void
3535 genIfxJump (iCode * ic, char *jval)
3536 {
3537   symbol *jlbl;
3538   const char *inst;
3539
3540   /* if true label then we jump if condition
3541      supplied is true */
3542   if (IC_TRUE (ic))
3543     {
3544       jlbl = IC_TRUE (ic);
3545       if (!strcmp (jval, "a"))
3546         {
3547           inst = "nz";
3548         }
3549       else if (!strcmp (jval, "c"))
3550         {
3551           inst = "c";
3552         }
3553       else if (!strcmp (jval, "nc"))
3554         {
3555           inst = "nc";
3556         }
3557       else
3558         {
3559           /* The buffer contains the bit on A that we should test */
3560           inst = "nz";
3561         }
3562     }
3563   else
3564     {
3565       /* false label is present */
3566       jlbl = IC_FALSE (ic);
3567       if (!strcmp (jval, "a"))
3568         {
3569           inst = "z";
3570         }
3571       else if (!strcmp (jval, "c"))
3572         {
3573           inst = "nc";
3574         }
3575       else if (!strcmp (jval, "nc"))
3576         {
3577           inst = "c";
3578         }
3579       else
3580         {
3581           /* The buffer contains the bit on A that we should test */
3582           inst = "z";
3583         }
3584     }
3585   /* Z80 can do a conditional long jump */
3586   if (!strcmp (jval, "a"))
3587     {
3588       emit2 ("or a,a");
3589     }
3590   else if (!strcmp (jval, "c"))
3591     {
3592     }
3593   else if (!strcmp (jval, "nc"))
3594     {
3595     }
3596   else
3597     {
3598       emit2 ("bit %s,a", jval);
3599     }
3600   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3601
3602   /* mark the icode as generated */
3603   ic->generated = 1;
3604 }
3605
3606 #if DISABLED
3607 static const char *
3608 _getPairIdName (PAIR_ID id)
3609 {
3610   return _pairs[id].name;
3611 }
3612 #endif
3613
3614 /** Generic compare for > or <
3615  */
3616 static void
3617 genCmp (operand * left, operand * right,
3618         operand * result, iCode * ifx, int sign)
3619 {
3620   int size, offset = 0;
3621   unsigned long lit = 0L;
3622   bool swap_sense = FALSE;
3623
3624   /* if left & right are bit variables */
3625   if (AOP_TYPE (left) == AOP_CRY &&
3626       AOP_TYPE (right) == AOP_CRY)
3627     {
3628       /* Cant happen on the Z80 */
3629       wassertl (0, "Tried to compare two bits");
3630     }
3631   else
3632     {
3633       /* subtract right from left if at the
3634          end the carry flag is set then we know that
3635          left is greater than right */
3636       size = max (AOP_SIZE (left), AOP_SIZE (right));
3637
3638       /* if unsigned char cmp with lit, just compare */
3639       if ((size == 1) &&
3640           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3641         {
3642           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3643           if (sign)
3644             {
3645               emit2 ("xor a,!immedbyte", 0x80);
3646               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3647             }
3648           else
3649             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3650         }
3651       else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3652         {
3653           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3654           // Pull left into DE and right into HL
3655           aopGet (AOP(left), LSB, FALSE);
3656           emit2 ("ld d,h");
3657           emit2 ("ld e,l");
3658           aopGet (AOP(right), LSB, FALSE);
3659
3660           while (size--)
3661             {
3662               if (size == 0 && sign)
3663                 {
3664                   // Highest byte when signed needs the bits flipped
3665                   // Save the flags
3666                   emit2 ("push af");
3667                   emit2 ("ld a,(de)");
3668                   emit2 ("xor #0x80");
3669                   emit2 ("ld e,a");
3670                   emit2 ("ld a,(hl)");
3671                   emit2 ("xor #0x80");
3672                   emit2 ("ld d,a");
3673                   emit2 ("pop af");
3674                   emit2 ("ld a,e");
3675                   emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3676                 }
3677               else
3678                 {
3679                   emit2 ("ld a,(de)");
3680                   emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3681                 }
3682               
3683               if (size != 0)
3684                 {
3685                   emit2 ("inc hl");
3686                   emit2 ("inc de");
3687                 }
3688               offset++;
3689             }
3690           spillPair (PAIR_HL);
3691         }
3692       else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3693         {
3694           setupPair (PAIR_HL, AOP (left), 0);
3695           aopGet (AOP(right), LSB, FALSE);
3696
3697           while (size--)
3698             {
3699               if (size == 0 && sign)
3700                 {
3701                   // Highest byte when signed needs the bits flipped
3702                   // Save the flags
3703                   emit2 ("push af");
3704                   emit2 ("ld a,(hl)");
3705                   emit2 ("xor #0x80");
3706                   emit2 ("ld l,a");
3707                   emit2 ("ld a,%d(iy)", offset);
3708                   emit2 ("xor #0x80");
3709                   emit2 ("ld h,a");
3710                   emit2 ("pop af");
3711                   emit2 ("ld a,l");
3712                   emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3713                 }
3714               else
3715                 {
3716                   emit2 ("ld a,(hl)");
3717                   emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3718                 }
3719               
3720               if (size != 0)
3721                 {
3722                   emit2 ("inc hl");
3723                 }
3724               offset++;
3725             }
3726           spillPair (PAIR_HL);
3727           spillPair (PAIR_IY);
3728         }
3729       else
3730         {
3731           if (AOP_TYPE (right) == AOP_LIT)
3732             {
3733               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3734               /* optimize if(x < 0) or if(x >= 0) */
3735               if (lit == 0L)
3736                 {
3737                   if (!sign)
3738                     {
3739                       /* No sign so it's always false */
3740                       _clearCarry();
3741                     }
3742                   else
3743                     {
3744                       /* Just load in the top most bit */
3745                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3746                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3747                         {
3748                           genIfxJump (ifx, "7");
3749                           return;
3750                         }
3751                       else
3752                         emit2 ("rlc a");
3753                     }
3754                   goto release;
3755                 }
3756             }
3757           
3758           if (sign)
3759             {
3760               /* First setup h and l contaning the top most bytes XORed */
3761               bool fDidXor = FALSE;
3762               if (AOP_TYPE (left) == AOP_LIT)
3763                 {
3764                   unsigned long lit = (unsigned long)
3765                   floatFromVal (AOP (left)->aopu.aop_lit);
3766                   emit2 ("ld %s,!immedbyte", _fTmp[0],
3767                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3768                 }
3769               else
3770                 {
3771                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3772                   emit2 ("xor a,!immedbyte", 0x80);
3773                   emit2 ("ld %s,a", _fTmp[0]);
3774                   fDidXor = TRUE;
3775                 }
3776               if (AOP_TYPE (right) == AOP_LIT)
3777                 {
3778                   unsigned long lit = (unsigned long)
3779                   floatFromVal (AOP (right)->aopu.aop_lit);
3780                   emit2 ("ld %s,!immedbyte", _fTmp[1],
3781                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3782                 }
3783               else
3784                 {
3785                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3786                   emit2 ("xor a,!immedbyte", 0x80);
3787                   emit2 ("ld %s,a", _fTmp[1]);
3788                   fDidXor = TRUE;
3789                 }
3790             }
3791           while (size--)
3792             {
3793               /* Do a long subtract */
3794               if (!sign || size)
3795                 {
3796                   _moveA (aopGet (AOP (left), offset, FALSE));
3797                 }
3798               if (sign && size == 0)
3799                 {
3800                   emit2 ("ld a,%s", _fTmp[0]);
3801                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3802                 }
3803               else
3804                 {
3805                   /* Subtract through, propagating the carry */
3806                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3807                   offset++;
3808                 }
3809             }
3810         }
3811     }
3812
3813 release:
3814   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3815     {
3816       outBitCLong (result, swap_sense);
3817     }
3818   else
3819     {
3820       /* if the result is used in the next
3821          ifx conditional branch then generate
3822          code a little differently */
3823       if (ifx)
3824         genIfxJump (ifx, swap_sense ? "nc" : "c");
3825       else
3826         outBitCLong (result, swap_sense);
3827       /* leave the result in acc */
3828     }
3829 }
3830
3831 /*-----------------------------------------------------------------*/
3832 /* genCmpGt :- greater than comparison                             */
3833 /*-----------------------------------------------------------------*/
3834 static void
3835 genCmpGt (iCode * ic, iCode * ifx)
3836 {
3837   operand *left, *right, *result;
3838   sym_link *letype, *retype;
3839   int sign;
3840
3841   left = IC_LEFT (ic);
3842   right = IC_RIGHT (ic);
3843   result = IC_RESULT (ic);
3844
3845   letype = getSpec (operandType (left));
3846   retype = getSpec (operandType (right));
3847   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3848   /* assign the amsops */
3849   aopOp (left, ic, FALSE, FALSE);
3850   aopOp (right, ic, FALSE, FALSE);
3851   aopOp (result, ic, TRUE, FALSE);
3852
3853   genCmp (right, left, result, ifx, sign);
3854
3855   freeAsmop (left, NULL, ic);
3856   freeAsmop (right, NULL, ic);
3857   freeAsmop (result, NULL, ic);
3858 }
3859
3860 /*-----------------------------------------------------------------*/
3861 /* genCmpLt - less than comparisons                                */
3862 /*-----------------------------------------------------------------*/
3863 static void
3864 genCmpLt (iCode * ic, iCode * ifx)
3865 {
3866   operand *left, *right, *result;
3867   sym_link *letype, *retype;
3868   int sign;
3869
3870   left = IC_LEFT (ic);
3871   right = IC_RIGHT (ic);
3872   result = IC_RESULT (ic);
3873
3874   letype = getSpec (operandType (left));
3875   retype = getSpec (operandType (right));
3876   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3877
3878   /* assign the amsops */
3879   aopOp (left, ic, FALSE, FALSE);
3880   aopOp (right, ic, FALSE, FALSE);
3881   aopOp (result, ic, TRUE, FALSE);
3882
3883   genCmp (left, right, result, ifx, sign);
3884
3885   freeAsmop (left, NULL, ic);
3886   freeAsmop (right, NULL, ic);
3887   freeAsmop (result, NULL, ic);
3888 }
3889
3890 /*-----------------------------------------------------------------*/
3891 /* gencjneshort - compare and jump if not equal                    */
3892 /*-----------------------------------------------------------------*/
3893 static void
3894 gencjneshort (operand * left, operand * right, symbol * lbl)
3895 {
3896   int size = max (AOP_SIZE (left), AOP_SIZE (right));
3897   int offset = 0;
3898   unsigned long lit = 0L;
3899
3900   /* Swap the left and right if it makes the computation easier */
3901   if (AOP_TYPE (left) == AOP_LIT)
3902     {
3903       operand *t = right;
3904       right = left;
3905       left = t;
3906     }
3907
3908   if (AOP_TYPE (right) == AOP_LIT)
3909     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3910
3911   /* if the right side is a literal then anything goes */
3912   if (AOP_TYPE (right) == AOP_LIT &&
3913       AOP_TYPE (left) != AOP_DIR)
3914     {
3915       if (lit == 0)
3916         {
3917           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3918           if (size > 1)
3919             {
3920               while (--size)
3921                 {
3922                   emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
3923                 }
3924             }
3925           else
3926             {
3927               emit2 ("or a,a");
3928             }
3929           emit2 ("jp nz,!tlabel", lbl->key + 100);
3930         }
3931       else
3932         {
3933           while (size--)
3934             {
3935               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3936               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3937                 emit2 ("or a,a");
3938               else
3939                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3940               emit2 ("jp nz,!tlabel", lbl->key + 100);
3941               offset++;
3942             }
3943         }
3944     }
3945   /* if the right side is in a register or in direct space or
3946      if the left is a pointer register & right is not */
3947   else if (AOP_TYPE (right) == AOP_REG ||
3948            AOP_TYPE (right) == AOP_DIR ||
3949            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3950     {
3951       while (size--)
3952         {
3953           _moveA (aopGet (AOP (left), offset, FALSE));
3954           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3955               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3956             /* PENDING */
3957             emit2 ("jp nz,!tlabel", lbl->key + 100);
3958           else
3959             {
3960               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3961               emit2 ("jp nz,!tlabel", lbl->key + 100);
3962             }
3963           offset++;
3964         }
3965     }
3966   else
3967     {
3968       /* right is a pointer reg need both a & b */
3969       /* PENDING: is this required? */
3970       while (size--)
3971         {
3972           _moveA (aopGet (AOP (right), offset, FALSE));
3973           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3974           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3975           offset++;
3976         }
3977     }
3978 }
3979
3980 /*-----------------------------------------------------------------*/
3981 /* gencjne - compare and jump if not equal                         */
3982 /*-----------------------------------------------------------------*/
3983 static void
3984 gencjne (operand * left, operand * right, symbol * lbl)
3985 {
3986   symbol *tlbl = newiTempLabel (NULL);
3987
3988   gencjneshort (left, right, lbl);
3989
3990   /* PENDING: ?? */
3991   emit2 ("ld a,!one");
3992   emit2 ("!shortjp !tlabel", tlbl->key + 100);
3993   emitLabel (lbl->key + 100);
3994   emit2 ("xor a,a");
3995   emitLabel (tlbl->key + 100);
3996 }
3997
3998 /*-----------------------------------------------------------------*/
3999 /* genCmpEq - generates code for equal to                          */
4000 /*-----------------------------------------------------------------*/
4001 static void
4002 genCmpEq (iCode * ic, iCode * ifx)
4003 {
4004   operand *left, *right, *result;
4005
4006   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4007   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4008   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4009
4010   emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4011
4012   /* Swap operands if it makes the operation easier. ie if:
4013      1.  Left is a literal.
4014    */
4015   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4016     {
4017       operand *t = IC_RIGHT (ic);
4018       IC_RIGHT (ic) = IC_LEFT (ic);
4019       IC_LEFT (ic) = t;
4020     }
4021
4022   if (ifx && !AOP_SIZE (result))
4023     {
4024       symbol *tlbl;
4025       /* if they are both bit variables */
4026       if (AOP_TYPE (left) == AOP_CRY &&
4027           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4028         {
4029           wassertl (0, "Tried to compare two bits");
4030         }
4031       else
4032         {
4033           tlbl = newiTempLabel (NULL);
4034           gencjneshort (left, right, tlbl);
4035           if (IC_TRUE (ifx))
4036             {
4037               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4038               emitLabel (tlbl->key + 100);
4039             }
4040           else
4041             {
4042               /* PENDING: do this better */
4043               symbol *lbl = newiTempLabel (NULL);
4044               emit2 ("!shortjp !tlabel", lbl->key + 100);
4045               emitLabel (tlbl->key + 100);
4046               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4047               emitLabel (lbl->key + 100);
4048             }
4049         }
4050       /* mark the icode as generated */
4051       ifx->generated = 1;
4052       goto release;
4053     }
4054
4055   /* if they are both bit variables */
4056   if (AOP_TYPE (left) == AOP_CRY &&
4057       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4058     {
4059       wassertl (0, "Tried to compare a bit to either a literal or another bit");
4060     }
4061   else
4062     {
4063       gencjne (left, right, newiTempLabel (NULL));
4064       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4065         {
4066           wassert (0);
4067         }
4068       if (ifx)
4069         {
4070           genIfxJump (ifx, "a");
4071           goto release;
4072         }
4073       /* if the result is used in an arithmetic operation
4074          then put the result in place */
4075       if (AOP_TYPE (result) != AOP_CRY)
4076         {
4077           outAcc (result);
4078         }
4079       /* leave the result in acc */
4080     }
4081
4082 release:
4083   freeAsmop (left, NULL, ic);
4084   freeAsmop (right, NULL, ic);
4085   freeAsmop (result, NULL, ic);
4086 }
4087
4088 /*-----------------------------------------------------------------*/
4089 /* ifxForOp - returns the icode containing the ifx for operand     */
4090 /*-----------------------------------------------------------------*/
4091 static iCode *
4092 ifxForOp (operand * op, iCode * ic)
4093 {
4094   /* if true symbol then needs to be assigned */
4095   if (IS_TRUE_SYMOP (op))
4096     return NULL;
4097
4098   /* if this has register type condition and
4099      the next instruction is ifx with the same operand
4100      and live to of the operand is upto the ifx only then */
4101   if (ic->next &&
4102       ic->next->op == IFX &&
4103       IC_COND (ic->next)->key == op->key &&
4104       OP_SYMBOL (op)->liveTo <= ic->next->seq)
4105     return ic->next;
4106
4107   return NULL;
4108 }
4109
4110 /*-----------------------------------------------------------------*/
4111 /* genAndOp - for && operation                                     */
4112 /*-----------------------------------------------------------------*/
4113 static void
4114 genAndOp (iCode * ic)
4115 {
4116   operand *left, *right, *result;
4117   symbol *tlbl;
4118
4119   /* note here that && operations that are in an if statement are
4120      taken away by backPatchLabels only those used in arthmetic
4121      operations remain */
4122   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4123   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4124   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4125
4126   /* if both are bit variables */
4127   if (AOP_TYPE (left) == AOP_CRY &&
4128       AOP_TYPE (right) == AOP_CRY)
4129     {
4130       wassertl (0, "Tried to and two bits");
4131     }
4132   else
4133     {
4134       tlbl = newiTempLabel (NULL);
4135       _toBoolean (left);
4136       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4137       _toBoolean (right);
4138       emitLabel (tlbl->key + 100);
4139       outBitAcc (result);
4140     }
4141
4142   freeAsmop (left, NULL, ic);
4143   freeAsmop (right, NULL, ic);
4144   freeAsmop (result, NULL, ic);
4145 }
4146
4147 /*-----------------------------------------------------------------*/
4148 /* genOrOp - for || operation                                      */
4149 /*-----------------------------------------------------------------*/
4150 static void
4151 genOrOp (iCode * ic)
4152 {
4153   operand *left, *right, *result;
4154   symbol *tlbl;
4155
4156   /* note here that || operations that are in an
4157      if statement are taken away by backPatchLabels
4158      only those used in arthmetic operations remain */
4159   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4160   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4161   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4162
4163   /* if both are bit variables */
4164   if (AOP_TYPE (left) == AOP_CRY &&
4165       AOP_TYPE (right) == AOP_CRY)
4166     {
4167       wassertl (0, "Tried to OR two bits");
4168     }
4169   else
4170     {
4171       tlbl = newiTempLabel (NULL);
4172       _toBoolean (left);
4173       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4174       _toBoolean (right);
4175       emitLabel (tlbl->key + 100);
4176       outBitAcc (result);
4177     }
4178
4179   freeAsmop (left, NULL, ic);
4180   freeAsmop (right, NULL, ic);
4181   freeAsmop (result, NULL, ic);
4182 }
4183
4184 /*-----------------------------------------------------------------*/
4185 /* isLiteralBit - test if lit == 2^n                               */
4186 /*-----------------------------------------------------------------*/
4187 int
4188 isLiteralBit (unsigned long lit)
4189 {
4190   unsigned long pw[32] =
4191   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4192    0x100L, 0x200L, 0x400L, 0x800L,
4193    0x1000L, 0x2000L, 0x4000L, 0x8000L,
4194    0x10000L, 0x20000L, 0x40000L, 0x80000L,
4195    0x100000L, 0x200000L, 0x400000L, 0x800000L,
4196    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4197    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4198   int idx;
4199
4200   for (idx = 0; idx < 32; idx++)
4201     if (lit == pw[idx])
4202       return idx + 1;
4203   return 0;
4204 }
4205
4206 /*-----------------------------------------------------------------*/
4207 /* jmpTrueOrFalse -                                                */
4208 /*-----------------------------------------------------------------*/
4209 static void
4210 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4211 {
4212   // ugly but optimized by peephole
4213   if (IC_TRUE (ic))
4214     {
4215       symbol *nlbl = newiTempLabel (NULL);
4216       emit2 ("jp !tlabel", nlbl->key + 100);
4217       emitLabel (tlbl->key + 100);
4218       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4219       emitLabel (nlbl->key + 100);
4220     }
4221   else
4222     {
4223       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4224       emitLabel (tlbl->key + 100);
4225     }
4226   ic->generated = 1;
4227 }
4228
4229 /*-----------------------------------------------------------------*/
4230 /* genAnd  - code for and                                          */
4231 /*-----------------------------------------------------------------*/
4232 static void
4233 genAnd (iCode * ic, iCode * ifx)
4234 {
4235   operand *left, *right, *result;
4236   int size, offset = 0;
4237   unsigned long lit = 0L;
4238   int bytelit = 0;
4239
4240   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4241   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4242   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4243
4244   /* if left is a literal & right is not then exchange them */
4245   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4246       AOP_NEEDSACC (left))
4247     {
4248       operand *tmp = right;
4249       right = left;
4250       left = tmp;
4251     }
4252
4253   /* if result = right then exchange them */
4254   if (sameRegs (AOP (result), AOP (right)))
4255     {
4256       operand *tmp = right;
4257       right = left;
4258       left = tmp;
4259     }
4260
4261   /* if right is bit then exchange them */
4262   if (AOP_TYPE (right) == AOP_CRY &&
4263       AOP_TYPE (left) != AOP_CRY)
4264     {
4265       operand *tmp = right;
4266       right = left;
4267       left = tmp;
4268     }
4269   if (AOP_TYPE (right) == AOP_LIT)
4270     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4271
4272   size = AOP_SIZE (result);
4273
4274   if (AOP_TYPE (left) == AOP_CRY)
4275     {
4276       wassertl (0, "Tried to perform an AND with a bit as an operand");
4277       goto release;
4278     }
4279
4280   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
4281   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
4282   if ((AOP_TYPE (right) == AOP_LIT) &&
4283       (AOP_TYPE (result) == AOP_CRY) &&
4284       (AOP_TYPE (left) != AOP_CRY))
4285     {
4286       symbol *tlbl = newiTempLabel (NULL);
4287       int sizel = AOP_SIZE (left);
4288       if (size)
4289         {
4290           /* PENDING: Test case for this. */
4291           emit2 ("scf");
4292         }
4293       while (sizel--)
4294         {
4295           if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4296             {
4297               _moveA (aopGet (AOP (left), offset, FALSE));
4298               if (bytelit != 0x0FFL)
4299                 {
4300                   emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4301                 }
4302               else
4303                 {
4304                   /* For the flags */
4305                   emit2 ("or a,a");
4306                 }
4307               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4308             }
4309               offset++;
4310         }
4311       // bit = left & literal
4312       if (size)
4313         {
4314           emit2 ("clr c");
4315           emit2 ("!tlabeldef", tlbl->key + 100);
4316         }
4317       // if(left & literal)
4318       else
4319         {
4320           if (ifx)
4321             {
4322               jmpTrueOrFalse (ifx, tlbl);
4323             }
4324           goto release;
4325         }
4326       outBitC (result);
4327       goto release;
4328     }
4329
4330   /* if left is same as result */
4331   if (sameRegs (AOP (result), AOP (left)))
4332     {
4333       for (; size--; offset++)
4334         {
4335           if (AOP_TYPE (right) == AOP_LIT)
4336             {
4337               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4338                 continue;
4339               else
4340                 {
4341                   if (bytelit == 0)
4342                     aopPut (AOP (result), "!zero", offset);
4343                   else
4344                     {
4345                       _moveA (aopGet (AOP (left), offset, FALSE));
4346                       emit2 ("and a,%s",
4347                                 aopGet (AOP (right), offset, FALSE));
4348                       aopPut (AOP (left), "a", offset);
4349                     }
4350                 }
4351
4352             }
4353           else
4354             {
4355               if (AOP_TYPE (left) == AOP_ACC)
4356                 {
4357                   wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4358                 }
4359               else
4360                 {
4361                   _moveA (aopGet (AOP (left), offset, FALSE));
4362                   emit2 ("and a,%s",
4363                             aopGet (AOP (right), offset, FALSE));
4364                   aopPut (AOP (left), "a", offset);
4365                 }
4366             }
4367         }
4368     }
4369   else
4370     {
4371       // left & result in different registers
4372       if (AOP_TYPE (result) == AOP_CRY)
4373         {
4374           wassertl (0, "Tried to AND where the result is in carry");
4375         }
4376       else
4377         {
4378           for (; (size--); offset++)
4379             {
4380               // normal case
4381               // result = left & right
4382               if (AOP_TYPE (right) == AOP_LIT)
4383                 {
4384                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4385                     {
4386                       aopPut (AOP (result),
4387                               aopGet (AOP (left), offset, FALSE),
4388                               offset);
4389                       continue;
4390                     }
4391                   else if (bytelit == 0)
4392                     {
4393                       aopPut (AOP (result), "!zero", offset);
4394                       continue;
4395                     }
4396                 }
4397               // faster than result <- left, anl result,right
4398               // and better if result is SFR
4399               if (AOP_TYPE (left) == AOP_ACC)
4400                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4401               else
4402                 {
4403                   _moveA (aopGet (AOP (left), offset, FALSE));
4404                   emit2 ("and a,%s",
4405                             aopGet (AOP (right), offset, FALSE));
4406                 }
4407               aopPut (AOP (result), "a", offset);
4408             }
4409         }
4410
4411     }
4412
4413 release:
4414   freeAsmop (left, NULL, ic);
4415   freeAsmop (right, NULL, ic);
4416   freeAsmop (result, NULL, ic);
4417 }
4418
4419 /*-----------------------------------------------------------------*/
4420 /* genOr  - code for or                                            */
4421 /*-----------------------------------------------------------------*/
4422 static void
4423 genOr (iCode * ic, iCode * ifx)
4424 {
4425   operand *left, *right, *result;
4426   int size, offset = 0;
4427   unsigned long lit = 0L;
4428   int bytelit = 0;
4429
4430   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4431   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4432   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4433
4434   /* if left is a literal & right is not then exchange them */
4435   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4436       AOP_NEEDSACC (left))
4437     {
4438       operand *tmp = right;
4439       right = left;
4440       left = tmp;
4441     }
4442
4443   /* if result = right then exchange them */
4444   if (sameRegs (AOP (result), AOP (right)))
4445     {
4446       operand *tmp = right;
4447       right = left;
4448       left = tmp;
4449     }
4450
4451   /* if right is bit then exchange them */
4452   if (AOP_TYPE (right) == AOP_CRY &&
4453       AOP_TYPE (left) != AOP_CRY)
4454     {
4455       operand *tmp = right;
4456       right = left;
4457       left = tmp;
4458     }
4459   if (AOP_TYPE (right) == AOP_LIT)
4460     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4461
4462   size = AOP_SIZE (result);
4463
4464   if (AOP_TYPE (left) == AOP_CRY)
4465     {
4466       wassertl (0, "Tried to OR where left is a bit");
4467       goto release;
4468     }
4469
4470   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
4471   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
4472   if ((AOP_TYPE (right) == AOP_LIT) &&
4473       (AOP_TYPE (result) == AOP_CRY) &&
4474       (AOP_TYPE (left) != AOP_CRY))
4475     {
4476       symbol *tlbl = newiTempLabel (NULL);
4477       int sizel = AOP_SIZE (left);
4478
4479       if (size)
4480         {
4481           wassertl (0, "Result is assigned to a bit");
4482         }
4483       /* PENDING: Modeled after the AND code which is inefficent. */
4484       while (sizel--)
4485         {
4486           bytelit = (lit >> (offset * 8)) & 0x0FFL;
4487
4488           _moveA (aopGet (AOP (left), offset, FALSE));
4489           /* OR with any literal is the same as OR with itself. */
4490           emit2 ("or a,a");
4491           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4492
4493           offset++;
4494         }
4495       if (ifx)
4496         {
4497           jmpTrueOrFalse (ifx, tlbl);
4498         }
4499       goto release;
4500     }
4501
4502   /* if left is same as result */
4503   if (sameRegs (AOP (result), AOP (left)))
4504     {
4505       for (; size--; offset++)
4506         {
4507           if (AOP_TYPE (right) == AOP_LIT)
4508             {
4509               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4510                 continue;
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           else
4520             {
4521               if (AOP_TYPE (left) == AOP_ACC)
4522                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4523               else
4524                 {
4525                   _moveA (aopGet (AOP (left), offset, FALSE));
4526                   emit2 ("or a,%s",
4527                             aopGet (AOP (right), offset, FALSE));
4528                   aopPut (AOP (result), "a", offset);
4529                 }
4530             }
4531         }
4532     }
4533   else
4534     {
4535       // left & result in different registers
4536       if (AOP_TYPE (result) == AOP_CRY)
4537         {
4538           wassertl (0, "Result of OR is in a bit");
4539         }
4540       else
4541         for (; (size--); offset++)
4542           {
4543             // normal case
4544             // result = left & right
4545             if (AOP_TYPE (right) == AOP_LIT)
4546               {
4547                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4548                   {
4549                     aopPut (AOP (result),
4550                             aopGet (AOP (left), offset, FALSE),
4551                             offset);
4552                     continue;
4553                   }
4554               }
4555             // faster than result <- left, anl result,right
4556             // and better if result is SFR
4557             if (AOP_TYPE (left) == AOP_ACC)
4558               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4559             else
4560               {
4561                 _moveA (aopGet (AOP (left), offset, FALSE));
4562                 emit2 ("or a,%s",
4563                           aopGet (AOP (right), offset, FALSE));
4564               }
4565             aopPut (AOP (result), "a", offset);
4566             /* PENDING: something weird is going on here.  Add exception. */
4567             if (AOP_TYPE (result) == AOP_ACC)
4568               break;
4569           }
4570     }
4571
4572 release:
4573   freeAsmop (left, NULL, ic);
4574   freeAsmop (right, NULL, ic);
4575   freeAsmop (result, NULL, ic);
4576 }
4577
4578 /*-----------------------------------------------------------------*/
4579 /* genXor - code for xclusive or                                   */
4580 /*-----------------------------------------------------------------*/
4581 static void
4582 genXor (iCode * ic, iCode * ifx)
4583 {
4584   operand *left, *right, *result;
4585   int size, offset = 0;
4586   unsigned long lit = 0L;
4587
4588   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4589   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4590   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4591
4592   /* if left is a literal & right is not then exchange them */
4593   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4594       AOP_NEEDSACC (left))
4595     {
4596       operand *tmp = right;
4597       right = left;
4598       left = tmp;
4599     }
4600
4601   /* if result = right then exchange them */
4602   if (sameRegs (AOP (result), AOP (right)))
4603     {
4604       operand *tmp = right;
4605       right = left;
4606       left = tmp;
4607     }
4608
4609   /* if right is bit then exchange them */
4610   if (AOP_TYPE (right) == AOP_CRY &&
4611       AOP_TYPE (left) != AOP_CRY)
4612     {
4613       operand *tmp = right;
4614       right = left;
4615       left = tmp;
4616     }
4617   if (AOP_TYPE (right) == AOP_LIT)
4618     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4619
4620   size = AOP_SIZE (result);
4621
4622   if (AOP_TYPE (left) == AOP_CRY)
4623     {
4624       wassertl (0, "Tried to XOR a bit");
4625       goto release;
4626     }
4627
4628   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
4629   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
4630   if ((AOP_TYPE (right) == AOP_LIT) &&
4631       (AOP_TYPE (result) == AOP_CRY) &&
4632       (AOP_TYPE (left) != AOP_CRY))
4633     {
4634       symbol *tlbl = newiTempLabel (NULL);
4635       int sizel = AOP_SIZE (left);
4636
4637       if (size)
4638         {
4639           /* PENDING: Test case for this. */
4640           wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4641         }
4642       while (sizel--)
4643         {
4644           _moveA (aopGet (AOP (left), offset, FALSE));
4645           emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4646           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4647           offset++;
4648         }
4649       if (ifx)
4650         {
4651           jmpTrueOrFalse (ifx, tlbl);
4652         }
4653       else
4654         {
4655           wassertl (0, "Result of XOR was destined for a bit");
4656         }
4657       goto release;
4658     }
4659
4660   /* if left is same as result */
4661   if (sameRegs (AOP (result), AOP (left)))
4662     {
4663       for (; size--; offset++)
4664         {
4665           if (AOP_TYPE (right) == AOP_LIT)
4666             {
4667               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4668                 continue;
4669               else
4670                 {
4671                   _moveA (aopGet (AOP (right), offset, FALSE));
4672                   emit2 ("xor a,%s",
4673                             aopGet (AOP (left), offset, FALSE));
4674                   aopPut (AOP (result), "a", offset);
4675                 }
4676             }
4677           else
4678             {
4679               if (AOP_TYPE (left) == AOP_ACC)
4680                 {
4681                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4682                 }
4683               else
4684                 {
4685                   _moveA (aopGet (AOP (right), offset, FALSE));
4686                   emit2 ("xor a,%s",
4687                             aopGet (AOP (left), offset, FALSE));
4688                   aopPut (AOP (result), "a", 0);
4689                 }
4690             }
4691         }
4692     }
4693   else
4694     {
4695       // left & result in different registers
4696       if (AOP_TYPE (result) == AOP_CRY)
4697         {
4698           wassertl (0, "Result of XOR is in a bit");
4699         }
4700       else
4701         for (; (size--); offset++)
4702           {
4703             // normal case
4704             // result = left & right
4705             if (AOP_TYPE (right) == AOP_LIT)
4706               {
4707                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4708                   {
4709                     aopPut (AOP (result),
4710                             aopGet (AOP (left), offset, FALSE),
4711                             offset);
4712                     continue;
4713                   }
4714               }
4715             // faster than result <- left, anl result,right
4716             // and better if result is SFR
4717             if (AOP_TYPE (left) == AOP_ACC) 
4718               {
4719                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4720               }
4721             else
4722               {
4723                 _moveA (aopGet (AOP (right), offset, FALSE));
4724                 emit2 ("xor a,%s",
4725                           aopGet (AOP (left), offset, FALSE));
4726               }
4727             aopPut (AOP (result), "a", offset);
4728           }
4729     }
4730
4731 release:
4732   freeAsmop (left, NULL, ic);
4733   freeAsmop (right, NULL, ic);
4734   freeAsmop (result, NULL, ic);
4735 }
4736
4737 /*-----------------------------------------------------------------*/
4738 /* genInline - write the inline code out                           */
4739 /*-----------------------------------------------------------------*/
4740 static void
4741 genInline (iCode * ic)
4742 {
4743   char *buffer, *bp, *bp1;
4744
4745   _G.lines.isInline += (!options.asmpeep);
4746
4747   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4748   strcpy (buffer, IC_INLINE (ic));
4749
4750   /* emit each line as a code */
4751   while (*bp)
4752     {
4753       if (*bp == '\n')
4754         {
4755           *bp++ = '\0';
4756           emit2 (bp1);
4757           bp1 = bp;
4758         }
4759       else
4760         {
4761           if (*bp == ':')
4762             {
4763               bp++;
4764               *bp = '\0';
4765               bp++;
4766               emit2 (bp1);
4767               bp1 = bp;
4768             }
4769           else
4770             bp++;
4771         }
4772     }
4773   if (bp1 != bp)
4774     emit2 (bp1);
4775   _G.lines.isInline -= (!options.asmpeep);
4776
4777 }
4778
4779 /*-----------------------------------------------------------------*/
4780 /* genRRC - rotate right with carry                                */
4781 /*-----------------------------------------------------------------*/
4782 static void
4783 genRRC (iCode * ic)
4784 {
4785   wassert (0);
4786 }
4787
4788 /*-----------------------------------------------------------------*/
4789 /* genRLC - generate code for rotate left with carry               */
4790 /*-----------------------------------------------------------------*/
4791 static void
4792 genRLC (iCode * ic)
4793 {
4794   wassert (0);
4795 }
4796
4797 /*-----------------------------------------------------------------*/
4798 /* genGetHbit - generates code get highest order bit               */
4799 /*-----------------------------------------------------------------*/
4800 static void
4801 genGetHbit (iCode * ic)
4802 {
4803   operand *left, *result;
4804   left = IC_LEFT (ic);
4805   result = IC_RESULT (ic);
4806   aopOp (left, ic, FALSE, FALSE);
4807   aopOp (result, ic, FALSE, FALSE);
4808
4809   /* get the highest order byte into a */
4810   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4811
4812   if (AOP_TYPE (result) == AOP_CRY)
4813     {
4814       emit2 ("rl a");
4815       outBitC (result);
4816     }
4817   else
4818     {
4819       emit2 ("rlc a");
4820       /* PENDING: For re-target. */
4821       emit2 ("and a,#1");
4822       outAcc (result);
4823     }
4824
4825
4826   freeAsmop (left, NULL, ic);
4827   freeAsmop (result, NULL, ic);
4828 }
4829
4830 static void
4831 emitRsh2 (asmop *aop, int size, int is_signed)
4832 {
4833   int offset = 0;
4834
4835   while (size--)
4836     {
4837       const char *l = aopGet (aop, size, FALSE);
4838       if (offset == 0)
4839         {
4840           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4841         }
4842       else
4843         {
4844           emit2 ("rr %s", l);
4845         }
4846       offset++;
4847     }
4848 }
4849
4850 /*-----------------------------------------------------------------*/
4851 /* shiftR2Left2Result - shift right two bytes from left to result  */
4852 /*-----------------------------------------------------------------*/
4853 static void
4854 shiftR2Left2Result (operand * left, int offl,
4855                     operand * result, int offr,
4856                     int shCount, int is_signed)
4857 {
4858   int size = 2;
4859   symbol *tlbl, *tlbl1;
4860
4861   movLeft2Result (left, offl, result, offr, 0);
4862   movLeft2Result (left, offl + 1, result, offr + 1, 0);
4863
4864   /*  if (AOP(result)->type == AOP_REG) { */
4865   
4866   tlbl = newiTempLabel (NULL);
4867   tlbl1 = newiTempLabel (NULL);
4868
4869   /* Left is already in result - so now do the shift */
4870   if (shCount <= 4)
4871     {
4872       while (shCount--)
4873         {
4874           emitRsh2 (AOP (result), size, is_signed);
4875         }
4876     }
4877   else
4878     {
4879       emit2 ("ld a,!immedbyte+1", shCount);
4880       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4881       emitLabel (tlbl->key + 100);
4882
4883       emitRsh2 (AOP (result), size, is_signed);
4884
4885       emitLabel (tlbl1->key + 100);
4886       emit2 ("dec a");
4887       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4888     }
4889 }
4890
4891 /*-----------------------------------------------------------------*/
4892 /* shiftL2Left2Result - shift left two bytes from left to result   */
4893 /*-----------------------------------------------------------------*/
4894 static void
4895 shiftL2Left2Result (operand * left, int offl,
4896                     operand * result, int offr, int shCount)
4897 {
4898   if (sameRegs (AOP (result), AOP (left)) &&
4899       ((offl + MSB16) == offr))
4900     {
4901       wassert (0);
4902     }
4903   else
4904     {
4905       /* Copy left into result */
4906       movLeft2Result (left, offl, result, offr, 0);
4907       movLeft2Result (left, offl + 1, result, offr + 1, 0);
4908     }
4909   /* PENDING: for now just see if it'll work. */
4910   /*if (AOP(result)->type == AOP_REG) { */
4911   {
4912     int size = 2;
4913     int offset = 0;
4914     symbol *tlbl, *tlbl1;
4915     const char *l;
4916
4917     tlbl = newiTempLabel (NULL);
4918     tlbl1 = newiTempLabel (NULL);
4919
4920     /* Left is already in result - so now do the shift */
4921     if (shCount > 1)
4922       {
4923         emit2 ("ld a,!immedbyte+1", shCount);
4924         emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4925         emitLabel (tlbl->key + 100);
4926       }
4927
4928     while (size--)
4929       {
4930         l = aopGet (AOP (result), offset, FALSE);
4931
4932         if (offset == 0)
4933           {
4934             emit2 ("sla %s", l);
4935           }
4936         else
4937           {
4938             emit2 ("rl %s", l);
4939           }
4940
4941         offset++;
4942       }
4943     if (shCount > 1)
4944       {
4945         emitLabel (tlbl1->key + 100);
4946         emit2 ("dec a");
4947         emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4948       }
4949   }
4950 }
4951
4952 /*-----------------------------------------------------------------*/
4953 /* AccRol - rotate left accumulator by known count                 */
4954 /*-----------------------------------------------------------------*/
4955 static void
4956 AccRol (int shCount)
4957 {
4958   shCount &= 0x0007;            // shCount : 0..7
4959
4960   switch (shCount)
4961     {
4962     case 0:
4963       break;
4964     case 1:
4965       emit2 ("sla a");
4966       break;
4967     case 2:
4968       emit2 ("sla a");
4969       emit2 ("rl a");
4970       break;
4971     case 3:
4972       emit2 ("sla a");
4973       emit2 ("rl a");
4974       emit2 ("rl a");
4975       break;
4976     case 4:
4977       emit2 ("sla a");
4978       emit2 ("rl a");
4979       emit2 ("rl a");
4980       emit2 ("rl a");
4981       break;
4982     case 5:
4983       emit2 ("srl a");
4984       emit2 ("rr a");
4985       emit2 ("rr a");
4986       break;
4987     case 6:
4988       emit2 ("srl a");
4989       emit2 ("rr a");
4990       break;
4991     case 7:
4992       emit2 ("srl a");
4993       break;
4994     }
4995 }
4996
4997 /*-----------------------------------------------------------------*/
4998 /* AccLsh - left shift accumulator by known count                  */
4999 /*-----------------------------------------------------------------*/
5000 static void
5001 AccLsh (int shCount)
5002 {
5003   static const unsigned char SLMask[] =
5004     {
5005       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5006     };
5007
5008   if (shCount != 0)
5009     {
5010       if (shCount == 1)
5011         {
5012           emit2 ("add a,a");
5013         }
5014       else if (shCount == 2)
5015         {
5016           emit2 ("add a,a");
5017           emit2 ("add a,a");
5018         }
5019       else
5020         {
5021           /* rotate left accumulator */
5022           AccRol (shCount);
5023           /* and kill the lower order bits */
5024           emit2 ("and a,!immedbyte", SLMask[shCount]);
5025         }
5026     }
5027 }
5028
5029 /*-----------------------------------------------------------------*/
5030 /* shiftL1Left2Result - shift left one byte from left to result    */
5031 /*-----------------------------------------------------------------*/
5032 static void
5033 shiftL1Left2Result (operand * left, int offl,
5034                     operand * result, int offr, int shCount)
5035 {
5036   const char *l;
5037   l = aopGet (AOP (left), offl, FALSE);
5038   _moveA (l);
5039   /* shift left accumulator */
5040   AccLsh (shCount);
5041   aopPut (AOP (result), "a", offr);
5042 }
5043
5044
5045 /*-----------------------------------------------------------------*/
5046 /* genlshTwo - left shift two bytes by known amount != 0           */
5047 /*-----------------------------------------------------------------*/
5048 static void
5049 genlshTwo (operand * result, operand * left, int shCount)
5050 {
5051   int size = AOP_SIZE (result);
5052
5053   wassert (size == 2);
5054
5055   /* if shCount >= 8 */
5056   if (shCount >= 8)
5057     {
5058       shCount -= 8;
5059       if (size > 1)
5060         {
5061           if (shCount)
5062             {
5063               movLeft2Result (left, LSB, result, MSB16, 0);
5064               aopPut (AOP (result), "!zero", 0);
5065               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5066             }
5067           else
5068             {
5069               movLeft2Result (left, LSB, result, MSB16, 0);
5070               aopPut (AOP (result), "!zero", 0);
5071             }
5072         }
5073       else
5074         {
5075           aopPut (AOP (result), "!zero", LSB);
5076         }
5077     }
5078   /*  1 <= shCount <= 7 */
5079   else
5080     {
5081       if (size == 1)
5082         {
5083           wassert (0);
5084         }
5085       else
5086         {
5087           shiftL2Left2Result (left, LSB, result, LSB, shCount);
5088         }
5089     }
5090 }
5091
5092 /*-----------------------------------------------------------------*/
5093 /* genlshOne - left shift a one byte quantity by known count       */
5094 /*-----------------------------------------------------------------*/
5095 static void
5096 genlshOne (operand * result, operand * left, int shCount)
5097 {
5098   shiftL1Left2Result (left, LSB, result, LSB, shCount);
5099 }
5100
5101 /*-----------------------------------------------------------------*/
5102 /* genLeftShiftLiteral - left shifting by known count              */
5103 /*-----------------------------------------------------------------*/
5104 static void
5105 genLeftShiftLiteral (operand * left,
5106                      operand * right,
5107                      operand * result,
5108                      iCode * ic)
5109 {
5110   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5111   int size;
5112
5113   freeAsmop (right, NULL, ic);
5114
5115   aopOp (left, ic, FALSE, FALSE);
5116   aopOp (result, ic, FALSE, FALSE);
5117
5118   size = getSize (operandType (result));
5119
5120   /* I suppose that the left size >= result size */
5121   if (shCount == 0)
5122     {
5123       wassert (0);
5124     }
5125
5126   else if (shCount >= (size * 8)) 
5127     {
5128       while (size--)
5129         {
5130           aopPut (AOP (result), "!zero", size);
5131         }
5132     }
5133   else
5134     {
5135       switch (size)
5136         {
5137         case 1:
5138           genlshOne (result, left, shCount);
5139           break;
5140         case 2:
5141           genlshTwo (result, left, shCount);
5142           break;
5143         case 4:
5144           wassertl (0, "Shifting of longs is currently unsupported");
5145           break;
5146         default:
5147           wassert (0);
5148         }
5149     }
5150   freeAsmop (left, NULL, ic);
5151   freeAsmop (result, NULL, ic);
5152 }
5153
5154 /*-----------------------------------------------------------------*/
5155 /* genLeftShift - generates code for left shifting                 */
5156 /*-----------------------------------------------------------------*/
5157 static void
5158 genLeftShift (iCode * ic)
5159 {
5160   int size, offset;
5161   const char *l;
5162   symbol *tlbl, *tlbl1;
5163   operand *left, *right, *result;
5164
5165   right = IC_RIGHT (ic);
5166   left = IC_LEFT (ic);
5167   result = IC_RESULT (ic);
5168
5169   aopOp (right, ic, FALSE, FALSE);
5170
5171   /* if the shift count is known then do it
5172      as efficiently as possible */
5173   if (AOP_TYPE (right) == AOP_LIT)
5174     {
5175       genLeftShiftLiteral (left, right, result, ic);
5176       return;
5177     }
5178
5179   /* shift count is unknown then we have to form a loop get the loop
5180      count in B : Note: we take only the lower order byte since
5181      shifting more that 32 bits make no sense anyway, ( the largest
5182      size of an object can be only 32 bits ) */
5183   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5184   emit2 ("inc a");
5185   freeAsmop (right, NULL, ic);
5186   aopOp (left, ic, FALSE, FALSE);
5187   aopOp (result, ic, FALSE, FALSE);
5188
5189   /* now move the left to the result if they are not the
5190      same */
5191
5192   if (!sameRegs (AOP (left), AOP (result)))
5193     {
5194
5195       size = AOP_SIZE (result);
5196       offset = 0;
5197       while (size--)
5198         {
5199           l = aopGet (AOP (left), offset, FALSE);
5200           aopPut (AOP (result), l, offset);
5201           offset++;
5202         }
5203     }
5204
5205   tlbl = newiTempLabel (NULL);
5206   size = AOP_SIZE (result);
5207   offset = 0;
5208   tlbl1 = newiTempLabel (NULL);
5209
5210   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5211   emitLabel (tlbl->key + 100);
5212   l = aopGet (AOP (result), offset, FALSE);
5213
5214   while (size--)
5215     {
5216       l = aopGet (AOP (result), offset, FALSE);
5217
5218       if (offset == 0)
5219         {
5220           emit2 ("sla %s", l);
5221         }
5222       else
5223         {
5224           emit2 ("rl %s", l);
5225         }
5226       offset++;
5227     }
5228   emitLabel (tlbl1->key + 100);
5229   emit2 ("dec a");
5230   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5231
5232   freeAsmop (left, NULL, ic);
5233   freeAsmop (result, NULL, ic);
5234 }
5235
5236 /*-----------------------------------------------------------------*/
5237 /* genrshOne - left shift two bytes by known amount != 0           */
5238 /*-----------------------------------------------------------------*/
5239 static void
5240 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5241 {
5242   /* Errk */
5243   int size = AOP_SIZE (result);
5244   const char *l;
5245
5246   wassert (size == 1);
5247   wassert (shCount < 8);
5248
5249   l = aopGet (AOP (left), 0, FALSE);
5250
5251   if (AOP (result)->type == AOP_REG)
5252     {
5253       aopPut (AOP (result), l, 0);
5254       l = aopGet (AOP (result), 0, FALSE);
5255       while (shCount--)
5256         {
5257           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5258         }
5259     }
5260   else
5261     {
5262       _moveA (l);
5263       while (shCount--)
5264         {
5265           emit2 ("%s a", is_signed ? "sra" : "srl");
5266         }
5267       aopPut (AOP (result), "a", 0);
5268     }
5269 }
5270
5271 /*-----------------------------------------------------------------*/
5272 /* AccRsh - right shift accumulator by known count                 */
5273 /*-----------------------------------------------------------------*/
5274 static void
5275 AccRsh (int shCount)
5276 {
5277   static const unsigned char SRMask[] =
5278     {
5279       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5280     };
5281
5282   if (shCount != 0)
5283     {
5284       /* rotate right accumulator */
5285       AccRol (8 - shCount);
5286       /* and kill the higher order bits */
5287       emit2 ("and a,!immedbyte", SRMask[shCount]);
5288     }
5289 }
5290
5291 /*-----------------------------------------------------------------*/
5292 /* shiftR1Left2Result - shift right one byte from left to result   */
5293 /*-----------------------------------------------------------------*/
5294 static void
5295 shiftR1Left2Result (operand * left, int offl,
5296                     operand * result, int offr,
5297                     int shCount, int sign)
5298 {
5299   _moveA (aopGet (AOP (left), offl, FALSE));
5300   if (sign)
5301     {
5302       while (shCount--)
5303         {
5304           emit2 ("%s a", sign ? "sra" : "srl");
5305         }
5306     }
5307   else
5308     {
5309       AccRsh (shCount);
5310     }
5311   aopPut (AOP (result), "a", offr);
5312 }
5313
5314 /*-----------------------------------------------------------------*/
5315 /* genrshTwo - right shift two bytes by known amount != 0          */
5316 /*-----------------------------------------------------------------*/
5317 static void
5318 genrshTwo (operand * result, operand * left,
5319            int shCount, int sign)
5320 {
5321   /* if shCount >= 8 */
5322   if (shCount >= 8)
5323     {
5324       shCount -= 8;
5325       if (shCount)
5326         {
5327           shiftR1Left2Result (left, MSB16, result, LSB,
5328                               shCount, sign);
5329         }
5330       else
5331         {
5332           movLeft2Result (left, MSB16, result, LSB, sign);
5333         }
5334       if (sign)
5335         {
5336           /* Sign extend the result */
5337           _moveA(aopGet (AOP (result), 0, FALSE));
5338           emit2 ("rlc a");
5339           emit2 ("sbc a,a");
5340
5341           aopPut (AOP (result), ACC_NAME, MSB16);
5342         }
5343       else
5344         {
5345           aopPut (AOP (result), "!zero", 1);
5346         }
5347     }
5348   /*  1 <= shCount <= 7 */
5349   else
5350     {
5351       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5352     }
5353 }
5354
5355 /*-----------------------------------------------------------------*/
5356 /* genRightShiftLiteral - left shifting by known count              */
5357 /*-----------------------------------------------------------------*/
5358 static void
5359 genRightShiftLiteral (operand * left,
5360                       operand * right,
5361                       operand * result,
5362                       iCode * ic,
5363                       int sign)
5364 {
5365   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5366   int size;
5367
5368   freeAsmop (right, NULL, ic);
5369
5370   aopOp (left, ic, FALSE, FALSE);
5371   aopOp (result, ic, FALSE, FALSE);
5372
5373   size = getSize (operandType (result));
5374
5375   /* I suppose that the left size >= result size */
5376   if (shCount == 0)
5377     {
5378       wassert (0);
5379     }
5380
5381   else if (shCount >= (size * 8))
5382     while (size--)
5383       aopPut (AOP (result), "!zero", size);
5384   else
5385     {
5386       switch (size)
5387         {
5388         case 1:
5389           genrshOne (result, left, shCount, sign);
5390           break;
5391         case 2:
5392           genrshTwo (result, left, shCount, sign);
5393           break;
5394         case 4:
5395           wassertl (0, "Asked to shift right a long which should be a function call");
5396           break;
5397         default:
5398           wassertl (0, "Entered default case in right shift delegate");
5399         }
5400     }
5401   freeAsmop (left, NULL, ic);
5402   freeAsmop (result, NULL, ic);
5403 }
5404
5405 /*-----------------------------------------------------------------*/
5406 /* genRightShift - generate code for right shifting                */
5407 /*-----------------------------------------------------------------*/
5408 static void
5409 genRightShift (iCode * ic)
5410 {
5411   operand *right, *left, *result;
5412   sym_link *retype;
5413   int size, offset, first = 1;
5414   const char *l;
5415   bool is_signed;
5416
5417   symbol *tlbl, *tlbl1;
5418
5419   /* if signed then we do it the hard way preserve the
5420      sign bit moving it inwards */
5421   retype = getSpec (operandType (IC_RESULT (ic)));
5422
5423   is_signed = !SPEC_USIGN (retype);
5424
5425   /* signed & unsigned types are treated the same : i.e. the
5426      signed is NOT propagated inwards : quoting from the
5427      ANSI - standard : "for E1 >> E2, is equivalent to division
5428      by 2**E2 if unsigned or if it has a non-negative value,
5429      otherwise the result is implementation defined ", MY definition
5430      is that the sign does not get propagated */
5431
5432   right = IC_RIGHT (ic);
5433   left = IC_LEFT (ic);
5434   result = IC_RESULT (ic);
5435
5436   aopOp (right, ic, FALSE, FALSE);
5437
5438   /* if the shift count is known then do it
5439      as efficiently as possible */
5440   if (AOP_TYPE (right) == AOP_LIT)
5441     {
5442       genRightShiftLiteral (left, right, result, ic, is_signed);
5443       return;
5444     }
5445
5446   aopOp (left, ic, FALSE, FALSE);
5447   aopOp (result, ic, FALSE, FALSE);
5448
5449   /* now move the left to the result if they are not the
5450      same */
5451   if (!sameRegs (AOP (left), AOP (result)) &&
5452       AOP_SIZE (result) > 1)
5453     {
5454
5455       size = AOP_SIZE (result);
5456       offset = 0;
5457       while (size--)
5458         {
5459           l = aopGet (AOP (left), offset, FALSE);
5460           aopPut (AOP (result), l, offset);
5461           offset++;
5462         }
5463     }
5464
5465   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5466   emit2 ("inc a");
5467   freeAsmop (right, NULL, ic);
5468
5469   tlbl = newiTempLabel (NULL);
5470   tlbl1 = newiTempLabel (NULL);
5471   size = AOP_SIZE (result);
5472   offset = size - 1;
5473
5474   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5475   emitLabel (tlbl->key + 100);
5476   while (size--)
5477     {
5478       l = aopGet (AOP (result), offset--, FALSE);
5479       if (first)
5480         {
5481           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5482           first = 0;
5483         }
5484       else
5485         {
5486           emit2 ("rr %s", l);
5487         }
5488     }
5489   emitLabel (tlbl1->key + 100);
5490   emit2 ("dec a");
5491   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5492
5493   freeAsmop (left, NULL, ic);
5494   freeAsmop (result, NULL, ic);
5495 }
5496
5497 /*-----------------------------------------------------------------*/
5498 /* genGenPointerGet -  get value from generic pointer space        */
5499 /*-----------------------------------------------------------------*/
5500 static void
5501 genGenPointerGet (operand * left,
5502                   operand * result, iCode * ic)
5503 {
5504   int size, offset;
5505   sym_link *retype = getSpec (operandType (result));
5506   int pair = PAIR_HL;
5507
5508   if (IS_GB)
5509     pair = PAIR_DE;
5510
5511   aopOp (left, ic, FALSE, FALSE);
5512   aopOp (result, ic, FALSE, FALSE);
5513
5514   if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5515     {
5516       /* Just do it */
5517       if (isPtrPair (AOP (left)))
5518         {
5519           tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5520           aopPut (AOP (result), buffer, 0);
5521         }
5522       else
5523         {
5524           emit2 ("ld a,!*pair", getPairName (AOP (left)));
5525           aopPut (AOP (result), "a", 0);
5526         }
5527       freeAsmop (left, NULL, ic);
5528       goto release;
5529     }
5530
5531   /* For now we always load into IY */
5532   /* if this is remateriazable */
5533   fetchPair (pair, AOP (left));
5534
5535   /* so iy now contains the address */
5536   freeAsmop (left, NULL, ic);
5537
5538   /* if bit then unpack */
5539   if (IS_BITVAR (retype))
5540     {
5541       wassert (0);
5542     }
5543   else
5544     {
5545       size = AOP_SIZE (result);
5546       offset = 0;
5547
5548       while (size--)
5549         {
5550           /* PENDING: make this better */
5551           if (!IS_GB && AOP (result)->type == AOP_REG)
5552             {
5553               aopPut (AOP (result), "!*hl", offset++);
5554             }
5555           else
5556             {
5557               emit2 ("ld a,!*pair", _pairs[pair].name);
5558               aopPut (AOP (result), "a", offset++);
5559             }
5560           if (size)
5561             {
5562               emit2 ("inc %s", _pairs[pair].name);
5563               _G.pairs[pair].offset++;
5564             }
5565         }
5566     }
5567
5568 release:
5569   freeAsmop (result, NULL, ic);
5570 }
5571
5572 /*-----------------------------------------------------------------*/
5573 /* genPointerGet - generate code for pointer get                   */
5574 /*-----------------------------------------------------------------*/
5575 static void
5576 genPointerGet (iCode * ic)
5577 {
5578   operand *left, *result;
5579   sym_link *type, *etype;
5580
5581   left = IC_LEFT (ic);
5582   result = IC_RESULT (ic);
5583
5584   /* depending on the type of pointer we need to
5585      move it to the correct pointer register */
5586   type = operandType (left);
5587   etype = getSpec (type);
5588
5589   genGenPointerGet (left, result, ic);
5590 }
5591
5592 bool
5593 isRegOrLit (asmop * aop)
5594 {
5595   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5596     return TRUE;
5597   return FALSE;
5598 }
5599
5600 /*-----------------------------------------------------------------*/
5601 /* genGenPointerSet - stores the value into a pointer location        */
5602 /*-----------------------------------------------------------------*/
5603 static void
5604 genGenPointerSet (operand * right,
5605                   operand * result, iCode * ic)
5606 {
5607   int size, offset;
5608   sym_link *retype = getSpec (operandType (right));
5609   PAIR_ID pairId = PAIR_HL;
5610
5611   aopOp (result, ic, FALSE, FALSE);
5612   aopOp (right, ic, FALSE, FALSE);
5613
5614   if (IS_GB)
5615     pairId = PAIR_DE;
5616
5617   /* Handle the exceptions first */
5618   if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5619     {
5620       /* Just do it */
5621       const char *l = aopGet (AOP (right), 0, FALSE);
5622       const char *pair = getPairName (AOP (result));
5623       if (canAssignToPtr (l) && isPtr (pair))
5624         {
5625           emit2 ("ld !*pair,%s", pair, l);
5626         }
5627       else
5628         {
5629           _moveA (l);
5630           emit2 ("ld !*pair,a", pair);
5631         }
5632       goto release;
5633     }
5634
5635   /* if the operand is already in dptr
5636      then we do nothing else we move the value to dptr */
5637   if (AOP_TYPE (result) != AOP_STR)
5638     {
5639       fetchPair (pairId, AOP (result));
5640     }
5641   /* so hl know contains the address */
5642   freeAsmop (result, NULL, ic);
5643
5644   /* if bit then unpack */
5645   if (IS_BITVAR (retype))
5646     {
5647       wassert (0);
5648     }
5649   else
5650     {
5651       size = AOP_SIZE (right);
5652       offset = 0;
5653
5654       while (size--)
5655         {
5656           const char *l = aopGet (AOP (right), offset, FALSE);
5657           if (isRegOrLit (AOP (right)) && !IS_GB)
5658             {
5659               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5660             }
5661           else
5662             {
5663               _moveA (l);
5664               emit2 ("ld !*pair,a", _pairs[pairId].name);
5665             }
5666           if (size)
5667             {
5668               emit2 ("inc %s", _pairs[pairId].name);
5669               _G.pairs[pairId].offset++;
5670             }
5671           offset++;
5672         }
5673     }
5674 release:
5675   freeAsmop (right, NULL, ic);
5676 }
5677
5678 /*-----------------------------------------------------------------*/
5679 /* genPointerSet - stores the value into a pointer location        */
5680 /*-----------------------------------------------------------------*/
5681 static void
5682 genPointerSet (iCode * ic)
5683 {
5684   operand *right, *result;
5685   sym_link *type, *etype;
5686
5687   right = IC_RIGHT (ic);
5688   result = IC_RESULT (ic);
5689
5690   /* depending on the type of pointer we need to
5691      move it to the correct pointer register */
5692   type = operandType (result);
5693   etype = getSpec (type);
5694
5695   genGenPointerSet (right, result, ic);
5696 }
5697
5698 /*-----------------------------------------------------------------*/
5699 /* genIfx - generate code for Ifx statement                        */
5700 /*-----------------------------------------------------------------*/
5701 static void
5702 genIfx (iCode * ic, iCode * popIc)
5703 {
5704   operand *cond = IC_COND (ic);
5705   int isbit = 0;
5706
5707   aopOp (cond, ic, FALSE, TRUE);
5708
5709   /* get the value into acc */
5710   if (AOP_TYPE (cond) != AOP_CRY)
5711     _toBoolean (cond);
5712   else
5713     isbit = 1;
5714   /* the result is now in the accumulator */
5715   freeAsmop (cond, NULL, ic);
5716
5717   /* if there was something to be popped then do it */
5718   if (popIc)
5719     genIpop (popIc);
5720
5721   /* if the condition is  a bit variable */
5722   if (isbit && IS_ITEMP (cond) &&
5723       SPIL_LOC (cond))
5724     genIfxJump (ic, SPIL_LOC (cond)->rname);
5725   else if (isbit && !IS_ITEMP (cond))
5726     genIfxJump (ic, OP_SYMBOL (cond)->rname);
5727   else
5728     genIfxJump (ic, "a");
5729
5730   ic->generated = 1;
5731 }
5732
5733 /*-----------------------------------------------------------------*/
5734 /* genAddrOf - generates code for address of                       */
5735 /*-----------------------------------------------------------------*/
5736 static void
5737 genAddrOf (iCode * ic)
5738 {
5739   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5740
5741   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5742
5743   /* if the operand is on the stack then we
5744      need to get the stack offset of this
5745      variable */
5746   if (IS_GB)
5747     {
5748       if (sym->onStack)
5749         {
5750           spillCached ();
5751           if (sym->stack <= 0)
5752             {
5753               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
5754             }
5755           else
5756             {
5757               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5758             }
5759           commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5760         }
5761       else
5762         {
5763           emit2 ("ld de,!hashedstr", sym->rname);
5764           commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
5765         }
5766     }
5767   else
5768     {
5769       spillCached ();
5770       if (sym->onStack)
5771         {
5772           /* if it has an offset  then we need to compute it */
5773           if (sym->stack > 0)
5774             emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5775           else
5776             emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5777           emit2 ("add hl,sp");
5778         }
5779       else
5780         {
5781           emit2 ("ld hl,#%s", sym->rname);
5782         }
5783       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5784     }
5785   freeAsmop (IC_RESULT (ic), NULL, ic);
5786 }
5787
5788 /*-----------------------------------------------------------------*/
5789 /* genAssign - generate code for assignment                        */
5790 /*-----------------------------------------------------------------*/
5791 static void
5792 genAssign (iCode * ic)
5793 {
5794   operand *result, *right;
5795   int size, offset;
5796   unsigned long lit = 0L;
5797
5798   result = IC_RESULT (ic);
5799   right = IC_RIGHT (ic);
5800
5801   /* Dont bother assigning if they are the same */
5802   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5803     {
5804       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5805       return;
5806     }
5807
5808   aopOp (right, ic, FALSE, FALSE);
5809   aopOp (result, ic, TRUE, FALSE);
5810
5811   /* if they are the same registers */
5812   if (sameRegs (AOP (right), AOP (result)))
5813     {
5814       emitDebug ("; (registers are the same)");
5815       goto release;
5816     }
5817
5818   /* if the result is a bit */
5819   if (AOP_TYPE (result) == AOP_CRY)
5820     {
5821       wassertl (0, "Tried to assign to a bit");
5822     }
5823
5824   /* general case */
5825   size = AOP_SIZE (result);
5826   offset = 0;
5827
5828   if (AOP_TYPE (right) == AOP_LIT)
5829     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5830   if (isPair (AOP (result)))
5831     {
5832       fetchPair (getPairId (AOP (result)), AOP (right));
5833     }
5834   else if ((size > 1) &&
5835            (AOP_TYPE (result) != AOP_REG) &&
5836            (AOP_TYPE (right) == AOP_LIT) &&
5837            !IS_FLOAT (operandType (right)) &&
5838            (lit < 256L))
5839     {
5840       bool fXored = FALSE;
5841       offset = 0;
5842       /* Work from the top down.
5843          Done this way so that we can use the cached copy of 0
5844          in A for a fast clear */
5845       while (size--)
5846         {
5847           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5848             {
5849               if (!fXored && size > 1)
5850                 {
5851                   emit2 ("xor a,a");
5852                   fXored = TRUE;
5853                 }
5854               if (fXored)
5855                 {
5856                   aopPut (AOP (result), "a", offset);
5857                 }
5858               else
5859                 {
5860                   aopPut (AOP (result), "!zero", offset);
5861                 }
5862             }
5863           else
5864             aopPut (AOP (result),
5865                     aopGet (AOP (right), offset, FALSE),
5866                     offset);
5867           offset++;
5868         }
5869     }
5870   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5871     {
5872       /* Special case.  Load into a and d, then load out. */
5873       _moveA (aopGet (AOP (right), 0, FALSE));
5874       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5875       aopPut (AOP (result), "a", 0);
5876       aopPut (AOP (result), "e", 1);
5877     }
5878   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5879     {
5880       /* Special case - simple memcpy */
5881       aopGet (AOP (right), LSB, FALSE);
5882       emit2 ("ld d,h");
5883       emit2 ("ld e,l");
5884       aopGet (AOP (result), LSB, FALSE);
5885
5886       while (size--)
5887         {
5888           emit2 ("ld a,(de)");
5889           /* Peephole will optimise this. */
5890           emit2 ("ld (hl),a");
5891
5892           if (size != 0)
5893             {
5894               emit2 ("inc hl");
5895               emit2 ("inc de");
5896             }
5897         }
5898       spillPair (PAIR_HL);
5899     }
5900   else
5901     {
5902       while (size--)
5903         {
5904           /* PENDING: do this check better */
5905           if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5906             {
5907               _moveA (aopGet (AOP (right), offset, FALSE));
5908               aopPut (AOP (result), "a", offset);
5909             }
5910           else
5911             aopPut (AOP (result),
5912                     aopGet (AOP (right), offset, FALSE),
5913                     offset);
5914           offset++;
5915         }
5916     }
5917
5918 release:
5919   freeAsmop (right, NULL, ic);
5920   freeAsmop (result, NULL, ic);
5921 }
5922
5923 /*-----------------------------------------------------------------*/
5924 /* genJumpTab - genrates code for jump table                       */
5925 /*-----------------------------------------------------------------*/
5926 static void
5927 genJumpTab (iCode * ic)
5928 {
5929   symbol *jtab;
5930   const char *l;
5931
5932   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5933   /* get the condition into accumulator */
5934   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5935   if (!IS_GB)
5936     emit2 ("push de");
5937   emit2 ("ld e,%s", l);
5938   emit2 ("ld d,!zero");
5939   jtab = newiTempLabel (NULL);
5940   spillCached ();
5941   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5942   emit2 ("add hl,de");
5943   emit2 ("add hl,de");
5944   emit2 ("add hl,de");
5945   freeAsmop (IC_JTCOND (ic), NULL, ic);
5946   if (!IS_GB)
5947     emit2 ("pop de");
5948   emit2 ("jp !*hl");
5949   emitLabel (jtab->key + 100);
5950   /* now generate the jump labels */
5951   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5952        jtab = setNextItem (IC_JTLABELS (ic)))
5953     emit2 ("jp !tlabel", jtab->key + 100);
5954 }
5955
5956 /*-----------------------------------------------------------------*/
5957 /* genCast - gen code for casting                                  */
5958 /*-----------------------------------------------------------------*/
5959 static void
5960 genCast (iCode * ic)
5961 {
5962   operand *result = IC_RESULT (ic);
5963   sym_link *ctype = operandType (IC_LEFT (ic));
5964   operand *right = IC_RIGHT (ic);
5965   int size, offset;
5966
5967   /* if they are equivalent then do nothing */
5968   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5969     return;
5970
5971   aopOp (right, ic, FALSE, FALSE);
5972   aopOp (result, ic, FALSE, FALSE);
5973
5974   /* if the result is a bit */
5975   if (AOP_TYPE (result) == AOP_CRY)
5976     {
5977       wassertl (0, "Tried to cast to a bit");
5978     }
5979
5980   /* if they are the same size : or less */
5981   if (AOP_SIZE (result) <= AOP_SIZE (right))
5982     {
5983
5984       /* if they are in the same place */
5985       if (sameRegs (AOP (right), AOP (result)))
5986         goto release;
5987
5988       /* if they in different places then copy */
5989       size = AOP_SIZE (result);
5990       offset = 0;
5991       while (size--)
5992         {
5993           aopPut (AOP (result),
5994                   aopGet (AOP (right), offset, FALSE),
5995                   offset);
5996           offset++;
5997         }
5998       goto release;
5999     }
6000
6001   /* So we now know that the size of destination is greater
6002      than the size of the source */
6003   /* we move to result for the size of source */
6004   size = AOP_SIZE (right);
6005   offset = 0;
6006   while (size--)
6007     {
6008       aopPut (AOP (result),
6009               aopGet (AOP (right), offset, FALSE),
6010               offset);
6011       offset++;
6012     }
6013
6014   /* now depending on the sign of the destination */
6015   size = AOP_SIZE (result) - AOP_SIZE (right);
6016   /* Unsigned or not an integral type - right fill with zeros */
6017   if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6018     {
6019       while (size--)
6020         aopPut (AOP (result), "!zero", offset++);
6021     }
6022   else
6023     {
6024       /* we need to extend the sign :{ */
6025         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6026                         FALSE);
6027       _moveA (l);
6028       emit2 ("rla ");
6029       emit2 ("sbc a,a");
6030       while (size--)
6031         aopPut (AOP (result), "a", offset++);
6032     }
6033
6034 release:
6035   freeAsmop (right, NULL, ic);
6036   freeAsmop (result, NULL, ic);
6037 }
6038
6039 /*-----------------------------------------------------------------*/
6040 /* genReceive - generate code for a receive iCode                  */
6041 /*-----------------------------------------------------------------*/
6042 static void
6043 genReceive (iCode * ic)
6044 {
6045   if (isOperandInFarSpace (IC_RESULT (ic)) &&
6046       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6047        IS_TRUE_SYMOP (IC_RESULT (ic))))
6048     {
6049       wassert (0);
6050     }
6051   else
6052     {
6053         // PENDING: HACK
6054         int size;
6055         int i;
6056
6057         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6058         size = AOP_SIZE(IC_RESULT(ic));
6059
6060         for (i = 0; i < size; i++) {
6061             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6062         }
6063     }
6064
6065   freeAsmop (IC_RESULT (ic), NULL, ic);
6066 }
6067
6068 enum
6069   {
6070     /** Maximum number of bytes to emit per line. */
6071     DBEMIT_MAX_RUN = 8
6072   };
6073
6074 /** Context for the byte output chunker. */
6075 typedef struct
6076 {
6077   unsigned char buffer[DBEMIT_MAX_RUN];
6078   int pos;
6079 } DBEMITCTX;
6080
6081
6082 /** Flushes a byte chunker by writing out all in the buffer and
6083     reseting. 
6084 */
6085 static void
6086 _dbFlush(DBEMITCTX *self)
6087 {
6088   char line[256];
6089
6090   if (self->pos > 0)
6091     {
6092       int i;
6093       sprintf(line, ".db 0x%02X", self->buffer[0]);
6094
6095       for (i = 1; i < self->pos; i++)
6096         {
6097           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6098         }
6099       emit2(line);
6100     }
6101   self->pos = 0;
6102 }
6103
6104 /** Write out another byte, buffering until a decent line is
6105     generated.
6106 */
6107 static void
6108 _dbEmit(DBEMITCTX *self, int c)
6109 {
6110   if (self->pos == DBEMIT_MAX_RUN)
6111     {
6112       _dbFlush(self);
6113     }
6114   self->buffer[self->pos++] = c;
6115 }
6116
6117 /** Context for a simple run length encoder. */
6118 typedef struct
6119 {
6120   unsigned last;
6121   unsigned char buffer[128];
6122   int pos;
6123   /** runLen may be equivalent to pos. */
6124   int runLen;
6125 } RLECTX;
6126
6127 enum
6128   {
6129     RLE_CHANGE_COST = 4,
6130     RLE_MAX_BLOCK = 127
6131   };
6132
6133 /** Flush the buffer of a run length encoder by writing out the run or
6134     data that it currently contains.
6135 */
6136 static void
6137 _rleCommit(RLECTX *self)
6138 {
6139   int i;
6140   if (self->pos != 0)
6141     {
6142       DBEMITCTX db;
6143       memset(&db, 0, sizeof(db));
6144           
6145       emit2(".db %u", self->pos);
6146       
6147       for (i = 0; i < self->pos; i++)
6148         {
6149           _dbEmit(&db, self->buffer[i]);
6150         }
6151       _dbFlush(&db);
6152     }
6153   /* Reset */
6154   self->pos = 0;
6155 }
6156
6157 /* Encoder design:
6158    Can get either a run or a block of random stuff.
6159    Only want to change state if a good run comes in or a run ends.
6160    Detecting run end is easy.
6161    Initial state?
6162
6163    Say initial state is in run, len zero, last zero.  Then if you get a
6164    few zeros then something else then a short run will be output.
6165    Seems OK.  While in run mode, keep counting.  While in random mode,
6166    keep a count of the run.  If run hits margin, output all up to run,
6167    restart, enter run mode.
6168 */
6169
6170 /** Add another byte into the run length encoder, flushing as
6171     required.  The run length encoder uses the Amiga IFF style, where
6172     a block is prefixed by its run length.  A positive length means
6173     the next n bytes pass straight through.  A negative length means
6174     that the next byte is repeated -n times.  A zero terminates the
6175     chunks.
6176 */
6177 static void
6178 _rleAppend(RLECTX *self, int c)
6179 {
6180   int i;
6181
6182   if (c != self->last)
6183     {
6184       /* The run has stopped.  See if it is worthwhile writing it out
6185          as a run.  Note that the random data comes in as runs of
6186          length one.
6187       */
6188       if (self->runLen > RLE_CHANGE_COST)
6189         {
6190           /* Yes, worthwhile. */
6191           /* Commit whatever was in the buffer. */
6192           _rleCommit(self);
6193           emit2(".db -%u,0x%02X", self->runLen, self->last);
6194         }
6195       else
6196         {
6197           /* Not worthwhile.  Append to the end of the random list. */
6198           for (i = 0; i < self->runLen; i++)
6199             {
6200               if (self->pos >= RLE_MAX_BLOCK)
6201                 {
6202                   /* Commit. */
6203                   _rleCommit(self);
6204                 }
6205               self->buffer[self->pos++] = self->last;
6206             }
6207         }
6208       self->runLen = 1;
6209       self->last = c;
6210     }
6211   else
6212     {
6213       if (self->runLen >= RLE_MAX_BLOCK)
6214         {
6215           /* Commit whatever was in the buffer. */
6216           _rleCommit(self);
6217
6218           emit2 (".db -%u,0x%02X", self->runLen, self->last);
6219           self->runLen = 0;
6220         }
6221       self->runLen++;
6222     }
6223 }
6224
6225 static void
6226 _rleFlush(RLECTX *self)
6227 {
6228   _rleAppend(self, -1);
6229   _rleCommit(self);
6230   self->pos = 0;
6231   self->last = 0;
6232   self->runLen = 0;
6233 }
6234
6235 /** genArrayInit - Special code for initialising an array with constant
6236    data.
6237 */
6238 static void
6239 genArrayInit (iCode * ic)
6240 {
6241   literalList *iLoop;
6242   int         ix;
6243   int         elementSize = 0, eIndex, i;
6244   unsigned    val, lastVal;
6245   sym_link    *type;
6246   RLECTX      rle;
6247
6248   memset(&rle, 0, sizeof(rle));
6249
6250   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6251
6252   _saveRegsForCall(ic, 0);
6253
6254   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6255   emit2 ("call __initrleblock");
6256     
6257   type = operandType(IC_LEFT(ic));
6258     
6259   if (type && type->next)
6260     {
6261       elementSize = getSize(type->next);
6262     }
6263   else
6264     {
6265       wassertl (0, "Can't determine element size in genArrayInit.");
6266     }
6267
6268   iLoop = IC_ARRAYILIST(ic);
6269   lastVal = (unsigned)-1;
6270
6271   /* Feed all the bytes into the run length encoder which will handle
6272      the actual output.
6273      This works well for mixed char data, and for random int and long
6274      data.
6275   */
6276   while (iLoop)
6277     {
6278       ix = iLoop->count;
6279
6280       if (ix != 0)
6281         {
6282           for (i = 0; i < ix; i++)
6283             {
6284               for (eIndex = 0; eIndex < elementSize; eIndex++)
6285                 {
6286                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6287                   _rleAppend(&rle, val);
6288                 }
6289             }
6290         }
6291         
6292       iLoop = iLoop->next;
6293     }
6294
6295   _rleFlush(&rle);
6296   /* Mark the end of the run. */
6297   emit2(".db 0");
6298
6299   _restoreRegsAfterCall();
6300
6301   spillCached ();
6302
6303   freeAsmop (IC_LEFT(ic), NULL, ic);
6304 }
6305
6306 /*-----------------------------------------------------------------*/
6307 /* genZ80Code - generate code for Z80 based controllers            */
6308 /*-----------------------------------------------------------------*/
6309 void
6310 genZ80Code (iCode * lic)
6311 {
6312   iCode *ic;
6313   int cln = 0;
6314
6315   /* Hack */
6316   if (IS_GB)
6317     {
6318       _fReturn = _gbz80_return;
6319       _fTmp = _gbz80_return;
6320     }
6321   else
6322     {
6323       _fReturn = _z80_return;
6324       _fTmp = _z80_return;
6325     }
6326
6327   _G.lines.head = _G.lines.current = NULL;
6328
6329   for (ic = lic; ic; ic = ic->next)
6330     {
6331
6332       if (cln != ic->lineno)
6333         {
6334           emit2 ("; %s %d", ic->filename, ic->lineno);
6335           cln = ic->lineno;
6336         }
6337       /* if the result is marked as
6338          spilt and rematerializable or code for
6339          this has already been generated then
6340          do nothing */
6341       if (resultRemat (ic) || ic->generated)
6342         continue;
6343
6344       /* depending on the operation */
6345       switch (ic->op)
6346         {
6347         case '!':
6348           emitDebug ("; genNot");
6349           genNot (ic);
6350           break;
6351
6352         case '~':
6353           emitDebug ("; genCpl");
6354           genCpl (ic);
6355           break;
6356
6357         case UNARYMINUS:
6358           emitDebug ("; genUminus");
6359           genUminus (ic);
6360           break;
6361
6362         case IPUSH:
6363           emitDebug ("; genIpush");
6364           genIpush (ic);
6365           break;
6366
6367         case IPOP:
6368           /* IPOP happens only when trying to restore a
6369              spilt live range, if there is an ifx statement
6370              following this pop then the if statement might
6371              be using some of the registers being popped which
6372              would destory the contents of the register so
6373              we need to check for this condition and handle it */
6374           if (ic->next &&
6375               ic->next->op == IFX &&
6376               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6377             {
6378               emitDebug ("; genIfx");
6379               genIfx (ic->next, ic);
6380             }
6381           else
6382             {
6383               emitDebug ("; genIpop");
6384               genIpop (ic);
6385             }
6386           break;
6387
6388         case CALL:
6389           emitDebug ("; genCall");
6390           genCall (ic);
6391           break;
6392
6393         case PCALL:
6394           emitDebug ("; genPcall");
6395           genPcall (ic);
6396           break;
6397
6398         case FUNCTION:
6399           emitDebug ("; genFunction");
6400           genFunction (ic);
6401           break;
6402
6403         case ENDFUNCTION:
6404           emitDebug ("; genEndFunction");
6405           genEndFunction (ic);
6406           break;
6407
6408         case RETURN:
6409           emitDebug ("; genRet");
6410           genRet (ic);
6411           break;
6412
6413         case LABEL:
6414           emitDebug ("; genLabel");
6415           genLabel (ic);
6416           break;
6417
6418         case GOTO:
6419           emitDebug ("; genGoto");
6420           genGoto (ic);
6421           break;
6422
6423         case '+':
6424           emitDebug ("; genPlus");
6425           genPlus (ic);
6426           break;
6427
6428         case '-':
6429           emitDebug ("; genMinus");
6430           genMinus (ic);
6431           break;
6432
6433         case '*':
6434           emitDebug ("; genMult");
6435           genMult (ic);
6436           break;
6437
6438         case '/':
6439           emitDebug ("; genDiv");
6440           genDiv (ic);
6441           break;
6442
6443         case '%':
6444           emitDebug ("; genMod");
6445           genMod (ic);
6446           break;
6447
6448         case '>':
6449           emitDebug ("; genCmpGt");
6450           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6451           break;
6452
6453         case '<':
6454           emitDebug ("; genCmpLt");
6455           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6456           break;
6457
6458         case LE_OP:
6459         case GE_OP:
6460         case NE_OP:
6461
6462           /* note these two are xlated by algebraic equivalence
6463              during parsing SDCC.y */
6464           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6465                   "got '>=' or '<=' shouldn't have come here");
6466           break;
6467
6468         case EQ_OP:
6469           emitDebug ("; genCmpEq");
6470           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6471           break;
6472
6473         case AND_OP:
6474           emitDebug ("; genAndOp");
6475           genAndOp (ic);
6476           break;
6477
6478         case OR_OP:
6479           emitDebug ("; genOrOp");
6480           genOrOp (ic);
6481           break;
6482
6483         case '^':
6484           emitDebug ("; genXor");
6485           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6486           break;
6487
6488         case '|':
6489           emitDebug ("; genOr");
6490           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6491           break;
6492
6493         case BITWISEAND:
6494           emitDebug ("; genAnd");
6495           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6496           break;
6497
6498         case INLINEASM:
6499           emitDebug ("; genInline");
6500           genInline (ic);
6501           break;
6502
6503         case RRC:
6504           emitDebug ("; genRRC");
6505           genRRC (ic);
6506           break;
6507
6508         case RLC:
6509           emitDebug ("; genRLC");
6510           genRLC (ic);
6511           break;
6512
6513         case GETHBIT:
6514           emitDebug ("; genGetHBIT");
6515           genGetHbit (ic);
6516           break;
6517
6518         case LEFT_OP:
6519           emitDebug ("; genLeftShift");
6520           genLeftShift (ic);
6521           break;
6522
6523         case RIGHT_OP:
6524           emitDebug ("; genRightShift");
6525           genRightShift (ic);
6526           break;
6527
6528         case GET_VALUE_AT_ADDRESS:
6529           emitDebug ("; genPointerGet");
6530           genPointerGet (ic);
6531           break;
6532
6533         case '=':
6534
6535           if (POINTER_SET (ic))
6536             {
6537               emitDebug ("; genAssign (pointer)");
6538               genPointerSet (ic);
6539             }
6540           else
6541             {
6542               emitDebug ("; genAssign");
6543               genAssign (ic);
6544             }
6545           break;
6546
6547         case IFX:
6548           emitDebug ("; genIfx");
6549           genIfx (ic, NULL);
6550           break;
6551
6552         case ADDRESS_OF:
6553           emitDebug ("; genAddrOf");
6554           genAddrOf (ic);
6555           break;
6556
6557         case JUMPTABLE:
6558           emitDebug ("; genJumpTab");
6559           genJumpTab (ic);
6560           break;
6561
6562         case CAST:
6563           emitDebug ("; genCast");
6564           genCast (ic);
6565           break;
6566
6567         case RECEIVE:
6568           emitDebug ("; genReceive");
6569           genReceive (ic);
6570           break;
6571
6572         case SEND:
6573           emitDebug ("; addSet");
6574           addSet (&_G.sendSet, ic);
6575           break;
6576
6577         case ARRAYINIT:
6578           emitDebug ("; genArrayInit");
6579           genArrayInit(ic);
6580           break;
6581             
6582         default:
6583           ic = ic;
6584         }
6585     }
6586
6587
6588   /* now we are ready to call the
6589      peep hole optimizer */
6590   if (!options.nopeep)
6591     peepHole (&_G.lines.head);
6592
6593   /* This is unfortunate */
6594   /* now do the actual printing */
6595   {
6596     FILE *fp = codeOutFile;
6597     if (isInHome () && codeOutFile == code->oFile)
6598       codeOutFile = home->oFile;
6599     printLine (_G.lines.head, codeOutFile);
6600     if (_G.flushStatics)
6601       {
6602         flushStatics ();
6603         _G.flushStatics = 0;
6604       }
6605     codeOutFile = fp;
6606   }
6607
6608   freeTrace(&_G.lines.trace);
6609   freeTrace(&_G.trace.aops);
6610 }
6611
6612 /*
6613   Attic
6614 static int
6615 _isPairUsed (iCode * ic, PAIR_ID pairId)
6616 {
6617   int ret = 0;
6618   switch (pairId)
6619     {
6620     case PAIR_DE:
6621       if (bitVectBitValue (ic->rMask, D_IDX))
6622         ret++;
6623       if (bitVectBitValue (ic->rMask, E_IDX))
6624         ret++;
6625       break;
6626     default:
6627       wassert (0);
6628     }
6629   return ret;
6630 }
6631
6632 static char *
6633 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6634 {
6635   unsigned long v;
6636   value *val = aop->aopu.aop_lit;
6637
6638   wassert (aop->type == AOP_LIT);
6639   wassert (!IS_FLOAT (val->type));
6640
6641   v = (unsigned long) floatFromVal (val);
6642
6643   if (xor)
6644     v ^= 0x8000;
6645   if (negate)
6646     v = 0-v;
6647   v &= 0xFFFF;
6648
6649   tsprintf (buffer, "!immedword", v);
6650   return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
6651 }
6652
6653
6654 */