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