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