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