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