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