* src/z80/gen.c (fetchLitPair): Changed so that it properly caches direct space...
[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   if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1794     {
1795       /* Create a new asmop with value zero */
1796       asmop *azero = newAsmop (AOP_SIMPLELIT);
1797       azero->aopu.aop_simplelit = 0;
1798       azero->size = size;
1799       _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1800       goto release;
1801     }
1802
1803   /* otherwise subtract from zero */
1804   size = AOP_SIZE (IC_LEFT (ic));
1805   offset = 0;
1806   _clearCarry();
1807   while (size--)
1808     {
1809       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1810       emit2 ("ld a,!zero");
1811       emit2 ("sbc a,%s", l);
1812       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1813     }
1814
1815   /* if any remaining bytes in the result */
1816   /* we just need to propagate the sign   */
1817   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1818     {
1819       emit2 ("rlc a");
1820       emit2 ("sbc a,a");
1821       while (size--)
1822         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1823     }
1824
1825 release:
1826   /* release the aops */
1827   freeAsmop (IC_LEFT (ic), NULL, ic);
1828   freeAsmop (IC_RESULT (ic), NULL, ic);
1829 }
1830
1831 /*-----------------------------------------------------------------*/
1832 /* assignResultValue -               */
1833 /*-----------------------------------------------------------------*/
1834 void
1835 assignResultValue (operand * oper)
1836 {
1837   int size = AOP_SIZE (oper);
1838   bool topInA = 0;
1839
1840   wassert (size <= 4);
1841   topInA = requiresHL (AOP (oper));
1842
1843 #if 0
1844   if (!IS_GB)
1845     wassert (size <= 2);
1846 #endif
1847   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1848     {
1849       /* We do it the hard way here. */
1850       _push (PAIR_HL);
1851       aopPut (AOP (oper), _fReturn[0], 0);
1852       aopPut (AOP (oper), _fReturn[1], 1);
1853       _pop (PAIR_DE);
1854       aopPut (AOP (oper), _fReturn[0], 2);
1855       aopPut (AOP (oper), _fReturn[1], 3);
1856     }
1857   else
1858     {
1859       while (size--)
1860         {
1861           aopPut (AOP (oper), _fReturn[size], size);
1862         }
1863     }
1864 }
1865
1866 static void
1867 _saveRegsForCall(iCode *ic, int sendSetSize)
1868 {
1869   /* Rules:
1870       o Stack parameters are pushed before this function enters
1871       o DE and BC may be used in this function.
1872       o HL and DE may be used to return the result.
1873       o HL and DE may be used to send variables.
1874       o DE and BC may be used to store the result value.
1875       o HL may be used in computing the sent value of DE
1876       o The iPushes for other parameters occur before any addSets
1877
1878      Logic: (to be run inside the first iPush or if none, before sending)
1879       o Compute if DE and/or BC are in use over the call
1880       o Compute if DE is used in the send set
1881       o Compute if DE and/or BC are used to hold the result value
1882       o If (DE is used, or in the send set) and is not used in the result, push.
1883       o If BC is used and is not in the result, push
1884       o 
1885       o If DE is used in the send set, fetch
1886       o If HL is used in the send set, fetch
1887       o Call
1888       o ...
1889   */
1890   if (_G.saves.saved == FALSE) {
1891     bool deInUse, bcInUse;
1892     bool deSending;
1893     bool bcInRet = FALSE, deInRet = FALSE;
1894     bitVect *rInUse;
1895
1896 #if 1
1897     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1898 #else
1899     if (IC_RESULT(ic))
1900       {
1901         rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
1902       }
1903     else 
1904       {
1905         /* Has no result, so in use is all of in use */
1906         rInUse = ic->rMask;
1907       }
1908 #endif
1909
1910     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1911     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1912
1913     deSending = (sendSetSize > 1);
1914
1915     emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1916
1917     if (bcInUse && bcInRet == FALSE) {
1918       _push(PAIR_BC);
1919       _G.stack.pushedBC = TRUE;
1920     }
1921     if (deInUse && deInRet == FALSE) {
1922       _push(PAIR_DE);
1923       _G.stack.pushedDE = TRUE;
1924     }
1925
1926     _G.saves.saved = TRUE;
1927   }
1928   else {
1929     /* Already saved. */
1930   }
1931 }
1932
1933 /*-----------------------------------------------------------------*/
1934 /* genIpush - genrate code for pushing this gets a little complex  */
1935 /*-----------------------------------------------------------------*/
1936 static void
1937 genIpush (iCode * ic)
1938 {
1939   int size, offset = 0;
1940   const char *l;
1941
1942   /* if this is not a parm push : ie. it is spill push
1943      and spill push is always done on the local stack */
1944   if (!ic->parmPush)
1945     {
1946       wassertl(0, "Encountered an unsupported spill push.");
1947       return;
1948     }
1949
1950   if (_G.saves.saved == FALSE) {
1951     /* Caller saves, and this is the first iPush. */
1952     /* Scan ahead until we find the function that we are pushing parameters to.
1953        Count the number of addSets on the way to figure out what registers
1954        are used in the send set.
1955     */
1956     int nAddSets = 0;
1957     iCode *walk = ic->next;
1958     
1959     while (walk) {
1960       if (walk->op == SEND) {
1961         nAddSets++;
1962       }
1963       else if (walk->op == CALL || walk->op == PCALL) {
1964         /* Found it. */
1965         break;
1966       }
1967       else {
1968         /* Keep looking. */
1969       }
1970       walk = walk->next;
1971     }
1972     _saveRegsForCall(walk, nAddSets);
1973   }
1974   else {
1975     /* Already saved by another iPush. */
1976   }
1977
1978   /* then do the push */
1979   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1980
1981   size = AOP_SIZE (IC_LEFT (ic));
1982
1983   if (isPair (AOP (IC_LEFT (ic))))
1984     {
1985       _G.stack.pushed += 2;
1986       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1987     }
1988   else
1989     {
1990       if (size == 2)
1991         {
1992           fetchHL (AOP (IC_LEFT (ic)));
1993           emit2 ("push hl");
1994           spillPair (PAIR_HL);
1995           _G.stack.pushed += 2;
1996           goto release;
1997         }
1998       if (size == 4)
1999         {
2000           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2001           emit2 ("push hl");
2002           spillPair (PAIR_HL);
2003           _G.stack.pushed += 2;
2004           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2005           emit2 ("push hl");
2006           spillPair (PAIR_HL);
2007           _G.stack.pushed += 2;
2008           goto release;
2009         }
2010       offset = size;
2011       while (size--)
2012         {
2013           if (AOP (IC_LEFT (ic))->type == AOP_IY)
2014             {
2015               char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2016               wassert (l);
2017               emit2 ("ld a,(%s)", l);
2018             }
2019           else
2020             {
2021               l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2022               emit2 ("ld a,%s", l);
2023             }
2024           emit2 ("push af");
2025           emit2 ("inc sp");
2026           _G.stack.pushed++;
2027         }
2028     }
2029 release:
2030   freeAsmop (IC_LEFT (ic), NULL, ic);
2031 }
2032
2033 /*-----------------------------------------------------------------*/
2034 /* genIpop - recover the registers: can happen only for spilling   */
2035 /*-----------------------------------------------------------------*/
2036 static void
2037 genIpop (iCode * ic)
2038 {
2039   int size, offset;
2040
2041
2042   /* if the temp was not pushed then */
2043   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2044     return;
2045
2046   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2047   size = AOP_SIZE (IC_LEFT (ic));
2048   offset = (size - 1);
2049   if (isPair (AOP (IC_LEFT (ic))))
2050     {
2051       emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2052     }
2053   else
2054     {
2055       while (size--)
2056         {
2057           emit2 ("dec sp");
2058           emit2 ("pop hl");
2059           spillPair (PAIR_HL);
2060           aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2061         }
2062     }
2063
2064   freeAsmop (IC_LEFT (ic), NULL, ic);
2065 }
2066
2067 /* This is quite unfortunate */
2068 static void
2069 setArea (int inHome)
2070 {
2071   /*
2072     static int lastArea = 0;
2073
2074      if (_G.in_home != inHome) {
2075      if (inHome) {
2076      const char *sz = port->mem.code_name;
2077      port->mem.code_name = "HOME";
2078      emit2("!area", CODE_NAME);
2079      port->mem.code_name = sz;
2080      }
2081      else
2082      emit2("!area", CODE_NAME); */
2083   _G.in_home = inHome;
2084   //    }
2085 }
2086
2087 static bool
2088 isInHome (void)
2089 {
2090   return _G.in_home;
2091 }
2092
2093 static int
2094 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2095 {
2096   int ret = 0;
2097   asmop *aop;
2098   symbol *sym = OP_SYMBOL (op);
2099
2100   if (sym->isspilt || sym->nRegs == 0)
2101     return 0;
2102
2103   aopOp (op, ic, FALSE, FALSE);
2104
2105   aop = AOP (op);
2106   if (aop->type == AOP_REG)
2107     {
2108       int i;
2109       for (i = 0; i < aop->size; i++)
2110         {
2111           if (pairId == PAIR_DE)
2112             {
2113               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2114               if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2115                 ret++;
2116               if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2117                 ret++;
2118             }
2119           else if (pairId == PAIR_BC)
2120             {
2121               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2122               if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2123                 ret++;
2124               if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2125                 ret++;
2126             }
2127           else
2128             {
2129               wassert (0);
2130             }
2131         }
2132     }
2133
2134   freeAsmop (IC_LEFT (ic), NULL, ic);
2135   return ret;
2136 }
2137
2138 /** Emit the code for a call statement
2139  */
2140 static void
2141 emitCall (iCode * ic, bool ispcall)
2142 {
2143   sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2144
2145   bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2146
2147   /* if caller saves & we have not saved then */
2148   if (!ic->regsSaved)
2149     {
2150       /* PENDING */
2151     }
2152
2153   _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2154
2155   /* if send set is not empty then assign */
2156   if (_G.sendSet)
2157     {
2158       iCode *sic;
2159       int send = 0;
2160       int nSend = elementsInSet(_G.sendSet);
2161       bool swapped = FALSE;
2162
2163       int _z80_sendOrder[] = {
2164         PAIR_BC, PAIR_DE
2165       };
2166
2167       if (nSend > 1) {
2168         /* Check if the parameters are swapped.  If so route through hl instead. */
2169         wassertl (nSend == 2, "Pedantic check.  Code only checks for the two send items case.");
2170
2171         sic = setFirstItem(_G.sendSet);
2172         sic = setNextItem(_G.sendSet);
2173
2174         if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2175           /* The second send value is loaded from one the one that holds the first
2176              send, i.e. it is overwritten. */
2177           /* Cache the first in HL, and load the second from HL instead. */
2178           emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2179           emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2180
2181           swapped = TRUE;
2182         }
2183       }
2184
2185       for (sic = setFirstItem (_G.sendSet); sic;
2186            sic = setNextItem (_G.sendSet))
2187         {
2188           int size;
2189           aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2190
2191           size = AOP_SIZE (IC_LEFT (sic));
2192           wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2193           wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2194
2195           // PENDING: Mild hack
2196           if (swapped == TRUE && send == 1) {
2197             if (size > 1) {
2198               emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2199             }
2200             else {
2201               emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2202             }
2203             emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2204           }
2205           else {
2206             fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2207           }
2208
2209           send++;
2210           freeAsmop (IC_LEFT (sic), NULL, sic);
2211         }
2212       _G.sendSet = NULL;
2213     }
2214
2215   if (ispcall)
2216     {
2217       if (IS_BANKEDCALL (detype))
2218         {
2219           werror (W_INDIR_BANKED);
2220         }
2221       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2222
2223       if (isLitWord (AOP (IC_LEFT (ic))))
2224         {
2225           emitDebug ("; Special case where the pCall is to a constant");
2226           emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2227         }
2228       else
2229         {
2230           symbol *rlbl = newiTempLabel (NULL);
2231           spillPair (PAIR_HL);
2232           emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2233           emit2 ("push hl");
2234           _G.stack.pushed += 2;
2235
2236           fetchHL (AOP (IC_LEFT (ic)));
2237           emit2 ("jp !*hl");
2238           emit2 ("!tlabeldef", (rlbl->key + 100));
2239           _G.stack.pushed -= 2;
2240         }
2241       freeAsmop (IC_LEFT (ic), NULL, ic);
2242     }
2243   else
2244     {
2245       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2246       OP_SYMBOL (IC_LEFT (ic))->rname :
2247       OP_SYMBOL (IC_LEFT (ic))->name;
2248       if (IS_BANKEDCALL (detype))
2249         {
2250           emit2 ("call banked_call");
2251           emit2 ("!dws", name);
2252           emit2 ("!dw !bankimmeds", name);
2253         }
2254       else
2255         {
2256           /* make the call */
2257           emit2 ("call %s", name);
2258         }
2259     }
2260   spillCached ();
2261
2262   /* Mark the regsiters as restored. */
2263   _G.saves.saved = FALSE;
2264
2265   /* if we need assign a result value */
2266   if ((IS_ITEMP (IC_RESULT (ic)) &&
2267        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2268         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2269       IS_TRUE_SYMOP (IC_RESULT (ic)))
2270     {
2271
2272       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2273
2274       assignResultValue (IC_RESULT (ic));
2275
2276       freeAsmop (IC_RESULT (ic), NULL, ic);
2277     }
2278
2279   /* adjust the stack for parameters if required */
2280   if (ic->parmBytes)
2281     {
2282       int i = ic->parmBytes;
2283
2284       _G.stack.pushed -= i;
2285       if (IS_GB)
2286         {
2287           emit2 ("!ldaspsp", i);
2288         }
2289       else
2290         {
2291           spillCached ();
2292           if (i > 6)
2293             {
2294               emit2 ("ld hl,#%d", i);
2295               emit2 ("add hl,sp");
2296               emit2 ("ld sp,hl");
2297             }
2298           else
2299             {
2300               while (i > 1)
2301                 {
2302                   emit2 ("pop hl");
2303                   i -= 2;
2304                 }
2305               if (i)
2306                 emit2 ("inc sp");
2307             }
2308           spillCached ();
2309         }
2310     }
2311
2312   if (_G.stack.pushedDE) 
2313     {
2314       bool dInUse = bitVectBitValue(rInUse, D_IDX);
2315       bool eInUse = bitVectBitValue(rInUse, E_IDX);
2316
2317       if (dInUse && eInUse) 
2318         {
2319           _pop (PAIR_DE);
2320         }
2321       else if (dInUse)
2322         {
2323           _pop(PAIR_HL);
2324           emit2 ("ld d,h");
2325         }
2326       else if (eInUse)
2327         {
2328           _pop(PAIR_HL);
2329           emit2 ("ld e,l");
2330         }
2331       else
2332         {
2333           wassertl (0, "Neither D or E were in use but it was pushed.");
2334         }
2335       _G.stack.pushedDE = FALSE;
2336     }
2337   
2338   if (_G.stack.pushedBC) 
2339     {
2340       bool bInUse = bitVectBitValue(rInUse, B_IDX);
2341       bool cInUse = bitVectBitValue(rInUse, C_IDX);
2342
2343       // If both B and C are used in the return value, then we won't get
2344       // here.
2345       if (bInUse && cInUse) 
2346         {
2347           _pop (PAIR_BC);
2348         }
2349       else if (bInUse)
2350         {
2351           _pop(PAIR_HL);
2352           emit2 ("ld b,h");
2353         }
2354       else if (cInUse)
2355         {
2356           _pop(PAIR_HL);
2357           emit2 ("ld c,l");
2358         }
2359       else
2360         {
2361           wassertl (0, "Neither B or C were in use but it was pushed.");
2362         }
2363       _G.stack.pushedBC = FALSE;
2364     }
2365 }
2366
2367 /*-----------------------------------------------------------------*/
2368 /* genCall - generates a call statement                            */
2369 /*-----------------------------------------------------------------*/
2370 static void
2371 genCall (iCode * ic)
2372 {
2373   emitCall (ic, FALSE);
2374 }
2375
2376 /*-----------------------------------------------------------------*/
2377 /* genPcall - generates a call by pointer statement                */
2378 /*-----------------------------------------------------------------*/
2379 static void
2380 genPcall (iCode * ic)
2381 {
2382   emitCall (ic, TRUE);
2383 }
2384
2385 /*-----------------------------------------------------------------*/
2386 /* resultRemat - result  is rematerializable                       */
2387 /*-----------------------------------------------------------------*/
2388 static int
2389 resultRemat (iCode * ic)
2390 {
2391   if (SKIP_IC (ic) || ic->op == IFX)
2392     return 0;
2393
2394   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2395     {
2396       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2397       if (sym->remat && !POINTER_SET (ic))
2398         return 1;
2399     }
2400
2401   return 0;
2402 }
2403
2404 extern set *publics;
2405
2406 /*-----------------------------------------------------------------*/
2407 /* genFunction - generated code for function entry                 */
2408 /*-----------------------------------------------------------------*/
2409 static void
2410 genFunction (iCode * ic)
2411 {
2412   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2413   sym_link *fetype;
2414
2415 #if CALLEE_SAVES
2416   bool bcInUse = FALSE;
2417   bool deInUse = FALSE;
2418 #endif
2419
2420   setArea (IS_NONBANKED (sym->etype));
2421
2422   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2423      else.
2424   */
2425   _G.receiveOffset = 0;
2426
2427 #if 0
2428   /* PENDING: hack */
2429   if (!IS_STATIC (sym->etype))
2430     {
2431       addSetIfnotP (&publics, sym);
2432     }
2433 #endif
2434
2435   /* Record the last function name for debugging. */
2436   _G.lastFunctionName = sym->rname;
2437   
2438   /* Create the function header */
2439   emit2 ("!functionheader", sym->name);
2440   /* PENDING: portability. */
2441   emit2 ("__%s_start:", sym->rname);
2442   emit2 ("!functionlabeldef", sym->rname);
2443
2444   if (options.profile) 
2445     {
2446       emit2 ("!profileenter");
2447     }
2448
2449   fetype = getSpec (operandType (IC_LEFT (ic)));
2450
2451   /* if critical function then turn interrupts off */
2452   if (SPEC_CRTCL (fetype))
2453     emit2 ("!di");
2454
2455   /* if this is an interrupt service routine then save all potentially used registers. */
2456   if (IS_ISR (sym->etype))
2457     {
2458       emit2 ("!pusha");
2459     }
2460
2461   /* PENDING: callee-save etc */
2462
2463   _G.stack.param_offset = 0;
2464
2465 #if CALLEE_SAVES
2466   /* Detect which registers are used. */
2467   if (sym->regsUsed)
2468     {
2469       int i;
2470       for (i = 0; i < sym->regsUsed->size; i++)
2471         {
2472           if (bitVectBitValue (sym->regsUsed, i))
2473             {
2474               switch (i)
2475                 {
2476                 case C_IDX:
2477                 case B_IDX:
2478                   bcInUse = TRUE;
2479                   break;
2480                 case D_IDX:
2481                 case E_IDX:
2482                   if (IS_Z80) {
2483                     deInUse = TRUE;
2484                   }
2485                   else {
2486                     /* Other systems use DE as a temporary. */
2487                   }
2488                   break;
2489                 }
2490             }
2491         }
2492     }
2493
2494   if (bcInUse) 
2495     {
2496       emit2 ("push bc");
2497       _G.stack.param_offset += 2;
2498     }
2499
2500   _G.stack.pushedBC = bcInUse;
2501
2502   if (deInUse)
2503     {
2504       emit2 ("push de");
2505       _G.stack.param_offset += 2;
2506     }
2507
2508   _G.stack.pushedDE = deInUse;
2509 #endif
2510
2511   /* adjust the stack for the function */
2512   _G.stack.last = sym->stack;
2513
2514   if (sym->stack)
2515     emit2 ("!enterx", sym->stack);
2516   else
2517     emit2 ("!enter");
2518   _G.stack.offset = sym->stack;
2519 }
2520
2521 /*-----------------------------------------------------------------*/
2522 /* genEndFunction - generates epilogue for functions               */
2523 /*-----------------------------------------------------------------*/
2524 static void
2525 genEndFunction (iCode * ic)
2526 {
2527   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2528
2529   if (IS_ISR (sym->etype))
2530     {
2531       wassert (0);
2532     }
2533   else
2534     {
2535       if (SPEC_CRTCL (sym->etype))
2536         emit2 ("!ei");
2537
2538       /* PENDING: calleeSave */
2539
2540       if (_G.stack.offset)
2541         {
2542           emit2 ("!leavex", _G.stack.offset);
2543         }
2544       else
2545         {
2546           emit2 ("!leave");
2547         }
2548
2549 #if CALLEE_SAVES
2550       if (_G.stack.pushedDE) 
2551         {
2552           emit2 ("pop de");
2553           _G.stack.pushedDE = FALSE;
2554         }
2555
2556       if (_G.stack.pushedDE) 
2557         {
2558           emit2 ("pop bc");
2559           _G.stack.pushedDE = FALSE;
2560         }
2561 #endif
2562
2563       if (options.profile) 
2564         {
2565           emit2 ("!profileexit");
2566         }
2567
2568
2569       /* Both baned and non-banked just ret */
2570       emit2 ("ret");
2571
2572       /* PENDING: portability. */
2573       emit2 ("__%s_end:", sym->rname);
2574     }
2575   _G.flushStatics = 1;
2576   _G.stack.pushed = 0;
2577   _G.stack.offset = 0;
2578 }
2579
2580 /*-----------------------------------------------------------------*/
2581 /* genRet - generate code for return statement                     */
2582 /*-----------------------------------------------------------------*/
2583 static void
2584 genRet (iCode * ic)
2585 {
2586     const char *l;
2587   /* Errk.  This is a hack until I can figure out how
2588      to cause dehl to spill on a call */
2589   int size, offset = 0;
2590
2591   /* if we have no return value then
2592      just generate the "ret" */
2593   if (!IC_LEFT (ic))
2594     goto jumpret;
2595
2596   /* we have something to return then
2597      move the return value into place */
2598   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2599   size = AOP_SIZE (IC_LEFT (ic));
2600
2601   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2602     {
2603       if (IS_GB)
2604         {
2605           emit2 ("ld de,%s", l);
2606         }
2607       else
2608         {
2609           emit2 ("ld hl,%s", l);
2610         }
2611     }
2612   else
2613     {
2614       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2615         {
2616           fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2617           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2618         }
2619       else
2620         {
2621           while (size--)
2622             {
2623               l = aopGet (AOP (IC_LEFT (ic)), offset,
2624                           FALSE);
2625               if (strcmp (_fReturn[offset], l))
2626                 emit2 ("ld %s,%s", _fReturn[offset++], l);
2627             }
2628         }
2629     }
2630   freeAsmop (IC_LEFT (ic), NULL, ic);
2631
2632 jumpret:
2633   /* generate a jump to the return label
2634      if the next is not the return statement */
2635   if (!(ic->next && ic->next->op == LABEL &&
2636         IC_LABEL (ic->next) == returnLabel))
2637
2638     emit2 ("jp !tlabel", returnLabel->key + 100);
2639 }
2640
2641 /*-----------------------------------------------------------------*/
2642 /* genLabel - generates a label                                    */
2643 /*-----------------------------------------------------------------*/
2644 static void
2645 genLabel (iCode * ic)
2646 {
2647   /* special case never generate */
2648   if (IC_LABEL (ic) == entryLabel)
2649     return;
2650
2651   emitLabel (IC_LABEL (ic)->key + 100);
2652 }
2653
2654 /*-----------------------------------------------------------------*/
2655 /* genGoto - generates a ljmp                                      */
2656 /*-----------------------------------------------------------------*/
2657 static void
2658 genGoto (iCode * ic)
2659 {
2660   emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2661 }
2662
2663 /*-----------------------------------------------------------------*/
2664 /* genPlusIncr :- does addition with increment if possible         */
2665 /*-----------------------------------------------------------------*/
2666 static bool
2667 genPlusIncr (iCode * ic)
2668 {
2669   unsigned int icount;
2670   unsigned int size = getDataSize (IC_RESULT (ic));
2671   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2672
2673   /* will try to generate an increment */
2674   /* if the right side is not a literal
2675      we cannot */
2676   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2677     return FALSE;
2678
2679   emitDebug ("; genPlusIncr");
2680
2681   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2682
2683   /* If result is a pair */
2684   if (resultId != PAIR_INVALID)
2685     {
2686       if (isLitWord (AOP (IC_LEFT (ic))))
2687         {
2688           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2689           return TRUE;
2690         }
2691       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2692         {
2693           fetchPair (resultId, AOP (IC_RIGHT (ic)));
2694           emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2695           return TRUE;
2696         }
2697       if (icount > 5)
2698         return FALSE;
2699       /* Inc a pair */
2700       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2701         {
2702           if (icount > 2)
2703             return FALSE;
2704           movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2705           movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2706         }
2707       while (icount--)
2708         {
2709           emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2710         }
2711       return TRUE;
2712     }
2713
2714   /* if the literal value of the right hand side
2715      is greater than 4 then it is not worth it */
2716   if (icount > 4)
2717     return FALSE;
2718
2719   /* if increment 16 bits in register */
2720   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2721       size > 1 &&
2722       icount == 1
2723     )
2724     {
2725       int offset = 0;
2726       symbol *tlbl = NULL;
2727       tlbl = newiTempLabel (NULL);
2728       while (size--)
2729         {
2730           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2731           if (size)
2732             {
2733               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2734             }
2735         }
2736       emitLabel (tlbl->key + 100);
2737       return TRUE;
2738     }
2739
2740   /* if the sizes are greater than 1 then we cannot */
2741   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2742       AOP_SIZE (IC_LEFT (ic)) > 1)
2743     return FALSE;
2744
2745   /* we can if the aops of the left & result match or
2746      if they are in registers and the registers are the
2747      same */
2748   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2749     {
2750       while (icount--)
2751         {
2752           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2753         }
2754       return TRUE;
2755     }
2756
2757   return FALSE;
2758 }
2759
2760 /*-----------------------------------------------------------------*/
2761 /* outBitAcc - output a bit in acc                                 */
2762 /*-----------------------------------------------------------------*/
2763 void
2764 outBitAcc (operand * result)
2765 {
2766   symbol *tlbl = newiTempLabel (NULL);
2767   /* if the result is a bit */
2768   if (AOP_TYPE (result) == AOP_CRY)
2769     {
2770       wassert (0);
2771     }
2772   else
2773     {
2774       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2775       emit2 ("ld a,!one");
2776       emitLabel (tlbl->key + 100);
2777       outAcc (result);
2778     }
2779 }
2780
2781 /*-----------------------------------------------------------------*/
2782 /* genPlus - generates code for addition                           */
2783 /*-----------------------------------------------------------------*/
2784 static void
2785 genPlus (iCode * ic)
2786 {
2787   int size, offset = 0;
2788
2789   /* special cases :- */
2790
2791   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2792   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2793   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2794
2795   /* Swap the left and right operands if:
2796
2797      if literal, literal on the right or
2798      if left requires ACC or right is already
2799      in ACC */
2800
2801   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2802       (AOP_NEEDSACC (IC_LEFT (ic))) ||
2803       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2804     {
2805       operand *t = IC_RIGHT (ic);
2806       IC_RIGHT (ic) = IC_LEFT (ic);
2807       IC_LEFT (ic) = t;
2808     }
2809
2810   /* if both left & right are in bit
2811      space */
2812   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2813       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2814     {
2815       /* Cant happen */
2816       wassert (0);
2817     }
2818
2819   /* if left in bit space & right literal */
2820   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2821       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2822     {
2823       /* Can happen I guess */
2824       wassert (0);
2825     }
2826
2827   /* if I can do an increment instead
2828      of add then GOOD for ME */
2829   if (genPlusIncr (ic) == TRUE)
2830     goto release;
2831
2832   emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
2833
2834   size = getDataSize (IC_RESULT (ic));
2835
2836   /* Special case when left and right are constant */
2837   if (isPair (AOP (IC_RESULT (ic))))
2838     {
2839       char *left, *right;
2840       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2841       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2842
2843       if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2844           left && right)
2845         {
2846           /* It's a pair */
2847           /* PENDING: fix */
2848           char buffer[100];
2849           sprintf (buffer, "#(%s + %s)", left, right);
2850           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2851           goto release;
2852         }
2853     }
2854
2855   if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2856     {
2857       /* Fetch into HL then do the add */
2858       spillPair (PAIR_HL);
2859       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2860       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2861       goto release;
2862     }
2863
2864   /* Special case:
2865      ld hl,sp+n trashes C so we cant afford to do it during an
2866      add with stack based varibles.  Worst case is:
2867      ld  hl,sp+left
2868      ld  a,(hl)
2869      ld  hl,sp+right
2870      add (hl)
2871      ld  hl,sp+result
2872      ld  (hl),a
2873      ld  hl,sp+left+1
2874      ld  a,(hl)
2875      ld  hl,sp+right+1
2876      adc (hl)
2877      ld  hl,sp+result+1
2878      ld  (hl),a
2879      So you cant afford to load up hl if either left, right, or result
2880      is on the stack (*sigh*)  The alt is:
2881      ld  hl,sp+left
2882      ld  de,(hl)
2883      ld  hl,sp+right
2884      ld  hl,(hl)
2885      add hl,de
2886      ld  hl,sp+result
2887      ld  (hl),hl
2888      Combinations in here are:
2889      * If left or right are in bc then the loss is small - trap later
2890      * If the result is in bc then the loss is also small
2891    */
2892   if (IS_GB)
2893     {
2894       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2895           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2896           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2897         {
2898           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2899                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2900               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2901                AOP_SIZE (IC_RIGHT (ic)) <= 2))
2902             {
2903               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2904                 {
2905                   /* Swap left and right */
2906                   operand *t = IC_RIGHT (ic);
2907                   IC_RIGHT (ic) = IC_LEFT (ic);
2908                   IC_LEFT (ic) = t;
2909                 }
2910               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2911                 {
2912                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2913                   emit2 ("add hl,bc");
2914                 }
2915               else
2916                 {
2917                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2918                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2919                   emit2 ("add hl,de");
2920                 }
2921               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2922               goto release;
2923             }
2924         }
2925       if (size == 4)
2926         {
2927           /* Be paranoid on the GB with 4 byte variables due to how C
2928              can be trashed by lda hl,n(sp).
2929           */
2930           _gbz80_emitAddSubLong (ic, TRUE);
2931           goto release;
2932         }
2933     }
2934
2935   while (size--)
2936     {
2937       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2938         {
2939           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2940           if (offset == 0)
2941             emit2 ("add a,%s",
2942                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2943           else
2944             emit2 ("adc a,%s",
2945                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2946         }
2947       else
2948         {
2949           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2950           if (offset == 0)
2951             emit2 ("add a,%s",
2952                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2953           else
2954             emit2 ("adc a,%s",
2955                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2956         }
2957       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2958     }
2959
2960 release:
2961   freeAsmop (IC_LEFT (ic), NULL, ic);
2962   freeAsmop (IC_RIGHT (ic), NULL, ic);
2963   freeAsmop (IC_RESULT (ic), NULL, ic);
2964
2965 }
2966
2967 /*-----------------------------------------------------------------*/
2968 /* genMinusDec :- does subtraction with deccrement if possible     */
2969 /*-----------------------------------------------------------------*/
2970 static bool
2971 genMinusDec (iCode * ic)
2972 {
2973   unsigned int icount;
2974   unsigned int size = getDataSize (IC_RESULT (ic));
2975
2976   /* will try to generate an increment */
2977   /* if the right side is not a literal we cannot */
2978   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2979     return FALSE;
2980
2981   /* if the literal value of the right hand side
2982      is greater than 4 then it is not worth it */
2983   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2984     return FALSE;
2985
2986   size = getDataSize (IC_RESULT (ic));
2987
2988   /* if decrement 16 bits in register */
2989   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2990       (size > 1) && isPair (AOP (IC_RESULT (ic))))
2991     {
2992       while (icount--)
2993         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2994       return TRUE;
2995     }
2996
2997   /* If result is a pair */
2998   if (isPair (AOP (IC_RESULT (ic))))
2999     {
3000       movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
3001       movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
3002       while (icount--)
3003         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3004       return TRUE;
3005     }
3006
3007   /* if increment 16 bits in register */
3008   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3009       (size == 2)
3010       )
3011     {
3012       fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3013
3014       while (icount--) {
3015         emit2 ("dec %s", _getTempPairName());
3016       }
3017
3018       commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3019
3020       return TRUE;
3021     }
3022
3023
3024   /* if the sizes are greater than 1 then we cannot */
3025   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3026       AOP_SIZE (IC_LEFT (ic)) > 1)
3027     return FALSE;
3028
3029   /* we can if the aops of the left & result match or if they are in
3030      registers and the registers are the same */
3031   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3032     {
3033       while (icount--)
3034         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3035       return TRUE;
3036     }
3037
3038   return FALSE;
3039 }
3040
3041 /*-----------------------------------------------------------------*/
3042 /* genMinus - generates code for subtraction                       */
3043 /*-----------------------------------------------------------------*/
3044 static void
3045 genMinus (iCode * ic)
3046 {
3047   int size, offset = 0;
3048   unsigned long lit = 0L;
3049
3050   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3051   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3052   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3053
3054   /* special cases :- */
3055   /* if both left & right are in bit space */
3056   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3057       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3058     {
3059       wassert (0);
3060       goto release;
3061     }
3062
3063   /* if I can do an decrement instead of subtract then GOOD for ME */
3064   if (genMinusDec (ic) == TRUE)
3065     goto release;
3066
3067   size = getDataSize (IC_RESULT (ic));
3068
3069   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3070     {
3071     }
3072   else
3073     {
3074       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3075       lit = -(long) lit;
3076     }
3077
3078   /* Same logic as genPlus */
3079   if (IS_GB)
3080     {
3081       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3082           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3083           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3084         {
3085           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3086                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3087               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3088                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3089             {
3090               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3091               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3092
3093               if (left == PAIR_INVALID && right == PAIR_INVALID)
3094                 {
3095                   left = PAIR_DE;
3096                   right = PAIR_HL;
3097                 }
3098               else if (right == PAIR_INVALID)
3099                 right = PAIR_DE;
3100               else if (left == PAIR_INVALID)
3101                 left = PAIR_DE;
3102
3103               fetchPair (left, AOP (IC_LEFT (ic)));
3104               /* Order is important.  Right may be HL */
3105               fetchPair (right, AOP (IC_RIGHT (ic)));
3106
3107               emit2 ("ld a,%s", _pairs[left].l);
3108               emit2 ("sub a,%s", _pairs[right].l);
3109               emit2 ("ld e,a");
3110               emit2 ("ld a,%s", _pairs[left].h);
3111               emit2 ("sbc a,%s", _pairs[right].h);
3112
3113               aopPut (AOP (IC_RESULT (ic)), "a", 1);
3114               aopPut (AOP (IC_RESULT (ic)), "e", 0);
3115               goto release;
3116             }
3117         }
3118       if (size == 4)
3119         {
3120           /* Be paranoid on the GB with 4 byte variables due to how C
3121              can be trashed by lda hl,n(sp).
3122           */
3123           _gbz80_emitAddSubLong (ic, FALSE);
3124           goto release;
3125         }
3126     }
3127
3128   /* if literal, add a,#-lit, else normal subb */
3129   while (size--)
3130     {
3131       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3132       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3133         {
3134           if (!offset)
3135             emit2 ("sub a,%s",
3136                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3137           else
3138             emit2 ("sbc a,%s",
3139                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3140         }
3141       else
3142         {
3143           /* first add without previous c */
3144           if (!offset)
3145             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3146           else
3147             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3148         }
3149       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3150     }
3151
3152   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3153       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3154       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3155     wassert (0);
3156
3157 release:
3158   freeAsmop (IC_LEFT (ic), NULL, ic);
3159   freeAsmop (IC_RIGHT (ic), NULL, ic);
3160   freeAsmop (IC_RESULT (ic), NULL, ic);
3161 }
3162
3163 /*-----------------------------------------------------------------*/
3164 /* genMult - generates code for multiplication                     */
3165 /*-----------------------------------------------------------------*/
3166 static void
3167 genMult (iCode * ic)
3168 {
3169   /* Shouldn't occur - all done through function calls */
3170   wassert (0);
3171 }
3172
3173 /*-----------------------------------------------------------------*/
3174 /* genDiv - generates code for division                            */
3175 /*-----------------------------------------------------------------*/
3176 static void
3177 genDiv (iCode * ic)
3178 {
3179   /* Shouldn't occur - all done through function calls */
3180   wassert (0);
3181 }
3182
3183 /*-----------------------------------------------------------------*/
3184 /* genMod - generates code for division                            */
3185 /*-----------------------------------------------------------------*/
3186 static void
3187 genMod (iCode * ic)
3188 {
3189   /* Shouldn't occur - all done through function calls */
3190   wassert (0);
3191 }
3192
3193 /*-----------------------------------------------------------------*/
3194 /* genIfxJump :- will create a jump depending on the ifx           */
3195 /*-----------------------------------------------------------------*/
3196 static void
3197 genIfxJump (iCode * ic, char *jval)
3198 {
3199   symbol *jlbl;
3200   const char *inst;
3201
3202   /* if true label then we jump if condition
3203      supplied is true */
3204   if (IC_TRUE (ic))
3205     {
3206       jlbl = IC_TRUE (ic);
3207       if (!strcmp (jval, "a"))
3208         {
3209           inst = "nz";
3210         }
3211       else if (!strcmp (jval, "c"))
3212         {
3213           inst = "c";
3214         }
3215       else if (!strcmp (jval, "nc"))
3216         {
3217           inst = "nc";
3218         }
3219       else
3220         {
3221           /* The buffer contains the bit on A that we should test */
3222           inst = "nz";
3223         }
3224     }
3225   else
3226     {
3227       /* false label is present */
3228       jlbl = IC_FALSE (ic);
3229       if (!strcmp (jval, "a"))
3230         {
3231           inst = "z";
3232         }
3233       else if (!strcmp (jval, "c"))
3234         {
3235           inst = "nc";
3236         }
3237       else if (!strcmp (jval, "nc"))
3238         {
3239           inst = "c";
3240         }
3241       else
3242         {
3243           /* The buffer contains the bit on A that we should test */
3244           inst = "z";
3245         }
3246     }
3247   /* Z80 can do a conditional long jump */
3248   if (!strcmp (jval, "a"))
3249     {
3250       emit2 ("or a,a");
3251     }
3252   else if (!strcmp (jval, "c"))
3253     {
3254     }
3255   else if (!strcmp (jval, "nc"))
3256     {
3257     }
3258   else
3259     {
3260       emit2 ("bit %s,a", jval);
3261     }
3262   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3263
3264   /* mark the icode as generated */
3265   ic->generated = 1;
3266 }
3267
3268 #if DISABLED
3269 static const char *
3270 _getPairIdName (PAIR_ID id)
3271 {
3272   return _pairs[id].name;
3273 }
3274 #endif
3275
3276 /** Generic compare for > or <
3277  */
3278 static void
3279 genCmp (operand * left, operand * right,
3280         operand * result, iCode * ifx, int sign)
3281 {
3282   int size, offset = 0;
3283   unsigned long lit = 0L;
3284   bool swap_sense = FALSE;
3285
3286   /* if left & right are bit variables */
3287   if (AOP_TYPE (left) == AOP_CRY &&
3288       AOP_TYPE (right) == AOP_CRY)
3289     {
3290       /* Cant happen on the Z80 */
3291       wassert (0);
3292     }
3293   else
3294     {
3295       /* subtract right from left if at the
3296          end the carry flag is set then we know that
3297          left is greater than right */
3298       size = max (AOP_SIZE (left), AOP_SIZE (right));
3299
3300       /* if unsigned char cmp with lit, just compare */
3301       if ((size == 1) &&
3302           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3303         {
3304           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3305           if (sign)
3306             {
3307               emit2 ("xor a,!immedbyte", 0x80);
3308               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3309             }
3310           else
3311             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3312         }
3313       else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3314         {
3315           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3316           // Pull left into DE and right into HL
3317           aopGet (AOP(left), LSB, FALSE);
3318           emit2 ("ld d,h");
3319           emit2 ("ld e,l");
3320           aopGet (AOP(right), LSB, FALSE);
3321
3322           while (size--)
3323             {
3324               if (size == 0 && sign)
3325                 {
3326                   // Highest byte when signed needs the bits flipped
3327                   // Save the flags
3328                   emit2 ("push af");
3329                   emit2 ("ld a,(de)");
3330                   emit2 ("xor #0x80");
3331                   emit2 ("ld e,a");
3332                   emit2 ("ld a,(hl)");
3333                   emit2 ("xor #0x80");
3334                   emit2 ("ld d,a");
3335                   emit2 ("pop af");
3336                   emit2 ("ld a,e");
3337                   emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3338                 }
3339               else
3340                 {
3341                   emit2 ("ld a,(de)");
3342                   emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3343                 }
3344               
3345               if (size != 0)
3346                 {
3347                   emit2 ("inc hl");
3348                   emit2 ("inc de");
3349                 }
3350               offset++;
3351             }
3352           spillPair (PAIR_HL);
3353         }
3354       else
3355         {
3356 #if 0
3357           // PENDING: Doesn't work around zero
3358
3359           /* Special cases:
3360              On the GB:
3361              If the left or the right is a lit:
3362              Load -lit into HL, add to right via, check sense.
3363            */
3364           if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3365             {
3366               PAIR_ID id = PAIR_DE;
3367               asmop *lit = AOP (right);
3368               asmop *op = AOP (left);
3369               swap_sense = TRUE;
3370
3371               if (AOP_TYPE (left) == AOP_LIT)
3372                 {
3373                   swap_sense = FALSE;
3374                   lit = AOP (left);
3375                   op = AOP (right);
3376                 }
3377               if (sign)
3378                 {
3379                   emit2 ("ld e,%s", aopGet (op, 0, 0));
3380                   emit2 ("ld a,%s", aopGet (op, 1, 0));
3381                   emit2 ("xor a,!immedbyte", 0x80);
3382                   emit2 ("ld d,a");
3383                 }
3384               else
3385                 {
3386                   id = getPairId (op);
3387                   if (id == PAIR_INVALID)
3388                     {
3389                       fetchPair (PAIR_DE, op);
3390                       id = PAIR_DE;
3391                     }
3392                 }
3393               spillPair (PAIR_HL);
3394               emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3395               emit2 ("add hl,%s", _getPairIdName (id));
3396               goto release;
3397             }
3398 #endif
3399           if (AOP_TYPE (right) == AOP_LIT)
3400             {
3401               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3402               /* optimize if(x < 0) or if(x >= 0) */
3403               if (lit == 0L)
3404                 {
3405                   if (!sign)
3406                     {
3407                       /* No sign so it's always false */
3408                       _clearCarry();
3409                     }
3410                   else
3411                     {
3412                       /* Just load in the top most bit */
3413                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3414                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3415                         {
3416                           genIfxJump (ifx, "7");
3417                           return;
3418                         }
3419                       else
3420                         emit2 ("rlc a");
3421                     }
3422                   goto release;
3423                 }
3424             }
3425           if (sign)
3426             {
3427               /* First setup h and l contaning the top most bytes XORed */
3428               bool fDidXor = FALSE;
3429               if (AOP_TYPE (left) == AOP_LIT)
3430                 {
3431                   unsigned long lit = (unsigned long)
3432                   floatFromVal (AOP (left)->aopu.aop_lit);
3433                   emit2 ("ld %s,!immedbyte", _fTmp[0],
3434                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3435                 }
3436               else
3437                 {
3438                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3439                   emit2 ("xor a,!immedbyte", 0x80);
3440                   emit2 ("ld %s,a", _fTmp[0]);
3441                   fDidXor = TRUE;
3442                 }
3443               if (AOP_TYPE (right) == AOP_LIT)
3444                 {
3445                   unsigned long lit = (unsigned long)
3446                   floatFromVal (AOP (right)->aopu.aop_lit);
3447                   emit2 ("ld %s,!immedbyte", _fTmp[1],
3448                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3449                 }
3450               else
3451                 {
3452                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3453                   emit2 ("xor a,!immedbyte", 0x80);
3454                   emit2 ("ld %s,a", _fTmp[1]);
3455                   fDidXor = TRUE;
3456                 }
3457             }
3458           while (size--)
3459             {
3460               /* Do a long subtract */
3461               if (!sign || size)
3462                 {
3463                   _moveA (aopGet (AOP (left), offset, FALSE));
3464                 }
3465               if (sign && size == 0)
3466                 {
3467                   emit2 ("ld a,%s", _fTmp[0]);
3468                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3469                 }
3470               else
3471                 {
3472                   /* Subtract through, propagating the carry */
3473                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset++, FALSE));
3474                 }
3475             }
3476         }
3477     }
3478
3479 release:
3480   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3481     {
3482       outBitCLong (result, swap_sense);
3483     }
3484   else
3485     {
3486       /* if the result is used in the next
3487          ifx conditional branch then generate
3488          code a little differently */
3489       if (ifx)
3490         genIfxJump (ifx, swap_sense ? "nc" : "c");
3491       else
3492         outBitCLong (result, swap_sense);
3493       /* leave the result in acc */
3494     }
3495 }
3496
3497 /*-----------------------------------------------------------------*/
3498 /* genCmpGt :- greater than comparison                             */
3499 /*-----------------------------------------------------------------*/
3500 static void
3501 genCmpGt (iCode * ic, iCode * ifx)
3502 {
3503   operand *left, *right, *result;
3504   sym_link *letype, *retype;
3505   int sign;
3506
3507   left = IC_LEFT (ic);
3508   right = IC_RIGHT (ic);
3509   result = IC_RESULT (ic);
3510
3511   letype = getSpec (operandType (left));
3512   retype = getSpec (operandType (right));
3513   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3514   /* assign the amsops */
3515   aopOp (left, ic, FALSE, FALSE);
3516   aopOp (right, ic, FALSE, FALSE);
3517   aopOp (result, ic, TRUE, FALSE);
3518
3519   genCmp (right, left, result, ifx, sign);
3520
3521   freeAsmop (left, NULL, ic);
3522   freeAsmop (right, NULL, ic);
3523   freeAsmop (result, NULL, ic);
3524 }
3525
3526 /*-----------------------------------------------------------------*/
3527 /* genCmpLt - less than comparisons                                */
3528 /*-----------------------------------------------------------------*/
3529 static void
3530 genCmpLt (iCode * ic, iCode * ifx)
3531 {
3532   operand *left, *right, *result;
3533   sym_link *letype, *retype;
3534   int sign;
3535
3536   left = IC_LEFT (ic);
3537   right = IC_RIGHT (ic);
3538   result = IC_RESULT (ic);
3539
3540   letype = getSpec (operandType (left));
3541   retype = getSpec (operandType (right));
3542   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3543
3544   /* assign the amsops */
3545   aopOp (left, ic, FALSE, FALSE);
3546   aopOp (right, ic, FALSE, FALSE);
3547   aopOp (result, ic, TRUE, FALSE);
3548
3549   genCmp (left, right, result, ifx, sign);
3550
3551   freeAsmop (left, NULL, ic);
3552   freeAsmop (right, NULL, ic);
3553   freeAsmop (result, NULL, ic);
3554 }
3555
3556 /*-----------------------------------------------------------------*/
3557 /* gencjneshort - compare and jump if not equal                    */
3558 /*-----------------------------------------------------------------*/
3559 static void
3560 gencjneshort (operand * left, operand * right, symbol * lbl)
3561 {
3562   int size = max (AOP_SIZE (left), AOP_SIZE (right));
3563   int offset = 0;
3564   unsigned long lit = 0L;
3565
3566   /* Swap the left and right if it makes the computation easier */
3567   if (AOP_TYPE (left) == AOP_LIT)
3568     {
3569       operand *t = right;
3570       right = left;
3571       left = t;
3572     }
3573
3574   if (AOP_TYPE (right) == AOP_LIT)
3575     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3576
3577   /* if the right side is a literal then anything goes */
3578   if (AOP_TYPE (right) == AOP_LIT &&
3579       AOP_TYPE (left) != AOP_DIR)
3580     {
3581       if (lit == 0)
3582         {
3583           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3584           if (size > 1)
3585             {
3586               size--;
3587               offset++;
3588               while (size--)
3589                 {
3590                   emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3591                 }
3592             }
3593           else
3594             {
3595               emit2 ("or a,a");
3596             }
3597           emit2 ("jp nz,!tlabel", lbl->key + 100);
3598         }
3599       else
3600         {
3601           while (size--)
3602             {
3603               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3604               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3605                 emit2 ("or a,a");
3606               else
3607                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3608               emit2 ("jp nz,!tlabel", lbl->key + 100);
3609               offset++;
3610             }
3611         }
3612     }
3613   /* if the right side is in a register or in direct space or
3614      if the left is a pointer register & right is not */
3615   else if (AOP_TYPE (right) == AOP_REG ||
3616            AOP_TYPE (right) == AOP_DIR ||
3617            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3618     {
3619       while (size--)
3620         {
3621           _moveA (aopGet (AOP (left), offset, FALSE));
3622           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3623               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3624             /* PENDING */
3625             emit2 ("jp nz,!tlabel", lbl->key + 100);
3626           else
3627             {
3628               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3629               emit2 ("jp nz,!tlabel", lbl->key + 100);
3630             }
3631           offset++;
3632         }
3633     }
3634   else
3635     {
3636       /* right is a pointer reg need both a & b */
3637       /* PENDING: is this required? */
3638       while (size--)
3639         {
3640           _moveA (aopGet (AOP (right), offset, FALSE));
3641           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3642           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3643           offset++;
3644         }
3645     }
3646 }
3647
3648 /*-----------------------------------------------------------------*/
3649 /* gencjne - compare and jump if not equal                         */
3650 /*-----------------------------------------------------------------*/
3651 static void
3652 gencjne (operand * left, operand * right, symbol * lbl)
3653 {
3654   symbol *tlbl = newiTempLabel (NULL);
3655
3656   gencjneshort (left, right, lbl);
3657
3658   /* PENDING: ?? */
3659   emit2 ("ld a,!one");
3660   emit2 ("!shortjp !tlabel", tlbl->key + 100);
3661   emitLabel (lbl->key + 100);
3662   emit2 ("xor a,a");
3663   emitLabel (tlbl->key + 100);
3664 }
3665
3666 /*-----------------------------------------------------------------*/
3667 /* genCmpEq - generates code for equal to                          */
3668 /*-----------------------------------------------------------------*/
3669 static void
3670 genCmpEq (iCode * ic, iCode * ifx)
3671 {
3672   operand *left, *right, *result;
3673
3674   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3675   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3676   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3677
3678   emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3679
3680   /* Swap operands if it makes the operation easier. ie if:
3681      1.  Left is a literal.
3682    */
3683   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3684     {
3685       operand *t = IC_RIGHT (ic);
3686       IC_RIGHT (ic) = IC_LEFT (ic);
3687       IC_LEFT (ic) = t;
3688     }
3689
3690   if (ifx && !AOP_SIZE (result))
3691     {
3692       symbol *tlbl;
3693       /* if they are both bit variables */
3694       if (AOP_TYPE (left) == AOP_CRY &&
3695           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3696         {
3697           wassert (0);
3698         }
3699       else
3700         {
3701           tlbl = newiTempLabel (NULL);
3702           gencjneshort (left, right, tlbl);
3703           if (IC_TRUE (ifx))
3704             {
3705               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3706               emitLabel (tlbl->key + 100);
3707             }
3708           else
3709             {
3710               /* PENDING: do this better */
3711               symbol *lbl = newiTempLabel (NULL);
3712               emit2 ("!shortjp !tlabel", lbl->key + 100);
3713               emitLabel (tlbl->key + 100);
3714               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3715               emitLabel (lbl->key + 100);
3716             }
3717         }
3718       /* mark the icode as generated */
3719       ifx->generated = 1;
3720       goto release;
3721     }
3722
3723   /* if they are both bit variables */
3724   if (AOP_TYPE (left) == AOP_CRY &&
3725       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3726     {
3727       wassert (0);
3728     }
3729   else
3730     {
3731       gencjne (left, right, newiTempLabel (NULL));
3732       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3733         {
3734           wassert (0);
3735         }
3736       if (ifx)
3737         {
3738           genIfxJump (ifx, "a");
3739           goto release;
3740         }
3741       /* if the result is used in an arithmetic operation
3742          then put the result in place */
3743       if (AOP_TYPE (result) != AOP_CRY)
3744         {
3745           outAcc (result);
3746         }
3747       /* leave the result in acc */
3748     }
3749
3750 release:
3751   freeAsmop (left, NULL, ic);
3752   freeAsmop (right, NULL, ic);
3753   freeAsmop (result, NULL, ic);
3754 }
3755
3756 /*-----------------------------------------------------------------*/
3757 /* ifxForOp - returns the icode containing the ifx for operand     */
3758 /*-----------------------------------------------------------------*/
3759 static iCode *
3760 ifxForOp (operand * op, iCode * ic)
3761 {
3762   /* if true symbol then needs to be assigned */
3763   if (IS_TRUE_SYMOP (op))
3764     return NULL;
3765
3766   /* if this has register type condition and
3767      the next instruction is ifx with the same operand
3768      and live to of the operand is upto the ifx only then */
3769   if (ic->next &&
3770       ic->next->op == IFX &&
3771       IC_COND (ic->next)->key == op->key &&
3772       OP_SYMBOL (op)->liveTo <= ic->next->seq)
3773     return ic->next;
3774
3775   return NULL;
3776 }
3777
3778 /*-----------------------------------------------------------------*/
3779 /* genAndOp - for && operation                                     */
3780 /*-----------------------------------------------------------------*/
3781 static void
3782 genAndOp (iCode * ic)
3783 {
3784   operand *left, *right, *result;
3785   symbol *tlbl;
3786
3787   /* note here that && operations that are in an if statement are
3788      taken away by backPatchLabels only those used in arthmetic
3789      operations remain */
3790   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3791   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3792   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3793
3794   /* if both are bit variables */
3795   if (AOP_TYPE (left) == AOP_CRY &&
3796       AOP_TYPE (right) == AOP_CRY)
3797     {
3798       wassert (0);
3799     }
3800   else
3801     {
3802       tlbl = newiTempLabel (NULL);
3803       _toBoolean (left);
3804       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3805       _toBoolean (right);
3806       emitLabel (tlbl->key + 100);
3807       outBitAcc (result);
3808     }
3809
3810   freeAsmop (left, NULL, ic);
3811   freeAsmop (right, NULL, ic);
3812   freeAsmop (result, NULL, ic);
3813 }
3814
3815 /*-----------------------------------------------------------------*/
3816 /* genOrOp - for || operation                                      */
3817 /*-----------------------------------------------------------------*/
3818 static void
3819 genOrOp (iCode * ic)
3820 {
3821   operand *left, *right, *result;
3822   symbol *tlbl;
3823
3824   /* note here that || operations that are in an
3825      if statement are taken away by backPatchLabels
3826      only those used in arthmetic operations remain */
3827   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3828   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3829   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3830
3831   /* if both are bit variables */
3832   if (AOP_TYPE (left) == AOP_CRY &&
3833       AOP_TYPE (right) == AOP_CRY)
3834     {
3835       wassert (0);
3836     }
3837   else
3838     {
3839       tlbl = newiTempLabel (NULL);
3840       _toBoolean (left);
3841       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3842       _toBoolean (right);
3843       emitLabel (tlbl->key + 100);
3844       outBitAcc (result);
3845     }
3846
3847   freeAsmop (left, NULL, ic);
3848   freeAsmop (right, NULL, ic);
3849   freeAsmop (result, NULL, ic);
3850 }
3851
3852 /*-----------------------------------------------------------------*/
3853 /* isLiteralBit - test if lit == 2^n                               */
3854 /*-----------------------------------------------------------------*/
3855 int
3856 isLiteralBit (unsigned long lit)
3857 {
3858   unsigned long pw[32] =
3859   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3860    0x100L, 0x200L, 0x400L, 0x800L,
3861    0x1000L, 0x2000L, 0x4000L, 0x8000L,
3862    0x10000L, 0x20000L, 0x40000L, 0x80000L,
3863    0x100000L, 0x200000L, 0x400000L, 0x800000L,
3864    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3865    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3866   int idx;
3867
3868   for (idx = 0; idx < 32; idx++)
3869     if (lit == pw[idx])
3870       return idx + 1;
3871   return 0;
3872 }
3873
3874 /*-----------------------------------------------------------------*/
3875 /* jmpTrueOrFalse -                                                */
3876 /*-----------------------------------------------------------------*/
3877 static void
3878 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3879 {
3880   // ugly but optimized by peephole
3881   if (IC_TRUE (ic))
3882     {
3883       symbol *nlbl = newiTempLabel (NULL);
3884       emit2 ("jp !tlabel", nlbl->key + 100);
3885       emitLabel (tlbl->key + 100);
3886       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3887       emitLabel (nlbl->key + 100);
3888     }
3889   else
3890     {
3891       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3892       emitLabel (tlbl->key + 100);
3893     }
3894   ic->generated = 1;
3895 }
3896
3897 /*-----------------------------------------------------------------*/
3898 /* genAnd  - code for and                                          */
3899 /*-----------------------------------------------------------------*/
3900 static void
3901 genAnd (iCode * ic, iCode * ifx)
3902 {
3903   operand *left, *right, *result;
3904   int size, offset = 0;
3905   unsigned long lit = 0L;
3906   int bytelit = 0;
3907
3908   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3909   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3910   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3911
3912 #ifdef DEBUG_TYPE
3913   emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3914             AOP_TYPE (result),
3915             AOP_TYPE (left), AOP_TYPE (right));
3916   emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3917             AOP_SIZE (result),
3918             AOP_SIZE (left), AOP_SIZE (right));
3919 #endif
3920
3921   /* if left is a literal & right is not then exchange them */
3922   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3923       AOP_NEEDSACC (left))
3924     {
3925       operand *tmp = right;
3926       right = left;
3927       left = tmp;
3928     }
3929
3930   /* if result = right then exchange them */
3931   if (sameRegs (AOP (result), AOP (right)))
3932     {
3933       operand *tmp = right;
3934       right = left;
3935       left = tmp;
3936     }
3937
3938   /* if right is bit then exchange them */
3939   if (AOP_TYPE (right) == AOP_CRY &&
3940       AOP_TYPE (left) != AOP_CRY)
3941     {
3942       operand *tmp = right;
3943       right = left;
3944       left = tmp;
3945     }
3946   if (AOP_TYPE (right) == AOP_LIT)
3947     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3948
3949   size = AOP_SIZE (result);
3950
3951   if (AOP_TYPE (left) == AOP_CRY)
3952     {
3953       wassert (0);
3954       goto release;
3955     }
3956
3957   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
3958   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
3959   if ((AOP_TYPE (right) == AOP_LIT) &&
3960       (AOP_TYPE (result) == AOP_CRY) &&
3961       (AOP_TYPE (left) != AOP_CRY))
3962     {
3963       int posbit = isLiteralBit (lit);
3964       /* left &  2^n */
3965       if (posbit)
3966         {
3967           posbit--;
3968           _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3969           // bit = left & 2^n
3970           if (size)
3971             {
3972               wassert (0);
3973               emit2 ("mov c,acc.%d", posbit & 0x07);
3974             }
3975           // if(left &  2^n)
3976           else
3977             {
3978               if (ifx)
3979                 {
3980                   sprintf (buffer, "%d", posbit & 0x07);
3981                   genIfxJump (ifx, buffer);
3982                 }
3983               else
3984                 {
3985                   wassert (0);
3986                 }
3987               goto release;
3988             }
3989         }
3990       else
3991         {
3992           symbol *tlbl = newiTempLabel (NULL);
3993           int sizel = AOP_SIZE (left);
3994           if (size)
3995             {
3996               wassert (0);
3997               emit2 ("setb c");
3998             }
3999           while (sizel--)
4000             {
4001               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4002                 {
4003                   _moveA (aopGet (AOP (left), offset, FALSE));
4004                   // byte ==  2^n ?
4005                   if ((posbit = isLiteralBit (bytelit)) != 0)
4006                     {
4007                       wassert (0);
4008                       emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
4009                     }
4010                   else
4011                     {
4012                       if (bytelit != 0x0FFL)
4013                         emit2 ("and a,%s",
4014                                   aopGet (AOP (right), offset, FALSE));
4015                       else
4016                         /* For the flags */
4017                         emit2 ("or a,a");
4018                       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4019                     }
4020                 }
4021               offset++;
4022             }
4023           // bit = left & literal
4024           if (size)
4025             {
4026               emit2 ("clr c");
4027               emit2 ("!tlabeldef", tlbl->key + 100);
4028             }
4029           // if(left & literal)
4030           else
4031             {
4032               if (ifx)
4033                 jmpTrueOrFalse (ifx, tlbl);
4034               goto release;
4035             }
4036         }
4037       outBitC (result);
4038       goto release;
4039     }
4040
4041   /* if left is same as result */
4042   if (sameRegs (AOP (result), AOP (left)))
4043     {
4044       for (; size--; offset++)
4045         {
4046           if (AOP_TYPE (right) == AOP_LIT)
4047             {
4048               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4049                 continue;
4050               else
4051                 {
4052                   if (bytelit == 0)
4053                     aopPut (AOP (result), "!zero", offset);
4054                   else
4055                     {
4056                       _moveA (aopGet (AOP (left), offset, FALSE));
4057                       emit2 ("and a,%s",
4058                                 aopGet (AOP (right), offset, FALSE));
4059                       aopPut (AOP (left), "a", offset);
4060                     }
4061                 }
4062
4063             }
4064           else
4065             {
4066               if (AOP_TYPE (left) == AOP_ACC)
4067                 {
4068                   wassert (0);
4069                 }
4070               else
4071                 {
4072                   _moveA (aopGet (AOP (left), offset, FALSE));
4073                   emit2 ("and a,%s",
4074                             aopGet (AOP (right), offset, FALSE));
4075                   aopPut (AOP (left), "a", offset);
4076                 }
4077             }
4078         }
4079     }
4080   else
4081     {
4082       // left & result in different registers
4083       if (AOP_TYPE (result) == AOP_CRY)
4084         {
4085           wassert (0);
4086         }
4087       else
4088         {
4089           for (; (size--); offset++)
4090             {
4091               // normal case
4092               // result = left & right
4093               if (AOP_TYPE (right) == AOP_LIT)
4094                 {
4095                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4096                     {
4097                       aopPut (AOP (result),
4098                               aopGet (AOP (left), offset, FALSE),
4099                               offset);
4100                       continue;
4101                     }
4102                   else if (bytelit == 0)
4103                     {
4104                       aopPut (AOP (result), "!zero", offset);
4105                       continue;
4106                     }
4107                 }
4108               // faster than result <- left, anl result,right
4109               // and better if result is SFR
4110               if (AOP_TYPE (left) == AOP_ACC)
4111                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4112               else
4113                 {
4114                   _moveA (aopGet (AOP (left), offset, FALSE));
4115                   emit2 ("and a,%s",
4116                             aopGet (AOP (right), offset, FALSE));
4117                 }
4118               aopPut (AOP (result), "a", offset);
4119             }
4120         }
4121
4122     }
4123
4124 release:
4125   freeAsmop (left, NULL, ic);
4126   freeAsmop (right, NULL, ic);
4127   freeAsmop (result, NULL, ic);
4128 }
4129
4130 /*-----------------------------------------------------------------*/
4131 /* genOr  - code for or                                            */
4132 /*-----------------------------------------------------------------*/
4133 static void
4134 genOr (iCode * ic, iCode * ifx)
4135 {
4136   operand *left, *right, *result;
4137   int size, offset = 0;
4138   unsigned long lit = 0L;
4139
4140   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4141   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4142   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4143
4144 #if 1
4145   emitDebug ("; Type res[%d] = l[%d]&r[%d]",
4146             AOP_TYPE (result),
4147             AOP_TYPE (left), AOP_TYPE (right));
4148   emitDebug ("; Size res[%d] = l[%d]&r[%d]",
4149             AOP_SIZE (result),
4150             AOP_SIZE (left), AOP_SIZE (right));
4151 #endif
4152
4153   /* if left is a literal & right is not then exchange them */
4154   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4155       AOP_NEEDSACC (left))
4156     {
4157       operand *tmp = right;
4158       right = left;
4159       left = tmp;
4160     }
4161
4162   /* if result = right then exchange them */
4163   if (sameRegs (AOP (result), AOP (right)))
4164     {
4165       operand *tmp = right;
4166       right = left;
4167       left = tmp;
4168     }
4169
4170   /* if right is bit then exchange them */
4171   if (AOP_TYPE (right) == AOP_CRY &&
4172       AOP_TYPE (left) != AOP_CRY)
4173     {
4174       operand *tmp = right;
4175       right = left;
4176       left = tmp;
4177     }
4178   if (AOP_TYPE (right) == AOP_LIT)
4179     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4180
4181   size = AOP_SIZE (result);
4182
4183   if (AOP_TYPE (left) == AOP_CRY)
4184     {
4185       wassert (0);
4186       goto release;
4187     }
4188
4189   if ((AOP_TYPE (right) == AOP_LIT) &&
4190       (AOP_TYPE (result) == AOP_CRY) &&
4191       (AOP_TYPE (left) != AOP_CRY))
4192     {
4193       wassert (0);
4194       goto release;
4195     }
4196
4197   /* if left is same as result */
4198   if (sameRegs (AOP (result), AOP (left)))
4199     {
4200       for (; size--; offset++)
4201         {
4202           if (AOP_TYPE (right) == AOP_LIT)
4203             {
4204               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4205                 continue;
4206               else
4207                 {
4208                   _moveA (aopGet (AOP (left), offset, FALSE));
4209                   emit2 ("or a,%s",
4210                             aopGet (AOP (right), offset, FALSE));
4211                   aopPut (AOP (result), "a", offset);
4212                 }
4213             }
4214           else
4215             {
4216               if (AOP_TYPE (left) == AOP_ACC)
4217                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4218               else
4219                 {
4220                   _moveA (aopGet (AOP (left), offset, FALSE));
4221                   emit2 ("or a,%s",
4222                             aopGet (AOP (right), offset, FALSE));
4223                   aopPut (AOP (result), "a", offset);
4224                 }
4225             }
4226         }
4227     }
4228   else
4229     {
4230       // left & result in different registers
4231       if (AOP_TYPE (result) == AOP_CRY)
4232         {
4233           wassert (0);
4234         }
4235       else
4236         for (; (size--); offset++)
4237           {
4238             // normal case
4239             // result = left & right
4240             if (AOP_TYPE (right) == AOP_LIT)
4241               {
4242                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4243                   {
4244                     aopPut (AOP (result),
4245                             aopGet (AOP (left), offset, FALSE),
4246                             offset);
4247                     continue;
4248                   }
4249               }
4250             // faster than result <- left, anl result,right
4251             // and better if result is SFR
4252             if (AOP_TYPE (left) == AOP_ACC)
4253               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4254             else
4255               {
4256                 _moveA (aopGet (AOP (left), offset, FALSE));
4257                 emit2 ("or a,%s",
4258                           aopGet (AOP (right), offset, FALSE));
4259               }
4260             aopPut (AOP (result), "a", offset);
4261             /* PENDING: something weird is going on here.  Add exception. */
4262             if (AOP_TYPE (result) == AOP_ACC)
4263               break;
4264           }
4265     }
4266
4267 release:
4268   freeAsmop (left, NULL, ic);
4269   freeAsmop (right, NULL, ic);
4270   freeAsmop (result, NULL, ic);
4271 }
4272
4273 /*-----------------------------------------------------------------*/
4274 /* genXor - code for xclusive or                                   */
4275 /*-----------------------------------------------------------------*/
4276 static void
4277 genXor (iCode * ic, iCode * ifx)
4278 {
4279   operand *left, *right, *result;
4280   int size, offset = 0;
4281   unsigned long lit = 0L;
4282
4283   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4284   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4285   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4286
4287   /* if left is a literal & right is not then exchange them */
4288   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4289       AOP_NEEDSACC (left))
4290     {
4291       operand *tmp = right;
4292       right = left;
4293       left = tmp;
4294     }
4295
4296   /* if result = right then exchange them */
4297   if (sameRegs (AOP (result), AOP (right)))
4298     {
4299       operand *tmp = right;
4300       right = left;
4301       left = tmp;
4302     }
4303
4304   /* if right is bit then exchange them */
4305   if (AOP_TYPE (right) == AOP_CRY &&
4306       AOP_TYPE (left) != AOP_CRY)
4307     {
4308       operand *tmp = right;
4309       right = left;
4310       left = tmp;
4311     }
4312   if (AOP_TYPE (right) == AOP_LIT)
4313     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4314
4315   size = AOP_SIZE (result);
4316
4317   if (AOP_TYPE (left) == AOP_CRY)
4318     {
4319       wassert (0);
4320       goto release;
4321     }
4322
4323   if ((AOP_TYPE (right) == AOP_LIT) &&
4324       (AOP_TYPE (result) == AOP_CRY) &&
4325       (AOP_TYPE (left) != AOP_CRY))
4326     {
4327       wassert (0);
4328       goto release;
4329     }
4330
4331   /* if left is same as result */
4332   if (sameRegs (AOP (result), AOP (left)))
4333     {
4334       for (; size--; offset++)
4335         {
4336           if (AOP_TYPE (right) == AOP_LIT)
4337             {
4338               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4339                 continue;
4340               else
4341                 {
4342                   _moveA (aopGet (AOP (right), offset, FALSE));
4343                   emit2 ("xor a,%s",
4344                             aopGet (AOP (left), offset, FALSE));
4345                   aopPut (AOP (result), "a", offset);
4346                 }
4347             }
4348           else
4349             {
4350               if (AOP_TYPE (left) == AOP_ACC)
4351                 {
4352                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4353                 }
4354               else
4355                 {
4356                   _moveA (aopGet (AOP (right), offset, FALSE));
4357                   emit2 ("xor a,%s",
4358                             aopGet (AOP (left), offset, FALSE));
4359                   aopPut (AOP (result), "a", 0);
4360                 }
4361             }
4362         }
4363     }
4364   else
4365     {
4366       // left & result in different registers
4367       if (AOP_TYPE (result) == AOP_CRY)
4368         {
4369           wassert (0);
4370         }
4371       else
4372         for (; (size--); offset++)
4373           {
4374             // normal case
4375             // result = left & right
4376             if (AOP_TYPE (right) == AOP_LIT)
4377               {
4378                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4379                   {
4380                     aopPut (AOP (result),
4381                             aopGet (AOP (left), offset, FALSE),
4382                             offset);
4383                     continue;
4384                   }
4385               }
4386             // faster than result <- left, anl result,right
4387             // and better if result is SFR
4388             if (AOP_TYPE (left) == AOP_ACC) 
4389               {
4390                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4391               }
4392             else
4393               {
4394                 _moveA (aopGet (AOP (right), offset, FALSE));
4395                 emit2 ("xor a,%s",
4396                           aopGet (AOP (left), offset, FALSE));
4397               }
4398             aopPut (AOP (result), "a", offset);
4399           }
4400     }
4401
4402 release:
4403   freeAsmop (left, NULL, ic);
4404   freeAsmop (right, NULL, ic);
4405   freeAsmop (result, NULL, ic);
4406 }
4407
4408 /*-----------------------------------------------------------------*/
4409 /* genInline - write the inline code out                           */
4410 /*-----------------------------------------------------------------*/
4411 static void
4412 genInline (iCode * ic)
4413 {
4414   char *buffer, *bp, *bp1;
4415
4416   _G.lines.isInline += (!options.asmpeep);
4417
4418   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4419   strcpy (buffer, IC_INLINE (ic));
4420
4421   /* emit each line as a code */
4422   while (*bp)
4423     {
4424       if (*bp == '\n')
4425         {
4426           *bp++ = '\0';
4427           emit2 (bp1);
4428           bp1 = bp;
4429         }
4430       else
4431         {
4432           if (*bp == ':')
4433             {
4434               bp++;
4435               *bp = '\0';
4436               bp++;
4437               emit2 (bp1);
4438               bp1 = bp;
4439             }
4440           else
4441             bp++;
4442         }
4443     }
4444   if (bp1 != bp)
4445     emit2 (bp1);
4446   _G.lines.isInline -= (!options.asmpeep);
4447
4448 }
4449
4450 /*-----------------------------------------------------------------*/
4451 /* genRRC - rotate right with carry                                */
4452 /*-----------------------------------------------------------------*/
4453 static void
4454 genRRC (iCode * ic)
4455 {
4456   wassert (0);
4457 }
4458
4459 /*-----------------------------------------------------------------*/
4460 /* genRLC - generate code for rotate left with carry               */
4461 /*-----------------------------------------------------------------*/
4462 static void
4463 genRLC (iCode * ic)
4464 {
4465   wassert (0);
4466 }
4467
4468 /*-----------------------------------------------------------------*/
4469 /* genGetHbit - generates code get highest order bit               */
4470 /*-----------------------------------------------------------------*/
4471 static void
4472 genGetHbit (iCode * ic)
4473 {
4474   operand *left, *result;
4475   left = IC_LEFT (ic);
4476   result = IC_RESULT (ic);
4477   aopOp (left, ic, FALSE, FALSE);
4478   aopOp (result, ic, FALSE, FALSE);
4479
4480   /* get the highest order byte into a */
4481   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4482
4483   if (AOP_TYPE (result) == AOP_CRY)
4484     {
4485       emit2 ("rl a");
4486       outBitC (result);
4487     }
4488   else
4489     {
4490       emit2 ("rlc a");
4491       /* PENDING: For re-target. */
4492       emit2 ("and a,#1");
4493       outAcc (result);
4494     }
4495
4496
4497   freeAsmop (left, NULL, ic);
4498   freeAsmop (result, NULL, ic);
4499 }
4500
4501 static void
4502 emitRsh2 (asmop *aop, int size, int is_signed)
4503 {
4504   int offset = 0;
4505
4506   while (size--)
4507     {
4508       const char *l = aopGet (aop, size, FALSE);
4509       if (offset == 0)
4510         {
4511           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4512         }
4513       else
4514         {
4515           emit2 ("rr %s", l);
4516         }
4517       offset++;
4518     }
4519 }
4520
4521 /*-----------------------------------------------------------------*/
4522 /* shiftR2Left2Result - shift right two bytes from left to result  */
4523 /*-----------------------------------------------------------------*/
4524 static void
4525 shiftR2Left2Result (operand * left, int offl,
4526                     operand * result, int offr,
4527                     int shCount, int is_signed)
4528 {
4529   int size = 2;
4530   symbol *tlbl, *tlbl1;
4531
4532   movLeft2Result (left, offl, result, offr, 0);
4533   movLeft2Result (left, offl + 1, result, offr + 1, 0);
4534
4535   /*  if (AOP(result)->type == AOP_REG) { */
4536   
4537   tlbl = newiTempLabel (NULL);
4538   tlbl1 = newiTempLabel (NULL);
4539
4540   /* Left is already in result - so now do the shift */
4541   if (shCount <= 2)
4542     {
4543       while (shCount--)
4544         {
4545           emitRsh2 (AOP (result), size, is_signed);
4546         }
4547     }
4548   else
4549     {
4550       emit2 ("ld a,!immedbyte+1", shCount);
4551       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4552       emitLabel (tlbl->key + 100);
4553
4554       emitRsh2 (AOP (result), size, is_signed);
4555
4556       emitLabel (tlbl1->key + 100);
4557       emit2 ("dec a");
4558       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4559     }
4560 }
4561
4562 /*-----------------------------------------------------------------*/
4563 /* shiftL2Left2Result - shift left two bytes from left to result   */
4564 /*-----------------------------------------------------------------*/
4565 static void
4566 shiftL2Left2Result (operand * left, int offl,
4567                     operand * result, int offr, int shCount)
4568 {
4569   if (sameRegs (AOP (result), AOP (left)) &&
4570       ((offl + MSB16) == offr))
4571     {
4572       wassert (0);
4573     }
4574   else
4575     {
4576       /* Copy left into result */
4577       movLeft2Result (left, offl, result, offr, 0);
4578       movLeft2Result (left, offl + 1, result, offr + 1, 0);
4579     }
4580   /* PENDING: for now just see if it'll work. */
4581   /*if (AOP(result)->type == AOP_REG) { */
4582   {
4583     int size = 2;
4584     int offset = 0;
4585     symbol *tlbl, *tlbl1;
4586     const char *l;
4587
4588     tlbl = newiTempLabel (NULL);
4589     tlbl1 = newiTempLabel (NULL);
4590
4591     /* Left is already in result - so now do the shift */
4592     if (shCount > 1)
4593       {
4594         emit2 ("ld a,!immedbyte+1", shCount);
4595         emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4596         emitLabel (tlbl->key + 100);
4597       }
4598
4599     while (size--)
4600       {
4601         l = aopGet (AOP (result), offset, FALSE);
4602
4603         if (offset == 0)
4604           {
4605             emit2 ("sla %s", l);
4606           }
4607         else
4608           {
4609             emit2 ("rl %s", l);
4610           }
4611
4612         offset++;
4613       }
4614     if (shCount > 1)
4615       {
4616         emitLabel (tlbl1->key + 100);
4617         emit2 ("dec a");
4618         emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4619       }
4620   }
4621 }
4622
4623 /*-----------------------------------------------------------------*/
4624 /* AccRol - rotate left accumulator by known count                 */
4625 /*-----------------------------------------------------------------*/
4626 static void
4627 AccRol (int shCount)
4628 {
4629   shCount &= 0x0007;            // shCount : 0..7
4630
4631   switch (shCount)
4632     {
4633     case 0:
4634       break;
4635     case 1:
4636       emit2 ("sla a");
4637       break;
4638     case 2:
4639       emit2 ("sla a");
4640       emit2 ("rl a");
4641       break;
4642     case 3:
4643       emit2 ("sla a");
4644       emit2 ("rl a");
4645       emit2 ("rl a");
4646       break;
4647     case 4:
4648       emit2 ("sla a");
4649       emit2 ("rl a");
4650       emit2 ("rl a");
4651       emit2 ("rl a");
4652       break;
4653     case 5:
4654       emit2 ("srl a");
4655       emit2 ("rr a");
4656       emit2 ("rr a");
4657       break;
4658     case 6:
4659       emit2 ("srl a");
4660       emit2 ("rr a");
4661       break;
4662     case 7:
4663       emit2 ("srl a");
4664       break;
4665     }
4666 }
4667
4668 /*-----------------------------------------------------------------*/
4669 /* AccLsh - left shift accumulator by known count                  */
4670 /*-----------------------------------------------------------------*/
4671 static void
4672 AccLsh (int shCount)
4673 {
4674   static const unsigned char SLMask[] =
4675     {
4676       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4677     };
4678
4679   if (shCount != 0)
4680     {
4681       if (shCount == 1)
4682         {
4683           emit2 ("add a,a");
4684         }
4685       else if (shCount == 2)
4686         {
4687           emit2 ("add a,a");
4688           emit2 ("add a,a");
4689         }
4690       else
4691         {
4692           /* rotate left accumulator */
4693           AccRol (shCount);
4694           /* and kill the lower order bits */
4695           emit2 ("and a,!immedbyte", SLMask[shCount]);
4696         }
4697     }
4698 }
4699
4700 /*-----------------------------------------------------------------*/
4701 /* shiftL1Left2Result - shift left one byte from left to result    */
4702 /*-----------------------------------------------------------------*/
4703 static void
4704 shiftL1Left2Result (operand * left, int offl,
4705                     operand * result, int offr, int shCount)
4706 {
4707   const char *l;
4708   l = aopGet (AOP (left), offl, FALSE);
4709   _moveA (l);
4710   /* shift left accumulator */
4711   AccLsh (shCount);
4712   aopPut (AOP (result), "a", offr);
4713 }
4714
4715
4716 /*-----------------------------------------------------------------*/
4717 /* genlshTwo - left shift two bytes by known amount != 0           */
4718 /*-----------------------------------------------------------------*/
4719 static void
4720 genlshTwo (operand * result, operand * left, int shCount)
4721 {
4722   int size = AOP_SIZE (result);
4723
4724   wassert (size == 2);
4725
4726   /* if shCount >= 8 */
4727   if (shCount >= 8)
4728     {
4729       shCount -= 8;
4730       if (size > 1)
4731         {
4732           if (shCount)
4733             {
4734               movLeft2Result (left, LSB, result, MSB16, 0);
4735               aopPut (AOP (result), "!zero", 0);
4736               shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4737             }
4738           else
4739             {
4740               movLeft2Result (left, LSB, result, MSB16, 0);
4741               aopPut (AOP (result), "!zero", 0);
4742             }
4743         }
4744       else
4745         {
4746           aopPut (AOP (result), "!zero", LSB);
4747         }
4748     }
4749   /*  1 <= shCount <= 7 */
4750   else
4751     {
4752       if (size == 1)
4753         {
4754           wassert (0);
4755         }
4756       else
4757         {
4758           shiftL2Left2Result (left, LSB, result, LSB, shCount);
4759         }
4760     }
4761 }
4762
4763 /*-----------------------------------------------------------------*/
4764 /* genlshOne - left shift a one byte quantity by known count       */
4765 /*-----------------------------------------------------------------*/
4766 static void
4767 genlshOne (operand * result, operand * left, int shCount)
4768 {
4769   shiftL1Left2Result (left, LSB, result, LSB, shCount);
4770 }
4771
4772 /*-----------------------------------------------------------------*/
4773 /* genLeftShiftLiteral - left shifting by known count              */
4774 /*-----------------------------------------------------------------*/
4775 static void
4776 genLeftShiftLiteral (operand * left,
4777                      operand * right,
4778                      operand * result,
4779                      iCode * ic)
4780 {
4781   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4782   int size;
4783
4784   freeAsmop (right, NULL, ic);
4785
4786   aopOp (left, ic, FALSE, FALSE);
4787   aopOp (result, ic, FALSE, FALSE);
4788
4789   size = getSize (operandType (result));
4790
4791 #if VIEW_SIZE
4792   emitDebug ("; shift left  result %d, left %d", size,
4793             AOP_SIZE (left));
4794 #endif
4795
4796   /* I suppose that the left size >= result size */
4797   if (shCount == 0)
4798     {
4799       wassert (0);
4800     }
4801
4802   else if (shCount >= (size * 8)) 
4803     {
4804       while (size--)
4805         {
4806           aopPut (AOP (result), "!zero", size);
4807         }
4808     }
4809   else
4810     {
4811       switch (size)
4812         {
4813         case 1:
4814           genlshOne (result, left, shCount);
4815           break;
4816         case 2:
4817           genlshTwo (result, left, shCount);
4818           break;
4819         case 4:
4820           wassertl (0, "Shifting of longs is currently unsupported");
4821           break;
4822         default:
4823           wassert (0);
4824         }
4825     }
4826   freeAsmop (left, NULL, ic);
4827   freeAsmop (result, NULL, ic);
4828 }
4829
4830 /*-----------------------------------------------------------------*/
4831 /* genLeftShift - generates code for left shifting                 */
4832 /*-----------------------------------------------------------------*/
4833 static void
4834 genLeftShift (iCode * ic)
4835 {
4836   int size, offset;
4837   const char *l;
4838   symbol *tlbl, *tlbl1;
4839   operand *left, *right, *result;
4840
4841   right = IC_RIGHT (ic);
4842   left = IC_LEFT (ic);
4843   result = IC_RESULT (ic);
4844
4845   aopOp (right, ic, FALSE, FALSE);
4846
4847   /* if the shift count is known then do it
4848      as efficiently as possible */
4849   if (AOP_TYPE (right) == AOP_LIT)
4850     {
4851       genLeftShiftLiteral (left, right, result, ic);
4852       return;
4853     }
4854
4855   /* shift count is unknown then we have to form a loop get the loop
4856      count in B : Note: we take only the lower order byte since
4857      shifting more that 32 bits make no sense anyway, ( the largest
4858      size of an object can be only 32 bits ) */
4859   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4860   emit2 ("inc a");
4861   freeAsmop (right, NULL, ic);
4862   aopOp (left, ic, FALSE, FALSE);
4863   aopOp (result, ic, FALSE, FALSE);
4864
4865   /* now move the left to the result if they are not the
4866      same */
4867 #if 1
4868   if (!sameRegs (AOP (left), AOP (result)))
4869     {
4870
4871       size = AOP_SIZE (result);
4872       offset = 0;
4873       while (size--)
4874         {
4875           l = aopGet (AOP (left), offset, FALSE);
4876           aopPut (AOP (result), l, offset);
4877           offset++;
4878         }
4879     }
4880 #else
4881   size = AOP_SIZE (result);
4882   offset = 0;
4883   while (size--)
4884     {
4885       l = aopGet (AOP (left), offset, FALSE);
4886       aopPut (AOP (result), l, offset);
4887       offset++;
4888     }
4889 #endif
4890
4891
4892   tlbl = newiTempLabel (NULL);
4893   size = AOP_SIZE (result);
4894   offset = 0;
4895   tlbl1 = newiTempLabel (NULL);
4896
4897   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4898   emitLabel (tlbl->key + 100);
4899   l = aopGet (AOP (result), offset, FALSE);
4900
4901   while (size--)
4902     {
4903       l = aopGet (AOP (result), offset, FALSE);
4904
4905       if (offset == 0)
4906         {
4907           emit2 ("sla %s", l);
4908         }
4909       else
4910         {
4911           emit2 ("rl %s", l);
4912         }
4913       offset++;
4914     }
4915   emitLabel (tlbl1->key + 100);
4916   emit2 ("dec a");
4917   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4918
4919   freeAsmop (left, NULL, ic);
4920   freeAsmop (result, NULL, ic);
4921 }
4922
4923 /*-----------------------------------------------------------------*/
4924 /* genrshOne - left shift two bytes by known amount != 0           */
4925 /*-----------------------------------------------------------------*/
4926 static void
4927 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4928 {
4929   /* Errk */
4930   int size = AOP_SIZE (result);
4931   const char *l;
4932
4933   wassert (size == 1);
4934   wassert (shCount < 8);
4935
4936   l = aopGet (AOP (left), 0, FALSE);
4937
4938   emit2 ("or a,a");
4939
4940   if (AOP (result)->type == AOP_REG)
4941     {
4942       aopPut (AOP (result), l, 0);
4943       l = aopGet (AOP (result), 0, FALSE);
4944       while (shCount--)
4945         {
4946           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4947         }
4948     }
4949   else
4950     {
4951       _moveA (l);
4952       while (shCount--)
4953         {
4954           emit2 ("%s a", is_signed ? "sra" : "srl");
4955         }
4956       aopPut (AOP (result), "a", 0);
4957     }
4958 }
4959
4960 /*-----------------------------------------------------------------*/
4961 /* AccRsh - right shift accumulator by known count                 */
4962 /*-----------------------------------------------------------------*/
4963 static void
4964 AccRsh (int shCount)
4965 {
4966   static const unsigned char SRMask[] =
4967     {
4968       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4969     };
4970
4971   if (shCount != 0)
4972     {
4973       /* rotate right accumulator */
4974       AccRol (8 - shCount);
4975       /* and kill the higher order bits */
4976       emit2 ("and a,!immedbyte", SRMask[shCount]);
4977     }
4978 }
4979
4980 /*-----------------------------------------------------------------*/
4981 /* shiftR1Left2Result - shift right one byte from left to result   */
4982 /*-----------------------------------------------------------------*/
4983 static void
4984 shiftR1Left2Result (operand * left, int offl,
4985                     operand * result, int offr,
4986                     int shCount, int sign)
4987 {
4988   _moveA (aopGet (AOP (left), offl, FALSE));
4989   if (sign)
4990     {
4991       wassert (0);
4992     }
4993   else
4994     {
4995       AccRsh (shCount);
4996     }
4997   aopPut (AOP (result), "a", offr);
4998 }
4999
5000 /*-----------------------------------------------------------------*/
5001 /* genrshTwo - right shift two bytes by known amount != 0          */
5002 /*-----------------------------------------------------------------*/
5003 static void
5004 genrshTwo (operand * result, operand * left,
5005            int shCount, int sign)
5006 {
5007   /* if shCount >= 8 */
5008   if (shCount >= 8)
5009     {
5010       shCount -= 8;
5011       if (shCount)
5012         {
5013           shiftR1Left2Result (left, MSB16, result, LSB,
5014                               shCount, sign);
5015         }
5016       else
5017         {
5018           movLeft2Result (left, MSB16, result, LSB, sign);
5019         }
5020       aopPut (AOP (result), "!zero", 1);
5021     }
5022   /*  1 <= shCount <= 7 */
5023   else
5024     {
5025       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5026     }
5027 }
5028
5029 /*-----------------------------------------------------------------*/
5030 /* genRightShiftLiteral - left shifting by known count              */
5031 /*-----------------------------------------------------------------*/
5032 static void
5033 genRightShiftLiteral (operand * left,
5034                       operand * right,
5035                       operand * result,
5036                       iCode * ic,
5037                       int sign)
5038 {
5039   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5040   int size;
5041
5042   freeAsmop (right, NULL, ic);
5043
5044   aopOp (left, ic, FALSE, FALSE);
5045   aopOp (result, ic, FALSE, FALSE);
5046
5047   size = getSize (operandType (result));
5048
5049   emitDebug ("; shift right  result %d, left %d", size,
5050             AOP_SIZE (left));
5051
5052   /* I suppose that the left size >= result size */
5053   if (shCount == 0)
5054     {
5055       wassert (0);
5056     }
5057
5058   else if (shCount >= (size * 8))
5059     while (size--)
5060       aopPut (AOP (result), "!zero", size);
5061   else
5062     {
5063       switch (size)
5064         {
5065         case 1:
5066           genrshOne (result, left, shCount, sign);
5067           break;
5068         case 2:
5069           /* PENDING: sign support */
5070           genrshTwo (result, left, shCount, sign);
5071           break;
5072         case 4:
5073           wassertl (0, "Asked to shift right a long which should be a function call");
5074           break;
5075         default:
5076           wassertl (0, "Entered default case in right shift delegate");
5077         }
5078     }
5079   freeAsmop (left, NULL, ic);
5080   freeAsmop (result, NULL, ic);
5081 }
5082
5083 /*-----------------------------------------------------------------*/
5084 /* genRightShift - generate code for right shifting                */
5085 /*-----------------------------------------------------------------*/
5086 static void
5087 genRightShift (iCode * ic)
5088 {
5089   operand *right, *left, *result;
5090   sym_link *retype;
5091   int size, offset, first = 1;
5092   const char *l;
5093   bool is_signed;
5094
5095   symbol *tlbl, *tlbl1;
5096
5097   /* if signed then we do it the hard way preserve the
5098      sign bit moving it inwards */
5099   retype = getSpec (operandType (IC_RESULT (ic)));
5100
5101   is_signed = !SPEC_USIGN (retype);
5102
5103   /* signed & unsigned types are treated the same : i.e. the
5104      signed is NOT propagated inwards : quoting from the
5105      ANSI - standard : "for E1 >> E2, is equivalent to division
5106      by 2**E2 if unsigned or if it has a non-negative value,
5107      otherwise the result is implementation defined ", MY definition
5108      is that the sign does not get propagated */
5109
5110   right = IC_RIGHT (ic);
5111   left = IC_LEFT (ic);
5112   result = IC_RESULT (ic);
5113
5114   aopOp (right, ic, FALSE, FALSE);
5115
5116   /* if the shift count is known then do it
5117      as efficiently as possible */
5118   if (AOP_TYPE (right) == AOP_LIT)
5119     {
5120       genRightShiftLiteral (left, right, result, ic, is_signed);
5121       return;
5122     }
5123
5124   aopOp (left, ic, FALSE, FALSE);
5125   aopOp (result, ic, FALSE, FALSE);
5126
5127   /* now move the left to the result if they are not the
5128      same */
5129   if (!sameRegs (AOP (left), AOP (result)) &&
5130       AOP_SIZE (result) > 1)
5131     {
5132
5133       size = AOP_SIZE (result);
5134       offset = 0;
5135       while (size--)
5136         {
5137           l = aopGet (AOP (left), offset, FALSE);
5138           aopPut (AOP (result), l, offset);
5139           offset++;
5140         }
5141     }
5142
5143   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5144   emit2 ("inc a");
5145   freeAsmop (right, NULL, ic);
5146
5147   tlbl = newiTempLabel (NULL);
5148   tlbl1 = newiTempLabel (NULL);
5149   size = AOP_SIZE (result);
5150   offset = size - 1;
5151
5152   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5153   emitLabel (tlbl->key + 100);
5154   while (size--)
5155     {
5156       l = aopGet (AOP (result), offset--, FALSE);
5157       if (first)
5158         {
5159           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5160           first = 0;
5161         }
5162       else
5163         {
5164           emit2 ("rr %s", l);
5165         }
5166     }
5167   emitLabel (tlbl1->key + 100);
5168   emit2 ("dec a");
5169   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5170
5171   freeAsmop (left, NULL, ic);
5172   freeAsmop (result, NULL, ic);
5173 }
5174
5175 /*-----------------------------------------------------------------*/
5176 /* genGenPointerGet -  get value from generic pointer space        */
5177 /*-----------------------------------------------------------------*/
5178 static void
5179 genGenPointerGet (operand * left,
5180                   operand * result, iCode * ic)
5181 {
5182   int size, offset;
5183   sym_link *retype = getSpec (operandType (result));
5184   int pair = PAIR_HL;
5185
5186   if (IS_GB)
5187     pair = PAIR_DE;
5188
5189   aopOp (left, ic, FALSE, FALSE);
5190   aopOp (result, ic, FALSE, FALSE);
5191
5192   if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5193     {
5194       /* Just do it */
5195       if (isPtrPair (AOP (left)))
5196         {
5197           tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5198           aopPut (AOP (result), buffer, 0);
5199         }
5200       else
5201         {
5202           emit2 ("ld a,!*pair", getPairName (AOP (left)));
5203           aopPut (AOP (result), "a", 0);
5204         }
5205       freeAsmop (left, NULL, ic);
5206       goto release;
5207     }
5208
5209   /* For now we always load into IY */
5210   /* if this is remateriazable */
5211   fetchPair (pair, AOP (left));
5212
5213   /* so iy now contains the address */
5214   freeAsmop (left, NULL, ic);
5215
5216   /* if bit then unpack */
5217   if (IS_BITVAR (retype))
5218     {
5219       wassert (0);
5220     }
5221   else
5222     {
5223       size = AOP_SIZE (result);
5224       offset = 0;
5225
5226       while (size--)
5227         {
5228           /* PENDING: make this better */
5229           if (!IS_GB && AOP (result)->type == AOP_REG)
5230             {
5231               aopPut (AOP (result), "!*hl", offset++);
5232             }
5233           else
5234             {
5235               emit2 ("ld a,!*pair", _pairs[pair].name);
5236               aopPut (AOP (result), "a", offset++);
5237             }
5238           if (size)
5239             {
5240               emit2 ("inc %s", _pairs[pair].name);
5241               _G.pairs[pair].offset++;
5242             }
5243         }
5244     }
5245
5246 release:
5247   freeAsmop (result, NULL, ic);
5248 }
5249
5250 /*-----------------------------------------------------------------*/
5251 /* genPointerGet - generate code for pointer get                   */
5252 /*-----------------------------------------------------------------*/
5253 static void
5254 genPointerGet (iCode * ic)
5255 {
5256   operand *left, *result;
5257   sym_link *type, *etype;
5258
5259   left = IC_LEFT (ic);
5260   result = IC_RESULT (ic);
5261
5262   /* depending on the type of pointer we need to
5263      move it to the correct pointer register */
5264   type = operandType (left);
5265   etype = getSpec (type);
5266
5267   genGenPointerGet (left, result, ic);
5268 }
5269
5270 bool
5271 isRegOrLit (asmop * aop)
5272 {
5273   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5274     return TRUE;
5275   return FALSE;
5276 }
5277
5278 /*-----------------------------------------------------------------*/
5279 /* genGenPointerSet - stores the value into a pointer location        */
5280 /*-----------------------------------------------------------------*/
5281 static void
5282 genGenPointerSet (operand * right,
5283                   operand * result, iCode * ic)
5284 {
5285   int size, offset;
5286   sym_link *retype = getSpec (operandType (right));
5287   PAIR_ID pairId = PAIR_HL;
5288
5289   aopOp (result, ic, FALSE, FALSE);
5290   aopOp (right, ic, FALSE, FALSE);
5291
5292   if (IS_GB)
5293     pairId = PAIR_DE;
5294
5295   /* Handle the exceptions first */
5296   if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5297     {
5298       /* Just do it */
5299       const char *l = aopGet (AOP (right), 0, FALSE);
5300       const char *pair = getPairName (AOP (result));
5301       if (canAssignToPtr (l) && isPtr (pair))
5302         {
5303           emit2 ("ld !*pair,%s", pair, l);
5304         }
5305       else
5306         {
5307           _moveA (l);
5308           emit2 ("ld !*pair,a", pair);
5309         }
5310       goto release;
5311     }
5312
5313   /* if the operand is already in dptr
5314      then we do nothing else we move the value to dptr */
5315   if (AOP_TYPE (result) != AOP_STR)
5316     {
5317       fetchPair (pairId, AOP (result));
5318     }
5319   /* so hl know contains the address */
5320   freeAsmop (result, NULL, ic);
5321
5322   /* if bit then unpack */
5323   if (IS_BITVAR (retype))
5324     {
5325       wassert (0);
5326     }
5327   else
5328     {
5329       size = AOP_SIZE (right);
5330       offset = 0;
5331
5332       while (size--)
5333         {
5334           const char *l = aopGet (AOP (right), offset, FALSE);
5335           if (isRegOrLit (AOP (right)) && !IS_GB)
5336             {
5337               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5338             }
5339           else
5340             {
5341               _moveA (l);
5342               emit2 ("ld !*pair,a", _pairs[pairId].name);
5343             }
5344           if (size)
5345             {
5346               emit2 ("inc %s", _pairs[pairId].name);
5347               _G.pairs[pairId].offset++;
5348             }
5349           offset++;
5350         }
5351     }
5352 release:
5353   freeAsmop (right, NULL, ic);
5354 }
5355
5356 /*-----------------------------------------------------------------*/
5357 /* genPointerSet - stores the value into a pointer location        */
5358 /*-----------------------------------------------------------------*/
5359 static void
5360 genPointerSet (iCode * ic)
5361 {
5362   operand *right, *result;
5363   sym_link *type, *etype;
5364
5365   right = IC_RIGHT (ic);
5366   result = IC_RESULT (ic);
5367
5368   /* depending on the type of pointer we need to
5369      move it to the correct pointer register */
5370   type = operandType (result);
5371   etype = getSpec (type);
5372
5373   genGenPointerSet (right, result, ic);
5374 }
5375
5376 /*-----------------------------------------------------------------*/
5377 /* genIfx - generate code for Ifx statement                        */
5378 /*-----------------------------------------------------------------*/
5379 static void
5380 genIfx (iCode * ic, iCode * popIc)
5381 {
5382   operand *cond = IC_COND (ic);
5383   int isbit = 0;
5384
5385   aopOp (cond, ic, FALSE, TRUE);
5386
5387   /* get the value into acc */
5388   if (AOP_TYPE (cond) != AOP_CRY)
5389     _toBoolean (cond);
5390   else
5391     isbit = 1;
5392   /* the result is now in the accumulator */
5393   freeAsmop (cond, NULL, ic);
5394
5395   /* if there was something to be popped then do it */
5396   if (popIc)
5397     genIpop (popIc);
5398
5399   /* if the condition is  a bit variable */
5400   if (isbit && IS_ITEMP (cond) &&
5401       SPIL_LOC (cond))
5402     genIfxJump (ic, SPIL_LOC (cond)->rname);
5403   else if (isbit && !IS_ITEMP (cond))
5404     genIfxJump (ic, OP_SYMBOL (cond)->rname);
5405   else
5406     genIfxJump (ic, "a");
5407
5408   ic->generated = 1;
5409 }
5410
5411 /*-----------------------------------------------------------------*/
5412 /* genAddrOf - generates code for address of                       */
5413 /*-----------------------------------------------------------------*/
5414 static void
5415 genAddrOf (iCode * ic)
5416 {
5417   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5418
5419   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5420
5421   /* if the operand is on the stack then we
5422      need to get the stack offset of this
5423      variable */
5424   if (IS_GB)
5425     {
5426       if (sym->onStack)
5427         {
5428           spillCached ();
5429           if (sym->stack <= 0)
5430             {
5431               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5432             }
5433           else
5434             {
5435               emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5436             }
5437           emit2 ("ld d,h");
5438           emit2 ("ld e,l");
5439         }
5440       else
5441         {
5442           emit2 ("ld de,!hashedstr", sym->rname);
5443         }
5444       aopPut (AOP (IC_RESULT (ic)), "e", 0);
5445       aopPut (AOP (IC_RESULT (ic)), "d", 1);
5446     }
5447   else
5448     {
5449       spillCached ();
5450       if (sym->onStack)
5451         {
5452           /* if it has an offset  then we need to compute it */
5453           if (sym->stack > 0)
5454             emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5455           else
5456             emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5457           emit2 ("add hl,sp");
5458         }
5459       else
5460         {
5461           emit2 ("ld hl,#%s", sym->rname);
5462         }
5463       aopPut (AOP (IC_RESULT (ic)), "l", 0);
5464       aopPut (AOP (IC_RESULT (ic)), "h", 1);
5465     }
5466   freeAsmop (IC_RESULT (ic), NULL, ic);
5467 }
5468
5469 /*-----------------------------------------------------------------*/
5470 /* genAssign - generate code for assignment                        */
5471 /*-----------------------------------------------------------------*/
5472 static void
5473 genAssign (iCode * ic)
5474 {
5475   operand *result, *right;
5476   int size, offset;
5477   unsigned long lit = 0L;
5478
5479   result = IC_RESULT (ic);
5480   right = IC_RIGHT (ic);
5481
5482 #if 1
5483   /* Dont bother assigning if they are the same */
5484   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5485     {
5486       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5487       return;
5488     }
5489 #endif
5490
5491   aopOp (right, ic, FALSE, FALSE);
5492   aopOp (result, ic, TRUE, FALSE);
5493
5494   /* if they are the same registers */
5495   if (sameRegs (AOP (right), AOP (result)))
5496     {
5497       emitDebug ("; (registers are the same)");
5498       goto release;
5499     }
5500
5501   /* if the result is a bit */
5502   if (AOP_TYPE (result) == AOP_CRY)
5503     {
5504       wassert (0);
5505     }
5506
5507   /* general case */
5508   size = AOP_SIZE (result);
5509   offset = 0;
5510
5511   if (AOP_TYPE (right) == AOP_LIT)
5512     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5513   if (isPair (AOP (result)))
5514     {
5515       fetchPair (getPairId (AOP (result)), AOP (right));
5516     }
5517   else if ((size > 1) &&
5518            (AOP_TYPE (result) != AOP_REG) &&
5519            (AOP_TYPE (right) == AOP_LIT) &&
5520            !IS_FLOAT (operandType (right)) &&
5521            (lit < 256L))
5522     {
5523       bool fXored = FALSE;
5524       offset = 0;
5525       /* Work from the top down.
5526          Done this way so that we can use the cached copy of 0
5527          in A for a fast clear */
5528       while (size--)
5529         {
5530           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5531             {
5532               if (!fXored && size > 1)
5533                 {
5534                   emit2 ("xor a,a");
5535                   fXored = TRUE;
5536                 }
5537               if (fXored)
5538                 {
5539                   aopPut (AOP (result), "a", offset);
5540                 }
5541               else
5542                 {
5543                   aopPut (AOP (result), "!zero", offset);
5544                 }
5545             }
5546           else
5547             aopPut (AOP (result),
5548                     aopGet (AOP (right), offset, FALSE),
5549                     offset);
5550           offset++;
5551         }
5552     }
5553   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5554     {
5555       /* Special case.  Load into a and d, then load out. */
5556       _moveA (aopGet (AOP (right), 0, FALSE));
5557       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5558       aopPut (AOP (result), "a", 0);
5559       aopPut (AOP (result), "e", 1);
5560     }
5561   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5562     {
5563       /* Special case - simple memcpy */
5564       aopGet (AOP (right), LSB, FALSE);
5565       emit2 ("ld d,h");
5566       emit2 ("ld e,l");
5567       aopGet (AOP (result), LSB, FALSE);
5568
5569       while (size--)
5570         {
5571           emit2 ("ld a,(de)");
5572           /* Peephole will optimise this. */
5573           emit2 ("ld (hl),a");
5574
5575           if (size != 0)
5576             {
5577               emit2 ("inc hl");
5578               emit2 ("inc de");
5579             }
5580         }
5581       spillPair (PAIR_HL);
5582     }
5583   else
5584     {
5585       while (size--)
5586         {
5587           /* PENDING: do this check better */
5588           if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5589             {
5590               _moveA (aopGet (AOP (right), offset, FALSE));
5591               aopPut (AOP (result), "a", offset);
5592             }
5593           else
5594             aopPut (AOP (result),
5595                     aopGet (AOP (right), offset, FALSE),
5596                     offset);
5597           offset++;
5598         }
5599     }
5600
5601 release:
5602   freeAsmop (right, NULL, ic);
5603   freeAsmop (result, NULL, ic);
5604 }
5605
5606 /*-----------------------------------------------------------------*/
5607 /* genJumpTab - genrates code for jump table                       */
5608 /*-----------------------------------------------------------------*/
5609 static void
5610 genJumpTab (iCode * ic)
5611 {
5612   symbol *jtab;
5613   const char *l;
5614
5615   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5616   /* get the condition into accumulator */
5617   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5618   if (!IS_GB)
5619     emit2 ("push de");
5620   emit2 ("ld e,%s", l);
5621   emit2 ("ld d,!zero");
5622   jtab = newiTempLabel (NULL);
5623   spillCached ();
5624   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5625   emit2 ("add hl,de");
5626   emit2 ("add hl,de");
5627   emit2 ("add hl,de");
5628   freeAsmop (IC_JTCOND (ic), NULL, ic);
5629   if (!IS_GB)
5630     emit2 ("pop de");
5631   emit2 ("jp !*hl");
5632   emitLabel (jtab->key + 100);
5633   /* now generate the jump labels */
5634   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5635        jtab = setNextItem (IC_JTLABELS (ic)))
5636     emit2 ("jp !tlabel", jtab->key + 100);
5637 }
5638
5639 /*-----------------------------------------------------------------*/
5640 /* genCast - gen code for casting                                  */
5641 /*-----------------------------------------------------------------*/
5642 static void
5643 genCast (iCode * ic)
5644 {
5645   operand *result = IC_RESULT (ic);
5646   sym_link *ctype = operandType (IC_LEFT (ic));
5647   operand *right = IC_RIGHT (ic);
5648   int size, offset;
5649
5650   /* if they are equivalent then do nothing */
5651   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5652     return;
5653
5654   aopOp (right, ic, FALSE, FALSE);
5655   aopOp (result, ic, FALSE, FALSE);
5656
5657   /* if the result is a bit */
5658   if (AOP_TYPE (result) == AOP_CRY)
5659     {
5660       wassert (0);
5661     }
5662
5663   /* if they are the same size : or less */
5664   if (AOP_SIZE (result) <= AOP_SIZE (right))
5665     {
5666
5667       /* if they are in the same place */
5668       if (sameRegs (AOP (right), AOP (result)))
5669         goto release;
5670
5671       /* if they in different places then copy */
5672       size = AOP_SIZE (result);
5673       offset = 0;
5674       while (size--)
5675         {
5676           aopPut (AOP (result),
5677                   aopGet (AOP (right), offset, FALSE),
5678                   offset);
5679           offset++;
5680         }
5681       goto release;
5682     }
5683
5684   /* PENDING: should be OK. */
5685 #if 0
5686   /* if the result is of type pointer */
5687   if (IS_PTR (ctype))
5688     {
5689       wassert (0);
5690     }
5691 #endif
5692
5693   /* so we now know that the size of destination is greater
5694      than the size of the source */
5695   /* we move to result for the size of source */
5696   size = AOP_SIZE (right);
5697   offset = 0;
5698   while (size--)
5699     {
5700       aopPut (AOP (result),
5701               aopGet (AOP (right), offset, FALSE),
5702               offset);
5703       offset++;
5704     }
5705
5706   /* now depending on the sign of the destination */
5707   size = AOP_SIZE (result) - AOP_SIZE (right);
5708   /* Unsigned or not an integral type - right fill with zeros */
5709   if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5710     {
5711       while (size--)
5712         aopPut (AOP (result), "!zero", offset++);
5713     }
5714   else
5715     {
5716       /* we need to extend the sign :{ */
5717         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5718                         FALSE);
5719       _moveA (l);
5720       emitDebug ("; genCast: sign extend untested.");
5721       emit2 ("rla ");
5722       emit2 ("sbc a,a");
5723       while (size--)
5724         aopPut (AOP (result), "a", offset++);
5725     }
5726
5727 release:
5728   freeAsmop (right, NULL, ic);
5729   freeAsmop (result, NULL, ic);
5730 }
5731
5732 /*-----------------------------------------------------------------*/
5733 /* genReceive - generate code for a receive iCode                  */
5734 /*-----------------------------------------------------------------*/
5735 static void
5736 genReceive (iCode * ic)
5737 {
5738   if (isOperandInFarSpace (IC_RESULT (ic)) &&
5739       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5740        IS_TRUE_SYMOP (IC_RESULT (ic))))
5741     {
5742       wassert (0);
5743     }
5744   else
5745     {
5746         // PENDING: HACK
5747         int size;
5748         int i;
5749
5750         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5751         size = AOP_SIZE(IC_RESULT(ic));
5752
5753         for (i = 0; i < size; i++) {
5754             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5755         }
5756     }
5757
5758   freeAsmop (IC_RESULT (ic), NULL, ic);
5759 }
5760
5761 enum
5762   {
5763     /** Maximum number of bytes to emit per line. */
5764     DBEMIT_MAX_RUN = 8
5765   };
5766
5767 /** Context for the byte output chunker. */
5768 typedef struct
5769 {
5770   unsigned char buffer[DBEMIT_MAX_RUN];
5771   int pos;
5772 } DBEMITCTX;
5773
5774
5775 /** Flushes a byte chunker by writing out all in the buffer and
5776     reseting. 
5777 */
5778 static void
5779 _dbFlush(DBEMITCTX *self)
5780 {
5781   char line[256];
5782
5783   if (self->pos > 0)
5784     {
5785       int i;
5786       sprintf(line, ".db 0x%02X", self->buffer[0]);
5787
5788       for (i = 1; i < self->pos; i++)
5789         {
5790           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5791         }
5792       emit2(line);
5793     }
5794   self->pos = 0;
5795 }
5796
5797 /** Write out another byte, buffering until a decent line is
5798     generated.
5799 */
5800 static void
5801 _dbEmit(DBEMITCTX *self, int c)
5802 {
5803   if (self->pos == DBEMIT_MAX_RUN)
5804     {
5805       _dbFlush(self);
5806     }
5807   self->buffer[self->pos++] = c;
5808 }
5809
5810 /** Context for a simple run length encoder. */
5811 typedef struct
5812 {
5813   unsigned last;
5814   unsigned char buffer[128];
5815   int pos;
5816   /** runLen may be equivalent to pos. */
5817   int runLen;
5818 } RLECTX;
5819
5820 enum
5821   {
5822     RLE_CHANGE_COST = 4,
5823     RLE_MAX_BLOCK = 127
5824   };
5825
5826 /** Flush the buffer of a run length encoder by writing out the run or
5827     data that it currently contains.
5828 */
5829 static void
5830 _rleCommit(RLECTX *self)
5831 {
5832   int i;
5833   if (self->pos != 0)
5834     {
5835       DBEMITCTX db;
5836       memset(&db, 0, sizeof(db));
5837           
5838       emit2(".db %u", self->pos);
5839       
5840       for (i = 0; i < self->pos; i++)
5841         {
5842           _dbEmit(&db, self->buffer[i]);
5843         }
5844       _dbFlush(&db);
5845     }
5846   /* Reset */
5847   self->pos = 0;
5848 }
5849
5850 /* Encoder design:
5851    Can get either a run or a block of random stuff.
5852    Only want to change state if a good run comes in or a run ends.
5853    Detecting run end is easy.
5854    Initial state?
5855
5856    Say initial state is in run, len zero, last zero.  Then if you get a
5857    few zeros then something else then a short run will be output.
5858    Seems OK.  While in run mode, keep counting.  While in random mode,
5859    keep a count of the run.  If run hits margin, output all up to run,
5860    restart, enter run mode.
5861 */
5862
5863 /** Add another byte into the run length encoder, flushing as
5864     required.  The run length encoder uses the Amiga IFF style, where
5865     a block is prefixed by its run length.  A positive length means
5866     the next n bytes pass straight through.  A negative length means
5867     that the next byte is repeated -n times.  A zero terminates the
5868     chunks.
5869 */
5870 static void
5871 _rleAppend(RLECTX *self, int c)
5872 {
5873   int i;
5874
5875   if (c != self->last)
5876     {
5877       /* The run has stopped.  See if it is worthwhile writing it out
5878          as a run.  Note that the random data comes in as runs of
5879          length one.
5880       */
5881       if (self->runLen > RLE_CHANGE_COST)
5882         {
5883           /* Yes, worthwhile. */
5884           /* Commit whatever was in the buffer. */
5885           _rleCommit(self);
5886           emit2(".db -%u,0x%02X", self->runLen, self->last);
5887         }
5888       else
5889         {
5890           /* Not worthwhile.  Append to the end of the random list. */
5891           for (i = 0; i < self->runLen; i++)
5892             {
5893               if (self->pos >= RLE_MAX_BLOCK)
5894                 {
5895                   /* Commit. */
5896                   _rleCommit(self);
5897                 }
5898               self->buffer[self->pos++] = self->last;
5899             }
5900         }
5901       self->runLen = 1;
5902       self->last = c;
5903     }
5904   else
5905     {
5906       if (self->runLen >= RLE_MAX_BLOCK)
5907         {
5908           /* Commit whatever was in the buffer. */
5909           _rleCommit(self);
5910
5911           emit2 (".db -%u,0x%02X", self->runLen, self->last);
5912           self->runLen = 0;
5913         }
5914       self->runLen++;
5915     }
5916 }
5917
5918 static void
5919 _rleFlush(RLECTX *self)
5920 {
5921   _rleAppend(self, -1);
5922   _rleCommit(self);
5923   self->pos = 0;
5924   self->last = 0;
5925   self->runLen = 0;
5926 }
5927
5928 /** genArrayInit - Special code for initialising an array with constant
5929    data.
5930 */
5931 static void
5932 genArrayInit (iCode * ic)
5933 {
5934   literalList *iLoop;
5935   int         ix;
5936   int         elementSize = 0, eIndex, i;
5937   unsigned    val, lastVal;
5938   sym_link    *type;
5939   RLECTX      rle;
5940
5941   memset(&rle, 0, sizeof(rle));
5942
5943   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5944
5945   if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5946     {
5947       /* Emit the support function call and the destination address. */
5948       emit2("call __initrleblock");
5949       emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5950     }
5951   else
5952     {
5953       wassertl (0, "Unexpected operand to genArrayInit.\n");
5954     }
5955     
5956   type = operandType(IC_LEFT(ic));
5957     
5958   if (type && type->next)
5959     {
5960       elementSize = getSize(type->next);
5961     }
5962   else
5963     {
5964       wassertl (0, "Can't determine element size in genArrayInit.");
5965     }
5966
5967   iLoop = IC_ARRAYILIST(ic);
5968   lastVal = (unsigned)-1;
5969
5970   /* Feed all the bytes into the run length encoder which will handle
5971      the actual output.
5972      This works well for mixed char data, and for random int and long
5973      data.
5974   */
5975   while (iLoop)
5976     {
5977       ix = iLoop->count;
5978
5979       if (ix != 0)
5980         {
5981           for (i = 0; i < ix; i++)
5982             {
5983               for (eIndex = 0; eIndex < elementSize; eIndex++)
5984                 {
5985                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5986                   _rleAppend(&rle, val);
5987                 }
5988             }
5989         }
5990         
5991       iLoop = iLoop->next;
5992     }
5993
5994   _rleFlush(&rle);
5995   /* Mark the end of the run. */
5996   emit2(".db 0");
5997
5998   freeAsmop (IC_LEFT(ic), NULL, ic);
5999 }
6000
6001 /*-----------------------------------------------------------------*/
6002 /* genZ80Code - generate code for Z80 based controllers            */
6003 /*-----------------------------------------------------------------*/
6004 void
6005 genZ80Code (iCode * lic)
6006 {
6007   iCode *ic;
6008   int cln = 0;
6009
6010   /* HACK */
6011   if (IS_GB)
6012     {
6013       _fReturn = _gbz80_return;
6014       _fTmp = _gbz80_return;
6015     }
6016   else
6017     {
6018       _fReturn = _z80_return;
6019       _fTmp = _z80_return;
6020     }
6021
6022   _G.lines.head = _G.lines.current = NULL;
6023
6024   for (ic = lic; ic; ic = ic->next)
6025     {
6026
6027       if (cln != ic->lineno)
6028         {
6029           emit2 ("; %s %d", ic->filename, ic->lineno);
6030           cln = ic->lineno;
6031         }
6032       /* if the result is marked as
6033          spilt and rematerializable or code for
6034          this has already been generated then
6035          do nothing */
6036       if (resultRemat (ic) || ic->generated)
6037         continue;
6038
6039       /* depending on the operation */
6040       switch (ic->op)
6041         {
6042         case '!':
6043           emitDebug ("; genNot");
6044           genNot (ic);
6045           break;
6046
6047         case '~':
6048           emitDebug ("; genCpl");
6049           genCpl (ic);
6050           break;
6051
6052         case UNARYMINUS:
6053           emitDebug ("; genUminus");
6054           genUminus (ic);
6055           break;
6056
6057         case IPUSH:
6058           emitDebug ("; genIpush");
6059           genIpush (ic);
6060           break;
6061
6062         case IPOP:
6063           /* IPOP happens only when trying to restore a
6064              spilt live range, if there is an ifx statement
6065              following this pop then the if statement might
6066              be using some of the registers being popped which
6067              would destory the contents of the register so
6068              we need to check for this condition and handle it */
6069           if (ic->next &&
6070               ic->next->op == IFX &&
6071               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6072             {
6073               emitDebug ("; genIfx");
6074               genIfx (ic->next, ic);
6075             }
6076           else
6077             {
6078               emitDebug ("; genIpop");
6079               genIpop (ic);
6080             }
6081           break;
6082
6083         case CALL:
6084           emitDebug ("; genCall");
6085           genCall (ic);
6086           break;
6087
6088         case PCALL:
6089           emitDebug ("; genPcall");
6090           genPcall (ic);
6091           break;
6092
6093         case FUNCTION:
6094           emitDebug ("; genFunction");
6095           genFunction (ic);
6096           break;
6097
6098         case ENDFUNCTION:
6099           emitDebug ("; genEndFunction");
6100           genEndFunction (ic);
6101           break;
6102
6103         case RETURN:
6104           emitDebug ("; genRet");
6105           genRet (ic);
6106           break;
6107
6108         case LABEL:
6109           emitDebug ("; genLabel");
6110           genLabel (ic);
6111           break;
6112
6113         case GOTO:
6114           emitDebug ("; genGoto");
6115           genGoto (ic);
6116           break;
6117
6118         case '+':
6119           emitDebug ("; genPlus");
6120           genPlus (ic);
6121           break;
6122
6123         case '-':
6124           emitDebug ("; genMinus");
6125           genMinus (ic);
6126           break;
6127
6128         case '*':
6129           emitDebug ("; genMult");
6130           genMult (ic);
6131           break;
6132
6133         case '/':
6134           emitDebug ("; genDiv");
6135           genDiv (ic);
6136           break;
6137
6138         case '%':
6139           emitDebug ("; genMod");
6140           genMod (ic);
6141           break;
6142
6143         case '>':
6144           emitDebug ("; genCmpGt");
6145           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6146           break;
6147
6148         case '<':
6149           emitDebug ("; genCmpLt");
6150           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6151           break;
6152
6153         case LE_OP:
6154         case GE_OP:
6155         case NE_OP:
6156
6157           /* note these two are xlated by algebraic equivalence
6158              during parsing SDCC.y */
6159           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6160                   "got '>=' or '<=' shouldn't have come here");
6161           break;
6162
6163         case EQ_OP:
6164           emitDebug ("; genCmpEq");
6165           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6166           break;
6167
6168         case AND_OP:
6169           emitDebug ("; genAndOp");
6170           genAndOp (ic);
6171           break;
6172
6173         case OR_OP:
6174           emitDebug ("; genOrOp");
6175           genOrOp (ic);
6176           break;
6177
6178         case '^':
6179           emitDebug ("; genXor");
6180           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6181           break;
6182
6183         case '|':
6184           emitDebug ("; genOr");
6185           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6186           break;
6187
6188         case BITWISEAND:
6189           emitDebug ("; genAnd");
6190           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6191           break;
6192
6193         case INLINEASM:
6194           emitDebug ("; genInline");
6195           genInline (ic);
6196           break;
6197
6198         case RRC:
6199           emitDebug ("; genRRC");
6200           genRRC (ic);
6201           break;
6202
6203         case RLC:
6204           emitDebug ("; genRLC");
6205           genRLC (ic);
6206           break;
6207
6208         case GETHBIT:
6209           emitDebug ("; genGetHBIT");
6210           genGetHbit (ic);
6211           break;
6212
6213         case LEFT_OP:
6214           emitDebug ("; genLeftShift");
6215           genLeftShift (ic);
6216           break;
6217
6218         case RIGHT_OP:
6219           emitDebug ("; genRightShift");
6220           genRightShift (ic);
6221           break;
6222
6223         case GET_VALUE_AT_ADDRESS:
6224           emitDebug ("; genPointerGet");
6225           genPointerGet (ic);
6226           break;
6227
6228         case '=':
6229
6230           if (POINTER_SET (ic))
6231             {
6232               emitDebug ("; genAssign (pointer)");
6233               genPointerSet (ic);
6234             }
6235           else
6236             {
6237               emitDebug ("; genAssign");
6238               genAssign (ic);
6239             }
6240           break;
6241
6242         case IFX:
6243           emitDebug ("; genIfx");
6244           genIfx (ic, NULL);
6245           break;
6246
6247         case ADDRESS_OF:
6248           emitDebug ("; genAddrOf");
6249           genAddrOf (ic);
6250           break;
6251
6252         case JUMPTABLE:
6253           emitDebug ("; genJumpTab");
6254           genJumpTab (ic);
6255           break;
6256
6257         case CAST:
6258           emitDebug ("; genCast");
6259           genCast (ic);
6260           break;
6261
6262         case RECEIVE:
6263           emitDebug ("; genReceive");
6264           genReceive (ic);
6265           break;
6266
6267         case SEND:
6268           emitDebug ("; addSet");
6269           addSet (&_G.sendSet, ic);
6270           break;
6271
6272         case ARRAYINIT:
6273             genArrayInit(ic);
6274             break;
6275             
6276         default:
6277           ic = ic;
6278           /*      piCode(ic,stdout); */
6279
6280         }
6281     }
6282
6283
6284   /* now we are ready to call the
6285      peep hole optimizer */
6286   if (!options.nopeep)
6287     peepHole (&_G.lines.head);
6288
6289   /* This is unfortunate */
6290   /* now do the actual printing */
6291   {
6292     FILE *fp = codeOutFile;
6293     if (isInHome () && codeOutFile == code->oFile)
6294       codeOutFile = home->oFile;
6295     printLine (_G.lines.head, codeOutFile);
6296     if (_G.flushStatics)
6297       {
6298         flushStatics ();
6299         _G.flushStatics = 0;
6300       }
6301     codeOutFile = fp;
6302   }
6303 }
6304
6305 /*
6306   Attic
6307 static int
6308 _isPairUsed (iCode * ic, PAIR_ID pairId)
6309 {
6310   int ret = 0;
6311   switch (pairId)
6312     {
6313     case PAIR_DE:
6314       if (bitVectBitValue (ic->rMask, D_IDX))
6315         ret++;
6316       if (bitVectBitValue (ic->rMask, E_IDX))
6317         ret++;
6318       break;
6319     default:
6320       wassert (0);
6321     }
6322   return ret;
6323 }
6324
6325 static char *
6326 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6327 {
6328   unsigned long v;
6329   value *val = aop->aopu.aop_lit;
6330
6331   wassert (aop->type == AOP_LIT);
6332   wassert (!IS_FLOAT (val->type));
6333
6334   v = (unsigned long) floatFromVal (val);
6335
6336   if (xor)
6337     v ^= 0x8000;
6338   if (negate)
6339     v = 0-v;
6340   v &= 0xFFFF;
6341
6342   tsprintf (buffer, "!immedword", v);
6343   return gc_strdup (buffer);
6344 }
6345
6346
6347 */