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