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