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