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