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