Fixed bug 772726
[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       emit2 ("ld d,h");
1836       aopPut (aop, "a", 0);
1837       aopPut (aop, "d", 1);
1838     }
1839   else
1840     {
1841       /* Special cases */
1842       if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1843         {
1844           char *l = aopGetLitWordLong (aop, 0, FALSE);
1845           wassert (l);
1846
1847           emit2 ("ld (%s),%s", l, _pairs[id].name);
1848         }
1849       else
1850         {
1851           aopPut (aop, _pairs[id].l, 0);
1852           aopPut (aop, _pairs[id].h, 1);
1853         }
1854     }
1855 }
1856
1857 /*-----------------------------------------------------------------*/
1858 /* getDataSize - get the operand data size                         */
1859 /*-----------------------------------------------------------------*/
1860 int
1861 getDataSize (operand * op)
1862 {
1863   int size;
1864   size = AOP_SIZE (op);
1865   if (size == 3)
1866     {
1867       /* pointer */
1868       wassertl (0, "Somehow got a three byte data pointer");
1869     }
1870   return size;
1871 }
1872
1873 /*-----------------------------------------------------------------*/
1874 /* movLeft2Result - move byte from left to result                  */
1875 /*-----------------------------------------------------------------*/
1876 static void
1877 movLeft2Result (operand * left, int offl,
1878                 operand * result, int offr, int sign)
1879 {
1880   const char *l;
1881
1882   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1883     {
1884       l = aopGet (AOP (left), offl, FALSE);
1885
1886       if (!sign)
1887         {
1888           aopPut (AOP (result), l, offr);
1889         }
1890       else
1891         {
1892           if (getDataSize (left) == offl + 1)
1893             {
1894               emit2 ("ld a,%s", l);
1895               aopPut (AOP (result), "a", offr);
1896             }
1897         }
1898     }
1899 }
1900
1901 static void
1902 movLeft2ResultLong (operand * left, int offl,
1903                 operand * result, int offr, int sign,
1904                 int size)
1905 {
1906   if (size == 1)
1907     {
1908       movLeft2Result (left, offl, result, offr, sign);
1909     }
1910   else
1911     {
1912       wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1913       wassertl (size == 2, "Only implemented for two bytes or one");
1914
1915       if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1916         {
1917           emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1918           emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1919           emit2 ("ld l,a");
1920           spillPair (PAIR_HL);
1921         }
1922       else if ( getPairId ( AOP (result)) == PAIR_IY)
1923         {
1924           PAIR_ID id = getPairId (AOP (left));
1925           if (id != PAIR_INVALID) 
1926             {
1927               emit2("push %s", _pairs[id].name);
1928               emit2("pop iy");
1929             }
1930           else
1931             {
1932               /* PENDING */
1933               emitDebug("Error");
1934             }
1935         }
1936       else
1937         {
1938           movLeft2Result (left, offl, result, offr, sign);
1939           movLeft2Result (left, offl+1, result, offr+1, sign);
1940         }
1941     }
1942 }
1943
1944 /** Put Acc into a register set
1945  */
1946 void
1947 outAcc (operand * result)
1948 {
1949   int size, offset;
1950   size = getDataSize (result);
1951   if (size)
1952     {
1953       aopPut (AOP (result), "a", 0);
1954       size--;
1955       offset = 1;
1956       /* unsigned or positive */
1957       while (size--)
1958         {
1959           aopPut (AOP (result), "!zero", offset++);
1960         }
1961     }
1962 }
1963
1964 /** Take the value in carry and put it into a register
1965  */
1966 void
1967 outBitCLong (operand * result, bool swap_sense)
1968 {
1969   /* if the result is bit */
1970   if (AOP_TYPE (result) == AOP_CRY)
1971     {
1972       wassertl (0, "Tried to write carry to a bit");
1973     }
1974   else
1975     {
1976       emit2 ("ld a,!zero");
1977       emit2 ("rla");
1978       if (swap_sense)
1979         emit2 ("xor a,!immedbyte", 1);
1980       outAcc (result);
1981     }
1982 }
1983
1984 void
1985 outBitC (operand * result)
1986 {
1987   outBitCLong (result, FALSE);
1988 }
1989
1990 /*-----------------------------------------------------------------*/
1991 /* toBoolean - emit code for orl a,operator(sizeop)                */
1992 /*-----------------------------------------------------------------*/
1993 void
1994 _toBoolean (operand * oper)
1995 {
1996   int size = AOP_SIZE (oper);
1997   int offset = 0;
1998   if (size > 1)
1999     {
2000       emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2001       size--;
2002       while (size--)
2003         emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2004     }
2005   else
2006     {
2007       if (AOP (oper)->type != AOP_ACC)
2008         {
2009           _clearCarry();
2010           emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2011         }
2012     }
2013 }
2014
2015 /*-----------------------------------------------------------------*/
2016 /* genNotFloat - generates not for float operations              */
2017 /*-----------------------------------------------------------------*/
2018 static void
2019 genNotFloat (operand * op, operand * res)
2020 {
2021   int size, offset;
2022   symbol *tlbl;
2023
2024   emitDebug ("; genNotFloat");
2025
2026   /* we will put 127 in the first byte of
2027      the result */
2028   aopPut (AOP (res), "!immedbyte", 0x7F);
2029   size = AOP_SIZE (op) - 1;
2030   offset = 1;
2031
2032   _moveA (aopGet (op->aop, offset++, FALSE));
2033
2034   while (size--)
2035     {
2036       emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
2037     }
2038
2039   tlbl = newiTempLabel (NULL);
2040   aopPut (res->aop, "!one", 1);
2041   emit2 ("!shortjp z !tlabel", tlbl->key + 100);
2042   aopPut (res->aop, "!zero", 1);
2043
2044   emitLabel(tlbl->key + 100);
2045
2046   size = res->aop->size - 2;
2047   offset = 2;
2048   /* put zeros in the rest */
2049   while (size--)
2050     aopPut (res->aop, "!zero", offset++);
2051 }
2052
2053 /*-----------------------------------------------------------------*/
2054 /* genNot - generate code for ! operation                          */
2055 /*-----------------------------------------------------------------*/
2056 static void
2057 genNot (iCode * ic)
2058 {
2059   sym_link *optype = operandType (IC_LEFT (ic));
2060
2061   /* assign asmOps to operand & result */
2062   aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2063   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2064
2065   /* if in bit space then a special case */
2066   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2067     {
2068       wassertl (0, "Tried to negate a bit");
2069     }
2070
2071   /* if type float then do float */
2072   if (IS_FLOAT (optype))
2073     {
2074       genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
2075       goto release;
2076     }
2077
2078   _toBoolean (IC_LEFT (ic));
2079
2080   /* Not of A:
2081      If A == 0, !A = 1
2082      else A = 0
2083      So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2084   emit2 ("sub a,!one");
2085   outBitC (IC_RESULT (ic));
2086
2087  release:
2088   /* release the aops */
2089   freeAsmop (IC_LEFT (ic), NULL, ic);
2090   freeAsmop (IC_RESULT (ic), NULL, ic);
2091 }
2092
2093 /*-----------------------------------------------------------------*/
2094 /* genCpl - generate code for complement                           */
2095 /*-----------------------------------------------------------------*/
2096 static void
2097 genCpl (iCode * ic)
2098 {
2099   int offset = 0;
2100   int size;
2101
2102
2103   /* assign asmOps to operand & result */
2104   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2105   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2106
2107   /* if both are in bit space then
2108      a special case */
2109   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2110       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2111     {
2112       wassertl (0, "Left and the result are in bit space");
2113     }
2114
2115   size = AOP_SIZE (IC_RESULT (ic));
2116   while (size--)
2117     {
2118       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2119       _moveA (l);
2120       emit2("cpl");
2121       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2122     }
2123
2124   /* release the aops */
2125   freeAsmop (IC_LEFT (ic), NULL, ic);
2126   freeAsmop (IC_RESULT (ic), NULL, ic);
2127 }
2128
2129 static void
2130 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2131 {
2132   /* Logic:
2133        ld de,right.lw
2134        setup hl to left
2135        de = hl - de
2136        push flags
2137        store de into result
2138        pop flags
2139        ld de,right.hw
2140        setup hl
2141        de = hl -de
2142        store de into result
2143   */
2144   const char *first = isAdd ? "add" : "sub";
2145   const char *later = isAdd ? "adc" : "sbc";
2146
2147   wassertl (IS_GB, "Code is only relevent to the gbz80");
2148   wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2149
2150   fetchPair (PAIR_DE, left);
2151
2152   emit2 ("ld a,e");
2153   emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2154   emit2 ("ld e,a");
2155   emit2 ("ld a,d");
2156   emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2157
2158   _push (PAIR_AF);
2159   aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2160   aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2161
2162   fetchPairLong (PAIR_DE, left, NULL, MSB24);
2163   aopGet (right, MSB24, FALSE);
2164
2165   _pop (PAIR_AF);
2166   emit2 ("ld a,e");
2167   emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2168   emit2 ("ld e,a");
2169   emit2 ("ld a,d");
2170   emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2171
2172   aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2173   aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2174 }
2175
2176 static void
2177 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2178 {
2179   _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2180 }
2181
2182 /*-----------------------------------------------------------------*/
2183 /* genUminusFloat - unary minus for floating points                */
2184 /*-----------------------------------------------------------------*/
2185 static void
2186 genUminusFloat (operand * op, operand * result)
2187 {
2188   int size, offset = 0;
2189
2190   emitDebug("; genUminusFloat");
2191
2192   /* for this we just need to flip the
2193      first it then copy the rest in place */
2194   size = AOP_SIZE (op) - 1;
2195
2196   _moveA(aopGet (AOP (op), MSB32, FALSE));
2197
2198   emit2("xor a,!immedbyte", 0x80);
2199   aopPut (AOP (result), "a", MSB32);
2200
2201   while (size--)
2202     {
2203       aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2204       offset++;
2205     }
2206 }
2207
2208 /*-----------------------------------------------------------------*/
2209 /* genUminus - unary minus code generation                         */
2210 /*-----------------------------------------------------------------*/
2211 static void
2212 genUminus (iCode * ic)
2213 {
2214   int offset, size;
2215   sym_link *optype, *rtype;
2216
2217   /* assign asmops */
2218   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2219   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2220
2221   /* if both in bit space then special
2222      case */
2223   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2224       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2225     {
2226       wassertl (0, "Left and right are in bit space");
2227       goto release;
2228     }
2229
2230   optype = operandType (IC_LEFT (ic));
2231   rtype = operandType (IC_RESULT (ic));
2232
2233   /* if float then do float stuff */
2234   if (IS_FLOAT (optype))
2235     {
2236       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2237       goto release;
2238     }
2239
2240   /* otherwise subtract from zero */
2241   size = AOP_SIZE (IC_LEFT (ic));
2242
2243   if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2244     {
2245       /* Create a new asmop with value zero */
2246       asmop *azero = newAsmop (AOP_SIMPLELIT);
2247       azero->aopu.aop_simplelit = 0;
2248       azero->size = size;
2249       _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2250       goto release;
2251     }
2252
2253   offset = 0;
2254   _clearCarry();
2255   while (size--)
2256     {
2257       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2258       emit2 ("ld a,!zero");
2259       emit2 ("sbc a,%s", l);
2260       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2261     }
2262
2263   /* if any remaining bytes in the result */
2264   /* we just need to propagate the sign   */
2265   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2266     {
2267       emit2 ("rlc a");
2268       emit2 ("sbc a,a");
2269       while (size--)
2270         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2271     }
2272
2273 release:
2274   /* release the aops */
2275   freeAsmop (IC_LEFT (ic), NULL, ic);
2276   freeAsmop (IC_RESULT (ic), NULL, ic);
2277 }
2278
2279 /*-----------------------------------------------------------------*/
2280 /* assignResultValue -               */
2281 /*-----------------------------------------------------------------*/
2282 void
2283 assignResultValue (operand * oper)
2284 {
2285   int size = AOP_SIZE (oper);
2286   bool topInA = 0;
2287
2288   wassertl (size <= 4, "Got a result that is bigger than four bytes");
2289   topInA = requiresHL (AOP (oper));
2290
2291   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2292     {
2293       /* We do it the hard way here. */
2294       _push (PAIR_HL);
2295       aopPut (AOP (oper), _fReturn[0], 0);
2296       aopPut (AOP (oper), _fReturn[1], 1);
2297       _pop (PAIR_DE);
2298       aopPut (AOP (oper), _fReturn[0], 2);
2299       aopPut (AOP (oper), _fReturn[1], 3);
2300     }
2301   else
2302     {
2303       while (size--)
2304         {
2305           aopPut (AOP (oper), _fReturn[size], size);
2306         }
2307     }
2308 }
2309
2310 /** Simple restore that doesn't take into account what is used in the
2311     return.
2312 */
2313 static void
2314 _restoreRegsAfterCall(void)
2315 {
2316   if (_G.stack.pushedDE)
2317     {
2318       _pop ( PAIR_DE);
2319       _G.stack.pushedDE = FALSE;
2320     }
2321   if (_G.stack.pushedBC)
2322     {
2323       _pop ( PAIR_BC);
2324       _G.stack.pushedBC = FALSE;
2325     }
2326   _G.saves.saved = FALSE;
2327 }
2328
2329 static void
2330 _saveRegsForCall(iCode *ic, int sendSetSize)
2331 {
2332   /* Rules:
2333       o Stack parameters are pushed before this function enters
2334       o DE and BC may be used in this function.
2335       o HL and DE may be used to return the result.
2336       o HL and DE may be used to send variables.
2337       o DE and BC may be used to store the result value.
2338       o HL may be used in computing the sent value of DE
2339       o The iPushes for other parameters occur before any addSets
2340
2341      Logic: (to be run inside the first iPush or if none, before sending)
2342       o Compute if DE and/or BC are in use over the call
2343       o Compute if DE is used in the send set
2344       o Compute if DE and/or BC are used to hold the result value
2345       o If (DE is used, or in the send set) and is not used in the result, push.
2346       o If BC is used and is not in the result, push
2347       o 
2348       o If DE is used in the send set, fetch
2349       o If HL is used in the send set, fetch
2350       o Call
2351       o ...
2352   */
2353   if (_G.saves.saved == FALSE) {
2354     bool deInUse, bcInUse;
2355     bool deSending;
2356     bool bcInRet = FALSE, deInRet = FALSE;
2357     bitVect *rInUse;
2358
2359     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2360
2361     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2362     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2363
2364     deSending = (sendSetSize > 1);
2365
2366     emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2367
2368     if (bcInUse && bcInRet == FALSE) {
2369       _push(PAIR_BC);
2370       _G.stack.pushedBC = TRUE;
2371     }
2372     if (deInUse && deInRet == FALSE) {
2373       _push(PAIR_DE);
2374       _G.stack.pushedDE = TRUE;
2375     }
2376
2377     _G.saves.saved = TRUE;
2378   }
2379   else {
2380     /* Already saved. */
2381   }
2382 }
2383
2384 /*-----------------------------------------------------------------*/
2385 /* genIpush - genrate code for pushing this gets a little complex  */
2386 /*-----------------------------------------------------------------*/
2387 static void
2388 genIpush (iCode * ic)
2389 {
2390   int size, offset = 0;
2391   const char *l;
2392
2393   /* if this is not a parm push : ie. it is spill push
2394      and spill push is always done on the local stack */
2395   if (!ic->parmPush)
2396     {
2397       wassertl(0, "Encountered an unsupported spill push.");
2398       return;
2399     }
2400
2401   if (_G.saves.saved == FALSE) {
2402     /* Caller saves, and this is the first iPush. */
2403     /* Scan ahead until we find the function that we are pushing parameters to.
2404        Count the number of addSets on the way to figure out what registers
2405        are used in the send set.
2406     */
2407     int nAddSets = 0;
2408     iCode *walk = ic->next;
2409     
2410     while (walk) {
2411       if (walk->op == SEND) {
2412         nAddSets++;
2413       }
2414       else if (walk->op == CALL || walk->op == PCALL) {
2415         /* Found it. */
2416         break;
2417       }
2418       else {
2419         /* Keep looking. */
2420       }
2421       walk = walk->next;
2422     }
2423     _saveRegsForCall(walk, nAddSets);
2424   }
2425   else {
2426     /* Already saved by another iPush. */
2427   }
2428
2429   /* then do the push */
2430   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2431
2432   size = AOP_SIZE (IC_LEFT (ic));
2433
2434   if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2435     {
2436       _G.stack.pushed += 2;
2437       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2438     }
2439   else
2440     {
2441       if (size == 2)
2442         {
2443           fetchHL (AOP (IC_LEFT (ic)));
2444           emit2 ("push hl");
2445           spillPair (PAIR_HL);
2446           _G.stack.pushed += 2;
2447           goto release;
2448         }
2449       if (size == 4)
2450         {
2451           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2452           emit2 ("push hl");
2453           spillPair (PAIR_HL);
2454           _G.stack.pushed += 2;
2455           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2456           emit2 ("push hl");
2457           spillPair (PAIR_HL);
2458           _G.stack.pushed += 2;
2459           goto release;
2460         }
2461       offset = size;
2462       while (size--)
2463         {
2464           if (AOP (IC_LEFT (ic))->type == AOP_IY)
2465             {
2466               char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2467               wassert (l);
2468               emit2 ("ld a,(%s)", l);
2469             }
2470           else
2471             {
2472               l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2473               emit2 ("ld a,%s", l);
2474             }
2475           emit2 ("push af");
2476           emit2 ("inc sp");
2477           _G.stack.pushed++;
2478         }
2479     }
2480 release:
2481   freeAsmop (IC_LEFT (ic), NULL, ic);
2482 }
2483
2484 /*-----------------------------------------------------------------*/
2485 /* genIpop - recover the registers: can happen only for spilling   */
2486 /*-----------------------------------------------------------------*/
2487 static void
2488 genIpop (iCode * ic)
2489 {
2490   int size, offset;
2491
2492
2493   /* if the temp was not pushed then */
2494   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2495     return;
2496
2497   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2498   size = AOP_SIZE (IC_LEFT (ic));
2499   offset = (size - 1);
2500   if (isPair (AOP (IC_LEFT (ic))))
2501     {
2502       emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2503     }
2504   else
2505     {
2506       while (size--)
2507         {
2508           emit2 ("dec sp");
2509           emit2 ("pop hl");
2510           spillPair (PAIR_HL);
2511           aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2512         }
2513     }
2514
2515   freeAsmop (IC_LEFT (ic), NULL, ic);
2516 }
2517
2518 /* This is quite unfortunate */
2519 static void
2520 setArea (int inHome)
2521 {
2522   /*
2523     static int lastArea = 0;
2524
2525      if (_G.in_home != inHome) {
2526      if (inHome) {
2527      const char *sz = port->mem.code_name;
2528      port->mem.code_name = "HOME";
2529      emit2("!area", CODE_NAME);
2530      port->mem.code_name = sz;
2531      }
2532      else
2533      emit2("!area", CODE_NAME); */
2534   _G.in_home = inHome;
2535   //    }
2536 }
2537
2538 static bool
2539 isInHome (void)
2540 {
2541   return _G.in_home;
2542 }
2543
2544 static int
2545 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2546 {
2547   int ret = 0;
2548   asmop *aop;
2549   symbol *sym = OP_SYMBOL (op);
2550
2551   if (sym->isspilt || sym->nRegs == 0)
2552     return 0;
2553
2554   aopOp (op, ic, FALSE, FALSE);
2555
2556   aop = AOP (op);
2557   if (aop->type == AOP_REG)
2558     {
2559       int i;
2560       for (i = 0; i < aop->size; i++)
2561         {
2562           if (pairId == PAIR_DE)
2563             {
2564               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2565               if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2566                 ret++;
2567               if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2568                 ret++;
2569             }
2570           else if (pairId == PAIR_BC)
2571             {
2572               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2573               if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2574                 ret++;
2575               if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2576                 ret++;
2577             }
2578           else
2579             {
2580               wassert (0);
2581             }
2582         }
2583     }
2584
2585   freeAsmop (IC_LEFT (ic), NULL, ic);
2586   return ret;
2587 }
2588
2589 /** Emit the code for a call statement
2590  */
2591 static void
2592 emitCall (iCode * ic, bool ispcall)
2593 {
2594   sym_link *dtype = operandType (IC_LEFT (ic));
2595
2596   /* if caller saves & we have not saved then */
2597   if (!ic->regsSaved)
2598     {
2599       /* PENDING */
2600     }
2601
2602   _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2603
2604   /* if send set is not empty then assign */
2605   if (_G.sendSet)
2606     {
2607       iCode *sic;
2608       int send = 0;
2609       int nSend = elementsInSet(_G.sendSet);
2610       bool swapped = FALSE;
2611
2612       int _z80_sendOrder[] = {
2613         PAIR_BC, PAIR_DE
2614       };
2615
2616       if (nSend > 1) {
2617         /* Check if the parameters are swapped.  If so route through hl instead. */
2618         wassertl (nSend == 2, "Pedantic check.  Code only checks for the two send items case.");
2619
2620         sic = setFirstItem(_G.sendSet);
2621         sic = setNextItem(_G.sendSet);
2622
2623         if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2624           /* The second send value is loaded from one the one that holds the first
2625              send, i.e. it is overwritten. */
2626           /* Cache the first in HL, and load the second from HL instead. */
2627           emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2628           emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2629
2630           swapped = TRUE;
2631         }
2632       }
2633
2634       for (sic = setFirstItem (_G.sendSet); sic;
2635            sic = setNextItem (_G.sendSet))
2636         {
2637           int size;
2638           aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2639
2640           size = AOP_SIZE (IC_LEFT (sic));
2641           wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2642           wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2643
2644           // PENDING: Mild hack
2645           if (swapped == TRUE && send == 1) {
2646             if (size > 1) {
2647               emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2648             }
2649             else {
2650               emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2651             }
2652             emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2653           }
2654           else {
2655             fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2656           }
2657
2658           send++;
2659           freeAsmop (IC_LEFT (sic), NULL, sic);
2660         }
2661       _G.sendSet = NULL;
2662     }
2663
2664   if (ispcall)
2665     {
2666       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2667         {
2668           werror (W_INDIR_BANKED);
2669         }
2670       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2671
2672       if (isLitWord (AOP (IC_LEFT (ic))))
2673         {
2674           emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2675         }
2676       else
2677         {
2678           symbol *rlbl = newiTempLabel (NULL);
2679           spillPair (PAIR_HL);
2680           emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2681           emit2 ("push hl");
2682           _G.stack.pushed += 2;
2683
2684           fetchHL (AOP (IC_LEFT (ic)));
2685           emit2 ("jp !*hl");
2686           emit2 ("!tlabeldef", (rlbl->key + 100));
2687           _G.stack.pushed -= 2;
2688         }
2689       freeAsmop (IC_LEFT (ic), NULL, ic);
2690     }
2691   else
2692     {
2693       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2694       OP_SYMBOL (IC_LEFT (ic))->rname :
2695       OP_SYMBOL (IC_LEFT (ic))->name;
2696       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2697         {
2698           emit2 ("call banked_call");
2699           emit2 ("!dws", name);
2700           emit2 ("!dw !bankimmeds", name);
2701         }
2702       else
2703         {
2704           /* make the call */
2705           emit2 ("call %s", name);
2706         }
2707     }
2708   spillCached ();
2709
2710   /* Mark the regsiters as restored. */
2711   _G.saves.saved = FALSE;
2712
2713   /* if we need assign a result value */
2714   if ((IS_ITEMP (IC_RESULT (ic)) &&
2715        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2716         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2717       IS_TRUE_SYMOP (IC_RESULT (ic)))
2718     {
2719
2720       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2721
2722       assignResultValue (IC_RESULT (ic));
2723
2724       freeAsmop (IC_RESULT (ic), NULL, ic);
2725     }
2726
2727   /* adjust the stack for parameters if required */
2728   if (ic->parmBytes)
2729     {
2730       int i = ic->parmBytes;
2731
2732       _G.stack.pushed -= i;
2733       if (IS_GB)
2734         {
2735           emit2 ("!ldaspsp", i);
2736         }
2737       else
2738         {
2739           spillCached ();
2740           if (i > 8)
2741             {
2742               emit2 ("ld iy,!immedword", i);
2743               emit2 ("add iy,sp");
2744               emit2 ("ld sp,iy");
2745             }
2746           else
2747             {
2748               while (i > 1)
2749                 {
2750                   emit2 ("pop af");
2751                   i -= 2;
2752                 }
2753               if (i)
2754                 {
2755                   emit2 ("inc sp");
2756                 }
2757             }
2758         }
2759     }
2760
2761   spillCached ();
2762
2763   if (_G.stack.pushedDE) 
2764     {
2765       bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2766       bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2767
2768       if (dInRet && eInRet)
2769         {
2770           wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2771         }
2772       else if (dInRet)
2773         {
2774           /* Only restore E */
2775           emit2 ("ld a,d");
2776           _pop (PAIR_DE);
2777           emit2 ("ld d,a");
2778         }
2779       else if (eInRet)
2780         {
2781           /* Only restore D */
2782           _pop (PAIR_AF);
2783           emit2 ("ld d,a");
2784         }
2785       else
2786         {
2787           _pop (PAIR_DE);
2788         }
2789       _G.stack.pushedDE = FALSE;
2790     }
2791   
2792   if (_G.stack.pushedBC) 
2793     {
2794       bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2795       bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2796
2797       if (bInRet && cInRet)
2798         {
2799           wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2800         }
2801       else if (bInRet)
2802         {
2803           /* Only restore C */
2804           emit2 ("ld a,b");
2805           _pop (PAIR_BC);
2806           emit2 ("ld b,a");
2807         }
2808       else if (cInRet)
2809         {
2810           /* Only restore B */
2811           _pop (PAIR_AF);
2812           emit2 ("ld b,a");
2813         }
2814       else
2815         {
2816           _pop (PAIR_BC);
2817         }
2818       _G.stack.pushedBC = FALSE;
2819     }
2820 }
2821
2822 /*-----------------------------------------------------------------*/
2823 /* genCall - generates a call statement                            */
2824 /*-----------------------------------------------------------------*/
2825 static void
2826 genCall (iCode * ic)
2827 {
2828   emitCall (ic, FALSE);
2829 }
2830
2831 /*-----------------------------------------------------------------*/
2832 /* genPcall - generates a call by pointer statement                */
2833 /*-----------------------------------------------------------------*/
2834 static void
2835 genPcall (iCode * ic)
2836 {
2837   emitCall (ic, TRUE);
2838 }
2839
2840 /*-----------------------------------------------------------------*/
2841 /* resultRemat - result  is rematerializable                       */
2842 /*-----------------------------------------------------------------*/
2843 static int
2844 resultRemat (iCode * ic)
2845 {
2846   if (SKIP_IC (ic) || ic->op == IFX)
2847     return 0;
2848
2849   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2850     {
2851       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2852       if (sym->remat && !POINTER_SET (ic))
2853         return 1;
2854     }
2855
2856   return 0;
2857 }
2858
2859 extern set *publics;
2860
2861 /*-----------------------------------------------------------------*/
2862 /* genFunction - generated code for function entry                 */
2863 /*-----------------------------------------------------------------*/
2864 static void
2865 genFunction (iCode * ic)
2866 {
2867   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2868   sym_link *ftype;
2869
2870   bool bcInUse = FALSE;
2871   bool deInUse = FALSE;
2872
2873   setArea (IFFUNC_NONBANKED (sym->type));
2874
2875   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2876      else.
2877   */
2878   _G.receiveOffset = 0;
2879
2880   /* Record the last function name for debugging. */
2881   _G.lastFunctionName = sym->rname;
2882   
2883   /* Create the function header */
2884   emit2 ("!functionheader", sym->name);
2885   sprintf (buffer, "%s_start", sym->rname);
2886   emit2 ("!labeldef", buffer);
2887   emit2 ("!functionlabeldef", sym->rname);
2888
2889   if (options.profile) 
2890     {
2891       emit2 ("!profileenter");
2892     }
2893
2894   ftype = operandType (IC_LEFT (ic));
2895
2896   /* if critical function then turn interrupts off */
2897   if (IFFUNC_ISCRITICAL (ftype))
2898     emit2 ("!di");
2899
2900   /* if this is an interrupt service routine then save all potentially used registers. */
2901   if (IFFUNC_ISISR (sym->type))
2902     {
2903       emit2 ("!pusha");
2904     }
2905
2906   /* PENDING: callee-save etc */
2907
2908   _G.stack.param_offset = 0;
2909
2910   if (z80_opts.calleeSavesBC)
2911     {
2912       bcInUse = TRUE;
2913     }
2914
2915   /* Detect which registers are used. */
2916   if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2917     {
2918       int i;
2919       for (i = 0; i < sym->regsUsed->size; i++)
2920         {
2921           if (bitVectBitValue (sym->regsUsed, i))
2922             {
2923               switch (i)
2924                 {
2925                 case C_IDX:
2926                 case B_IDX:
2927                   bcInUse = TRUE;
2928                   break;
2929                 case D_IDX:
2930                 case E_IDX:
2931                   if (IS_Z80) {
2932                     deInUse = TRUE;
2933                   }
2934                   else {
2935                     /* Other systems use DE as a temporary. */
2936                   }
2937                   break;
2938                 }
2939             }
2940         }
2941     }
2942
2943   if (bcInUse) 
2944     {
2945       emit2 ("push bc");
2946       _G.stack.param_offset += 2;
2947     }
2948
2949   _G.calleeSaves.pushedBC = bcInUse;
2950
2951   if (deInUse)
2952     {
2953       emit2 ("push de");
2954       _G.stack.param_offset += 2;
2955     }
2956
2957   _G.calleeSaves.pushedDE = deInUse;
2958
2959   /* adjust the stack for the function */
2960   _G.stack.last = sym->stack;
2961
2962   if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2963     emit2 ("!enterxl", sym->stack);
2964   else if (sym->stack)
2965     emit2 ("!enterx", sym->stack);
2966   else
2967     emit2 ("!enter");
2968   _G.stack.offset = sym->stack;
2969 }
2970
2971 /*-----------------------------------------------------------------*/
2972 /* genEndFunction - generates epilogue for functions               */
2973 /*-----------------------------------------------------------------*/
2974 static void
2975 genEndFunction (iCode * ic)
2976 {
2977   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2978
2979   if (IFFUNC_ISISR (sym->type))
2980     {
2981       wassertl (0, "Tried to close an interrupt support function");
2982     }
2983   else
2984     {
2985       if (IFFUNC_ISCRITICAL (sym->type))
2986         emit2 ("!ei");
2987
2988       /* PENDING: calleeSave */
2989
2990       if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2991         {
2992           emit2 ("!leavexl", _G.stack.offset);
2993         }
2994       else if (_G.stack.offset)
2995         {
2996           emit2 ("!leavex", _G.stack.offset);
2997         }
2998       else
2999         {
3000           emit2 ("!leave");
3001         }
3002
3003       if (_G.calleeSaves.pushedDE) 
3004         {
3005           emit2 ("pop de");
3006           _G.calleeSaves.pushedDE = FALSE;
3007         }
3008
3009       if (_G.calleeSaves.pushedBC) 
3010         {
3011           emit2 ("pop bc");
3012           _G.calleeSaves.pushedBC = FALSE;
3013         }
3014
3015       if (options.profile) 
3016         {
3017           emit2 ("!profileexit");
3018         }
3019
3020
3021       /* Both baned and non-banked just ret */
3022       emit2 ("ret");
3023
3024       sprintf (buffer, "%s_end", sym->rname);
3025       emit2 ("!labeldef", buffer);
3026     }
3027   _G.flushStatics = 1;
3028   _G.stack.pushed = 0;
3029   _G.stack.offset = 0;
3030 }
3031
3032 /*-----------------------------------------------------------------*/
3033 /* genRet - generate code for return statement                     */
3034 /*-----------------------------------------------------------------*/
3035 static void
3036 genRet (iCode * ic)
3037 {
3038     const char *l;
3039   /* Errk.  This is a hack until I can figure out how
3040      to cause dehl to spill on a call */
3041   int size, offset = 0;
3042
3043   /* if we have no return value then
3044      just generate the "ret" */
3045   if (!IC_LEFT (ic))
3046     goto jumpret;
3047
3048   /* we have something to return then
3049      move the return value into place */
3050   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3051   size = AOP_SIZE (IC_LEFT (ic));
3052
3053   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3054     {
3055       if (IS_GB)
3056         {
3057           emit2 ("ld de,%s", l);
3058         }
3059       else
3060         {
3061           emit2 ("ld hl,%s", l);
3062         }
3063     }
3064   else
3065     {
3066       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3067         {
3068           fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3069           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3070         }
3071       else
3072         {
3073           while (size--)
3074             {
3075               l = aopGet (AOP (IC_LEFT (ic)), offset,
3076                           FALSE);
3077               if (strcmp (_fReturn[offset], l))
3078                 emit2 ("ld %s,%s", _fReturn[offset++], l);
3079             }
3080         }
3081     }
3082   freeAsmop (IC_LEFT (ic), NULL, ic);
3083
3084 jumpret:
3085   /* generate a jump to the return label
3086      if the next is not the return statement */
3087   if (!(ic->next && ic->next->op == LABEL &&
3088         IC_LABEL (ic->next) == returnLabel))
3089
3090     emit2 ("jp !tlabel", returnLabel->key + 100);
3091 }
3092
3093 /*-----------------------------------------------------------------*/
3094 /* genLabel - generates a label                                    */
3095 /*-----------------------------------------------------------------*/
3096 static void
3097 genLabel (iCode * ic)
3098 {
3099   /* special case never generate */
3100   if (IC_LABEL (ic) == entryLabel)
3101     return;
3102
3103   emitLabel (IC_LABEL (ic)->key + 100);
3104 }
3105
3106 /*-----------------------------------------------------------------*/
3107 /* genGoto - generates a ljmp                                      */
3108 /*-----------------------------------------------------------------*/
3109 static void
3110 genGoto (iCode * ic)
3111 {
3112   emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3113 }
3114
3115 /*-----------------------------------------------------------------*/
3116 /* genPlusIncr :- does addition with increment if possible         */
3117 /*-----------------------------------------------------------------*/
3118 static bool
3119 genPlusIncr (iCode * ic)
3120 {
3121   unsigned int icount;
3122   unsigned int size = getDataSize (IC_RESULT (ic));
3123   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3124
3125   /* will try to generate an increment */
3126   /* if the right side is not a literal
3127      we cannot */
3128   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3129     return FALSE;
3130
3131   emitDebug ("; genPlusIncr");
3132
3133   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3134
3135   /* If result is a pair */
3136   if (resultId != PAIR_INVALID)
3137     {
3138       if (isLitWord (AOP (IC_LEFT (ic))))
3139         {
3140           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3141           return TRUE;
3142         }
3143       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3144         {
3145           if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3146             {
3147               PAIR_ID freep = getFreePairId (ic);
3148               if (freep != PAIR_INVALID)
3149                 {
3150                   fetchPair (freep, AOP (IC_RIGHT (ic)));
3151                   emit2 ("add hl,%s", _pairs[freep].name);
3152                   return TRUE;
3153                 }
3154             }
3155           else
3156             {
3157               fetchPair (resultId, AOP (IC_RIGHT (ic)));
3158               emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3159               return TRUE;
3160             }
3161         }
3162       if (icount > 5)
3163         return FALSE;
3164       /* Inc a pair */
3165       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3166         {
3167           if (icount > 2)
3168             return FALSE;
3169           movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3170         }
3171       while (icount--)
3172         {
3173           emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3174         }
3175       return TRUE;
3176     }
3177
3178   if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3179     {
3180       fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3181       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3182       return TRUE;
3183     }
3184
3185   /* if the literal value of the right hand side
3186      is greater than 4 then it is not worth it */
3187   if (icount > 4)
3188     return FALSE;
3189
3190   /* if increment 16 bits in register */
3191   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3192       size > 1 &&
3193       icount == 1
3194     )
3195     {
3196       int offset = 0;
3197       symbol *tlbl = NULL;
3198       tlbl = newiTempLabel (NULL);
3199       while (size--)
3200         {
3201           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3202           if (size)
3203             {
3204               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3205             }
3206         }
3207       emitLabel (tlbl->key + 100);
3208       return TRUE;
3209     }
3210
3211   /* if the sizes are greater than 1 then we cannot */
3212   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3213       AOP_SIZE (IC_LEFT (ic)) > 1)
3214     return FALSE;
3215
3216   /* If the result is in a register then we can load then increment.
3217    */
3218   if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3219     {
3220       aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3221       while (icount--)
3222         {
3223           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3224         }
3225       return TRUE;
3226     }
3227
3228   /* we can if the aops of the left & result match or
3229      if they are in registers and the registers are the
3230      same */
3231   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3232     {
3233       while (icount--)
3234         {
3235           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3236         }
3237       return TRUE;
3238     }
3239
3240   return FALSE;
3241 }
3242
3243 /*-----------------------------------------------------------------*/
3244 /* outBitAcc - output a bit in acc                                 */
3245 /*-----------------------------------------------------------------*/
3246 void
3247 outBitAcc (operand * result)
3248 {
3249   symbol *tlbl = newiTempLabel (NULL);
3250   /* if the result is a bit */
3251   if (AOP_TYPE (result) == AOP_CRY)
3252     {
3253       wassertl (0, "Tried to write A into a bit");
3254     }
3255   else
3256     {
3257       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3258       emit2 ("ld a,!one");
3259       emitLabel (tlbl->key + 100);
3260       outAcc (result);
3261     }
3262 }
3263
3264 bool
3265 couldDestroyCarry (asmop *aop)
3266 {
3267   if (aop)
3268     {
3269       if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3270         {
3271           return TRUE;
3272         }
3273     }
3274   return FALSE;
3275 }
3276
3277 static void
3278 shiftIntoPair (int idx, asmop *aop)
3279 {
3280   PAIR_ID id = PAIR_INVALID;
3281
3282   wassertl (IS_Z80, "Only implemented for the Z80");
3283   //  wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3284
3285   switch (idx) 
3286     {
3287     case 0:
3288       id = PAIR_HL;
3289       break;
3290     case 1:
3291       id = PAIR_DE;
3292       _push (PAIR_DE);
3293       break;
3294     default:
3295       wassertl (0, "Internal error - hit default case");
3296     }
3297
3298   emitDebug ("; Shift into pair idx %u", idx);
3299
3300   if (id == PAIR_HL)
3301     {
3302       setupPair (PAIR_HL, aop, 0);
3303     }
3304   else
3305     {
3306       setupPair (PAIR_IY, aop, 0);
3307       emit2 ("push iy");
3308       emit2 ("pop %s", _pairs[id].name);
3309     }
3310
3311   aop->type = AOP_PAIRPTR;
3312   aop->aopu.aop_pairId = id;
3313   _G.pairs[id].offset = 0;
3314   _G.pairs[id].last_type = aop->type;
3315 }
3316
3317 static void 
3318 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3319 {
3320   wassert (left && right);
3321
3322   if (IS_Z80)
3323     {
3324       if (couldDestroyCarry (right) && couldDestroyCarry (result))
3325         {
3326           shiftIntoPair (0, right);
3327           shiftIntoPair (1, result);
3328         }
3329       else if (couldDestroyCarry (right))
3330         {
3331           shiftIntoPair (0, right);
3332         }
3333       else if (couldDestroyCarry (result))
3334         {
3335           shiftIntoPair (0, result);
3336         }
3337       else
3338         {
3339           /* Fine */
3340         }
3341     }
3342 }
3343
3344 /*-----------------------------------------------------------------*/
3345 /* genPlus - generates code for addition                           */
3346 /*-----------------------------------------------------------------*/
3347 static void
3348 genPlus (iCode * ic)
3349 {
3350   int size, offset = 0;
3351
3352   /* special cases :- */
3353
3354   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3355   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3356   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3357
3358   /* Swap the left and right operands if:
3359
3360      if literal, literal on the right or
3361      if left requires ACC or right is already
3362      in ACC */
3363
3364   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3365       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3366       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3367     {
3368       operand *t = IC_RIGHT (ic);
3369       IC_RIGHT (ic) = IC_LEFT (ic);
3370       IC_LEFT (ic) = t;
3371     }
3372
3373   /* if both left & right are in bit
3374      space */
3375   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3376       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3377     {
3378       /* Cant happen */
3379       wassertl (0, "Tried to add two bits");
3380     }
3381
3382   /* if left in bit space & right literal */
3383   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3384       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3385     {
3386       /* Can happen I guess */
3387       wassertl (0, "Tried to add a bit to a literal");
3388     }
3389
3390   /* if I can do an increment instead
3391      of add then GOOD for ME */
3392   if (genPlusIncr (ic) == TRUE)
3393     goto release;
3394
3395   emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3396
3397   size = getDataSize (IC_RESULT (ic));
3398
3399   /* Special case when left and right are constant */
3400   if (isPair (AOP (IC_RESULT (ic))))
3401     {
3402       char *left, *right;
3403       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3404       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3405
3406       if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3407           left && right)
3408         {
3409           /* It's a pair */
3410           /* PENDING: fix */
3411           char buffer[100];
3412           sprintf (buffer, "#(%s + %s)", left, right);
3413           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3414           goto release;
3415         }
3416     }
3417
3418   if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3419     {
3420       /* Fetch into HL then do the add */
3421       PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3422       PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3423
3424       spillPair (PAIR_HL);
3425       
3426       if (left == PAIR_HL && right != PAIR_INVALID)
3427         {
3428           emit2 ("add hl,%s", _pairs[right].name);
3429           goto release;
3430         }
3431       else if (right == PAIR_HL && left != PAIR_INVALID)
3432         {
3433           emit2 ("add hl,%s", _pairs[left].name);
3434           goto release;
3435         }
3436       else if (right != PAIR_INVALID && right != PAIR_HL)
3437         {
3438           fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3439           emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3440           goto release;
3441         }
3442       else if (left != PAIR_INVALID && left != PAIR_HL)
3443         { 
3444           fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3445           emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3446           goto release;
3447         }
3448       else
3449         {
3450           /* Can't do it */
3451         }
3452     }
3453
3454   if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3455     {
3456       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3457       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3458       spillCached();
3459       commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3460       goto release;
3461     }
3462
3463   /* Special case:
3464      ld hl,sp+n trashes C so we cant afford to do it during an
3465      add with stack based varibles.  Worst case is:
3466      ld  hl,sp+left
3467      ld  a,(hl)
3468      ld  hl,sp+right
3469      add (hl)
3470      ld  hl,sp+result
3471      ld  (hl),a
3472      ld  hl,sp+left+1
3473      ld  a,(hl)
3474      ld  hl,sp+right+1
3475      adc (hl)
3476      ld  hl,sp+result+1
3477      ld  (hl),a
3478      So you cant afford to load up hl if either left, right, or result
3479      is on the stack (*sigh*)  The alt is:
3480      ld  hl,sp+left
3481      ld  de,(hl)
3482      ld  hl,sp+right
3483      ld  hl,(hl)
3484      add hl,de
3485      ld  hl,sp+result
3486      ld  (hl),hl
3487      Combinations in here are:
3488      * If left or right are in bc then the loss is small - trap later
3489      * If the result is in bc then the loss is also small
3490    */
3491   if (IS_GB)
3492     {
3493       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3494           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3495           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3496         {
3497           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3498                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3499               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3500                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3501             {
3502               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3503                 {
3504                   /* Swap left and right */
3505                   operand *t = IC_RIGHT (ic);
3506                   IC_RIGHT (ic) = IC_LEFT (ic);
3507                   IC_LEFT (ic) = t;
3508                 }
3509               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3510                 {
3511                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3512                   emit2 ("add hl,bc");
3513                 }
3514               else
3515                 {
3516                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3517                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3518                   emit2 ("add hl,de");
3519                 }
3520               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3521               goto release;
3522             }
3523         }
3524       if (size == 4)
3525         {
3526           /* Be paranoid on the GB with 4 byte variables due to how C
3527              can be trashed by lda hl,n(sp).
3528           */
3529           _gbz80_emitAddSubLong (ic, TRUE);
3530           goto release;
3531         }
3532     }
3533
3534   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3535
3536   while (size--)
3537     {
3538       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3539         {
3540           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3541           if (offset == 0)
3542             emit2 ("add a,%s",
3543                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3544           else
3545             emit2 ("adc a,%s",
3546                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3547         }
3548       else
3549         {
3550           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3551           if (offset == 0)
3552             emit2 ("add a,%s",
3553                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3554           else
3555             emit2 ("adc a,%s",
3556                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3557         }
3558       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3559     }
3560
3561 release:
3562   freeAsmop (IC_LEFT (ic), NULL, ic);
3563   freeAsmop (IC_RIGHT (ic), NULL, ic);
3564   freeAsmop (IC_RESULT (ic), NULL, ic);
3565
3566 }
3567
3568 /*-----------------------------------------------------------------*/
3569 /* genMinusDec :- does subtraction with deccrement if possible     */
3570 /*-----------------------------------------------------------------*/
3571 static bool
3572 genMinusDec (iCode * ic)
3573 {
3574   unsigned int icount;
3575   unsigned int size = getDataSize (IC_RESULT (ic));
3576
3577   /* will try to generate an increment */
3578   /* if the right side is not a literal we cannot */
3579   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3580     return FALSE;
3581
3582   /* if the literal value of the right hand side
3583      is greater than 4 then it is not worth it */
3584   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3585     return FALSE;
3586
3587   size = getDataSize (IC_RESULT (ic));
3588
3589   /* if decrement 16 bits in register */
3590   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3591       (size > 1) && isPair (AOP (IC_RESULT (ic))))
3592     {
3593       while (icount--)
3594         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3595       return TRUE;
3596     }
3597
3598   /* If result is a pair */
3599   if (isPair (AOP (IC_RESULT (ic))))
3600     {
3601       movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3602       while (icount--)
3603         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3604       return TRUE;
3605     }
3606
3607   /* if increment 16 bits in register */
3608   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3609       (size == 2)
3610       )
3611     {
3612       fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3613
3614       while (icount--) {
3615         emit2 ("dec %s", _getTempPairName());
3616       }
3617
3618       commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3619
3620       return TRUE;
3621     }
3622
3623
3624   /* if the sizes are greater than 1 then we cannot */
3625   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3626       AOP_SIZE (IC_LEFT (ic)) > 1)
3627     return FALSE;
3628
3629   /* we can if the aops of the left & result match or if they are in
3630      registers and the registers are the same */
3631   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3632     {
3633       while (icount--)
3634         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3635       return TRUE;
3636     }
3637
3638   return FALSE;
3639 }
3640
3641 /*-----------------------------------------------------------------*/
3642 /* genMinus - generates code for subtraction                       */
3643 /*-----------------------------------------------------------------*/
3644 static void
3645 genMinus (iCode * ic)
3646 {
3647   int size, offset = 0;
3648   unsigned long lit = 0L;
3649
3650   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3651   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3652   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3653
3654   /* special cases :- */
3655   /* if both left & right are in bit space */
3656   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3657       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3658     {
3659       wassertl (0, "Tried to subtract two bits");
3660       goto release;
3661     }
3662
3663   /* if I can do an decrement instead of subtract then GOOD for ME */
3664   if (genMinusDec (ic) == TRUE)
3665     goto release;
3666
3667   size = getDataSize (IC_RESULT (ic));
3668
3669   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3670     {
3671     }
3672   else
3673     {
3674       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3675       lit = -(long) lit;
3676     }
3677
3678   /* Same logic as genPlus */
3679   if (IS_GB)
3680     {
3681       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3682           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3683           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3684         {
3685           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3686                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3687               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3688                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3689             {
3690               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3691               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3692
3693               if (left == PAIR_INVALID && right == PAIR_INVALID)
3694                 {
3695                   left = PAIR_DE;
3696                   right = PAIR_HL;
3697                 }
3698               else if (right == PAIR_INVALID)
3699                 right = PAIR_DE;
3700               else if (left == PAIR_INVALID)
3701                 left = PAIR_DE;
3702
3703               fetchPair (left, AOP (IC_LEFT (ic)));
3704               /* Order is important.  Right may be HL */
3705               fetchPair (right, AOP (IC_RIGHT (ic)));
3706
3707               emit2 ("ld a,%s", _pairs[left].l);
3708               emit2 ("sub a,%s", _pairs[right].l);
3709               emit2 ("ld e,a");
3710               emit2 ("ld a,%s", _pairs[left].h);
3711               emit2 ("sbc a,%s", _pairs[right].h);
3712
3713               if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3714                 {
3715                   aopPut (AOP (IC_RESULT (ic)), "a", 1);
3716                 }
3717               aopPut (AOP (IC_RESULT (ic)), "e", 0);
3718               goto release;
3719             }
3720         }
3721       if (size == 4)
3722         {
3723           /* Be paranoid on the GB with 4 byte variables due to how C
3724              can be trashed by lda hl,n(sp).
3725           */
3726           _gbz80_emitAddSubLong (ic, FALSE);
3727           goto release;
3728         }
3729     }
3730
3731   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3732
3733   /* if literal, add a,#-lit, else normal subb */
3734   while (size--)
3735     {
3736       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3737       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3738         {
3739           if (!offset)
3740             emit2 ("sub a,%s",
3741                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3742           else
3743             emit2 ("sbc a,%s",
3744                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3745         }
3746       else
3747         {
3748           /* first add without previous c */
3749           if (!offset)
3750             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3751           else
3752             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3753         }
3754       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3755     }
3756
3757   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3758       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3759       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3760     {
3761       wassertl (0, "Tried to subtract on a long pointer");
3762     }
3763
3764 release:
3765   freeAsmop (IC_LEFT (ic), NULL, ic);
3766   freeAsmop (IC_RIGHT (ic), NULL, ic);
3767   freeAsmop (IC_RESULT (ic), NULL, ic);
3768 }
3769
3770 /*-----------------------------------------------------------------*/
3771 /* genMult - generates code for multiplication                     */
3772 /*-----------------------------------------------------------------*/
3773 static void
3774 genMult (iCode * ic)
3775 {
3776   int val;
3777   int count, i;
3778   /* If true then the final operation should be a subtract */
3779   bool active = FALSE;
3780
3781   /* Shouldn't occur - all done through function calls */
3782   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3783   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3784   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3785
3786   if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3787       AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3788       AOP_SIZE (IC_RESULT (ic)) > 2)
3789     {
3790       wassertl (0, "Multiplication is handled through support function calls");
3791     }
3792
3793   /* Swap left and right such that right is a literal */
3794   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3795     {
3796       operand *t = IC_RIGHT (ic);
3797       IC_RIGHT (ic) = IC_LEFT (ic);
3798       IC_LEFT (ic) = t;
3799     }
3800
3801   wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3802
3803   val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3804   //  wassertl (val > 0, "Multiply must be positive");
3805   wassertl (val != 1, "Can't multiply by 1");
3806
3807   if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3808     _push (PAIR_DE);
3809     _G.stack.pushedDE = TRUE;
3810   }
3811
3812   if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3813     {
3814       emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3815       emit2 ("ld a,e");
3816       emit2 ("rlc a");
3817       emit2 ("sbc a,a");
3818       emit2 ("ld d,a");
3819     }
3820   else
3821     {
3822       fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3823     }
3824
3825   i = val;
3826
3827   /* Fully unroled version of mul.s.  Not the most efficient.
3828    */
3829   for (count = 0; count < 16; count++)
3830     {
3831       if (count != 0 && active)
3832         {
3833           emit2 ("add hl,hl");
3834         }
3835       if (i & 0x8000U)
3836         {
3837           if (active == FALSE)
3838             {
3839               emit2 ("ld l,e");
3840               emit2 ("ld h,d");
3841             }
3842           else
3843             {
3844               emit2 ("add hl,de");
3845             }
3846           active = TRUE;
3847         }
3848       i <<= 1;
3849     }
3850
3851   spillCached();
3852
3853   if (IS_Z80 && _G.stack.pushedDE)
3854     {
3855       _pop (PAIR_DE);
3856       _G.stack.pushedDE = FALSE;
3857     }
3858
3859   commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3860
3861   freeAsmop (IC_LEFT (ic), NULL, ic);
3862   freeAsmop (IC_RIGHT (ic), NULL, ic);
3863   freeAsmop (IC_RESULT (ic), NULL, ic);
3864 }
3865
3866 /*-----------------------------------------------------------------*/
3867 /* genDiv - generates code for division                            */
3868 /*-----------------------------------------------------------------*/
3869 static void
3870 genDiv (iCode * ic)
3871 {
3872   /* Shouldn't occur - all done through function calls */
3873   wassertl (0, "Division is handled through support function calls");
3874 }
3875
3876 /*-----------------------------------------------------------------*/
3877 /* genMod - generates code for division                            */
3878 /*-----------------------------------------------------------------*/
3879 static void
3880 genMod (iCode * ic)
3881 {
3882   /* Shouldn't occur - all done through function calls */
3883   wassert (0);
3884 }
3885
3886 /*-----------------------------------------------------------------*/
3887 /* genIfxJump :- will create a jump depending on the ifx           */
3888 /*-----------------------------------------------------------------*/
3889 static void
3890 genIfxJump (iCode * ic, char *jval)
3891 {
3892   symbol *jlbl;
3893   const char *inst;
3894
3895   /* if true label then we jump if condition
3896      supplied is true */
3897   if (IC_TRUE (ic))
3898     {
3899       jlbl = IC_TRUE (ic);
3900       if (!strcmp (jval, "a"))
3901         {
3902           inst = "nz";
3903         }
3904       else if (!strcmp (jval, "c"))
3905         {
3906           inst = "c";
3907         }
3908       else if (!strcmp (jval, "nc"))
3909         {
3910           inst = "nc";
3911         }
3912       else if (!strcmp (jval, "m"))
3913         {
3914           inst = "m";
3915         }
3916       else if (!strcmp (jval, "p"))
3917         {
3918           inst = "p";
3919         }
3920       else
3921         {
3922           /* The buffer contains the bit on A that we should test */
3923           inst = "nz";
3924         }
3925     }
3926   else
3927     {
3928       /* false label is present */
3929       jlbl = IC_FALSE (ic);
3930       if (!strcmp (jval, "a"))
3931         {
3932           inst = "z";
3933         }
3934       else if (!strcmp (jval, "c"))
3935         {
3936           inst = "nc";
3937         }
3938       else if (!strcmp (jval, "nc"))
3939         {
3940           inst = "c";
3941         }
3942       else if (!strcmp (jval, "m"))
3943         {
3944           inst = "p";
3945         }
3946       else if (!strcmp (jval, "p"))
3947         {
3948           inst = "m";
3949         }
3950       else
3951         {
3952           /* The buffer contains the bit on A that we should test */
3953           inst = "z";
3954         }
3955     }
3956   /* Z80 can do a conditional long jump */
3957   if (!strcmp (jval, "a"))
3958     {
3959       emit2 ("or a,a");
3960     }
3961   else if (!strcmp (jval, "c"))
3962     {
3963     }
3964   else if (!strcmp (jval, "nc"))
3965     {
3966     }
3967   else if (!strcmp (jval, "m"))
3968     {
3969     }
3970   else if (!strcmp (jval, "p"))
3971     {
3972     }
3973   else
3974     {
3975       emit2 ("bit %s,a", jval);
3976     }
3977   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3978
3979   /* mark the icode as generated */
3980   ic->generated = 1;
3981 }
3982
3983 #if DISABLED
3984 static const char *
3985 _getPairIdName (PAIR_ID id)
3986 {
3987   return _pairs[id].name;
3988 }
3989 #endif
3990
3991 #if OLD
3992       /* if unsigned char cmp with lit, just compare */
3993       if ((size == 1) &&
3994           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3995         {
3996           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3997           if (sign)
3998             {
3999               emit2 ("xor a,!immedbyte", 0x80);
4000               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4001             }
4002           else
4003             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4004         }
4005       else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4006         {
4007           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4008           // Pull left into DE and right into HL
4009           aopGet (AOP(left), LSB, FALSE);
4010           emit2 ("ld d,h");
4011           emit2 ("ld e,l");
4012           aopGet (AOP(right), LSB, FALSE);
4013
4014           while (size--)
4015             {
4016               if (size == 0 && sign)
4017                 {
4018                   // Highest byte when signed needs the bits flipped
4019                   // Save the flags
4020                   emit2 ("push af");
4021                   emit2 ("ld a,(de)");
4022                   emit2 ("xor !immedbyte", 0x80);
4023                   emit2 ("ld e,a");
4024                   emit2 ("ld a,(hl)");
4025                   emit2 ("xor !immedbyte", 0x80);
4026                   emit2 ("ld d,a");
4027                   emit2 ("pop af");
4028                   emit2 ("ld a,e");
4029                   emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4030                 }
4031               else
4032                 {
4033                   emit2 ("ld a,(de)");
4034                   emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4035                 }
4036               
4037               if (size != 0)
4038                 {
4039                   emit2 ("inc hl");
4040                   emit2 ("inc de");
4041                 }
4042               offset++;
4043             }
4044           spillPair (PAIR_HL);
4045         }
4046       else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4047         {
4048           setupPair (PAIR_HL, AOP (left), 0);
4049           aopGet (AOP(right), LSB, FALSE);
4050
4051           while (size--)
4052             {
4053               if (size == 0 && sign)
4054                 {
4055                   // Highest byte when signed needs the bits flipped
4056                   // Save the flags
4057                   emit2 ("push af");
4058                   emit2 ("ld a,(hl)");
4059                   emit2 ("xor !immedbyte", 0x80);
4060                   emit2 ("ld l,a");
4061                   emit2 ("ld a,%d(iy)", offset);
4062                   emit2 ("xor !immedbyte", 0x80);
4063                   emit2 ("ld h,a");
4064                   emit2 ("pop af");
4065                   emit2 ("ld a,l");
4066                   emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4067                 }
4068               else
4069                 {
4070                   emit2 ("ld a,(hl)");
4071                   emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4072                 }
4073               
4074               if (size != 0)
4075                 {
4076                   emit2 ("inc hl");
4077                 }
4078               offset++;
4079             }
4080           spillPair (PAIR_HL);
4081           spillPair (PAIR_IY);
4082         }
4083       else
4084         {
4085           if (AOP_TYPE (right) == AOP_LIT)
4086             {
4087               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4088               /* optimize if(x < 0) or if(x >= 0) */
4089               if (lit == 0L)
4090                 {
4091                   if (!sign)
4092                     {
4093                       /* No sign so it's always false */
4094                       _clearCarry();
4095                     }
4096                   else
4097                     {
4098                       /* Just load in the top most bit */
4099                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4100                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4101                         {
4102                           genIfxJump (ifx, "7");
4103                           return;
4104                         }
4105                       else
4106                         emit2 ("rlc a");
4107                     }
4108                   goto release;
4109                 }
4110             }
4111           
4112           if (sign)
4113             {
4114               /* First setup h and l contaning the top most bytes XORed */
4115               bool fDidXor = FALSE;
4116               if (AOP_TYPE (left) == AOP_LIT)
4117                 {
4118                   unsigned long lit = (unsigned long)
4119                   floatFromVal (AOP (left)->aopu.aop_lit);
4120                   emit2 ("ld %s,!immedbyte", _fTmp[0],
4121                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4122                 }
4123               else
4124                 {
4125                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4126                   emit2 ("xor a,!immedbyte", 0x80);
4127                   emit2 ("ld %s,a", _fTmp[0]);
4128                   fDidXor = TRUE;
4129                 }
4130               if (AOP_TYPE (right) == AOP_LIT)
4131                 {
4132                   unsigned long lit = (unsigned long)
4133                   floatFromVal (AOP (right)->aopu.aop_lit);
4134                   emit2 ("ld %s,!immedbyte", _fTmp[1],
4135                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4136                 }
4137               else
4138                 {
4139                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4140                   emit2 ("xor a,!immedbyte", 0x80);
4141                   emit2 ("ld %s,a", _fTmp[1]);
4142                   fDidXor = TRUE;
4143                 }
4144             }
4145           while (size--)
4146             {
4147               /* Do a long subtract */
4148               if (!sign || size)
4149                 {
4150                   _moveA (aopGet (AOP (left), offset, FALSE));
4151                 }
4152               if (sign && size == 0)
4153                 {
4154                   emit2 ("ld a,%s", _fTmp[0]);
4155                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4156                 }
4157               else
4158                 {
4159                   /* Subtract through, propagating the carry */
4160                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4161                   offset++;
4162                 }
4163             }
4164         }
4165     }
4166 #endif
4167
4168 /** Generic compare for > or <
4169  */
4170 static void
4171 genCmp (operand * left, operand * right,
4172         operand * result, iCode * ifx, int sign)
4173 {
4174   int size, offset = 0;
4175   unsigned long lit = 0L;
4176   bool swap_sense = FALSE;
4177
4178   /* if left & right are bit variables */
4179   if (AOP_TYPE (left) == AOP_CRY &&
4180       AOP_TYPE (right) == AOP_CRY)
4181     {
4182       /* Cant happen on the Z80 */
4183       wassertl (0, "Tried to compare two bits");
4184     }
4185   else
4186     {
4187       /* Do a long subtract of right from left. */
4188       size = max (AOP_SIZE (left), AOP_SIZE (right));
4189
4190       if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4191         {
4192           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4193           // Pull left into DE and right into HL
4194           aopGet (AOP(left), LSB, FALSE);
4195           emit2 ("ld d,h");
4196           emit2 ("ld e,l");
4197           aopGet (AOP(right), LSB, FALSE);
4198
4199           while (size--)
4200             {
4201               emit2 ("ld a,(de)");
4202               emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4203               
4204               if (size != 0)
4205                 {
4206                   emit2 ("inc hl");
4207                   emit2 ("inc de");
4208                 }
4209               offset++;
4210             }
4211           spillPair (PAIR_HL);
4212           goto release;
4213         }
4214
4215       if (AOP_TYPE (right) == AOP_LIT)
4216         {
4217           lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4218           /* optimize if(x < 0) or if(x >= 0) */
4219           if (lit == 0)
4220             {
4221               if (!sign)
4222                 {
4223                   /* No sign so it's always false */
4224                   _clearCarry();
4225                 }
4226               else
4227                 {
4228                   /* Just load in the top most bit */
4229                   _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4230                   if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4231                     {
4232                       genIfxJump (ifx, "7");
4233                       return;
4234                     }
4235                   else
4236                     {
4237                       if (!sign) 
4238                         {
4239                           emit2 ("rlc a");
4240                         }
4241                       if (ifx)
4242                         {
4243                           genIfxJump (ifx, swap_sense ? "c" : "nc");
4244                           return;
4245                         }
4246                     }
4247                 }
4248               goto release;
4249             }
4250         }
4251
4252       while (size--)
4253         {
4254           _moveA (aopGet (AOP (left), offset, FALSE));
4255           /* Subtract through, propagating the carry */
4256           emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4257           offset++;
4258         }
4259     }
4260
4261 release:
4262   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4263     {
4264       if (sign)
4265         {
4266           /* Shift the sign bit up into carry */
4267           emit2 ("rlca");
4268         }
4269       outBitCLong (result, swap_sense);
4270     }
4271   else
4272     {
4273       /* if the result is used in the next
4274          ifx conditional branch then generate
4275          code a little differently */
4276       if (ifx)
4277         {
4278           if (sign)
4279             {
4280               if (IS_GB)
4281                 {
4282                   emit2 ("rlca");
4283                   genIfxJump (ifx, swap_sense ? "nc" : "c");
4284                 }
4285               else
4286                 {
4287                   genIfxJump (ifx, swap_sense ? "p" : "m");
4288                 }
4289             }
4290           else
4291             {
4292               genIfxJump (ifx, swap_sense ? "nc" : "c");
4293             }
4294         }
4295       else
4296         {
4297           if (sign)
4298             {
4299               /* Shift the sign bit up into carry */
4300               emit2 ("rlca");
4301             }
4302           outBitCLong (result, swap_sense);
4303         }
4304       /* leave the result in acc */
4305     }
4306 }
4307
4308 /*-----------------------------------------------------------------*/
4309 /* genCmpGt :- greater than comparison                             */
4310 /*-----------------------------------------------------------------*/
4311 static void
4312 genCmpGt (iCode * ic, iCode * ifx)
4313 {
4314   operand *left, *right, *result;
4315   sym_link *letype, *retype;
4316   int sign;
4317
4318   left = IC_LEFT (ic);
4319   right = IC_RIGHT (ic);
4320   result = IC_RESULT (ic);
4321
4322   letype = getSpec (operandType (left));
4323   retype = getSpec (operandType (right));
4324   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4325   /* assign the amsops */
4326   aopOp (left, ic, FALSE, FALSE);
4327   aopOp (right, ic, FALSE, FALSE);
4328   aopOp (result, ic, TRUE, FALSE);
4329
4330   genCmp (right, left, result, ifx, sign);
4331
4332   freeAsmop (left, NULL, ic);
4333   freeAsmop (right, NULL, ic);
4334   freeAsmop (result, NULL, ic);
4335 }
4336
4337 /*-----------------------------------------------------------------*/
4338 /* genCmpLt - less than comparisons                                */
4339 /*-----------------------------------------------------------------*/
4340 static void
4341 genCmpLt (iCode * ic, iCode * ifx)
4342 {
4343   operand *left, *right, *result;
4344   sym_link *letype, *retype;
4345   int sign;
4346
4347   left = IC_LEFT (ic);
4348   right = IC_RIGHT (ic);
4349   result = IC_RESULT (ic);
4350
4351   letype = getSpec (operandType (left));
4352   retype = getSpec (operandType (right));
4353   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4354
4355   /* assign the amsops */
4356   aopOp (left, ic, FALSE, FALSE);
4357   aopOp (right, ic, FALSE, FALSE);
4358   aopOp (result, ic, TRUE, FALSE);
4359
4360   genCmp (left, right, result, ifx, sign);
4361
4362   freeAsmop (left, NULL, ic);
4363   freeAsmop (right, NULL, ic);
4364   freeAsmop (result, NULL, ic);
4365 }
4366
4367 /*-----------------------------------------------------------------*/
4368 /* gencjneshort - compare and jump if not equal                    */
4369 /*-----------------------------------------------------------------*/
4370 static void
4371 gencjneshort (operand * left, operand * right, symbol * lbl)
4372 {
4373   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4374   int offset = 0;
4375   unsigned long lit = 0L;
4376
4377   /* Swap the left and right if it makes the computation easier */
4378   if (AOP_TYPE (left) == AOP_LIT)
4379     {
4380       operand *t = right;
4381       right = left;
4382       left = t;
4383     }
4384
4385   if (AOP_TYPE (right) == AOP_LIT)
4386     {
4387       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4388     }
4389
4390   /* if the right side is a literal then anything goes */
4391   if (AOP_TYPE (right) == AOP_LIT &&
4392       AOP_TYPE (left) != AOP_DIR)
4393     {
4394       if (lit == 0)
4395         {
4396           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4397           if (size > 1)
4398             {
4399               while (--size)
4400                 {
4401                   emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4402                 }
4403             }
4404           else
4405             {
4406               emit2 ("or a,a");
4407             }
4408           emit2 ("jp nz,!tlabel", lbl->key + 100);
4409         }
4410       else
4411         {
4412           while (size--)
4413             {
4414               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4415               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4416                 emit2 ("or a,a");
4417               else
4418                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4419               emit2 ("jp nz,!tlabel", lbl->key + 100);
4420               offset++;
4421             }
4422         }
4423     }
4424   /* if the right side is in a register or in direct space or
4425      if the left is a pointer register & right is not */
4426   else if (AOP_TYPE (right) == AOP_REG ||
4427            AOP_TYPE (right) == AOP_DIR ||
4428            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4429     {
4430       while (size--)
4431         {
4432           _moveA (aopGet (AOP (left), offset, FALSE));
4433           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4434               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4435             /* PENDING */
4436             emit2 ("jp nz,!tlabel", lbl->key + 100);
4437           else
4438             {
4439               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4440               emit2 ("jp nz,!tlabel", lbl->key + 100);
4441             }
4442           offset++;
4443         }
4444     }
4445   else
4446     {
4447       /* right is a pointer reg need both a & b */
4448       /* PENDING: is this required? */
4449       while (size--)
4450         {
4451           _moveA (aopGet (AOP (right), offset, FALSE));
4452           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4453           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4454           offset++;
4455         }
4456     }
4457 }
4458
4459 /*-----------------------------------------------------------------*/
4460 /* gencjne - compare and jump if not equal                         */
4461 /*-----------------------------------------------------------------*/
4462 static void
4463 gencjne (operand * left, operand * right, symbol * lbl)
4464 {
4465   symbol *tlbl = newiTempLabel (NULL);
4466
4467   gencjneshort (left, right, lbl);
4468
4469   /* PENDING: ?? */
4470   emit2 ("ld a,!one");
4471   emit2 ("!shortjp !tlabel", tlbl->key + 100);
4472   emitLabel (lbl->key + 100);
4473   emit2 ("xor a,a");
4474   emitLabel (tlbl->key + 100);
4475 }
4476
4477 /*-----------------------------------------------------------------*/
4478 /* genCmpEq - generates code for equal to                          */
4479 /*-----------------------------------------------------------------*/
4480 static void
4481 genCmpEq (iCode * ic, iCode * ifx)
4482 {
4483   operand *left, *right, *result;
4484
4485   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4486   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4487   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4488
4489   emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4490
4491   /* Swap operands if it makes the operation easier. ie if:
4492      1.  Left is a literal.
4493    */
4494   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4495     {
4496       operand *t = IC_RIGHT (ic);
4497       IC_RIGHT (ic) = IC_LEFT (ic);
4498       IC_LEFT (ic) = t;
4499     }
4500
4501   if (ifx && !AOP_SIZE (result))
4502     {
4503       symbol *tlbl;
4504       /* if they are both bit variables */
4505       if (AOP_TYPE (left) == AOP_CRY &&
4506           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4507         {
4508           wassertl (0, "Tried to compare two bits");
4509         }
4510       else
4511         {
4512           tlbl = newiTempLabel (NULL);
4513           gencjneshort (left, right, tlbl);
4514           if (IC_TRUE (ifx))
4515             {
4516               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4517               emitLabel (tlbl->key + 100);
4518             }
4519           else
4520             {
4521               /* PENDING: do this better */
4522               symbol *lbl = newiTempLabel (NULL);
4523               emit2 ("!shortjp !tlabel", lbl->key + 100);
4524               emitLabel (tlbl->key + 100);
4525               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4526               emitLabel (lbl->key + 100);
4527             }
4528         }
4529       /* mark the icode as generated */
4530       ifx->generated = 1;
4531       goto release;
4532     }
4533
4534   /* if they are both bit variables */
4535   if (AOP_TYPE (left) == AOP_CRY &&
4536       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4537     {
4538       wassertl (0, "Tried to compare a bit to either a literal or another bit");
4539     }
4540   else
4541     {
4542       emitDebug(";4");
4543       
4544       gencjne (left, right, newiTempLabel (NULL));
4545       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4546         {
4547           wassert (0);
4548         }
4549       if (ifx)
4550         {
4551           emitDebug(";5");
4552           genIfxJump (ifx, "a");
4553           goto release;
4554         }
4555       /* if the result is used in an arithmetic operation
4556          then put the result in place */
4557       if (AOP_TYPE (result) != AOP_CRY)
4558         {
4559           emitDebug(";6");
4560           outAcc (result);
4561         }
4562       /* leave the result in acc */
4563     }
4564
4565 release:
4566   freeAsmop (left, NULL, ic);
4567   freeAsmop (right, NULL, ic);
4568   freeAsmop (result, NULL, ic);
4569 }
4570
4571 /*-----------------------------------------------------------------*/
4572 /* ifxForOp - returns the icode containing the ifx for operand     */
4573 /*-----------------------------------------------------------------*/
4574 static iCode *
4575 ifxForOp (operand * op, iCode * ic)
4576 {
4577   /* if true symbol then needs to be assigned */
4578   if (IS_TRUE_SYMOP (op))
4579     return NULL;
4580
4581   /* if this has register type condition and
4582      the next instruction is ifx with the same operand
4583      and live to of the operand is upto the ifx only then */
4584   if (ic->next &&
4585       ic->next->op == IFX &&
4586       IC_COND (ic->next)->key == op->key &&
4587       OP_SYMBOL (op)->liveTo <= ic->next->seq)
4588     return ic->next;
4589
4590   return NULL;
4591 }
4592
4593 /*-----------------------------------------------------------------*/
4594 /* genAndOp - for && operation                                     */
4595 /*-----------------------------------------------------------------*/
4596 static void
4597 genAndOp (iCode * ic)
4598 {
4599   operand *left, *right, *result;
4600   symbol *tlbl;
4601
4602   /* note here that && operations that are in an if statement are
4603      taken away by backPatchLabels only those used in arthmetic
4604      operations remain */
4605   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4606   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4607   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4608
4609   /* if both are bit variables */
4610   if (AOP_TYPE (left) == AOP_CRY &&
4611       AOP_TYPE (right) == AOP_CRY)
4612     {
4613       wassertl (0, "Tried to and two bits");
4614     }
4615   else
4616     {
4617       tlbl = newiTempLabel (NULL);
4618       _toBoolean (left);
4619       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4620       _toBoolean (right);
4621       emitLabel (tlbl->key + 100);
4622       outBitAcc (result);
4623     }
4624
4625   freeAsmop (left, NULL, ic);
4626   freeAsmop (right, NULL, ic);
4627   freeAsmop (result, NULL, ic);
4628 }
4629
4630 /*-----------------------------------------------------------------*/
4631 /* genOrOp - for || operation                                      */
4632 /*-----------------------------------------------------------------*/
4633 static void
4634 genOrOp (iCode * ic)
4635 {
4636   operand *left, *right, *result;
4637   symbol *tlbl;
4638
4639   /* note here that || operations that are in an
4640      if statement are taken away by backPatchLabels
4641      only those used in arthmetic operations remain */
4642   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4643   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4644   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4645
4646   /* if both are bit variables */
4647   if (AOP_TYPE (left) == AOP_CRY &&
4648       AOP_TYPE (right) == AOP_CRY)
4649     {
4650       wassertl (0, "Tried to OR two bits");
4651     }
4652   else
4653     {
4654       tlbl = newiTempLabel (NULL);
4655       _toBoolean (left);
4656       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4657       _toBoolean (right);
4658       emitLabel (tlbl->key + 100);
4659       outBitAcc (result);
4660     }
4661
4662   freeAsmop (left, NULL, ic);
4663   freeAsmop (right, NULL, ic);
4664   freeAsmop (result, NULL, ic);
4665 }
4666
4667 /*-----------------------------------------------------------------*/
4668 /* isLiteralBit - test if lit == 2^n                               */
4669 /*-----------------------------------------------------------------*/
4670 int
4671 isLiteralBit (unsigned long lit)
4672 {
4673   unsigned long pw[32] =
4674   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4675    0x100L, 0x200L, 0x400L, 0x800L,
4676    0x1000L, 0x2000L, 0x4000L, 0x8000L,
4677    0x10000L, 0x20000L, 0x40000L, 0x80000L,
4678    0x100000L, 0x200000L, 0x400000L, 0x800000L,
4679    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4680    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4681   int idx;
4682
4683   for (idx = 0; idx < 32; idx++)
4684     if (lit == pw[idx])
4685       return idx + 1;
4686   return 0;
4687 }
4688
4689 /*-----------------------------------------------------------------*/
4690 /* jmpTrueOrFalse -                                                */
4691 /*-----------------------------------------------------------------*/
4692 static void
4693 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4694 {
4695   // ugly but optimized by peephole
4696   if (IC_TRUE (ic))
4697     {
4698       symbol *nlbl = newiTempLabel (NULL);
4699       emit2 ("jp !tlabel", nlbl->key + 100);
4700       emitLabel (tlbl->key + 100);
4701       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4702       emitLabel (nlbl->key + 100);
4703     }
4704   else
4705     {
4706       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4707       emitLabel (tlbl->key + 100);
4708     }
4709   ic->generated = 1;
4710 }
4711
4712 /*-----------------------------------------------------------------*/
4713 /* genAnd  - code for and                                          */
4714 /*-----------------------------------------------------------------*/
4715 static void
4716 genAnd (iCode * ic, iCode * ifx)
4717 {
4718   operand *left, *right, *result;
4719   int size, offset = 0;
4720   unsigned long lit = 0L;
4721   int bytelit = 0;
4722
4723   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4724   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4725   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4726
4727   /* if left is a literal & right is not then exchange them */
4728   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4729       AOP_NEEDSACC (left))
4730     {
4731       operand *tmp = right;
4732       right = left;
4733       left = tmp;
4734     }
4735
4736   /* if result = right then exchange them */
4737   if (sameRegs (AOP (result), AOP (right)))
4738     {
4739       operand *tmp = right;
4740       right = left;
4741       left = tmp;
4742     }
4743
4744   /* if right is bit then exchange them */
4745   if (AOP_TYPE (right) == AOP_CRY &&
4746       AOP_TYPE (left) != AOP_CRY)
4747     {
4748       operand *tmp = right;
4749       right = left;
4750       left = tmp;
4751     }
4752   if (AOP_TYPE (right) == AOP_LIT)
4753     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4754
4755   size = AOP_SIZE (result);
4756
4757   if (AOP_TYPE (left) == AOP_CRY)
4758     {
4759       wassertl (0, "Tried to perform an AND with a bit as an operand");
4760       goto release;
4761     }
4762
4763   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
4764   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
4765   if ((AOP_TYPE (right) == AOP_LIT) &&
4766       (AOP_TYPE (result) == AOP_CRY) &&
4767       (AOP_TYPE (left) != AOP_CRY))
4768     {
4769       symbol *tlbl = newiTempLabel (NULL);
4770       int sizel = AOP_SIZE (left);
4771       if (size)
4772         {
4773           /* PENDING: Test case for this. */
4774           emit2 ("scf");
4775         }
4776       while (sizel--)
4777         {
4778           if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4779             {
4780               _moveA (aopGet (AOP (left), offset, FALSE));
4781               if (bytelit != 0x0FFL)
4782                 {
4783                   emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4784                 }
4785               else
4786                 {
4787                   /* For the flags */
4788                   emit2 ("or a,a");
4789                 }
4790               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4791             }
4792               offset++;
4793         }
4794       // bit = left & literal
4795       if (size)
4796         {
4797           emit2 ("clr c");
4798           emit2 ("!tlabeldef", tlbl->key + 100);
4799         }
4800       // if(left & literal)
4801       else
4802         {
4803           if (ifx)
4804             {
4805               jmpTrueOrFalse (ifx, tlbl);
4806             }
4807           goto release;
4808         }
4809       outBitC (result);
4810       goto release;
4811     }
4812
4813   /* if left is same as result */
4814   if (sameRegs (AOP (result), AOP (left)))
4815     {
4816       for (; size--; offset++)
4817         {
4818           if (AOP_TYPE (right) == AOP_LIT)
4819             {
4820               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4821                 continue;
4822               else
4823                 {
4824                   if (bytelit == 0)
4825                     aopPut (AOP (result), "!zero", offset);
4826                   else
4827                     {
4828                       _moveA (aopGet (AOP (left), offset, FALSE));
4829                       emit2 ("and a,%s",
4830                                 aopGet (AOP (right), offset, FALSE));
4831                       aopPut (AOP (left), "a", offset);
4832                     }
4833                 }
4834
4835             }
4836           else
4837             {
4838               if (AOP_TYPE (left) == AOP_ACC)
4839                 {
4840                   wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4841                 }
4842               else
4843                 {
4844                   _moveA (aopGet (AOP (left), offset, FALSE));
4845                   emit2 ("and a,%s",
4846                             aopGet (AOP (right), offset, FALSE));
4847                   aopPut (AOP (left), "a", offset);
4848                 }
4849             }
4850         }
4851     }
4852   else
4853     {
4854       // left & result in different registers
4855       if (AOP_TYPE (result) == AOP_CRY)
4856         {
4857           wassertl (0, "Tried to AND where the result is in carry");
4858         }
4859       else
4860         {
4861           for (; (size--); offset++)
4862             {
4863               // normal case
4864               // result = left & right
4865               if (AOP_TYPE (right) == AOP_LIT)
4866                 {
4867                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4868                     {
4869                       aopPut (AOP (result),
4870                               aopGet (AOP (left), offset, FALSE),
4871                               offset);
4872                       continue;
4873                     }
4874                   else if (bytelit == 0)
4875                     {
4876                       aopPut (AOP (result), "!zero", offset);
4877                       continue;
4878                     }
4879                 }
4880               // faster than result <- left, anl result,right
4881               // and better if result is SFR
4882               if (AOP_TYPE (left) == AOP_ACC)
4883                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4884               else
4885                 {
4886                   _moveA (aopGet (AOP (left), offset, FALSE));
4887                   emit2 ("and a,%s",
4888                             aopGet (AOP (right), offset, FALSE));
4889                 }
4890               aopPut (AOP (result), "a", offset);
4891             }
4892         }
4893
4894     }
4895
4896 release:
4897   freeAsmop (left, NULL, ic);
4898   freeAsmop (right, NULL, ic);
4899   freeAsmop (result, NULL, ic);
4900 }
4901
4902 /*-----------------------------------------------------------------*/
4903 /* genOr  - code for or                                            */
4904 /*-----------------------------------------------------------------*/
4905 static void
4906 genOr (iCode * ic, iCode * ifx)
4907 {
4908   operand *left, *right, *result;
4909   int size, offset = 0;
4910   unsigned long lit = 0L;
4911   int bytelit = 0;
4912
4913   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4914   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4915   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4916
4917   /* if left is a literal & right is not then exchange them */
4918   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4919       AOP_NEEDSACC (left))
4920     {
4921       operand *tmp = right;
4922       right = left;
4923       left = tmp;
4924     }
4925
4926   /* if result = right then exchange them */
4927   if (sameRegs (AOP (result), AOP (right)))
4928     {
4929       operand *tmp = right;
4930       right = left;
4931       left = tmp;
4932     }
4933
4934   /* if right is bit then exchange them */
4935   if (AOP_TYPE (right) == AOP_CRY &&
4936       AOP_TYPE (left) != AOP_CRY)
4937     {
4938       operand *tmp = right;
4939       right = left;
4940       left = tmp;
4941     }
4942   if (AOP_TYPE (right) == AOP_LIT)
4943     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4944
4945   size = AOP_SIZE (result);
4946
4947   if (AOP_TYPE (left) == AOP_CRY)
4948     {
4949       wassertl (0, "Tried to OR where left is a bit");
4950       goto release;
4951     }
4952
4953   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
4954   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
4955   if ((AOP_TYPE (right) == AOP_LIT) &&
4956       (AOP_TYPE (result) == AOP_CRY) &&
4957       (AOP_TYPE (left) != AOP_CRY))
4958     {
4959       symbol *tlbl = newiTempLabel (NULL);
4960       int sizel = AOP_SIZE (left);
4961
4962       if (size)
4963         {
4964           wassertl (0, "Result is assigned to a bit");
4965         }
4966       /* PENDING: Modeled after the AND code which is inefficent. */
4967       while (sizel--)
4968         {
4969           bytelit = (lit >> (offset * 8)) & 0x0FFL;
4970
4971           _moveA (aopGet (AOP (left), offset, FALSE));
4972           /* OR with any literal is the same as OR with itself. */
4973           emit2 ("or a,a");
4974           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4975
4976           offset++;
4977         }
4978       if (ifx)
4979         {
4980           jmpTrueOrFalse (ifx, tlbl);
4981         }
4982       goto release;
4983     }
4984
4985   /* if left is same as result */
4986   if (sameRegs (AOP (result), AOP (left)))
4987     {
4988       for (; size--; offset++)
4989         {
4990           if (AOP_TYPE (right) == AOP_LIT)
4991             {
4992               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4993                 continue;
4994               else
4995                 {
4996                   _moveA (aopGet (AOP (left), offset, FALSE));
4997                   emit2 ("or a,%s",
4998                             aopGet (AOP (right), offset, FALSE));
4999                   aopPut (AOP (result), "a", offset);
5000                 }
5001             }
5002           else
5003             {
5004               if (AOP_TYPE (left) == AOP_ACC)
5005                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5006               else
5007                 {
5008                   _moveA (aopGet (AOP (left), offset, FALSE));
5009                   emit2 ("or a,%s",
5010                             aopGet (AOP (right), offset, FALSE));
5011                   aopPut (AOP (result), "a", offset);
5012                 }
5013             }
5014         }
5015     }
5016   else
5017     {
5018       // left & result in different registers
5019       if (AOP_TYPE (result) == AOP_CRY)
5020         {
5021           wassertl (0, "Result of OR is in a bit");
5022         }
5023       else
5024         for (; (size--); offset++)
5025           {
5026             // normal case
5027             // result = left & right
5028             if (AOP_TYPE (right) == AOP_LIT)
5029               {
5030                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5031                   {
5032                     aopPut (AOP (result),
5033                             aopGet (AOP (left), offset, FALSE),
5034                             offset);
5035                     continue;
5036                   }
5037               }
5038             // faster than result <- left, anl result,right
5039             // and better if result is SFR
5040             if (AOP_TYPE (left) == AOP_ACC)
5041               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5042             else
5043               {
5044                 _moveA (aopGet (AOP (left), offset, FALSE));
5045                 emit2 ("or a,%s",
5046                           aopGet (AOP (right), offset, FALSE));
5047               }
5048             aopPut (AOP (result), "a", offset);
5049             /* PENDING: something weird is going on here.  Add exception. */
5050             if (AOP_TYPE (result) == AOP_ACC)
5051               break;
5052           }
5053     }
5054
5055 release:
5056   freeAsmop (left, NULL, ic);
5057   freeAsmop (right, NULL, ic);
5058   freeAsmop (result, NULL, ic);
5059 }
5060
5061 /*-----------------------------------------------------------------*/
5062 /* genXor - code for xclusive or                                   */
5063 /*-----------------------------------------------------------------*/
5064 static void
5065 genXor (iCode * ic, iCode * ifx)
5066 {
5067   operand *left, *right, *result;
5068   int size, offset = 0;
5069   unsigned long lit = 0L;
5070
5071   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5072   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5073   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5074
5075   /* if left is a literal & right is not then exchange them */
5076   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5077       AOP_NEEDSACC (left))
5078     {
5079       operand *tmp = right;
5080       right = left;
5081       left = tmp;
5082     }
5083
5084   /* if result = right then exchange them */
5085   if (sameRegs (AOP (result), AOP (right)))
5086     {
5087       operand *tmp = right;
5088       right = left;
5089       left = tmp;
5090     }
5091
5092   /* if right is bit then exchange them */
5093   if (AOP_TYPE (right) == AOP_CRY &&
5094       AOP_TYPE (left) != AOP_CRY)
5095     {
5096       operand *tmp = right;
5097       right = left;
5098       left = tmp;
5099     }
5100   if (AOP_TYPE (right) == AOP_LIT)
5101     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5102
5103   size = AOP_SIZE (result);
5104
5105   if (AOP_TYPE (left) == AOP_CRY)
5106     {
5107       wassertl (0, "Tried to XOR a bit");
5108       goto release;
5109     }
5110
5111   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5112   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5113   if ((AOP_TYPE (right) == AOP_LIT) &&
5114       (AOP_TYPE (result) == AOP_CRY) &&
5115       (AOP_TYPE (left) != AOP_CRY))
5116     {
5117       symbol *tlbl = newiTempLabel (NULL);
5118       int sizel = AOP_SIZE (left);
5119
5120       if (size)
5121         {
5122           /* PENDING: Test case for this. */
5123           wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5124         }
5125       while (sizel--)
5126         {
5127           _moveA (aopGet (AOP (left), offset, FALSE));
5128           emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5129           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5130           offset++;
5131         }
5132       if (ifx)
5133         {
5134           jmpTrueOrFalse (ifx, tlbl);
5135         }
5136       else
5137         {
5138           wassertl (0, "Result of XOR was destined for a bit");
5139         }
5140       goto release;
5141     }
5142
5143   /* if left is same as result */
5144   if (sameRegs (AOP (result), AOP (left)))
5145     {
5146       for (; size--; offset++)
5147         {
5148           if (AOP_TYPE (right) == AOP_LIT)
5149             {
5150               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5151                 continue;
5152               else
5153                 {
5154                   _moveA (aopGet (AOP (right), offset, FALSE));
5155                   emit2 ("xor a,%s",
5156                             aopGet (AOP (left), offset, FALSE));
5157                   aopPut (AOP (result), "a", offset);
5158                 }
5159             }
5160           else
5161             {
5162               if (AOP_TYPE (left) == AOP_ACC)
5163                 {
5164                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5165                 }
5166               else
5167                 {
5168                   _moveA (aopGet (AOP (right), offset, FALSE));
5169                   emit2 ("xor a,%s",
5170                             aopGet (AOP (left), offset, FALSE));
5171                   aopPut (AOP (result), "a", 0);
5172                 }
5173             }
5174         }
5175     }
5176   else
5177     {
5178       // left & result in different registers
5179       if (AOP_TYPE (result) == AOP_CRY)
5180         {
5181           wassertl (0, "Result of XOR is in a bit");
5182         }
5183       else
5184         for (; (size--); offset++)
5185           {
5186             // normal case
5187             // result = left & right
5188             if (AOP_TYPE (right) == AOP_LIT)
5189               {
5190                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5191                   {
5192                     aopPut (AOP (result),
5193                             aopGet (AOP (left), offset, FALSE),
5194                             offset);
5195                     continue;
5196                   }
5197               }
5198             // faster than result <- left, anl result,right
5199             // and better if result is SFR
5200             if (AOP_TYPE (left) == AOP_ACC) 
5201               {
5202                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5203               }
5204             else
5205               {
5206                 _moveA (aopGet (AOP (right), offset, FALSE));
5207                 emit2 ("xor a,%s",
5208                           aopGet (AOP (left), offset, FALSE));
5209               }
5210             aopPut (AOP (result), "a", offset);
5211           }
5212     }
5213
5214 release:
5215   freeAsmop (left, NULL, ic);
5216   freeAsmop (right, NULL, ic);
5217   freeAsmop (result, NULL, ic);
5218 }
5219
5220 /*-----------------------------------------------------------------*/
5221 /* genInline - write the inline code out                           */
5222 /*-----------------------------------------------------------------*/
5223 static void
5224 genInline (iCode * ic)
5225 {
5226   char *buffer, *bp, *bp1;
5227
5228   _G.lines.isInline += (!options.asmpeep);
5229
5230   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5231   strcpy (buffer, IC_INLINE (ic));
5232
5233   /* emit each line as a code */
5234   while (*bp)
5235     {
5236       if (*bp == '\n')
5237         {
5238           *bp++ = '\0';
5239           emit2 (bp1);
5240           bp1 = bp;
5241         }
5242       else
5243         {
5244           if (*bp == ':')
5245             {
5246               bp++;
5247               *bp = '\0';
5248               bp++;
5249               emit2 (bp1);
5250               bp1 = bp;
5251             }
5252           else
5253             bp++;
5254         }
5255     }
5256   if (bp1 != bp)
5257     emit2 (bp1);
5258   _G.lines.isInline -= (!options.asmpeep);
5259
5260 }
5261
5262 /*-----------------------------------------------------------------*/
5263 /* genRRC - rotate right with carry                                */
5264 /*-----------------------------------------------------------------*/
5265 static void
5266 genRRC (iCode * ic)
5267 {
5268   wassert (0);
5269 }
5270
5271 /*-----------------------------------------------------------------*/
5272 /* genRLC - generate code for rotate left with carry               */
5273 /*-----------------------------------------------------------------*/
5274 static void
5275 genRLC (iCode * ic)
5276 {
5277   wassert (0);
5278 }
5279
5280 /*-----------------------------------------------------------------*/
5281 /* genGetHbit - generates code get highest order bit               */
5282 /*-----------------------------------------------------------------*/
5283 static void
5284 genGetHbit (iCode * ic)
5285 {
5286   operand *left, *result;
5287   left = IC_LEFT (ic);
5288   result = IC_RESULT (ic);
5289
5290   aopOp (left, ic, FALSE, FALSE);
5291   aopOp (result, ic, FALSE, FALSE);
5292
5293   /* get the highest order byte into a */
5294   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5295
5296   if (AOP_TYPE (result) == AOP_CRY)
5297     {
5298       emit2 ("rl a");
5299       outBitC (result);
5300     }
5301   else
5302     {
5303       emit2 ("rlc a");
5304       emit2 ("and a,!one");
5305       outAcc (result);
5306     }
5307
5308
5309   freeAsmop (left, NULL, ic);
5310   freeAsmop (result, NULL, ic);
5311 }
5312
5313 static void
5314 emitRsh2 (asmop *aop, int size, int is_signed)
5315 {
5316   int offset = 0;
5317
5318   while (size--)
5319     {
5320       const char *l = aopGet (aop, size, FALSE);
5321       if (offset == 0)
5322         {
5323           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5324         }
5325       else
5326         {
5327           emit2 ("rr %s", l);
5328         }
5329       offset++;
5330     }
5331 }
5332
5333 /*-----------------------------------------------------------------*/
5334 /* shiftR2Left2Result - shift right two bytes from left to result  */
5335 /*-----------------------------------------------------------------*/
5336 static void
5337 shiftR2Left2Result (operand * left, int offl,
5338                     operand * result, int offr,
5339                     int shCount, int is_signed)
5340 {
5341   int size = 2;
5342   symbol *tlbl, *tlbl1;
5343
5344   movLeft2Result (left, offl, result, offr, 0);
5345   movLeft2Result (left, offl + 1, result, offr + 1, 0);
5346
5347   /*  if (AOP(result)->type == AOP_REG) { */
5348   
5349   tlbl = newiTempLabel (NULL);
5350   tlbl1 = newiTempLabel (NULL);
5351
5352   /* Left is already in result - so now do the shift */
5353   if (shCount <= 4)
5354     {
5355       while (shCount--)
5356         {
5357           emitRsh2 (AOP (result), size, is_signed);
5358         }
5359     }
5360   else
5361     {
5362       emit2 ("ld a,!immedbyte+1", shCount);
5363       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5364       emitLabel (tlbl->key + 100);
5365
5366       emitRsh2 (AOP (result), size, is_signed);
5367
5368       emitLabel (tlbl1->key + 100);
5369       emit2 ("dec a");
5370       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5371     }
5372 }
5373
5374 /*-----------------------------------------------------------------*/
5375 /* shiftL2Left2Result - shift left two bytes from left to result   */
5376 /*-----------------------------------------------------------------*/
5377 static void
5378 shiftL2Left2Result (operand * left, int offl,
5379                     operand * result, int offr, int shCount)
5380 {
5381   if (sameRegs (AOP (result), AOP (left)) &&
5382       ((offl + MSB16) == offr))
5383     {
5384       wassert (0);
5385     }
5386   else
5387     {
5388       /* Copy left into result */
5389       movLeft2Result (left, offl, result, offr, 0);
5390       movLeft2Result (left, offl + 1, result, offr + 1, 0);
5391     }
5392
5393   if (getPairId (AOP (result)) == PAIR_HL)
5394     {
5395       while (shCount--)
5396         {
5397           emit2 ("add hl,hl");
5398         }
5399     }
5400   else
5401     {
5402     int size = 2;
5403     int offset = 0;
5404     symbol *tlbl, *tlbl1;
5405     const char *l;
5406
5407     tlbl = newiTempLabel (NULL);
5408     tlbl1 = newiTempLabel (NULL);
5409
5410     if (AOP (result)->type == AOP_REG)
5411       {
5412         while (shCount--)
5413           {
5414             for (offset = 0; offset < size; offset++)
5415               {
5416                 l = aopGet (AOP (result), offset, FALSE);
5417             
5418                 if (offset == 0)
5419                   {
5420                     emit2 ("sla %s", l);
5421                   }
5422                 else
5423                   {
5424                     emit2 ("rl %s", l);
5425                   }
5426               }
5427           }
5428       }
5429     else
5430       {
5431         /* Left is already in result - so now do the shift */
5432         if (shCount > 1)
5433           {
5434             emit2 ("ld a,!immedbyte+1", shCount);
5435             emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5436             emitLabel (tlbl->key + 100);
5437           }
5438
5439         while (size--)
5440           {
5441             l = aopGet (AOP (result), offset, FALSE);
5442             
5443             if (offset == 0)
5444               {
5445                 emit2 ("sla %s", l);
5446               }
5447             else
5448               {
5449                 emit2 ("rl %s", l);
5450               }
5451             
5452             offset++;
5453           }
5454         if (shCount > 1)
5455           {
5456             emitLabel (tlbl1->key + 100);
5457             emit2 ("dec a");
5458             emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5459           }
5460       }
5461   }
5462 }
5463
5464 /*-----------------------------------------------------------------*/
5465 /* AccRol - rotate left accumulator by known count                 */
5466 /*-----------------------------------------------------------------*/
5467 static void
5468 AccRol (int shCount)
5469 {
5470   shCount &= 0x0007;            // shCount : 0..7
5471
5472   switch (shCount)
5473     {
5474     case 0:
5475       break;
5476     case 1:
5477       emit2 ("sla a");
5478       break;
5479     case 2:
5480       emit2 ("sla a");
5481       emit2 ("rl a");
5482       break;
5483     case 3:
5484       emit2 ("sla a");
5485       emit2 ("rl a");
5486       emit2 ("rl a");
5487       break;
5488     case 4:
5489       emit2 ("sla a");
5490       emit2 ("rl a");
5491       emit2 ("rl a");
5492       emit2 ("rl a");
5493       break;
5494     case 5:
5495       emit2 ("srl a");
5496       emit2 ("rr a");
5497       emit2 ("rr a");
5498       break;
5499     case 6:
5500       emit2 ("srl a");
5501       emit2 ("rr a");
5502       break;
5503     case 7:
5504       emit2 ("srl a");
5505       break;
5506     }
5507 }
5508
5509 /*-----------------------------------------------------------------*/
5510 /* AccLsh - left shift accumulator by known count                  */
5511 /*-----------------------------------------------------------------*/
5512 static void
5513 AccLsh (int shCount)
5514 {
5515   static const unsigned char SLMask[] =
5516     {
5517       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5518     };
5519
5520   if (shCount != 0)
5521     {
5522       if (shCount == 1)
5523         {
5524           emit2 ("add a,a");
5525         }
5526       else if (shCount == 2)
5527         {
5528           emit2 ("add a,a");
5529           emit2 ("add a,a");
5530         }
5531       else
5532         {
5533           /* rotate left accumulator */
5534           AccRol (shCount);
5535           /* and kill the lower order bits */
5536           emit2 ("and a,!immedbyte", SLMask[shCount]);
5537         }
5538     }
5539 }
5540
5541 /*-----------------------------------------------------------------*/
5542 /* shiftL1Left2Result - shift left one byte from left to result    */
5543 /*-----------------------------------------------------------------*/
5544 static void
5545 shiftL1Left2Result (operand * left, int offl,
5546                     operand * result, int offr, int shCount)
5547 {
5548   const char *l;
5549   l = aopGet (AOP (left), offl, FALSE);
5550   _moveA (l);
5551   /* shift left accumulator */
5552   AccLsh (shCount);
5553   aopPut (AOP (result), "a", offr);
5554 }
5555
5556
5557 /*-----------------------------------------------------------------*/
5558 /* genlshTwo - left shift two bytes by known amount != 0           */
5559 /*-----------------------------------------------------------------*/
5560 static void
5561 genlshTwo (operand * result, operand * left, int shCount)
5562 {
5563   int size = AOP_SIZE (result);
5564
5565   wassert (size == 2);
5566
5567   /* if shCount >= 8 */
5568   if (shCount >= 8)
5569     {
5570       shCount -= 8;
5571       if (size > 1)
5572         {
5573           if (shCount)
5574             {
5575               movLeft2Result (left, LSB, result, MSB16, 0);
5576               aopPut (AOP (result), "!zero", 0);
5577               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5578             }
5579           else
5580             {
5581               movLeft2Result (left, LSB, result, MSB16, 0);
5582               aopPut (AOP (result), "!zero", 0);
5583             }
5584         }
5585       else
5586         {
5587           aopPut (AOP (result), "!zero", LSB);
5588         }
5589     }
5590   /*  1 <= shCount <= 7 */
5591   else
5592     {
5593       if (size == 1)
5594         {
5595           wassert (0);
5596         }
5597       else
5598         {
5599           shiftL2Left2Result (left, LSB, result, LSB, shCount);
5600         }
5601     }
5602 }
5603
5604 /*-----------------------------------------------------------------*/
5605 /* genlshOne - left shift a one byte quantity by known count       */
5606 /*-----------------------------------------------------------------*/
5607 static void
5608 genlshOne (operand * result, operand * left, int shCount)
5609 {
5610   shiftL1Left2Result (left, LSB, result, LSB, shCount);
5611 }
5612
5613 /*-----------------------------------------------------------------*/
5614 /* genLeftShiftLiteral - left shifting by known count              */
5615 /*-----------------------------------------------------------------*/
5616 static void
5617 genLeftShiftLiteral (operand * left,
5618                      operand * right,
5619                      operand * result,
5620                      iCode * ic)
5621 {
5622   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5623   int size;
5624
5625   freeAsmop (right, NULL, ic);
5626
5627   aopOp (left, ic, FALSE, FALSE);
5628   aopOp (result, ic, FALSE, FALSE);
5629
5630   size = getSize (operandType (result));
5631
5632   /* I suppose that the left size >= result size */
5633   if (shCount == 0)
5634     {
5635       wassert (0);
5636     }
5637
5638   else if (shCount >= (size * 8)) 
5639     {
5640       while (size--)
5641         {
5642           aopPut (AOP (result), "!zero", size);
5643         }
5644     }
5645   else
5646     {
5647       switch (size)
5648         {
5649         case 1:
5650           genlshOne (result, left, shCount);
5651           break;
5652         case 2:
5653           genlshTwo (result, left, shCount);
5654           break;
5655         case 4:
5656           wassertl (0, "Shifting of longs is currently unsupported");
5657           break;
5658         default:
5659           wassert (0);
5660         }
5661     }
5662   freeAsmop (left, NULL, ic);
5663   freeAsmop (result, NULL, ic);
5664 }
5665
5666 /*-----------------------------------------------------------------*/
5667 /* genLeftShift - generates code for left shifting                 */
5668 /*-----------------------------------------------------------------*/
5669 static void
5670 genLeftShift (iCode * ic)
5671 {
5672   int size, offset;
5673   const char *l;
5674   symbol *tlbl, *tlbl1;
5675   operand *left, *right, *result;
5676
5677   right = IC_RIGHT (ic);
5678   left = IC_LEFT (ic);
5679   result = IC_RESULT (ic);
5680
5681   aopOp (right, ic, FALSE, FALSE);
5682
5683   /* if the shift count is known then do it
5684      as efficiently as possible */
5685   if (AOP_TYPE (right) == AOP_LIT)
5686     {
5687       genLeftShiftLiteral (left, right, result, ic);
5688       return;
5689     }
5690
5691   /* shift count is unknown then we have to form a loop get the loop
5692      count in B : Note: we take only the lower order byte since
5693      shifting more that 32 bits make no sense anyway, ( the largest
5694      size of an object can be only 32 bits ) */
5695   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5696   emit2 ("inc a");
5697   freeAsmop (right, NULL, ic);
5698   aopOp (left, ic, FALSE, FALSE);
5699   aopOp (result, ic, FALSE, FALSE);
5700
5701   /* now move the left to the result if they are not the
5702      same */
5703
5704   if (!sameRegs (AOP (left), AOP (result)))
5705     {
5706
5707       size = AOP_SIZE (result);
5708       offset = 0;
5709       while (size--)
5710         {
5711           l = aopGet (AOP (left), offset, FALSE);
5712           aopPut (AOP (result), l, offset);
5713           offset++;
5714         }
5715     }
5716
5717   tlbl = newiTempLabel (NULL);
5718   size = AOP_SIZE (result);
5719   offset = 0;
5720   tlbl1 = newiTempLabel (NULL);
5721
5722   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5723   emitLabel (tlbl->key + 100);
5724   l = aopGet (AOP (result), offset, FALSE);
5725
5726   while (size--)
5727     {
5728       l = aopGet (AOP (result), offset, FALSE);
5729
5730       if (offset == 0)
5731         {
5732           emit2 ("sla %s", l);
5733         }
5734       else
5735         {
5736           emit2 ("rl %s", l);
5737         }
5738       offset++;
5739     }
5740   emitLabel (tlbl1->key + 100);
5741   emit2 ("dec a");
5742   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5743
5744   freeAsmop (left, NULL, ic);
5745   freeAsmop (result, NULL, ic);
5746 }
5747
5748 /*-----------------------------------------------------------------*/
5749 /* genrshOne - left shift two bytes by known amount != 0           */
5750 /*-----------------------------------------------------------------*/
5751 static void
5752 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5753 {
5754   /* Errk */
5755   int size = AOP_SIZE (result);
5756   const char *l;
5757
5758   wassert (size == 1);
5759   wassert (shCount < 8);
5760
5761   l = aopGet (AOP (left), 0, FALSE);
5762
5763   if (AOP (result)->type == AOP_REG)
5764     {
5765       aopPut (AOP (result), l, 0);
5766       l = aopGet (AOP (result), 0, FALSE);
5767       while (shCount--)
5768         {
5769           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5770         }
5771     }
5772   else
5773     {
5774       _moveA (l);
5775       while (shCount--)
5776         {
5777           emit2 ("%s a", is_signed ? "sra" : "srl");
5778         }
5779       aopPut (AOP (result), "a", 0);
5780     }
5781 }
5782
5783 /*-----------------------------------------------------------------*/
5784 /* AccRsh - right shift accumulator by known count                 */
5785 /*-----------------------------------------------------------------*/
5786 static void
5787 AccRsh (int shCount)
5788 {
5789   static const unsigned char SRMask[] =
5790     {
5791       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5792     };
5793
5794   if (shCount != 0)
5795     {
5796       /* rotate right accumulator */
5797       AccRol (8 - shCount);
5798       /* and kill the higher order bits */
5799       emit2 ("and a,!immedbyte", SRMask[shCount]);
5800     }
5801 }
5802
5803 /*-----------------------------------------------------------------*/
5804 /* shiftR1Left2Result - shift right one byte from left to result   */
5805 /*-----------------------------------------------------------------*/
5806 static void
5807 shiftR1Left2Result (operand * left, int offl,
5808                     operand * result, int offr,
5809                     int shCount, int sign)
5810 {
5811   _moveA (aopGet (AOP (left), offl, FALSE));
5812   if (sign)
5813     {
5814       while (shCount--)
5815         {
5816           emit2 ("%s a", sign ? "sra" : "srl");
5817         }
5818     }
5819   else
5820     {
5821       AccRsh (shCount);
5822     }
5823   aopPut (AOP (result), "a", offr);
5824 }
5825
5826 /*-----------------------------------------------------------------*/
5827 /* genrshTwo - right shift two bytes by known amount != 0          */
5828 /*-----------------------------------------------------------------*/
5829 static void
5830 genrshTwo (operand * result, operand * left,
5831            int shCount, int sign)
5832 {
5833   /* if shCount >= 8 */
5834   if (shCount >= 8)
5835     {
5836       shCount -= 8;
5837       if (shCount)
5838         {
5839           shiftR1Left2Result (left, MSB16, result, LSB,
5840                               shCount, sign);
5841         }
5842       else
5843         {
5844           movLeft2Result (left, MSB16, result, LSB, sign);
5845         }
5846       if (sign)
5847         {
5848           /* Sign extend the result */
5849           _moveA(aopGet (AOP (result), 0, FALSE));
5850           emit2 ("rlc a");
5851           emit2 ("sbc a,a");
5852
5853           aopPut (AOP (result), ACC_NAME, MSB16);
5854         }
5855       else
5856         {
5857           aopPut (AOP (result), "!zero", 1);
5858         }
5859     }
5860   /*  1 <= shCount <= 7 */
5861   else
5862     {
5863       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5864     }
5865 }
5866
5867 /*-----------------------------------------------------------------*/
5868 /* genRightShiftLiteral - left shifting by known count              */
5869 /*-----------------------------------------------------------------*/
5870 static void
5871 genRightShiftLiteral (operand * left,
5872                       operand * right,
5873                       operand * result,
5874                       iCode * ic,
5875                       int sign)
5876 {
5877   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5878   int size;
5879
5880   freeAsmop (right, NULL, ic);
5881
5882   aopOp (left, ic, FALSE, FALSE);
5883   aopOp (result, ic, FALSE, FALSE);
5884
5885   size = getSize (operandType (result));
5886
5887   /* I suppose that the left size >= result size */
5888   if (shCount == 0)
5889     {
5890       wassert (0);
5891     }
5892
5893   else if (shCount >= (size * 8)) {
5894     const char *s;
5895     if (!SPEC_USIGN(getSpec(operandType(left)))) {
5896       _moveA(aopGet (AOP (left), 0, FALSE));
5897       emit2 ("rlc a");
5898       emit2 ("sbc a,a");
5899       s=ACC_NAME;
5900     } else {
5901       s="!zero";
5902     }
5903     while (size--)
5904       aopPut (AOP (result), s, size);
5905   }
5906   else
5907     {
5908       switch (size)
5909         {
5910         case 1:
5911           genrshOne (result, left, shCount, sign);
5912           break;
5913         case 2:
5914           genrshTwo (result, left, shCount, sign);
5915           break;
5916         case 4:
5917           wassertl (0, "Asked to shift right a long which should be a function call");
5918           break;
5919         default:
5920           wassertl (0, "Entered default case in right shift delegate");
5921         }
5922     }
5923   freeAsmop (left, NULL, ic);
5924   freeAsmop (result, NULL, ic);
5925 }
5926
5927 /*-----------------------------------------------------------------*/
5928 /* genRightShift - generate code for right shifting                */
5929 /*-----------------------------------------------------------------*/
5930 static void
5931 genRightShift (iCode * ic)
5932 {
5933   operand *right, *left, *result;
5934   sym_link *retype;
5935   int size, offset, first = 1;
5936   const char *l;
5937   bool is_signed;
5938
5939   symbol *tlbl, *tlbl1;
5940
5941   /* if signed then we do it the hard way preserve the
5942      sign bit moving it inwards */
5943   retype = getSpec (operandType (IC_RESULT (ic)));
5944
5945   is_signed = !SPEC_USIGN (retype);
5946
5947   /* signed & unsigned types are treated the same : i.e. the
5948      signed is NOT propagated inwards : quoting from the
5949      ANSI - standard : "for E1 >> E2, is equivalent to division
5950      by 2**E2 if unsigned or if it has a non-negative value,
5951      otherwise the result is implementation defined ", MY definition
5952      is that the sign does not get propagated */
5953
5954   right = IC_RIGHT (ic);
5955   left = IC_LEFT (ic);
5956   result = IC_RESULT (ic);
5957
5958   aopOp (right, ic, FALSE, FALSE);
5959
5960   /* if the shift count is known then do it
5961      as efficiently as possible */
5962   if (AOP_TYPE (right) == AOP_LIT)
5963     {
5964       genRightShiftLiteral (left, right, result, ic, is_signed);
5965       return;
5966     }
5967
5968   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5969   emit2 ("inc a");
5970   freeAsmop (right, NULL, ic);
5971
5972   aopOp (left, ic, FALSE, FALSE);
5973   aopOp (result, ic, FALSE, FALSE);
5974
5975   /* now move the left to the result if they are not the
5976      same */
5977   if (!sameRegs (AOP (left), AOP (result)))
5978     {
5979
5980       size = AOP_SIZE (result);
5981       offset = 0;
5982       while (size--)
5983         {
5984           l = aopGet (AOP (left), offset, FALSE);
5985           aopPut (AOP (result), l, offset);
5986           offset++;
5987         }
5988     }
5989
5990   tlbl = newiTempLabel (NULL);
5991   tlbl1 = newiTempLabel (NULL);
5992   size = AOP_SIZE (result);
5993   offset = size - 1;
5994
5995   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5996   emitLabel (tlbl->key + 100);
5997   while (size--)
5998     {
5999       l = aopGet (AOP (result), offset--, FALSE);
6000       if (first)
6001         {
6002           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6003           first = 0;
6004         }
6005       else
6006         {
6007           emit2 ("rr %s", l);
6008         }
6009     }
6010   emitLabel (tlbl1->key + 100);
6011   emit2 ("dec a");
6012   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6013
6014   freeAsmop (left, NULL, ic);
6015   freeAsmop (result, NULL, ic);
6016 }
6017
6018 /*-----------------------------------------------------------------*/
6019 /* genGenPointerGet -  get value from generic pointer space        */
6020 /*-----------------------------------------------------------------*/
6021 static void
6022 genGenPointerGet (operand * left,
6023                   operand * result, iCode * ic)
6024 {
6025   int size, offset;
6026   sym_link *retype = getSpec (operandType (result));
6027   int pair = PAIR_HL;
6028
6029   if (IS_GB)
6030     pair = PAIR_DE;
6031
6032   aopOp (left, ic, FALSE, FALSE);
6033   aopOp (result, ic, FALSE, FALSE);
6034
6035   size = AOP_SIZE (result);
6036
6037   if (isPair (AOP (left)) && size == 1)
6038     {
6039       /* Just do it */
6040       if (isPtrPair (AOP (left)))
6041         {
6042           tsprintf (buffer, sizeof(buffer), 
6043                     "!*pair", getPairName (AOP (left)));
6044           aopPut (AOP (result), buffer, 0);
6045         }
6046       else
6047         {
6048           emit2 ("ld a,!*pair", getPairName (AOP (left)));
6049           aopPut (AOP (result), "a", 0);
6050         }
6051       freeAsmop (left, NULL, ic);
6052       goto release;
6053     }
6054
6055   if (getPairId (AOP (left)) == PAIR_IY)
6056     {
6057       /* Just do it */
6058       offset = 0;
6059       while (size--) 
6060         {
6061           char at[20];
6062           tsprintf (at, sizeof(at), "!*iyx", offset);
6063           aopPut (AOP (result), at, offset);
6064           offset++;
6065         }
6066  
6067       freeAsmop (left, NULL, ic);
6068       goto release;
6069     }
6070
6071   /* For now we always load into IY */
6072   /* if this is remateriazable */
6073   fetchPair (pair, AOP (left));
6074
6075   /* if bit then unpack */
6076   if (IS_BITVAR (retype))
6077     {
6078       wassert (0);
6079     }
6080   else if (getPairId (AOP (result)) == PAIR_HL)
6081     {
6082       wassertl (size == 2, "HL must be of size 2");
6083       emit2 ("ld a,!*hl");
6084       emit2 ("inc hl");
6085       emit2 ("ld h,!*hl");
6086       emit2 ("ld l,a");
6087       spillPair (PAIR_HL);
6088     }
6089   else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6090     {
6091       size = AOP_SIZE (result);
6092       offset = 0;
6093
6094       while (size--)
6095         {
6096           /* PENDING: make this better */
6097           if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6098             {
6099               aopPut (AOP (result), "!*hl", offset++);
6100             }
6101           else
6102             {
6103               emit2 ("ld a,!*pair", _pairs[pair].name);
6104               aopPut (AOP (result), "a", offset++);
6105             }
6106           if (size)
6107             {
6108               emit2 ("inc %s", _pairs[pair].name);
6109               _G.pairs[pair].offset++;
6110             }
6111         }
6112       /* Fixup HL back down */
6113       for (size = AOP_SIZE (result)-1; size; size--)
6114         {
6115           emit2 ("dec %s", _pairs[pair].name);
6116         }
6117     }
6118   else
6119     {
6120       size = AOP_SIZE (result);
6121       offset = 0;
6122
6123       while (size--)
6124         {
6125           /* PENDING: make this better */
6126           if (!IS_GB && 
6127               (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6128             {
6129               aopPut (AOP (result), "!*hl", offset++);
6130             }
6131           else
6132             {
6133               emit2 ("ld a,!*pair", _pairs[pair].name);
6134               aopPut (AOP (result), "a", offset++);
6135             }
6136           if (size)
6137             {
6138               emit2 ("inc %s", _pairs[pair].name);
6139               _G.pairs[pair].offset++;
6140             }
6141         }
6142     }
6143
6144   freeAsmop (left, NULL, ic);
6145
6146 release:
6147   freeAsmop (result, NULL, ic);
6148 }
6149
6150 /*-----------------------------------------------------------------*/
6151 /* genPointerGet - generate code for pointer get                   */
6152 /*-----------------------------------------------------------------*/
6153 static void
6154 genPointerGet (iCode * ic)
6155 {
6156   operand *left, *result;
6157   sym_link *type, *etype;
6158
6159   left = IC_LEFT (ic);
6160   result = IC_RESULT (ic);
6161
6162   /* depending on the type of pointer we need to
6163      move it to the correct pointer register */
6164   type = operandType (left);
6165   etype = getSpec (type);
6166
6167   genGenPointerGet (left, result, ic);
6168 }
6169
6170 bool
6171 isRegOrLit (asmop * aop)
6172 {
6173   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6174     return TRUE;
6175   return FALSE;
6176 }
6177
6178 /*-----------------------------------------------------------------*/
6179 /* genGenPointerSet - stores the value into a pointer location        */
6180 /*-----------------------------------------------------------------*/
6181 static void
6182 genGenPointerSet (operand * right,
6183                   operand * result, iCode * ic)
6184 {
6185   int size, offset;
6186   sym_link *retype = getSpec (operandType (right));
6187   PAIR_ID pairId = PAIR_HL;
6188   
6189   aopOp (result, ic, FALSE, FALSE);
6190   aopOp (right, ic, FALSE, FALSE);
6191
6192   if (IS_GB)
6193     pairId = PAIR_DE;
6194
6195   size = AOP_SIZE (right);
6196
6197   /* Handle the exceptions first */
6198   if (isPair (AOP (result)) && size == 1)
6199     {
6200       /* Just do it */
6201       const char *l = aopGet (AOP (right), 0, FALSE);
6202       const char *pair = getPairName (AOP (result));
6203       if (canAssignToPtr (l) && isPtr (pair))
6204         {
6205           emit2 ("ld !*pair,%s", pair, l);
6206         }
6207       else
6208         {
6209           _moveA (l);
6210           emit2 ("ld !*pair,a", pair);
6211         }
6212       goto release;
6213     }
6214   
6215   if ( getPairId( AOP (result)) == PAIR_IY)
6216     {
6217       /* Just do it */
6218       const char *l = aopGet (AOP (right), 0, FALSE);
6219
6220       offset = 0;
6221       while (size--) 
6222         {
6223           if (canAssignToPtr (l))
6224             {
6225               emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6226             }
6227           else
6228             {
6229               _moveA (aopGet (AOP (right), offset, FALSE));
6230               emit2 ("ld !*iyx,a", offset);
6231             }
6232           offset++;
6233         }
6234       goto release;
6235     }
6236   else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result))
6237     {
6238       offset = 0;
6239
6240       while (size--)
6241         {
6242           const char *l = aopGet (AOP (right), offset, FALSE);
6243           if (isRegOrLit (AOP (right)) && !IS_GB)
6244             {
6245               emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6246             }
6247           else
6248             {
6249               _moveA (l);
6250               emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6251             }
6252           if (size)
6253             {
6254               emit2 ("inc %s", _pairs[PAIR_HL].name);
6255               _G.pairs[PAIR_HL].offset++;
6256             }
6257           offset++;
6258         }
6259
6260       /* Fixup HL back down */
6261       for (size = AOP_SIZE (right)-1; size; size--)
6262         {
6263           emit2 ("dec %s", _pairs[PAIR_HL].name);
6264         }
6265       goto release;
6266     }
6267
6268   /* if the operand is already in dptr
6269      then we do nothing else we move the value to dptr */
6270   if (AOP_TYPE (result) != AOP_STR)
6271     {
6272       fetchPair (pairId, AOP (result));
6273     }
6274   /* so hl know contains the address */
6275   freeAsmop (result, NULL, ic);
6276
6277   /* if bit then unpack */
6278   if (IS_BITVAR (retype))
6279     {
6280       wassert (0);
6281     }
6282   else
6283     {
6284       offset = 0;
6285
6286       while (size--)
6287         {
6288           const char *l = aopGet (AOP (right), offset, FALSE);
6289           if (isRegOrLit (AOP (right)) && !IS_GB)
6290             {
6291               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6292             }
6293           else
6294             {
6295               _moveA (l);
6296               emit2 ("ld !*pair,a", _pairs[pairId].name);
6297             }
6298           if (size)
6299             {
6300               emit2 ("inc %s", _pairs[pairId].name);
6301               _G.pairs[pairId].offset++;
6302             }
6303           offset++;
6304         }
6305     }
6306 release:
6307   freeAsmop (right, NULL, ic);
6308 }
6309
6310 /*-----------------------------------------------------------------*/
6311 /* genPointerSet - stores the value into a pointer location        */
6312 /*-----------------------------------------------------------------*/
6313 static void
6314 genPointerSet (iCode * ic)
6315 {
6316   operand *right, *result;
6317   sym_link *type, *etype;
6318
6319   right = IC_RIGHT (ic);
6320   result = IC_RESULT (ic);
6321
6322   /* depending on the type of pointer we need to
6323      move it to the correct pointer register */
6324   type = operandType (result);
6325   etype = getSpec (type);
6326
6327   genGenPointerSet (right, result, ic);
6328 }
6329
6330 /*-----------------------------------------------------------------*/
6331 /* genIfx - generate code for Ifx statement                        */
6332 /*-----------------------------------------------------------------*/
6333 static void
6334 genIfx (iCode * ic, iCode * popIc)
6335 {
6336   operand *cond = IC_COND (ic);
6337   int isbit = 0;
6338
6339   aopOp (cond, ic, FALSE, TRUE);
6340
6341   /* get the value into acc */
6342   if (AOP_TYPE (cond) != AOP_CRY)
6343     _toBoolean (cond);
6344   else
6345     isbit = 1;
6346   /* the result is now in the accumulator */
6347   freeAsmop (cond, NULL, ic);
6348
6349   /* if there was something to be popped then do it */
6350   if (popIc)
6351     genIpop (popIc);
6352
6353   /* if the condition is  a bit variable */
6354   if (isbit && IS_ITEMP (cond) &&
6355       SPIL_LOC (cond))
6356     genIfxJump (ic, SPIL_LOC (cond)->rname);
6357   else if (isbit && !IS_ITEMP (cond))
6358     genIfxJump (ic, OP_SYMBOL (cond)->rname);
6359   else
6360     genIfxJump (ic, "a");
6361
6362   ic->generated = 1;
6363 }
6364
6365 /*-----------------------------------------------------------------*/
6366 /* genAddrOf - generates code for address of                       */
6367 /*-----------------------------------------------------------------*/
6368 static void
6369 genAddrOf (iCode * ic)
6370 {
6371   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6372
6373   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6374
6375   /* if the operand is on the stack then we
6376      need to get the stack offset of this
6377      variable */
6378   if (IS_GB)
6379     {
6380       if (sym->onStack)
6381         {
6382           spillCached ();
6383           if (sym->stack <= 0)
6384             {
6385               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6386             }
6387           else
6388             {
6389               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6390             }
6391           commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6392         }
6393       else
6394         {
6395           emit2 ("ld de,!hashedstr", sym->rname);
6396           commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6397         }
6398     }
6399   else
6400     {
6401       spillCached ();
6402       if (sym->onStack)
6403         {
6404           /* if it has an offset  then we need to compute it */
6405           if (sym->stack > 0)
6406             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6407           else
6408             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6409           emit2 ("add hl,sp");
6410         }
6411       else
6412         {
6413           emit2 ("ld hl,!hashedstr", sym->rname);
6414         }
6415       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6416     }
6417   freeAsmop (IC_RESULT (ic), NULL, ic);
6418 }
6419
6420 /*-----------------------------------------------------------------*/
6421 /* genAssign - generate code for assignment                        */
6422 /*-----------------------------------------------------------------*/
6423 static void
6424 genAssign (iCode * ic)
6425 {
6426   operand *result, *right;
6427   int size, offset;
6428   unsigned long lit = 0L;
6429
6430   result = IC_RESULT (ic);
6431   right = IC_RIGHT (ic);
6432
6433   /* Dont bother assigning if they are the same */
6434   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6435     {
6436       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6437       return;
6438     }
6439
6440   aopOp (right, ic, FALSE, FALSE);
6441   aopOp (result, ic, TRUE, FALSE);
6442
6443   /* if they are the same registers */
6444   if (sameRegs (AOP (right), AOP (result)))
6445     {
6446       emitDebug ("; (registers are the same)");
6447       goto release;
6448     }
6449
6450   /* if the result is a bit */
6451   if (AOP_TYPE (result) == AOP_CRY)
6452     {
6453       wassertl (0, "Tried to assign to a bit");
6454     }
6455
6456   /* general case */
6457   size = AOP_SIZE (result);
6458   offset = 0;
6459
6460   if (AOP_TYPE (right) == AOP_LIT)
6461     {
6462       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6463     }
6464
6465   if (isPair (AOP (result)))
6466     {
6467       fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6468     }
6469   else if ((size > 1) &&
6470            (AOP_TYPE (result) != AOP_REG) &&
6471            (AOP_TYPE (right) == AOP_LIT) &&
6472            !IS_FLOAT (operandType (right)) &&
6473            (lit < 256L))
6474     {
6475       bool fXored = FALSE;
6476       offset = 0;
6477       /* Work from the top down.
6478          Done this way so that we can use the cached copy of 0
6479          in A for a fast clear */
6480       while (size--)
6481         {
6482           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6483             {
6484               if (!fXored && size > 1)
6485                 {
6486                   emit2 ("xor a,a");
6487                   fXored = TRUE;
6488                 }
6489               if (fXored)
6490                 {
6491                   aopPut (AOP (result), "a", offset);
6492                 }
6493               else
6494                 {
6495                   aopPut (AOP (result), "!zero", offset);
6496                 }
6497             }
6498           else
6499             aopPut (AOP (result),
6500                     aopGet (AOP (right), offset, FALSE),
6501                     offset);
6502           offset++;
6503         }
6504     }
6505   else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6506     {
6507       emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6508       aopPut (AOP (result), "l", LSB);
6509       aopPut (AOP (result), "h", MSB16);
6510     }
6511   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6512     {
6513       /* Special case.  Load into a and d, then load out. */
6514       _moveA (aopGet (AOP (right), 0, FALSE));
6515       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6516       aopPut (AOP (result), "a", 0);
6517       aopPut (AOP (result), "e", 1);
6518     }
6519   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6520     {
6521       /* Special case - simple memcpy */
6522       aopGet (AOP (right), LSB, FALSE);
6523       emit2 ("ld d,h");
6524       emit2 ("ld e,l");
6525       aopGet (AOP (result), LSB, FALSE);
6526
6527       while (size--)
6528         {
6529           emit2 ("ld a,(de)");
6530           /* Peephole will optimise this. */
6531           emit2 ("ld (hl),a");
6532
6533           if (size != 0)
6534             {
6535               emit2 ("inc hl");
6536               emit2 ("inc de");
6537             }
6538         }
6539       spillPair (PAIR_HL);
6540     }
6541   else
6542     {
6543       while (size--)
6544         {
6545           /* PENDING: do this check better */
6546           if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6547             {
6548               _moveA (aopGet (AOP (right), offset, FALSE));
6549               aopPut (AOP (result), "a", offset);
6550             }
6551           else
6552             aopPut (AOP (result),
6553                     aopGet (AOP (right), offset, FALSE),
6554                     offset);
6555           offset++;
6556         }
6557     }
6558
6559 release:
6560   freeAsmop (right, NULL, ic);
6561   freeAsmop (result, NULL, ic);
6562 }
6563
6564 /*-----------------------------------------------------------------*/
6565 /* genJumpTab - genrates code for jump table                       */
6566 /*-----------------------------------------------------------------*/
6567 static void
6568 genJumpTab (iCode * ic)
6569 {
6570   symbol *jtab;
6571   const char *l;
6572
6573   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6574   /* get the condition into accumulator */
6575   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6576   if (!IS_GB)
6577     emit2 ("push de");
6578   emit2 ("ld e,%s", l);
6579   emit2 ("ld d,!zero");
6580   jtab = newiTempLabel (NULL);
6581   spillCached ();
6582   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6583   emit2 ("add hl,de");
6584   emit2 ("add hl,de");
6585   emit2 ("add hl,de");
6586   freeAsmop (IC_JTCOND (ic), NULL, ic);
6587   if (!IS_GB)
6588     emit2 ("pop de");
6589   emit2 ("jp !*hl");
6590   emitLabel (jtab->key + 100);
6591   /* now generate the jump labels */
6592   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6593        jtab = setNextItem (IC_JTLABELS (ic)))
6594     emit2 ("jp !tlabel", jtab->key + 100);
6595 }
6596
6597 /*-----------------------------------------------------------------*/
6598 /* genCast - gen code for casting                                  */
6599 /*-----------------------------------------------------------------*/
6600 static void
6601 genCast (iCode * ic)
6602 {
6603   operand *result = IC_RESULT (ic);
6604   sym_link *rtype = operandType (IC_RIGHT (ic));
6605   operand *right = IC_RIGHT (ic);
6606   int size, offset;
6607
6608   /* if they are equivalent then do nothing */
6609   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6610     return;
6611
6612   aopOp (right, ic, FALSE, FALSE);
6613   aopOp (result, ic, FALSE, FALSE);
6614
6615   /* if the result is a bit */
6616   if (AOP_TYPE (result) == AOP_CRY)
6617     {
6618       wassertl (0, "Tried to cast to a bit");
6619     }
6620
6621   /* if they are the same size : or less */
6622   if (AOP_SIZE (result) <= AOP_SIZE (right))
6623     {
6624
6625       /* if they are in the same place */
6626       if (sameRegs (AOP (right), AOP (result)))
6627         goto release;
6628
6629       /* if they in different places then copy */
6630       size = AOP_SIZE (result);
6631       offset = 0;
6632       while (size--)
6633         {
6634           aopPut (AOP (result),
6635                   aopGet (AOP (right), offset, FALSE),
6636                   offset);
6637           offset++;
6638         }
6639       goto release;
6640     }
6641
6642   /* So we now know that the size of destination is greater
6643      than the size of the source */
6644   /* we move to result for the size of source */
6645   size = AOP_SIZE (right);
6646   offset = 0;
6647   while (size--)
6648     {
6649       aopPut (AOP (result),
6650               aopGet (AOP (right), offset, FALSE),
6651               offset);
6652       offset++;
6653     }
6654
6655   /* now depending on the sign of the destination */
6656   size = AOP_SIZE (result) - AOP_SIZE (right);
6657   /* Unsigned or not an integral type - right fill with zeros */
6658   if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6659     {
6660       while (size--)
6661         aopPut (AOP (result), "!zero", offset++);
6662     }
6663   else
6664     {
6665       /* we need to extend the sign :{ */
6666         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6667                         FALSE);
6668       _moveA (l);
6669       emit2 ("rla ");
6670       emit2 ("sbc a,a");
6671       while (size--)
6672         aopPut (AOP (result), "a", offset++);
6673     }
6674
6675 release:
6676   freeAsmop (right, NULL, ic);
6677   freeAsmop (result, NULL, ic);
6678 }
6679
6680 /*-----------------------------------------------------------------*/
6681 /* genReceive - generate code for a receive iCode                  */
6682 /*-----------------------------------------------------------------*/
6683 static void
6684 genReceive (iCode * ic)
6685 {
6686   if (isOperandInFarSpace (IC_RESULT (ic)) &&
6687       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6688        IS_TRUE_SYMOP (IC_RESULT (ic))))
6689     {
6690       wassert (0);
6691     }
6692   else
6693     {
6694         // PENDING: HACK
6695         int size;
6696         int i;
6697
6698         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6699         size = AOP_SIZE(IC_RESULT(ic));
6700
6701         for (i = 0; i < size; i++) {
6702             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6703         }
6704     }
6705
6706   freeAsmop (IC_RESULT (ic), NULL, ic);
6707 }
6708
6709 enum
6710   {
6711     /** Maximum number of bytes to emit per line. */
6712     DBEMIT_MAX_RUN = 8
6713   };
6714
6715 /** Context for the byte output chunker. */
6716 typedef struct
6717 {
6718   unsigned char buffer[DBEMIT_MAX_RUN];
6719   int pos;
6720 } DBEMITCTX;
6721
6722
6723 /** Flushes a byte chunker by writing out all in the buffer and
6724     reseting. 
6725 */
6726 static void
6727 _dbFlush(DBEMITCTX *self)
6728 {
6729   char line[256];
6730
6731   if (self->pos > 0)
6732     {
6733       int i;
6734       sprintf(line, ".db 0x%02X", self->buffer[0]);
6735
6736       for (i = 1; i < self->pos; i++)
6737         {
6738           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6739         }
6740       emit2(line);
6741     }
6742   self->pos = 0;
6743 }
6744
6745 /** Write out another byte, buffering until a decent line is
6746     generated.
6747 */
6748 static void
6749 _dbEmit(DBEMITCTX *self, int c)
6750 {
6751   if (self->pos == DBEMIT_MAX_RUN)
6752     {
6753       _dbFlush(self);
6754     }
6755   self->buffer[self->pos++] = c;
6756 }
6757
6758 /** Context for a simple run length encoder. */
6759 typedef struct
6760 {
6761   unsigned last;
6762   unsigned char buffer[128];
6763   int pos;
6764   /** runLen may be equivalent to pos. */
6765   int runLen;
6766 } RLECTX;
6767
6768 enum
6769   {
6770     RLE_CHANGE_COST = 4,
6771     RLE_MAX_BLOCK = 127
6772   };
6773
6774 /** Flush the buffer of a run length encoder by writing out the run or
6775     data that it currently contains.
6776 */
6777 static void
6778 _rleCommit(RLECTX *self)
6779 {
6780   int i;
6781   if (self->pos != 0)
6782     {
6783       DBEMITCTX db;
6784       memset(&db, 0, sizeof(db));
6785           
6786       emit2(".db %u", self->pos);
6787       
6788       for (i = 0; i < self->pos; i++)
6789         {
6790           _dbEmit(&db, self->buffer[i]);
6791         }
6792       _dbFlush(&db);
6793     }
6794   /* Reset */
6795   self->pos = 0;
6796 }
6797
6798 /* Encoder design:
6799    Can get either a run or a block of random stuff.
6800    Only want to change state if a good run comes in or a run ends.
6801    Detecting run end is easy.
6802    Initial state?
6803
6804    Say initial state is in run, len zero, last zero.  Then if you get a
6805    few zeros then something else then a short run will be output.
6806    Seems OK.  While in run mode, keep counting.  While in random mode,
6807    keep a count of the run.  If run hits margin, output all up to run,
6808    restart, enter run mode.
6809 */
6810
6811 /** Add another byte into the run length encoder, flushing as
6812     required.  The run length encoder uses the Amiga IFF style, where
6813     a block is prefixed by its run length.  A positive length means
6814     the next n bytes pass straight through.  A negative length means
6815     that the next byte is repeated -n times.  A zero terminates the
6816     chunks.
6817 */
6818 static void
6819 _rleAppend(RLECTX *self, int c)
6820 {
6821   int i;
6822
6823   if (c != self->last)
6824     {
6825       /* The run has stopped.  See if it is worthwhile writing it out
6826          as a run.  Note that the random data comes in as runs of
6827          length one.
6828       */
6829       if (self->runLen > RLE_CHANGE_COST)
6830         {
6831           /* Yes, worthwhile. */
6832           /* Commit whatever was in the buffer. */
6833           _rleCommit(self);
6834           emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
6835         }
6836       else
6837         {
6838           /* Not worthwhile.  Append to the end of the random list. */
6839           for (i = 0; i < self->runLen; i++)
6840             {
6841               if (self->pos >= RLE_MAX_BLOCK)
6842                 {
6843                   /* Commit. */
6844                   _rleCommit(self);
6845                 }
6846               self->buffer[self->pos++] = self->last;
6847             }
6848         }
6849       self->runLen = 1;
6850       self->last = c;
6851     }
6852   else
6853     {
6854       if (self->runLen >= RLE_MAX_BLOCK)
6855         {
6856           /* Commit whatever was in the buffer. */
6857           _rleCommit(self);
6858
6859           emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
6860           self->runLen = 0;
6861         }
6862       self->runLen++;
6863     }
6864 }
6865
6866 static void
6867 _rleFlush(RLECTX *self)
6868 {
6869   _rleAppend(self, -1);
6870   _rleCommit(self);
6871   self->pos = 0;
6872   self->last = 0;
6873   self->runLen = 0;
6874 }
6875
6876 /** genArrayInit - Special code for initialising an array with constant
6877    data.
6878 */
6879 static void
6880 genArrayInit (iCode * ic)
6881 {
6882   literalList *iLoop;
6883   int         ix;
6884   int         elementSize = 0, eIndex, i;
6885   unsigned    val, lastVal;
6886   sym_link    *type;
6887   RLECTX      rle;
6888
6889   memset(&rle, 0, sizeof(rle));
6890
6891   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6892
6893   _saveRegsForCall(ic, 0);
6894
6895   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6896   emit2 ("call __initrleblock");
6897     
6898   type = operandType(IC_LEFT(ic));
6899     
6900   if (type && type->next)
6901     {
6902       elementSize = getSize(type->next);
6903     }
6904   else
6905     {
6906       wassertl (0, "Can't determine element size in genArrayInit.");
6907     }
6908
6909   iLoop = IC_ARRAYILIST(ic);
6910   lastVal = (unsigned)-1;
6911
6912   /* Feed all the bytes into the run length encoder which will handle
6913      the actual output.
6914      This works well for mixed char data, and for random int and long
6915      data.
6916   */
6917   while (iLoop)
6918     {
6919       ix = iLoop->count;
6920
6921       if (ix != 0)
6922         {
6923           for (i = 0; i < ix; i++)
6924             {
6925               for (eIndex = 0; eIndex < elementSize; eIndex++)
6926                 {
6927                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6928                   _rleAppend(&rle, val);
6929                 }
6930             }
6931         }
6932         
6933       iLoop = iLoop->next;
6934     }
6935
6936   _rleFlush(&rle);
6937   /* Mark the end of the run. */
6938   emit2(".db 0");
6939
6940   _restoreRegsAfterCall();
6941
6942   spillCached ();
6943
6944   freeAsmop (IC_LEFT(ic), NULL, ic);
6945 }
6946
6947 static void
6948 _swap (PAIR_ID one, PAIR_ID two)
6949 {
6950   if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6951     {
6952       emit2 ("ex de,hl");
6953     }
6954   else
6955     {
6956       emit2 ("ld a,%s", _pairs[one].l);
6957       emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6958       emit2 ("ld %s,a", _pairs[two].l);
6959       emit2 ("ld a,%s", _pairs[one].h);
6960       emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6961       emit2 ("ld %s,a", _pairs[two].h);
6962     }
6963 }
6964
6965 /* The problem is that we may have all three pairs used and they may
6966    be needed in a different order.
6967
6968    Note: Have ex de,hl
6969
6970    Combinations:
6971      hl = hl            => unity, fine
6972      bc = bc
6973      de = de
6974
6975      hl = hl            hl = hl, swap de <=> bc
6976      bc = de
6977      de = bc
6978
6979      hl = bc            Worst case
6980      bc = de
6981      de = hl
6982      
6983      hl = bc            de = de, swap bc <=> hl
6984      bc = hl
6985      de = de
6986
6987      hl = de            Worst case
6988      bc = hl
6989      de = bc
6990
6991      hl = de            bc = bc, swap hl <=> de
6992      bc = bc
6993      de = hl
6994
6995    Break it down into:
6996     * Any pair = pair are done last
6997     * Any pair = iTemp are done last
6998     * Any swaps can be done any time
6999
7000    A worst case:
7001     push p1
7002     p1 = p2
7003     p2 = p3
7004     pop  p3
7005
7006    So how do we detect the cases?
7007    How about a 3x3 matrix?
7008         source
7009    dest x x x x
7010         x x x x
7011         x x x x (Fourth for iTemp/other)
7012
7013    First determin which mode to use by counting the number of unity and
7014    iTemp assigns.
7015      Three - any order
7016      Two - Assign the pair first, then the rest
7017      One - Swap the two, then the rest
7018      Zero - Worst case.
7019 */
7020 static void
7021 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7022 {
7023   PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7024   PAIR_ID dest[3] = {
7025     PAIR_BC, PAIR_HL, PAIR_DE
7026   };
7027   int i, j, nunity = 0;
7028   memset (ids, PAIR_INVALID, sizeof (ids));
7029
7030   /* Sanity checks */
7031   wassert (nparams == 3);
7032
7033   /* First save everything that needs to be saved. */
7034   _saveRegsForCall (ic, 0);
7035
7036   /* Loading HL first means that DE is always fine. */
7037   for (i = 0; i < nparams; i++)
7038     {
7039       aopOp (pparams[i], ic, FALSE, FALSE);
7040       ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7041     }
7042
7043   /* Count the number of unity or iTemp assigns. */
7044   for (i = 0; i < 3; i++) 
7045     {
7046       if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7047         {
7048           nunity++;
7049         }
7050     }
7051
7052   if (nunity == 3)
7053     {
7054       /* Any order, fall through. */
7055     }
7056   else if (nunity == 2)
7057     {
7058       /* One is assigned.  Pull it out and assign. */
7059       for (i = 0; i < 3; i++)
7060         {
7061           for (j = 0; j < NUM_PAIRS; j++)
7062             {
7063               if (ids[dest[i]][j] == TRUE)
7064                 {
7065                   /* Found it.  See if it's the right one. */
7066                   if (j == PAIR_INVALID || j == dest[i])
7067                     {
7068                       /* Keep looking. */
7069                     }
7070                   else
7071                     {
7072                       fetchPair(dest[i], AOP (pparams[i]));
7073                       goto done;
7074                     }
7075                 }
7076             }
7077         }
7078     }
7079   else if (nunity == 1)
7080     {
7081       /* Find the pairs to swap. */
7082       for (i = 0; i < 3; i++)
7083         {
7084           for (j = 0; j < NUM_PAIRS; j++)
7085             {
7086               if (ids[dest[i]][j] == TRUE)
7087                 {
7088                   if (j == PAIR_INVALID || j == dest[i])
7089                     {
7090                       /* Keep looking. */
7091                     }
7092                   else
7093                     {
7094                       _swap (j, dest[i]);
7095                       goto done;
7096                     }
7097                 }
7098             }
7099         }
7100     }
7101   else
7102     {
7103       int next = getPairId (AOP (pparams[0]));
7104       emit2 ("push %s", _pairs[next].name);
7105
7106       if (next == dest[1])
7107         {
7108           fetchPair (dest[1], AOP (pparams[1]));
7109           fetchPair (dest[2], AOP (pparams[2]));
7110         }
7111       else
7112         {
7113           fetchPair (dest[2], AOP (pparams[2]));
7114           fetchPair (dest[1], AOP (pparams[1]));
7115         }
7116       emit2 ("pop %s", _pairs[dest[0]].name);
7117     }
7118  done:
7119   /* Finally pull out all of the iTemps */
7120   for (i = 0; i < 3; i++)
7121     {
7122       if (ids[dest[i]][PAIR_INVALID] == 1)
7123         {
7124           fetchPair (dest[i], AOP (pparams[i]));
7125         }
7126     }
7127 }
7128
7129 static void
7130 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7131 {
7132   operand *from, *to;
7133   symbol *label;
7134   bool deInUse;
7135
7136   wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7137   to = pparams[0];
7138   from = pparams[1];
7139
7140   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7141
7142   setupForBuiltin3 (ic, nParams, pparams);
7143
7144   label = newiTempLabel(NULL);
7145
7146   emitLabel (label->key);
7147   emit2 ("ld a,(hl)");
7148   emit2 ("ldi");
7149   emit2 ("or a");
7150   emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7151
7152   freeAsmop (from, NULL, ic->next);
7153   freeAsmop (to, NULL, ic);
7154 }
7155
7156 static void
7157 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7158 {
7159   operand *from, *to, *count;
7160   bool deInUse;
7161
7162   wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7163   to = pparams[2];
7164   from = pparams[1];
7165   count = pparams[0];
7166
7167   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7168
7169   setupForBuiltin3 (ic, nParams, pparams);
7170
7171   emit2 ("ldir");
7172
7173   freeAsmop (count, NULL, ic->next->next);
7174   freeAsmop (from, NULL, ic);
7175
7176   _restoreRegsAfterCall();
7177
7178   /* if we need assign a result value */
7179   if ((IS_ITEMP (IC_RESULT (ic)) &&
7180        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7181         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7182       IS_TRUE_SYMOP (IC_RESULT (ic)))
7183     {
7184       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7185       movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7186       freeAsmop (IC_RESULT (ic), NULL, ic);
7187     }
7188
7189   freeAsmop (to, NULL, ic->next);
7190 }
7191
7192 /*-----------------------------------------------------------------*/
7193 /* genBuiltIn - calls the appropriate function to  generating code */
7194 /* for a built in function                                         */
7195 /*-----------------------------------------------------------------*/
7196 static void genBuiltIn (iCode *ic)
7197 {
7198     operand *bi_parms[MAX_BUILTIN_ARGS];
7199     int nbi_parms;
7200     iCode *bi_iCode;
7201     symbol *bif;
7202
7203     /* get all the arguments for a built in function */
7204     bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7205
7206     /* which function is it */
7207     bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7208
7209     if (strcmp(bif->name,"__builtin_strcpy")==0) 
7210       {
7211         genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7212       } 
7213     else if (strcmp(bif->name,"__builtin_memcpy")==0) 
7214       {
7215         genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7216       } 
7217     else 
7218       {
7219         wassertl (0, "Unknown builtin function encountered");
7220       }
7221 }
7222
7223 /*-----------------------------------------------------------------*/
7224 /* genZ80Code - generate code for Z80 based controllers            */
7225 /*-----------------------------------------------------------------*/
7226 void
7227 genZ80Code (iCode * lic)
7228 {
7229   iCode *ic;
7230   int cln = 0;
7231
7232   /* Hack */
7233   if (IS_GB)
7234     {
7235       _fReturn = _gbz80_return;
7236       _fTmp = _gbz80_return;
7237     }
7238   else
7239     {
7240       _fReturn = _z80_return;
7241       _fTmp = _z80_return;
7242     }
7243
7244   _G.lines.head = _G.lines.current = NULL;
7245
7246   for (ic = lic; ic; ic = ic->next)
7247     {
7248
7249       if (cln != ic->lineno)
7250         {
7251           if (!options.noCcodeInAsm) {
7252             emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7253                    printCLine(ic->filename, ic->lineno));
7254           }
7255           cln = ic->lineno;
7256         }
7257       if (options.iCodeInAsm) {
7258         emit2 (";ic:%d: %s", ic->key, printILine(ic));
7259       }
7260       /* if the result is marked as
7261          spilt and rematerializable or code for
7262          this has already been generated then
7263          do nothing */
7264       if (resultRemat (ic) || ic->generated)
7265         continue;
7266
7267       /* depending on the operation */
7268       switch (ic->op)
7269         {
7270         case '!':
7271           emitDebug ("; genNot");
7272           genNot (ic);
7273           break;
7274
7275         case '~':
7276           emitDebug ("; genCpl");
7277           genCpl (ic);
7278           break;
7279
7280         case UNARYMINUS:
7281           emitDebug ("; genUminus");
7282           genUminus (ic);
7283           break;
7284
7285         case IPUSH:
7286           emitDebug ("; genIpush");
7287           genIpush (ic);
7288           break;
7289
7290         case IPOP:
7291           /* IPOP happens only when trying to restore a
7292              spilt live range, if there is an ifx statement
7293              following this pop then the if statement might
7294              be using some of the registers being popped which
7295              would destory the contents of the register so
7296              we need to check for this condition and handle it */
7297           if (ic->next &&
7298               ic->next->op == IFX &&
7299               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7300             {
7301               emitDebug ("; genIfx");
7302               genIfx (ic->next, ic);
7303             }
7304           else
7305             {
7306               emitDebug ("; genIpop");
7307               genIpop (ic);
7308             }
7309           break;
7310
7311         case CALL:
7312           emitDebug ("; genCall");
7313           genCall (ic);
7314           break;
7315
7316         case PCALL:
7317           emitDebug ("; genPcall");
7318           genPcall (ic);
7319           break;
7320
7321         case FUNCTION:
7322           emitDebug ("; genFunction");
7323           genFunction (ic);
7324           break;
7325
7326         case ENDFUNCTION:
7327           emitDebug ("; genEndFunction");
7328           genEndFunction (ic);
7329           break;
7330
7331         case RETURN:
7332           emitDebug ("; genRet");
7333           genRet (ic);
7334           break;
7335
7336         case LABEL:
7337           emitDebug ("; genLabel");
7338           genLabel (ic);
7339           break;
7340
7341         case GOTO:
7342           emitDebug ("; genGoto");
7343           genGoto (ic);
7344           break;
7345
7346         case '+':
7347           emitDebug ("; genPlus");
7348           genPlus (ic);
7349           break;
7350
7351         case '-':
7352           emitDebug ("; genMinus");
7353           genMinus (ic);
7354           break;
7355
7356         case '*':
7357           emitDebug ("; genMult");
7358           genMult (ic);
7359           break;
7360
7361         case '/':
7362           emitDebug ("; genDiv");
7363           genDiv (ic);
7364           break;
7365
7366         case '%':
7367           emitDebug ("; genMod");
7368           genMod (ic);
7369           break;
7370
7371         case '>':
7372           emitDebug ("; genCmpGt");
7373           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7374           break;
7375
7376         case '<':
7377           emitDebug ("; genCmpLt");
7378           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7379           break;
7380
7381         case LE_OP:
7382         case GE_OP:
7383         case NE_OP:
7384
7385           /* note these two are xlated by algebraic equivalence
7386              during parsing SDCC.y */
7387           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7388                   "got '>=' or '<=' shouldn't have come here");
7389           break;
7390
7391         case EQ_OP:
7392           emitDebug ("; genCmpEq");
7393           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7394           break;
7395
7396         case AND_OP:
7397           emitDebug ("; genAndOp");
7398           genAndOp (ic);
7399           break;
7400
7401         case OR_OP:
7402           emitDebug ("; genOrOp");
7403           genOrOp (ic);
7404           break;
7405
7406         case '^':
7407           emitDebug ("; genXor");
7408           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7409           break;
7410
7411         case '|':
7412           emitDebug ("; genOr");
7413           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7414           break;
7415
7416         case BITWISEAND:
7417           emitDebug ("; genAnd");
7418           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7419           break;
7420
7421         case INLINEASM:
7422           emitDebug ("; genInline");
7423           genInline (ic);
7424           break;
7425
7426         case RRC:
7427           emitDebug ("; genRRC");
7428           genRRC (ic);
7429           break;
7430
7431         case RLC:
7432           emitDebug ("; genRLC");
7433           genRLC (ic);
7434           break;
7435
7436         case GETHBIT:
7437           emitDebug ("; genGetHBIT");
7438           genGetHbit (ic);
7439           break;
7440
7441         case LEFT_OP:
7442           emitDebug ("; genLeftShift");
7443           genLeftShift (ic);
7444           break;
7445
7446         case RIGHT_OP:
7447           emitDebug ("; genRightShift");
7448           genRightShift (ic);
7449           break;
7450
7451         case GET_VALUE_AT_ADDRESS:
7452           emitDebug ("; genPointerGet");
7453           genPointerGet (ic);
7454           break;
7455
7456         case '=':
7457
7458           if (POINTER_SET (ic))
7459             {
7460               emitDebug ("; genAssign (pointer)");
7461               genPointerSet (ic);
7462             }
7463           else
7464             {
7465               emitDebug ("; genAssign");
7466               genAssign (ic);
7467             }
7468           break;
7469
7470         case IFX:
7471           emitDebug ("; genIfx");
7472           genIfx (ic, NULL);
7473           break;
7474
7475         case ADDRESS_OF:
7476           emitDebug ("; genAddrOf");
7477           genAddrOf (ic);
7478           break;
7479
7480         case JUMPTABLE:
7481           emitDebug ("; genJumpTab");
7482           genJumpTab (ic);
7483           break;
7484
7485         case CAST:
7486           emitDebug ("; genCast");
7487           genCast (ic);
7488           break;
7489
7490         case RECEIVE:
7491           emitDebug ("; genReceive");
7492           genReceive (ic);
7493           break;
7494
7495         case SEND:
7496           if (ic->builtinSEND)
7497             {
7498               emitDebug ("; genBuiltIn");
7499               genBuiltIn(ic);
7500             }
7501           else
7502             {
7503               emitDebug ("; addSet");
7504               addSet (&_G.sendSet, ic);
7505             }
7506           break;
7507
7508         case ARRAYINIT:
7509           emitDebug ("; genArrayInit");
7510           genArrayInit(ic);
7511           break;
7512             
7513         default:
7514           ic = ic;
7515         }
7516     }
7517
7518
7519   /* now we are ready to call the
7520      peep hole optimizer */
7521   if (!options.nopeep)
7522     peepHole (&_G.lines.head);
7523
7524   /* This is unfortunate */
7525   /* now do the actual printing */
7526   {
7527     FILE *fp = codeOutFile;
7528     if (isInHome () && codeOutFile == code->oFile)
7529       codeOutFile = home->oFile;
7530     printLine (_G.lines.head, codeOutFile);
7531     if (_G.flushStatics)
7532       {
7533         flushStatics ();
7534         _G.flushStatics = 0;
7535       }
7536     codeOutFile = fp;
7537   }
7538
7539   freeTrace(&_G.lines.trace);
7540   freeTrace(&_G.trace.aops);
7541 }
7542
7543 /*
7544   Attic
7545 static int
7546 _isPairUsed (iCode * ic, PAIR_ID pairId)
7547 {
7548   int ret = 0;
7549   switch (pairId)
7550     {
7551     case PAIR_DE:
7552       if (bitVectBitValue (ic->rMask, D_IDX))
7553         ret++;
7554       if (bitVectBitValue (ic->rMask, E_IDX))
7555         ret++;
7556       break;
7557     default:
7558       wassert (0);
7559     }
7560   return ret;
7561 }
7562
7563 static char *
7564 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7565 {
7566   unsigned long v;
7567   value *val = aop->aopu.aop_lit;
7568
7569   wassert (aop->type == AOP_LIT);
7570   wassert (!IS_FLOAT (val->type));
7571
7572   v = (unsigned long) floatFromVal (val);
7573
7574   if (xor)
7575     v ^= 0x8000;
7576   if (negate)
7577     v = 0-v;
7578   v &= 0xFFFF;
7579
7580   tsprintf (buffer, sizeof(buffer), "!immedword", v);
7581   return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
7582 }
7583
7584
7585 */