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