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