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