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