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