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