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