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