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