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