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