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