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