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