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