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