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