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