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