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