Most of the way to far fun support
[fw/sdcc] / src / z80 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - Z80 specific code generator.
3
4   Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
5                                                 ticks   dhry    size
6   Base with asm strcpy / strcmp / memcpy:       23198   141     1A14
7   Improved WORD push                            22784   144     19AE
8   With label1 on                                22694   144     197E
9   With label2 on                                22743   144     198A
10   With label3 on                                22776   144     1999
11   With label4 on                                22776   144     1999
12   With all 'label' on                           22661   144     196F
13   With loopInvariant on                         20919   156     19AB
14   With loopInduction on                         Breaks          198B
15   With all working on                           20796   158     196C
16   Slightly better genCmp(signed)                20597   159     195B
17   Better reg packing, first peephole            20038   163     1873
18   With assign packing                           19281   165     1849
19   5/3/00                                        17741   185     17B6
20
21   Michael Hope <michaelh@earthling.net> 2000
22   Based on the mcs51 generator - 
23                 Sandeep Dutta . sandeep.dutta@usa.net (1998)
24          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
25          
26   This program is free software; you can redistribute it and/or modify it
27   under the terms of the GNU General Public License as published by the
28   Free Software Foundation; either version 2, or (at your option) any
29   later version.
30   
31   This program is distributed in the hope that it will be useful,
32   but WITHOUT ANY WARRANTY; without even the implied warranty of
33   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34   GNU General Public License for more details.
35
36   
37   You should have received a copy of the GNU General Public License
38   along with this program; if not, write to the Free Software
39   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40   
41   In other words, you are welcome to use, share and improve this program.
42   You are forbidden to forbid anyone else to use, share and improve
43   what you give them.   Help stamp out software-hoarding!
44
45 -------------------------------------------------------------------------*/
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ctype.h>
51
52 #ifdef HAVE_SYS_ISA_DEFS_H
53 #include <sys/isa_defs.h>
54 #endif
55
56 #include "z80.h"
57 #include "SDCCpeeph.h"
58 #include "gen.h"
59 #include "SDCCglue.h"
60
61 /* this is the down and dirty file with all kinds of kludgy & hacky
62    stuff. This is what it is all about CODE GENERATION for a specific MCU.
63    Some of the routines may be reusable, will have to see */
64
65 static char *spname ;
66 static char *_z80_return[] = {"l", "h", "e", "d" };
67 static char *_gbz80_return[] = { "e", "d", "l", "h" };
68 static char **_fReturn;
69 static char **_fTmp;
70
71 /* PENDING: messy */
72 static char zero[20];
73
74 static char *accUse[] = {"a" };
75 static char *hlUse[] = { "l", "h" };
76 short rbank = -1;
77 short accInUse = 0 ;
78 short inLine = 0;
79 short debugLine = 0;
80 short nregssaved = 0;
81 extern int ptrRegReq ;
82 extern int nRegs;
83 extern FILE *codeOutFile;
84 set *sendSet = NULL;
85
86 typedef enum {
87     PAIR_INVALID,
88     PAIR_BC,
89     PAIR_DE,
90     PAIR_HL,
91     PAIR_IY,
92     PAIR_IX,
93     NUM_PAIRS
94 } PAIR_ID;
95
96 static struct {
97     const char *name;
98     const char *l;
99     const char *h;
100 } _pairs[NUM_PAIRS] = {
101     { "??", "?", "?" },
102     { "bc", "c", "b" },
103     { "de", "e", "d" },
104     { "hl", "l", "h" },
105     { "iy", "iy.l?", "iy.h?" },
106     { "ix", "ix.l?", "ix.h?" }
107 };
108     
109 #define RESULTONSTACK(x) \
110                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
111                          IC_RESULT(x)->aop->type == AOP_STK )
112
113 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
114 #define CLRC    emitcode("xor","a,a");
115
116 lineNode *lineHead = NULL;
117 lineNode *lineCurr = NULL;
118
119 static const unsigned char SLMask[] = 
120 {0xFF ,0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00};
121 static const unsigned char SRMask[] = 
122 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00};
123
124 #define LSB     0
125 #define MSB16   1
126 #define MSB24   2
127 #define MSB32   3
128
129 /* Stack frame:
130    IX+4         param0  LH
131    IX+2         ret     LH
132    IX+0         ix      LH
133    IX-2         temp0   LH
134 */
135
136 static struct {
137     struct {
138         AOP_TYPE last_type;
139         const char *lit;
140         int offset;
141     } pairs[NUM_PAIRS];
142     struct {
143         int last;
144         int pushed;
145         int param_offset;
146         int offset;
147         int pushed_bc;
148         int pushed_de;
149     } stack;
150     int frameId;
151     bool flush_statics;
152     bool in_home;
153 } _G;
154
155 static char *aopGet(asmop *aop, int offset, bool bit16);
156
157 static void _tidyUp(char *buf)
158 {
159     /* Clean up the line so that it is 'prettier' */
160     if (strchr(buf, ':')) {
161         /* Is a label - cant do anything */
162         return;
163     }
164     /* Change the first (and probably only) ' ' to a tab so
165        everything lines up.
166     */
167     while (*buf) {
168         if (*buf == ' ') {
169             *buf = '\t';
170             return;
171         }
172         buf++;
173     }
174 }
175
176 static void emit2(const char *szFormat, ...)
177 {
178     char buffer[256];
179     va_list ap;
180
181     va_start(ap, szFormat);
182
183     tvsprintf(buffer, szFormat, ap);
184
185     _tidyUp(buffer);
186     lineCurr = (lineCurr ?
187                 connectLine(lineCurr,newLineNode(buffer)) :
188                 (lineHead = newLineNode(buffer)));
189
190     lineCurr->isInline = inLine;
191     lineCurr->isDebug  = debugLine;
192 }
193
194 /*-----------------------------------------------------------------*/
195 /* emitcode - writes the code into a file : for now it is simple    */
196 /*-----------------------------------------------------------------*/
197 void emitcode (const char *inst, const char *fmt, ...)
198 {
199     va_list ap;
200     char lb[MAX_INLINEASM];  
201     char *lbp = lb;
202
203     va_start(ap,fmt);   
204
205     if (*inst != '\0') {
206         sprintf(lb,"%s\t",inst);
207         vsprintf(lb+(strlen(lb)),fmt,ap);
208     }  else 
209         vsprintf(lb,fmt,ap);
210
211     while (isspace(*lbp)) lbp++;
212
213     if (lbp && *lbp) 
214         lineCurr = (lineCurr ?
215                     connectLine(lineCurr,newLineNode(lb)) :
216                     (lineHead = newLineNode(lb)));
217     lineCurr->isInline = inLine;
218     lineCurr->isDebug  = debugLine;
219     va_end(ap);
220 }
221
222 /* Z80:
223     { "adjustsp", 
224       "\tld hl,#-%d\n"
225       "\tadd hl,sp\n"
226       "\tld sp,hl"
227     }
228     { "prelude",
229         "push bc"
230         "push de"
231         "push ix"
232         "ld ix,#0"
233         "add ix,sp"
234     { "leave" 
235     emitcode("ld", "sp,ix");
236     emitcode("pop", "ix");
237     emitcode("pop", "de");
238     }
239 }
240 */
241
242 const char *getPairName(asmop *aop)
243 {
244     if (aop->type == AOP_REG) {
245         switch (aop->aopu.aop_reg[0]->rIdx) {
246         case C_IDX:
247             return "bc";
248             break;
249         case E_IDX:
250             return "de";
251             break;
252         case L_IDX:
253             return "hl";
254             break;
255         }
256     }
257     else if (aop->type == AOP_STR) {
258         switch (*aop->aopu.aop_str[0]) {
259         case 'c':
260             return "bc";
261             break;
262         case 'e':
263             return "de";
264             break;
265         case 'l':
266             return "hl";
267             break;
268         }
269     }
270     wassert(0);
271     return NULL;
272 }
273
274 static PAIR_ID getPairId(asmop *aop)
275 {
276     if (aop->size == 2) {
277         if (aop->type == AOP_REG) {
278             if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
279                 return PAIR_BC;
280             }
281             if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
282                 return PAIR_DE;
283             }
284             if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
285                 return PAIR_HL;
286             }
287         }
288         if (aop->type == AOP_STR) {
289             if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
290                 return PAIR_BC;
291             }
292             if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
293                 return PAIR_DE;
294             }
295             if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
296                 return PAIR_HL;
297             }
298         }
299     }
300     return PAIR_INVALID;
301 }
302
303 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
304 bool isPair(asmop *aop)
305 {
306     return (getPairId(aop) != PAIR_INVALID);
307 }
308
309 bool isPtrPair(asmop *aop)
310 {
311     PAIR_ID pairId = getPairId(aop);
312     switch (pairId) {
313     case PAIR_HL:
314     case PAIR_IY:
315     case PAIR_IX:
316         return TRUE;
317     default:
318         return FALSE;
319     }
320 }
321 /** Push a register pair onto the stack */
322 void genPairPush(asmop *aop)
323 {
324     emitcode("push", "%s", getPairName(aop));
325 }
326
327
328 /*-----------------------------------------------------------------*/
329 /* newAsmop - creates a new asmOp                                  */
330 /*-----------------------------------------------------------------*/
331 static asmop *newAsmop (short type)
332 {
333     asmop *aop;
334
335     ALLOC(aop,sizeof(asmop));
336     aop->type = type;
337     return aop;
338 }
339
340 /*-----------------------------------------------------------------*/
341 /* aopForSym - for a true symbol                                   */
342 /*-----------------------------------------------------------------*/
343 static asmop *aopForSym (iCode *ic,symbol *sym,bool result, bool requires_a)
344 {
345     asmop *aop;
346     memmap *space;
347
348     wassert(ic);
349     wassert(sym);
350     wassert(sym->etype);
351
352     space = SPEC_OCLS(sym->etype);
353
354     /* if already has one */
355     if (sym->aop)
356         return sym->aop;
357
358     /* Assign depending on the storage class */
359     if (sym->onStack || sym->iaccess) {
360         emitcode("", "; AOP_STK for %s", sym->rname);
361         sym->aop = aop = newAsmop(AOP_STK);
362         aop->size = getSize(sym->type);
363         aop->aopu.aop_stk = sym->stack;
364         return aop;
365     }
366
367     /* special case for a function */
368     if (IS_FUNC(sym->type)) {   
369         sym->aop = aop = newAsmop(AOP_IMMD);    
370         ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
371         strcpy(aop->aopu.aop_immd,sym->rname);
372         aop->size = 2;
373         return aop;
374     }
375
376     if (IS_GB) {
377         /* if it is in direct space */
378         if (IN_REGSP(space) && !requires_a) {
379             sym->aop = aop = newAsmop (AOP_SFR);
380             aop->aopu.aop_dir = sym->rname ;
381             aop->size = getSize(sym->type);
382             emitcode("", "; AOP_SFR for %s", sym->rname);
383             return aop;
384         }
385     }
386
387     /* only remaining is far space */
388     /* in which case DPTR gets the address */
389     if (IS_GB) {
390         emitcode("", "; AOP_HL for %s", sym->rname);
391         sym->aop = aop = newAsmop(AOP_HL);
392     }
393     else {
394         sym->aop = aop = newAsmop(AOP_IY);
395     }
396     aop->size = getSize(sym->type);
397     aop->aopu.aop_dir = sym->rname;
398
399     /* if it is in code space */
400     if (IN_CODESPACE(space))
401         aop->code = 1;
402
403     return aop;     
404 }
405
406 /*-----------------------------------------------------------------*/
407 /* aopForRemat - rematerialzes an object                           */
408 /*-----------------------------------------------------------------*/
409 static asmop *aopForRemat (symbol *sym)
410 {
411     char *s = buffer;   
412     iCode *ic = sym->rematiCode;
413     asmop *aop = newAsmop(AOP_IMMD);
414
415     while (1) {
416         /* if plus or minus print the right hand side */
417         if (ic->op == '+' || ic->op == '-') {
418             /* PENDING: for re-target */
419             sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
420                     ic->op );
421             s += strlen(s);
422             ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
423             continue ;
424         }
425         /* we reached the end */
426         sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
427         break;
428     }
429
430     ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
431     strcpy(aop->aopu.aop_immd,buffer);    
432     return aop;        
433 }
434
435 /*-----------------------------------------------------------------*/
436 /* regsInCommon - two operands have some registers in common       */
437 /*-----------------------------------------------------------------*/
438 bool regsInCommon (operand *op1, operand *op2)
439 {
440     symbol *sym1, *sym2;
441     int i;
442
443     /* if they have registers in common */
444     if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
445         return FALSE ;
446
447     sym1 = OP_SYMBOL(op1);
448     sym2 = OP_SYMBOL(op2);
449
450     if (sym1->nRegs == 0 || sym2->nRegs == 0)
451         return FALSE ;
452
453     for (i = 0 ; i < sym1->nRegs ; i++) {
454         int j;
455         if (!sym1->regs[i])
456             continue ;
457
458         for (j = 0 ; j < sym2->nRegs ;j++ ) {
459             if (!sym2->regs[j])
460                 continue ;
461
462             if (sym2->regs[j] == sym1->regs[i])
463                 return TRUE ;
464         }
465     }
466
467     return FALSE ;
468 }
469
470 /*-----------------------------------------------------------------*/
471 /* operandsEqu - equivalent                                        */
472 /*-----------------------------------------------------------------*/
473 bool operandsEqu ( operand *op1, operand *op2)
474 {
475     symbol *sym1, *sym2;
476
477     /* if they not symbols */
478     if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
479         return FALSE;
480
481     sym1 = OP_SYMBOL(op1);
482     sym2 = OP_SYMBOL(op2);
483
484     /* if both are itemps & one is spilt
485        and the other is not then false */
486     if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
487         sym1->isspilt != sym2->isspilt )
488         return FALSE ;
489
490     /* if they are the same */
491     if (sym1 == sym2)
492         return 1;
493
494     if (strcmp(sym1->rname,sym2->rname) == 0)
495         return 2;
496
497
498     /* if left is a tmp & right is not */
499     if (IS_ITEMP(op1)  && 
500         !IS_ITEMP(op2) &&
501         sym1->isspilt  &&
502         (sym1->usl.spillLoc == sym2))
503         return 3;
504
505     if (IS_ITEMP(op2)  && 
506         !IS_ITEMP(op1) &&
507         sym2->isspilt  &&
508         sym1->level > 0 &&
509         (sym2->usl.spillLoc == sym1))
510         return 4;
511
512     return FALSE;
513 }
514
515 /*-----------------------------------------------------------------*/
516 /* sameRegs - two asmops have the same registers                   */
517 /*-----------------------------------------------------------------*/
518 bool sameRegs (asmop *aop1, asmop *aop2 )
519 {
520     int i;
521
522     if (aop1->type == AOP_SFR ||
523         aop2->type == AOP_SFR)
524         return FALSE;
525
526     if (aop1 == aop2) 
527         return TRUE;
528
529     if (aop1->type != AOP_REG ||
530         aop2->type != AOP_REG )
531         return FALSE;
532
533     if (aop1->size != aop2->size)
534         return FALSE ;
535
536     for (i = 0 ; i < aop1->size ; i++ )
537         if (aop1->aopu.aop_reg[i] !=
538             aop2->aopu.aop_reg[i] )
539             return FALSE ;
540
541     return TRUE ;
542 }
543
544 /*-----------------------------------------------------------------*/
545 /* aopOp - allocates an asmop for an operand  :                    */
546 /*-----------------------------------------------------------------*/
547 static void aopOp (operand *op, iCode *ic, bool result, bool requires_a)
548 {
549     asmop *aop;
550     symbol *sym;
551     int i;
552
553     if (!op)
554         return ;
555
556     /* if this a literal */
557     if (IS_OP_LITERAL(op)) {
558         op->aop = aop = newAsmop(AOP_LIT);
559         aop->aopu.aop_lit = op->operand.valOperand;
560         aop->size = getSize(operandType(op));
561         return;
562     }
563
564     /* if already has a asmop then continue */
565     if (op->aop)
566         return ;
567
568     /* if the underlying symbol has a aop */
569     if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
570         op->aop = OP_SYMBOL(op)->aop;
571         return;
572     }
573
574     /* if this is a true symbol */
575     if (IS_TRUE_SYMOP(op)) {    
576         op->aop = aopForSym(ic, OP_SYMBOL(op), result, requires_a);
577         return ;
578     }
579
580     /* this is a temporary : this has
581     only four choices :
582     a) register
583     b) spillocation
584     c) rematerialize 
585     d) conditional   
586     e) can be a return use only */
587
588     sym = OP_SYMBOL(op);
589
590     /* if the type is a conditional */
591     if (sym->regType == REG_CND) {
592         aop = op->aop = sym->aop = newAsmop(AOP_CRY);
593         aop->size = 0;
594         return;
595     }
596
597     /* if it is spilt then two situations
598     a) is rematerialize 
599     b) has a spill location */
600     if (sym->isspilt || sym->nRegs == 0) {
601         /* rematerialize it NOW */
602         if (sym->remat) {
603             sym->aop = op->aop = aop =
604                                       aopForRemat (sym);
605             aop->size = getSize(sym->type);
606             return;
607         }
608
609         if (sym->accuse) {
610             int i;
611             if (sym->accuse == ACCUSE_A) {
612                 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
613                 aop->size = getSize(sym->type);
614                 for ( i = 0 ; i < 2 ; i++ )
615                     aop->aopu.aop_str[i] = accUse[i];
616             }
617             else if (sym->accuse == ACCUSE_HL) {
618                 wassert(!IS_GB);
619                 aop = op->aop = sym->aop = newAsmop(AOP_HLREG);
620                 aop->size = getSize(sym->type);
621                 for ( i = 0 ; i < 2 ; i++ )
622                     aop->aopu.aop_str[i] = hlUse[i];
623             }
624             else
625                 wassert(0);
626             return;
627         }
628
629         if (sym->ruonly ) {
630             int i;
631             aop = op->aop = sym->aop = newAsmop(AOP_STR);
632             aop->size = getSize(sym->type);
633             for ( i = 0 ; i < 4 ; i++ )
634                 aop->aopu.aop_str[i] = _fReturn[i];
635             return;
636         }
637
638         /* else spill location  */
639         sym->aop = op->aop = aop = 
640                                   aopForSym(ic,sym->usl.spillLoc,result, requires_a);
641         aop->size = getSize(sym->type);
642         return;
643     }
644
645     /* must be in a register */
646     sym->aop = op->aop = aop = newAsmop(AOP_REG);
647     aop->size = sym->nRegs;
648     for ( i = 0 ; i < sym->nRegs ;i++)
649         aop->aopu.aop_reg[i] = sym->regs[i];
650 }
651
652 /*-----------------------------------------------------------------*/
653 /* freeAsmop - free up the asmop given to an operand               */
654 /*----------------------------------------------------------------*/
655 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
656 {   
657     asmop *aop ;
658
659     if (!op)
660         aop = aaop;
661     else 
662         aop = op->aop;
663
664     if (!aop)
665         return ;
666
667     if (aop->freed)
668         goto dealloc; 
669
670     aop->freed = 1;
671
672 dealloc:
673     /* all other cases just dealloc */
674     if (op ) {
675         op->aop = NULL;
676         if (IS_SYMOP(op)) {
677             OP_SYMBOL(op)->aop = NULL;    
678             /* if the symbol has a spill */
679             if (SPIL_LOC(op))
680                 SPIL_LOC(op)->aop = NULL;
681         }
682     }
683 }
684
685 bool isLitWord(asmop *aop)
686 {
687     /*    if (aop->size != 2)
688           return FALSE;*/
689     switch (aop->type) {
690     case AOP_IMMD:
691     case AOP_LIT:
692         return TRUE;
693     default:
694         return FALSE;
695     }
696 }
697
698 char *aopGetLitWordLong(asmop *aop, int offset, bool with_hash)
699 {
700     char *s = buffer ;
701     char *rs;
702
703 #if 0
704     if (aop->size != 2 && aop->type != AOP_HL)
705         return NULL;
706 #endif
707     /* depending on type */
708     switch (aop->type) {
709     case AOP_HL:
710     case AOP_IY:
711     case AOP_IMMD:
712         /* PENDING: for re-target */
713         if (with_hash)
714             tsprintf(s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
715         else
716             tsprintf(s, "%s + %d", aop->aopu.aop_immd, offset);
717         ALLOC_ATOMIC(rs,strlen(s)+1);
718         strcpy(rs,s);   
719         return rs;
720     case AOP_LIT: {
721         value * val = aop->aopu.aop_lit;
722         /* if it is a float then it gets tricky */
723         /* otherwise it is fairly simple */
724         if (!IS_FLOAT(val->type)) {
725             unsigned long v = floatFromVal(val);
726             if (offset == 2)
727                 v >>= 16;
728             if (with_hash)
729                 tsprintf(buffer, "!immedword", v);
730             else
731                 tsprintf(buffer, "!constword", v);
732             ALLOC_ATOMIC(rs,strlen(buffer)+1);
733             return strcpy (rs,buffer);
734         }
735         else {
736             /* A float */
737             Z80_FLOAT f;
738             convertFloat(&f, floatFromVal(val));
739             if (with_hash) 
740                 tsprintf(buffer, "!immedword", f.w[offset/2]);
741             else
742                 tsprintf(buffer, "!constword", f.w[offset/2]);
743             ALLOC_ATOMIC(rs,strlen(buffer)+1);
744             return strcpy (rs,buffer);
745         }
746     }
747     default:
748         return NULL;
749     }
750 }
751
752 char *aopGetWord(asmop *aop, int offset)
753 {
754     return aopGetLitWordLong(aop, offset, TRUE);
755 }
756
757 bool isPtr(const char *s) 
758 {
759     if (!strcmp(s, "hl"))
760         return TRUE;
761     if (!strcmp(s, "ix"))
762         return TRUE;
763     if (!strcmp(s, "iy"))
764         return TRUE;
765     return FALSE;
766 }
767
768 static void adjustPair(const char *pair, int *pold, int new)
769 {
770     wassert(pair);
771
772     while (*pold < new) {
773         emitcode("inc", "%s", pair);
774         (*pold)++;
775     }
776     while (*pold > new) {
777         emitcode("dec", "%s", pair);
778         (*pold)--;
779     }
780 }
781
782 static void spillPair(PAIR_ID pairId)
783 {
784     _G.pairs[pairId].last_type = AOP_INVALID;
785     _G.pairs[pairId].lit = NULL;
786 }
787
788 static void spillCached(void)
789 {
790     spillPair(PAIR_HL);
791     spillPair(PAIR_IY);
792 }
793
794 static bool requiresHL(asmop *aop)
795 {
796     switch (aop->type) {
797     case AOP_HL:
798     case AOP_STK:
799         return TRUE;
800     default:
801         return FALSE;
802     }
803 }
804
805 static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
806 {
807     const char *l;
808     const char *pair = _pairs[pairId].name;
809     l = aopGetLitWordLong(left, 0, FALSE);
810     wassert(l && pair);
811
812     if (isPtr(pair)) {
813         if (pairId == PAIR_HL || pairId == PAIR_IY) {
814             if (_G.pairs[pairId].last_type == left->type) {
815                 if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
816                     if (pairId == PAIR_HL && abs(_G.pairs[pairId].offset - offset) < 3) {
817                         adjustPair(pair, &_G.pairs[pairId].offset, offset);
818                         return;
819                     }
820                     if (pairId == PAIR_IY && abs(offset)<127) {
821                         return;
822                     }
823                 }
824             }
825         }
826         _G.pairs[pairId].last_type = left->type;
827         _G.pairs[pairId].lit = gc_strdup(l);
828         _G.pairs[pairId].offset = offset;
829     }
830     if (IS_GB && pairId == PAIR_DE) {
831         if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
832             if (abs(_G.pairs[pairId].offset - offset) < 3) {
833                 adjustPair(pair, &_G.pairs[pairId].offset, offset);
834                 return;
835             }
836         }
837         _G.pairs[pairId].last_type = left->type;
838         _G.pairs[pairId].lit = gc_strdup(l);
839         _G.pairs[pairId].offset = offset;
840     }
841     /* Both a lit on the right and a true symbol on the left */
842     if (offset)
843         emit2("ld %s,!hashedstr + %u", pair, l, offset);
844     else
845         emit2("ld %s,!hashedstr", pair, l);
846 }
847
848 static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
849 {
850     /* if this is remateriazable */
851     if (isLitWord(aop)) {
852         fetchLitPair(pairId, aop, offset);
853     }
854     else { /* we need to get it byte by byte */
855         if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
856             aopGet(aop, offset, FALSE);
857             switch (aop->size) {
858             case 1:
859                 emit2("ld l,!*hl");
860                 emit2("ld h,!immedbyte", 0);
861                 break;
862             case 2:
863                 emit2("!ldahli");
864                 emit2("ld h,!*hl");
865                 emit2("ld l,a");
866                 break;
867             default:
868                 emit2("; WARNING: mlh woosed out.  This code is invalid.");
869             }
870         }
871         else if (IS_Z80 && aop->type == AOP_IY) {
872             /* Instead of fetching relative to IY, just grab directly
873                from the address IY refers to */
874             char *l = aopGetLitWordLong(aop, offset, FALSE);
875             wassert(l);
876             emit2("ld %s,(%s)", _pairs[pairId].name, l);
877         }
878         else {
879             emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
880             emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
881         }
882         /* PENDING: check? */
883         if (pairId == PAIR_HL)
884             spillPair(PAIR_HL);
885     }
886 }
887
888 static void fetchPair(PAIR_ID pairId, asmop *aop)
889 {
890     fetchPairLong(pairId, aop, 0);
891 }
892
893 static void fetchHL(asmop *aop)
894 {
895     fetchPair(PAIR_HL, aop);
896 }
897
898 static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
899 {
900     assert(pairId == PAIR_HL || pairId == PAIR_IY);
901
902     switch (aop->type) {
903     case AOP_IY:
904         fetchLitPair(pairId, aop, 0);
905         break;
906     case AOP_HL:
907         fetchLitPair(pairId, aop, offset);
908         _G.pairs[pairId].offset = offset;
909         break;
910     case AOP_STK: {
911         /* Doesnt include _G.stack.pushed */
912         int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
913         if (aop->aopu.aop_stk > 0) {
914             abso += _G.stack.param_offset;
915         }
916         assert(pairId == PAIR_HL);
917         /* In some cases we can still inc or dec hl */
918         if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
919             adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
920         }
921         else {
922             emit2("!ldahlsp", abso +_G.stack.pushed);
923         }
924         _G.pairs[pairId].offset = abso;
925         break;
926     }
927     default:
928         wassert(0);
929     }
930     _G.pairs[pairId].last_type = aop->type;
931 }
932
933 static void emitLabel(int key)
934 {
935     emit2("!tlabeldef", key);
936     spillCached();
937 }
938
939 /*-----------------------------------------------------------------*/
940 /* aopGet - for fetching value of the aop                          */
941 /*-----------------------------------------------------------------*/
942 static char *aopGet(asmop *aop, int offset, bool bit16)
943 {
944     char *s = buffer ;
945     char *rs;
946
947     /* offset is greater than size then zero */
948     /* PENDING: this seems a bit screwed in some pointer cases. */
949     if (offset > (aop->size - 1) &&
950         aop->type != AOP_LIT)
951         return zero;
952
953     /* depending on type */
954     switch (aop->type) {
955     case AOP_IMMD:
956         /* PENDING: re-target */
957         if (bit16) 
958             tsprintf (s,"!immedwords", aop->aopu.aop_immd);
959         else
960             switch (offset) {
961             case 2:
962                 tsprintf(s, "!bankimmeds", aop->aopu.aop_immd);
963                 break;
964             case 1:
965                 tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
966                 break;
967             case 0:
968                 tsprintf(s, "!lsbimmeds", aop->aopu.aop_immd);
969                 break;
970             default:
971                 wassert(0);
972             }
973         ALLOC_ATOMIC(rs,strlen(s)+1);
974         strcpy(rs,s);   
975         return rs;
976         
977     case AOP_DIR:
978         wassert(IS_GB);
979         emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
980         sprintf(s, "a");
981         ALLOC_ATOMIC(rs,strlen(s)+1);
982         strcpy(rs,s);   
983         return rs;
984         
985     case AOP_SFR:
986         wassert(IS_GB);
987         emitcode("ldh", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
988         sprintf(s, "a");
989         ALLOC_ATOMIC(rs,strlen(s)+1);
990         strcpy(rs,s);   
991         return rs;
992
993     case AOP_REG:
994         return aop->aopu.aop_reg[offset]->name;
995
996     case AOP_HL:
997         wassert(IS_GB);
998         setupPair(PAIR_HL, aop, offset);
999         tsprintf(s, "!*hl");
1000         return gc_strdup(s);
1001
1002     case AOP_IY:
1003         wassert(IS_Z80);
1004         setupPair(PAIR_IY, aop, offset);
1005         tsprintf(s,"!*iyx", offset);
1006         ALLOC_ATOMIC(rs,strlen(s)+1);
1007         strcpy(rs,s);   
1008         return rs;
1009
1010     case AOP_STK:
1011         if (IS_GB) {
1012             setupPair(PAIR_HL, aop, offset);
1013             tsprintf(s, "!*hl");
1014         }
1015         else {
1016             tsprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
1017         }
1018         ALLOC_ATOMIC(rs,strlen(s)+1);
1019         strcpy(rs,s);   
1020         return rs;
1021         
1022     case AOP_CRY:
1023         wassert(0);
1024         
1025     case AOP_ACC:
1026         if (!offset) {
1027             return "a";
1028         }
1029         return "!zero";
1030
1031     case AOP_HLREG:
1032         wassert(offset < 2);
1033         return aop->aopu.aop_str[offset];
1034
1035     case AOP_LIT:
1036         return aopLiteral (aop->aopu.aop_lit,offset);
1037         
1038     case AOP_STR:
1039         aop->coff = offset;
1040         return aop->aopu.aop_str[offset];
1041     default:
1042         break;
1043     }
1044     wassertl(0, "aopget got unsupported aop->type");
1045     exit(0);
1046 }
1047
1048 bool isRegString(const char *s)
1049 {
1050     if (!strcmp(s, "b") ||
1051         !strcmp(s, "c") ||
1052         !strcmp(s, "d") ||
1053         !strcmp(s, "e") ||
1054         !strcmp(s, "a") ||
1055         !strcmp(s, "h") ||
1056         !strcmp(s, "l"))
1057         return TRUE;
1058     return FALSE;
1059 }
1060
1061 bool isConstant(const char *s)
1062 {
1063     /* This is a bit of a hack... */
1064     return  (*s == '#' || *s == '$');
1065 }
1066
1067 bool canAssignToPtr(const char *s)
1068 {
1069     if (isRegString(s))
1070         return TRUE;
1071     if (isConstant(s))
1072         return TRUE;
1073     return FALSE;
1074 }
1075
1076 /*-----------------------------------------------------------------*/
1077 /* aopPut - puts a string for a aop                                */
1078 /*-----------------------------------------------------------------*/
1079 static void aopPut (asmop *aop, const char *s, int offset)
1080 {
1081     if (aop->size && offset > ( aop->size - 1)) {
1082         werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1083                "aopPut got offset > aop->size");
1084         exit(0);
1085     }
1086
1087     /* will assign value to value */
1088     /* depending on where it is ofcourse */
1089     switch (aop->type) {
1090     case AOP_DIR:
1091         /* Direct.  Hmmm. */
1092         wassert(IS_GB);
1093         if (strcmp(s, "a"))
1094             emitcode("ld", "a,%s", s);
1095         emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
1096         break;
1097         
1098     case AOP_SFR:
1099         wassert(IS_GB);
1100         if (strcmp(s, "a"))
1101             emitcode("ld", "a,%s", s);
1102         emitcode("ldh", "(%s+%d),a", aop->aopu.aop_dir, offset);
1103         break;
1104         
1105     case AOP_REG:
1106         if (!strcmp(s, "!*hl"))
1107             emit2("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1108         else
1109             emit2("ld %s,%s",
1110                   aop->aopu.aop_reg[offset]->name, s);
1111         break;
1112         
1113     case AOP_IY:
1114         wassert(!IS_GB);
1115         setupPair(PAIR_IY, aop, offset);
1116         if (!canAssignToPtr(s)) {
1117             emit2("ld a,%s", s);
1118             emit2("ld !*iyx,a", offset);
1119         }
1120         else
1121             emit2("ld !*iyx,%s", offset, s);
1122         break;
1123     
1124     case AOP_HL:
1125         wassert(IS_GB);
1126         /* PENDING: for re-target */
1127         if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1128             emit2("ld a,!*hl");
1129             s = "a";
1130         }
1131         setupPair(PAIR_HL, aop, offset);
1132         
1133         emit2("ld !*hl,%s", s);
1134         break;
1135
1136     case AOP_STK:
1137         if (IS_GB) {
1138             /* PENDING: re-target */
1139             if (!strcmp(s, "!*hl") || !strcmp(s, "(hl)") || !strcmp(s, "[hl]")) {
1140                 emit2("ld a,!*hl");
1141                 s = "a";
1142             }
1143             setupPair(PAIR_HL, aop, offset);
1144             if (!canAssignToPtr(s)) {
1145                 emit2("ld a,%s", s);
1146                 emit2("ld !*hl,a");
1147             }
1148             else
1149                 emit2("ld !*hl,%s", s);
1150         }
1151         else {
1152             if (!canAssignToPtr(s)) {
1153                 emit2("ld a,%s", s);
1154                 emit2("ld !*ixx,a", aop->aopu.aop_stk+offset);
1155             }
1156             else
1157                 emit2("ld !*ixx,%s", aop->aopu.aop_stk+offset, s);
1158         }
1159         break;
1160         
1161     case AOP_CRY:
1162         /* if bit variable */
1163         if (!aop->aopu.aop_dir) {
1164             emit2("ld a,#0");
1165             emit2("rla");
1166         } else {
1167             /* In bit space but not in C - cant happen */
1168             wassert(0);
1169         }
1170         break;
1171         
1172     case AOP_STR:
1173         aop->coff = offset;
1174         if (strcmp(aop->aopu.aop_str[offset],s)) {
1175             emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1176         }
1177         break;
1178         
1179     case AOP_ACC:
1180         aop->coff = offset;
1181         if (!offset && (strcmp(s,"acc") == 0))
1182             break;
1183         if (offset>0) {
1184             
1185             emitcode("", "; Error aopPut AOP_ACC");
1186         }
1187         else {
1188             if (strcmp(aop->aopu.aop_str[offset],s))
1189                 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
1190         }
1191         break;
1192
1193     case AOP_HLREG:
1194         wassert(offset < 2);
1195         emit2("ld %s,%s", aop->aopu.aop_str[offset], s);
1196         break;
1197
1198     default :
1199         werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1200                "aopPut got unsupported aop->type");
1201         exit(0);    
1202     }    
1203 }
1204
1205 #define AOP(op) op->aop
1206 #define AOP_TYPE(op) AOP(op)->type
1207 #define AOP_SIZE(op) AOP(op)->size
1208 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1209
1210 static void commitPair(asmop *aop, PAIR_ID id)
1211 {
1212     if (id == PAIR_HL && requiresHL(aop)) {
1213         emit2("ld a,l");
1214         emit2("ld d,h");
1215         aopPut(aop, "a", 0);
1216         aopPut(aop, "d", 1);
1217     }
1218     else {
1219         aopPut(aop, _pairs[id].l, 0);
1220         aopPut(aop, _pairs[id].h, 1);
1221     }
1222 }
1223
1224 /*-----------------------------------------------------------------*/
1225 /* getDataSize - get the operand data size                         */
1226 /*-----------------------------------------------------------------*/
1227 int getDataSize(operand *op)
1228 {
1229     int size;
1230     size = AOP_SIZE(op);
1231     if(size == 3) {
1232         /* pointer */
1233         wassert(0);
1234     }
1235     return size;
1236 }
1237
1238 /*-----------------------------------------------------------------*/
1239 /* movLeft2Result - move byte from left to result                  */
1240 /*-----------------------------------------------------------------*/
1241 static void movLeft2Result (operand *left, int offl,
1242                             operand *result, int offr, int sign)
1243 {
1244     char *l;
1245     if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
1246         l = aopGet(AOP(left),offl,FALSE);
1247
1248         if (!sign) {
1249             aopPut(AOP(result),l,offr);
1250         }
1251         else {
1252             wassert(0);
1253         }
1254     }
1255 }
1256
1257
1258 /** Put Acc into a register set 
1259  */
1260 void outAcc(operand *result)
1261 {
1262     int size, offset;
1263     size = getDataSize(result);
1264     if (size){
1265         aopPut(AOP(result),"a",0);
1266         size--;
1267         offset = 1;
1268         /* unsigned or positive */
1269         while (size--){
1270             aopPut(AOP(result), zero, offset++);
1271         }
1272     }
1273 }
1274
1275 /** Take the value in carry and put it into a register
1276  */
1277 void outBitC(operand *result)
1278 {
1279     /* if the result is bit */
1280     if (AOP_TYPE(result) == AOP_CRY) {
1281         emitcode("", "; Note: outBitC form 1");
1282         aopPut(AOP(result),"blah",0);
1283     }
1284     else {
1285         emit2("ld a,!zero");
1286         emit2("rla");
1287         outAcc(result);
1288     }
1289 }
1290
1291 /*-----------------------------------------------------------------*/
1292 /* toBoolean - emit code for orl a,operator(sizeop)                */
1293 /*-----------------------------------------------------------------*/
1294 void toBoolean(operand *oper)
1295 {
1296     int size = AOP_SIZE(oper);
1297     int offset = 0;
1298     if (size>1) {
1299         emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
1300         size--;
1301         while (size--) 
1302             emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
1303     }
1304     else {
1305         if (AOP(oper)->type != AOP_ACC) {
1306             CLRC;
1307             emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
1308         }
1309     }
1310 }
1311
1312 /*-----------------------------------------------------------------*/
1313 /* genNot - generate code for ! operation                          */
1314 /*-----------------------------------------------------------------*/
1315 static void genNot (iCode *ic)
1316 {
1317     link *optype = operandType(IC_LEFT(ic));
1318
1319     /* assign asmOps to operand & result */
1320     aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
1321     aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1322
1323     /* if in bit space then a special case */
1324     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1325         wassert(0);
1326     }
1327
1328     /* if type float then do float */
1329     if (IS_FLOAT(optype)) {
1330         wassert(0);
1331     }
1332
1333     toBoolean(IC_LEFT(ic));
1334
1335     /* Not of A:
1336        If A == 0, !A = 1
1337        else A = 0
1338        So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1339     emit2("sub a,!one");
1340     outBitC(IC_RESULT(ic));
1341
1342     /* release the aops */
1343     freeAsmop(IC_LEFT(ic),NULL,ic);
1344     freeAsmop(IC_RESULT(ic),NULL,ic);
1345 }
1346
1347 /*-----------------------------------------------------------------*/
1348 /* genCpl - generate code for complement                           */
1349 /*-----------------------------------------------------------------*/
1350 static void genCpl (iCode *ic)
1351 {
1352     int offset = 0;
1353     int size ;
1354
1355
1356     /* assign asmOps to operand & result */
1357     aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1358     aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
1359
1360     /* if both are in bit space then 
1361     a special case */
1362     if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1363         AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) { 
1364         wassert(0);
1365     } 
1366
1367     size = AOP_SIZE(IC_RESULT(ic));
1368     while (size--) {
1369         char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1370         MOVA(l);       
1371         emitcode("cpl","");
1372         aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1373     }
1374
1375     /* release the aops */
1376     freeAsmop(IC_LEFT(ic),NULL,ic);
1377     freeAsmop(IC_RESULT(ic),NULL,ic);
1378 }
1379
1380 /*-----------------------------------------------------------------*/
1381 /* genUminus - unary minus code generation                         */
1382 /*-----------------------------------------------------------------*/
1383 static void genUminus (iCode *ic)
1384 {
1385     int offset ,size ;
1386     link *optype, *rtype;
1387
1388     /* assign asmops */
1389     aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1390     aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
1391
1392     /* if both in bit space then special
1393     case */
1394     if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1395         AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) { 
1396         wassert(0);
1397         goto release;
1398     } 
1399
1400     optype = operandType(IC_LEFT(ic));
1401     rtype = operandType(IC_RESULT(ic));
1402
1403     /* if float then do float stuff */
1404     if (IS_FLOAT(optype)) {
1405         wassert(0);
1406         goto release;
1407     }
1408
1409     /* otherwise subtract from zero */
1410     size = AOP_SIZE(IC_LEFT(ic));
1411     offset = 0 ;
1412     CLRC ;
1413     while(size--) {
1414         char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1415         emit2("ld a,!zero");
1416         emit2("sbc a,%s",l);
1417         aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1418     }
1419
1420     /* if any remaining bytes in the result */
1421     /* we just need to propagate the sign   */
1422     if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1423         emit2("rlc a");
1424         emit2("sbc a,a");
1425         while (size--) 
1426             aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1427     }       
1428
1429 release:
1430     /* release the aops */
1431     freeAsmop(IC_LEFT(ic),NULL,ic);
1432     freeAsmop(IC_RESULT(ic),NULL,ic);
1433 }
1434
1435 static void _push(PAIR_ID pairId)
1436 {
1437     emit2("push %s", _pairs[pairId].name);
1438     _G.stack.pushed += 2;
1439 }
1440
1441 static void _pop(PAIR_ID pairId)
1442 {
1443     emit2("pop %s", _pairs[pairId].name);
1444     _G.stack.pushed -= 2;
1445 }
1446
1447
1448 /*-----------------------------------------------------------------*/
1449 /* assignResultValue -                                             */
1450 /*-----------------------------------------------------------------*/
1451 void assignResultValue(operand * oper)
1452 {
1453     int size = AOP_SIZE(oper);
1454     bool topInA = 0;
1455
1456     wassert(size <= 4);
1457     topInA = requiresHL(AOP(oper));
1458
1459 #if 0
1460     if (!IS_GB)
1461         wassert(size <= 2);
1462 #endif
1463     if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
1464         /* We do it the hard way here. */
1465         _push(PAIR_HL);
1466         aopPut(AOP(oper), _fReturn[0], 0);
1467         aopPut(AOP(oper), _fReturn[1], 1);
1468         emitcode("pop", "de");
1469         _G.stack.pushed -= 2;
1470         aopPut(AOP(oper), _fReturn[0], 2);
1471         aopPut(AOP(oper), _fReturn[1], 3);
1472     }
1473     else {
1474         while (size--) {
1475             aopPut(AOP(oper), _fReturn[size], size);
1476         }
1477     }
1478 }
1479
1480 /*-----------------------------------------------------------------*/
1481 /* genIpush - genrate code for pushing this gets a little complex  */
1482 /*-----------------------------------------------------------------*/
1483 static void genIpush (iCode *ic)
1484 {
1485     int size, offset = 0 ;
1486     char *l;
1487
1488     /* if this is not a parm push : ie. it is spill push 
1489        and spill push is always done on the local stack */
1490     if (!ic->parmPush) {
1491         /* and the item is spilt then do nothing */
1492         if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1493             return ;
1494
1495         aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1496         size = AOP_SIZE(IC_LEFT(ic));
1497         /* push it on the stack */
1498         if (isPair(AOP(IC_LEFT(ic)))) {
1499             emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1500             _G.stack.pushed += 2;
1501         }
1502         else {
1503             offset = size;
1504             while (size--) {
1505                 /* Simple for now - load into A and PUSH AF */
1506                 if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1507                     char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1508                     wassert(l);
1509                     emit2("ld a,(%s)", l);
1510                 }
1511                 else {
1512                     l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1513                     emit2("ld a,%s", l);
1514                 }
1515                 emit2("push af");
1516                 emit2("inc sp");
1517                 _G.stack.pushed++;
1518             }
1519         }
1520         return ;        
1521     }
1522
1523     /* Hmmm... what about saving the currently used registers
1524        at this point? */
1525
1526     /* then do the push */
1527     aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1528
1529     size = AOP_SIZE(IC_LEFT(ic));
1530
1531     if (isPair(AOP(IC_LEFT(ic)))) {
1532         _G.stack.pushed+=2;
1533         emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1534     }
1535     else {
1536         if (size == 2) {
1537             fetchHL(AOP(IC_LEFT(ic)));
1538             emitcode("push", "hl");
1539             spillPair(PAIR_HL);
1540             _G.stack.pushed += 2;
1541             goto release;
1542         }
1543         if (size == 4) {
1544             fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
1545             emitcode("push", "hl");
1546             spillPair(PAIR_HL);
1547             _G.stack.pushed += 2;
1548             fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 0);
1549             emitcode("push", "hl");
1550             spillPair(PAIR_HL);
1551             _G.stack.pushed += 2;
1552             goto release;
1553         }
1554         offset = size;
1555         while (size--) {
1556             if (AOP(IC_LEFT(ic))->type == AOP_IY) {
1557                 char *l = aopGetLitWordLong(AOP(IC_LEFT(ic)), --offset, FALSE);
1558                 wassert(l);
1559                 emit2("ld a,(%s)", l);
1560             }
1561             else {
1562                 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1563                 emit2("ld a,%s", l);
1564             }
1565             emitcode("push", "af");
1566             emitcode("inc", "sp");
1567             _G.stack.pushed++;
1568         }       
1569     }
1570  release:
1571     freeAsmop(IC_LEFT(ic),NULL,ic);
1572 }
1573
1574 /*-----------------------------------------------------------------*/
1575 /* genIpop - recover the registers: can happen only for spilling   */
1576 /*-----------------------------------------------------------------*/
1577 static void genIpop (iCode *ic)
1578 {
1579     int size,offset ;
1580
1581
1582     /* if the temp was not pushed then */
1583     if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1584         return ;
1585
1586     aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1587     size = AOP_SIZE(IC_LEFT(ic));
1588     offset = (size-1);
1589     if (isPair(AOP(IC_LEFT(ic)))) {
1590         emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1591     }
1592     else {
1593         while (size--) {
1594             emitcode("dec", "sp");
1595             emitcode("pop", "hl");
1596             spillPair(PAIR_HL);
1597             aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1598         }
1599     }
1600
1601     freeAsmop(IC_LEFT(ic),NULL,ic);
1602 }
1603
1604 static int _isPairUsed(iCode *ic, PAIR_ID pairId)
1605 {
1606     int ret = 0;
1607     switch (pairId) {
1608     case PAIR_DE:
1609         if (bitVectBitValue(ic->rUsed, D_IDX))
1610             ret++;
1611         if (bitVectBitValue(ic->rUsed, E_IDX))
1612             ret++;
1613         break;
1614     default:
1615         wassert(0);
1616     }
1617     return ret;
1618 }
1619
1620 static int _opUsesPair(operand *op, iCode *ic, PAIR_ID pairId)
1621 {
1622     int ret = 0;
1623     asmop *aop;
1624     symbol *sym = OP_SYMBOL(op);
1625
1626     if (sym->isspilt || sym->nRegs == 0)
1627         return 0;
1628
1629     aopOp(op, ic, FALSE, FALSE);
1630     
1631     aop = AOP(op);
1632     if (aop->type == AOP_REG) {
1633         int i;
1634         for (i=0; i < aop->size; i++) {
1635             if (pairId == PAIR_DE) {
1636                 emit2("; name %s", aop->aopu.aop_reg[i]->name);
1637                 if (!strcmp(aop->aopu.aop_reg[i]->name, "e"))
1638                     ret++;
1639                 if (!strcmp(aop->aopu.aop_reg[i]->name, "d"))
1640                     ret++;
1641             }
1642             else {
1643                 wassert(0);
1644             }
1645         }
1646     }
1647
1648     freeAsmop(IC_LEFT(ic),NULL,ic);
1649     return ret;
1650 }
1651
1652 /* This is quite unfortunate */
1653 static void setArea(int inHome)
1654 {
1655     static int lastArea = 0;
1656
1657     /*    
1658     if (_G.in_home != inHome) {
1659         if (inHome) {
1660             const char *sz = port->mem.code_name;
1661             port->mem.code_name = "HOME";
1662             emit2("!area", CODE_NAME);
1663             port->mem.code_name = sz;
1664         }
1665         else
1666         emit2("!area", CODE_NAME);*/
1667         _G.in_home = inHome;
1668         //    }
1669 }
1670
1671 static bool isInHome(void)
1672 {
1673     return _G.in_home;
1674 }
1675
1676 /** Emit the code for a call statement 
1677  */
1678 static void emitCall(iCode *ic, bool ispcall)
1679 {
1680     int pushed_de = 0;
1681     link *detype = getSpec(operandType(IC_LEFT(ic)));
1682
1683     if (IS_BANKED(detype)) 
1684         emit2("; call to a banked function");
1685
1686     /* if caller saves & we have not saved then */
1687     if (!ic->regsSaved) {
1688         /* PENDING */
1689     }
1690     
1691     /* if send set is not empty then assign */
1692     if (sendSet) {
1693         iCode *sic;
1694         int send = 0;
1695         int n = elementsInSet(sendSet);
1696         if (IS_Z80 && n == 2 && _isPairUsed(ic, PAIR_DE)) {
1697             /* Only push de if it is used and if it's not used
1698                in the return value */
1699             /* Panic if partly used */
1700             if (_opUsesPair(IC_RESULT(ic), ic, PAIR_DE) == 1) {
1701                 emit2("; Warning: de crossover");
1702             }
1703             else if (!_opUsesPair(IC_RESULT(ic), ic, PAIR_DE)) {
1704                 /* Store away de */
1705                 _push(PAIR_DE);
1706                 pushed_de = 1;
1707             }
1708         }
1709         /* PENDING: HACK */
1710         if (IS_Z80 && n == 2 ) {
1711             /* Want to load HL first, then DE as HL may = DE */
1712             sic = setFirstItem(sendSet);
1713             sic = setNextItem(sendSet);
1714             aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1715             fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1716             send++;
1717             freeAsmop (IC_LEFT(sic),NULL,sic);
1718             sic = setFirstItem(sendSet);
1719             aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1720             fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1721             send++;
1722             freeAsmop (IC_LEFT(sic),NULL,sic);
1723         }
1724         else {
1725             for (sic = setFirstItem(sendSet) ; sic ; 
1726                  sic = setNextItem(sendSet)) {
1727                 int size;
1728                 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
1729                 size = AOP_SIZE(IC_LEFT(sic));
1730                 wassert(size <= 2);
1731                 /* Always send in pairs */
1732                 switch (send) {
1733                 case 0:
1734                     if (IS_Z80 && n == 1)
1735                         fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1736                     else
1737                         fetchPair(PAIR_DE, AOP(IC_LEFT(sic)));
1738                     break;
1739                 case 1:
1740                     fetchPair(PAIR_HL, AOP(IC_LEFT(sic)));
1741                     break;
1742                 default:
1743                     /* Send set too big */
1744                     wassert(0);
1745                 }
1746                 send++;
1747                 freeAsmop (IC_LEFT(sic),NULL,sic);
1748             }
1749         }
1750         sendSet = NULL;
1751         if (pushed_de) {
1752         }
1753     }
1754
1755     if (ispcall) {
1756         if (IS_BANKED(detype)) {
1757             werror(W_INDIR_BANKED);
1758         }
1759         aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1760
1761         if (isLitWord(AOP(IC_LEFT(ic)))) {
1762             emitcode("", "; Special case where the pCall is to a constant");
1763             emitcode("call", aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE));
1764         }
1765         else {
1766             symbol *rlbl = newiTempLabel(NULL);
1767             spillPair(PAIR_HL);
1768             emit2("ld hl,!immed!tlabel", (rlbl->key+100));
1769             emitcode("push", "hl");
1770             _G.stack.pushed += 2;
1771             
1772             fetchHL(AOP(IC_LEFT(ic)));
1773             emit2("jp !*hl");
1774             emit2("!tlabeldef", (rlbl->key+100));
1775             _G.stack.pushed -= 2;
1776         }
1777         freeAsmop(IC_LEFT(ic),NULL,ic); 
1778     }
1779     else {
1780         char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1781             OP_SYMBOL(IC_LEFT(ic))->rname :
1782             OP_SYMBOL(IC_LEFT(ic))->name;
1783         if (IS_BANKED(detype)) {
1784             emit2("call banked_call");
1785             emit2("!dws", name);
1786             emit2("!dw !bankimmeds", name);
1787         }
1788         else {
1789             /* make the call */
1790             emit2("call %s", name);
1791         }
1792     }
1793     spillCached();
1794
1795     /* if we need assign a result value */
1796     if ((IS_ITEMP(IC_RESULT(ic)) && 
1797          (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1798           OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1799         IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1800
1801         accInUse++;
1802         aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
1803         accInUse--;
1804
1805         assignResultValue(IC_RESULT(ic));
1806                 
1807         freeAsmop(IC_RESULT(ic),NULL, ic);
1808     }
1809
1810     /* adjust the stack for parameters if required */
1811     if (IC_LEFT(ic)->parmBytes) {
1812         int i = IC_LEFT(ic)->parmBytes;
1813         _G.stack.pushed -= i;
1814         if (IS_GB) {
1815             emit2("!ldaspsp", i);
1816         }
1817         else {
1818             spillCached();
1819             if (i>6) {
1820                 emitcode("ld", "hl,#%d", i);
1821                 emitcode("add", "hl,sp");
1822                 emitcode("ld", "sp,hl");
1823             }
1824             else {
1825                 while (i>1) {
1826                     emitcode("pop", "hl");
1827                     i-=2;
1828                 }
1829                 if (i) 
1830                     emitcode("inc", "sp");
1831             }
1832             spillCached();
1833         }
1834     }
1835     if (pushed_de)
1836         _pop(PAIR_DE);
1837 }
1838
1839 /*-----------------------------------------------------------------*/
1840 /* genCall - generates a call statement                            */
1841 /*-----------------------------------------------------------------*/
1842 static void genCall (iCode *ic)
1843 {
1844     link *detype = getSpec(operandType(IC_LEFT(ic)));
1845     emitCall(ic, FALSE);
1846 }
1847
1848 /*-----------------------------------------------------------------*/
1849 /* genPcall - generates a call by pointer statement                */
1850 /*-----------------------------------------------------------------*/
1851 static void genPcall (iCode *ic)
1852 {
1853     emitCall(ic, TRUE);
1854 }
1855
1856 /*-----------------------------------------------------------------*/
1857 /* resultRemat - result  is rematerializable                       */
1858 /*-----------------------------------------------------------------*/
1859 static int resultRemat (iCode *ic)
1860 {
1861     if (SKIP_IC(ic) || ic->op == IFX)
1862         return 0;
1863
1864     if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1865         symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1866         if (sym->remat && !POINTER_SET(ic)) 
1867             return 1;
1868     }
1869
1870     return 0;
1871 }
1872
1873 /*-----------------------------------------------------------------*/
1874 /* genFunction - generated code for function entry                 */
1875 /*-----------------------------------------------------------------*/
1876 static void genFunction (iCode *ic)
1877 {
1878     symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1879     link *fetype;
1880
1881     nregssaved = 0;
1882     setArea(IS_NONBANKED(sym->etype));
1883
1884     /* create the function header */
1885     emit2("!functionheader", sym->name);
1886     /* PENDING: portability. */
1887     emit2("__%s_start:", sym->rname);
1888     emit2("!functionlabeldef", sym->rname);
1889    
1890     fetype = getSpec(operandType(IC_LEFT(ic)));
1891     
1892     /* if critical function then turn interrupts off */
1893     if (SPEC_CRTCL(fetype))
1894         emit2("!di");
1895
1896     /* if this is an interrupt service routine then
1897     save acc, b, dpl, dph  */
1898     if (IS_ISR(sym->etype)) {
1899         emit2("!pusha");
1900     }
1901     /* PENDING: callee-save etc */
1902
1903     /* If BC or DE are used, then push */
1904     _G.stack.pushed_bc = 0;
1905     _G.stack.pushed_de = 0;
1906     _G.stack.param_offset = 0;
1907     if (sym->regsUsed) {
1908         int i;
1909         for ( i = 0 ; i < sym->regsUsed->size ; i++) {
1910             if (bitVectBitValue(sym->regsUsed, i)) {
1911                 switch (i) {
1912                 case C_IDX:
1913                 case B_IDX:
1914                     _G.stack.pushed_bc = 1;
1915                     break;
1916                 case D_IDX:
1917                 case E_IDX:
1918                     if (IS_Z80)
1919                         _G.stack.pushed_de = 1;
1920                     break;
1921                 }
1922             }
1923         }
1924         if (_G.stack.pushed_bc) {
1925             emit2("push bc");
1926             _G.stack.param_offset += 2;
1927         }
1928         if (_G.stack.pushed_de) {
1929             emit2("push de");
1930             _G.stack.param_offset += 2;
1931         }
1932     }
1933
1934     /* adjust the stack for the function */
1935     _G.stack.last = sym->stack;
1936
1937     if (sym->stack)
1938         emit2("!enterx", sym->stack);
1939     else
1940         emit2("!enter");
1941     _G.stack.offset = sym->stack;
1942 }
1943
1944 /*-----------------------------------------------------------------*/
1945 /* genEndFunction - generates epilogue for functions               */
1946 /*-----------------------------------------------------------------*/
1947 static void genEndFunction (iCode *ic)
1948 {
1949     symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1950
1951     if (IS_ISR(sym->etype)) {
1952         wassert(0);
1953     }
1954     else {
1955         if (SPEC_CRTCL(sym->etype))
1956             emit2("!ei");
1957         
1958         /* PENDING: calleeSave */
1959
1960         /* if debug then send end of function */
1961         if (options.debug && currFunc) { 
1962             debugLine = 1;
1963             emitcode("","C$%s$%d$%d$%d ==.",
1964                      ic->filename,currFunc->lastLine,
1965                      ic->level,ic->block); 
1966             if (IS_STATIC(currFunc->etype))         
1967                 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name); 
1968             else
1969                 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1970             debugLine = 0;
1971         }
1972         if (_G.stack.offset)
1973             emit2("!leavex", _G.stack.offset);
1974         else
1975             emit2("!leave");
1976
1977         if (_G.stack.pushed_de)
1978             emit2("pop de");
1979         if (_G.stack.pushed_bc)
1980             emit2("pop bc");
1981         /* Both baned and non-banked just ret */
1982         emit2("ret");
1983         
1984         /* PENDING: portability. */
1985         emit2("__%s_end:", sym->rname);
1986     }
1987     _G.flush_statics = 1;
1988     _G.stack.pushed = 0;
1989     _G.stack.offset = 0;
1990 }
1991
1992 /*-----------------------------------------------------------------*/
1993 /* genRet - generate code for return statement                     */
1994 /*-----------------------------------------------------------------*/
1995 static void genRet (iCode *ic)
1996 {
1997     char *l;
1998     /* Errk.  This is a hack until I can figure out how
1999        to cause dehl to spill on a call */
2000     int size,offset = 0;
2001     
2002     /* if we have no return value then
2003        just generate the "ret" */
2004     if (!IC_LEFT(ic)) 
2005         goto jumpret;       
2006     
2007     /* we have something to return then
2008        move the return value into place */
2009     aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
2010     size = AOP_SIZE(IC_LEFT(ic));
2011     
2012     if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
2013         if (IS_GB) {
2014             emitcode("ld", "de,%s", l);
2015         }
2016         else {
2017             emitcode("ld", "hl,%s", l);
2018         }
2019     }
2020     else {
2021         if (IS_GB && size == 4 && requiresHL(AOP(IC_LEFT(ic)))) {
2022             fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
2023             fetchPairLong(PAIR_HL, AOP(IC_LEFT(ic)), 2);
2024         }
2025         else {
2026             while (size--) {
2027                 l = aopGet(AOP(IC_LEFT(ic)),offset,
2028                            FALSE);
2029                 if (strcmp(_fReturn[offset],l))
2030                     emitcode("ld","%s,%s", _fReturn[offset++],l);
2031             }
2032         }
2033     }
2034     freeAsmop (IC_LEFT(ic),NULL,ic);
2035     
2036  jumpret:
2037         /* generate a jump to the return label
2038            if the next is not the return statement */
2039     if (!(ic->next && ic->next->op == LABEL &&
2040           IC_LABEL(ic->next) == returnLabel))
2041         
2042         emit2("jp !tlabel", returnLabel->key+100);
2043 }
2044
2045 /*-----------------------------------------------------------------*/
2046 /* genLabel - generates a label                                    */
2047 /*-----------------------------------------------------------------*/
2048 static void genLabel (iCode *ic)
2049 {
2050     /* special case never generate */
2051     if (IC_LABEL(ic) == entryLabel)
2052         return ;
2053
2054     emitLabel(IC_LABEL(ic)->key+100);
2055 }
2056
2057 /*-----------------------------------------------------------------*/
2058 /* genGoto - generates a ljmp                                      */
2059 /*-----------------------------------------------------------------*/
2060 static void genGoto (iCode *ic)
2061 {
2062     emit2("jp !tlabel", IC_LABEL(ic)->key+100);
2063 }
2064
2065 /*-----------------------------------------------------------------*/
2066 /* genPlusIncr :- does addition with increment if possible         */
2067 /*-----------------------------------------------------------------*/
2068 static bool genPlusIncr (iCode *ic)
2069 {
2070     unsigned int icount ;
2071     unsigned int size = getDataSize(IC_RESULT(ic));
2072     PAIR_ID resultId = getPairId(AOP(IC_RESULT(ic)));
2073
2074     /* will try to generate an increment */
2075     /* if the right side is not a literal 
2076        we cannot */
2077     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2078         return FALSE;
2079     
2080     emitcode("", "; genPlusIncr");
2081
2082     icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2083     
2084     /* If result is a pair */
2085     if (resultId != PAIR_INVALID) {
2086         if (isLitWord(AOP(IC_LEFT(ic)))) {
2087             fetchLitPair(getPairId(AOP(IC_RESULT(ic))), AOP(IC_LEFT(ic)), icount);
2088             return TRUE;
2089         }
2090         if (isPair(AOP(IC_LEFT(ic))) && resultId == PAIR_HL && icount > 2) {
2091             fetchPair(resultId, AOP(IC_RIGHT(ic)));
2092             emitcode("add", "hl,%s", getPairName(AOP(IC_LEFT(ic))));
2093             return TRUE;
2094         }
2095         if (icount > 5)
2096             return FALSE;
2097         /* Inc a pair */
2098         if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2099             if (icount > 2)
2100                 return FALSE;
2101             movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2102             movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2103         }
2104         while (icount--) {
2105             emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
2106         }
2107         return TRUE;
2108     }
2109
2110     /* if the literal value of the right hand side
2111        is greater than 4 then it is not worth it */
2112     if (icount > 4)
2113         return FALSE;
2114
2115     /* if increment 16 bits in register */
2116     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2117         size > 1 &&
2118         icount == 1
2119         ) {
2120         int offset = 0;
2121         symbol *tlbl = NULL;
2122         tlbl = newiTempLabel(NULL);
2123         while (size--) {
2124             emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)), offset++, FALSE));
2125             if (size) {
2126                 emit2("!shortjp nz,!tlabel", tlbl->key+100);
2127             }
2128         }
2129         emitLabel(tlbl->key+100);
2130         return TRUE;
2131     }
2132
2133     /* if the sizes are greater than 1 then we cannot */
2134     if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2135         AOP_SIZE(IC_LEFT(ic)) > 1   )
2136         return FALSE ;
2137     
2138     /* we can if the aops of the left & result match or
2139        if they are in registers and the registers are the
2140        same */
2141     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
2142         while (icount--)
2143             emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
2144         return TRUE ;
2145     }
2146     
2147     return FALSE ;
2148 }
2149
2150 /*-----------------------------------------------------------------*/
2151 /* outBitAcc - output a bit in acc                                 */
2152 /*-----------------------------------------------------------------*/
2153 void outBitAcc(operand *result)
2154 {
2155     symbol *tlbl = newiTempLabel(NULL);
2156     /* if the result is a bit */
2157     if (AOP_TYPE(result) == AOP_CRY){
2158         wassert(0);
2159     }
2160     else {
2161         emit2("!shortjp z,!tlabel", tlbl->key+100);
2162         emit2("ld a,!one");
2163         emitLabel(tlbl->key+100);
2164         outAcc(result);
2165     }
2166 }
2167
2168 /*-----------------------------------------------------------------*/
2169 /* genPlus - generates code for addition                           */
2170 /*-----------------------------------------------------------------*/
2171 static void genPlus (iCode *ic)
2172 {
2173     int size, offset = 0;
2174
2175     /* special cases :- */
2176
2177     aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2178     aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2179     aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2180
2181     /* Swap the left and right operands if:
2182
2183        if literal, literal on the right or
2184        if left requires ACC or right is already
2185        in ACC */
2186
2187     if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
2188         (AOP_NEEDSACC(IC_LEFT(ic))) ||
2189         AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
2190         operand *t = IC_RIGHT(ic);
2191         IC_RIGHT(ic) = IC_LEFT(ic);
2192         IC_LEFT(ic) = t;
2193     }
2194
2195     /* if both left & right are in bit
2196     space */
2197     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2198         AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2199         /* Cant happen */
2200         wassert(0);
2201     }
2202
2203     /* if left in bit space & right literal */
2204     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2205         AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
2206         /* Can happen I guess */
2207         wassert(0);
2208     }
2209
2210     /* if I can do an increment instead
2211     of add then GOOD for ME */
2212     if (genPlusIncr (ic) == TRUE)
2213         goto release;   
2214
2215     emit2("; genPlusIncr failed");
2216
2217     size = getDataSize(IC_RESULT(ic));
2218
2219     /* Special case when left and right are constant */
2220     if (isPair(AOP(IC_RESULT(ic)))) {
2221         char *left, *right;
2222         
2223         left = aopGetLitWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
2224         right = aopGetLitWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
2225         if (left && right) {
2226             /* It's a pair */
2227             /* PENDING: fix */
2228             char buffer[100];
2229             sprintf(buffer, "#(%s + %s)", left, right);
2230             emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
2231             goto release;
2232         }
2233     }
2234
2235     if (isPair(AOP(IC_RIGHT(ic))) && getPairId(AOP(IC_RESULT(ic))) == PAIR_HL) {
2236         /* Fetch into HL then do the add */
2237         spillPair(PAIR_HL);
2238         fetchPair(PAIR_HL, AOP(IC_LEFT(ic)));
2239         emitcode("add", "hl,%s", getPairName(AOP(IC_RIGHT(ic))));
2240         goto release;
2241     }
2242
2243     /* Special case:
2244        ld hl,sp+n trashes C so we cant afford to do it during an
2245        add with stack based varibles.  Worst case is:
2246         ld  hl,sp+left
2247         ld  a,(hl)
2248         ld  hl,sp+right
2249         add (hl)
2250         ld  hl,sp+result
2251         ld  (hl),a
2252         ld  hl,sp+left+1
2253         ld  a,(hl)
2254         ld  hl,sp+right+1
2255         adc (hl)
2256         ld  hl,sp+result+1
2257         ld  (hl),a
2258         So you cant afford to load up hl if either left, right, or result
2259         is on the stack (*sigh*)  The alt is:
2260         ld  hl,sp+left
2261         ld  de,(hl)
2262         ld  hl,sp+right
2263         ld  hl,(hl)
2264         add hl,de
2265         ld  hl,sp+result
2266         ld  (hl),hl
2267         Combinations in here are:
2268          * If left or right are in bc then the loss is small - trap later
2269          * If the result is in bc then the loss is also small
2270     */
2271     if (IS_GB) {
2272         if (AOP_TYPE(IC_LEFT(ic)) == AOP_STK ||
2273             AOP_TYPE(IC_RIGHT(ic)) == AOP_STK ||
2274             AOP_TYPE(IC_RESULT(ic)) == AOP_STK) {
2275             if ((AOP_SIZE(IC_LEFT(ic)) == 2 ||
2276                 AOP_SIZE(IC_RIGHT(ic)) == 2) &&
2277                 (AOP_SIZE(IC_LEFT(ic)) <= 2 &&
2278                  AOP_SIZE(IC_RIGHT(ic)) <= 2)) {
2279                 if (getPairId(AOP(IC_RIGHT(ic))) == PAIR_BC) {
2280                     /* Swap left and right */
2281                     operand *t = IC_RIGHT(ic);
2282                     IC_RIGHT(ic) = IC_LEFT(ic);
2283                     IC_LEFT(ic) = t;
2284                 }
2285                 if (getPairId(AOP(IC_LEFT(ic))) == PAIR_BC) {
2286                     fetchPair(PAIR_HL, AOP(IC_RIGHT(ic)));
2287                     emit2("add hl,bc");
2288                 }
2289                 else {
2290                     fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
2291                     fetchPair(PAIR_HL, AOP(IC_RIGHT(ic)));
2292                     emit2("add hl,de");
2293                 }
2294                 commitPair(AOP(IC_RESULT(ic)), PAIR_HL);
2295                 goto release;
2296             }
2297             else if (size == 4) {
2298                 emit2("; WARNING: This add is probably broken.\n");
2299             }
2300         }
2301     }
2302
2303     while(size--) {
2304         if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
2305             MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2306             if(offset == 0)
2307                 emit2("add a,%s",
2308                       aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2309             else
2310                 emit2("adc a,%s",
2311                       aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2312         } else {
2313             MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
2314             if(offset == 0)
2315                 emit2("add a,%s",
2316                       aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2317             else
2318                 emit2("adc a,%s",
2319                       aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2320         }
2321         aopPut(AOP(IC_RESULT(ic)),"a",offset++);      
2322     }
2323    
2324 release:
2325     freeAsmop(IC_LEFT(ic),NULL,ic);
2326     freeAsmop(IC_RIGHT(ic),NULL,ic);
2327     freeAsmop(IC_RESULT(ic),NULL,ic);
2328     
2329 }
2330
2331 /*-----------------------------------------------------------------*/
2332 /* genMinusDec :- does subtraction with deccrement if possible     */
2333 /*-----------------------------------------------------------------*/
2334 static bool genMinusDec (iCode *ic)
2335 {
2336     unsigned int icount ;
2337     unsigned int size = getDataSize(IC_RESULT(ic));
2338
2339     /* will try to generate an increment */
2340     /* if the right side is not a literal we cannot */
2341     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2342         return FALSE ;
2343
2344     /* if the literal value of the right hand side
2345     is greater than 4 then it is not worth it */
2346     if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
2347         return FALSE;
2348
2349     size = getDataSize(IC_RESULT(ic));
2350
2351 #if 0
2352     /* if increment 16 bits in register */
2353     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2354         (size > 1) &&
2355         (icount == 1)) {
2356         symbol *tlbl = newiTempLabel(NULL);
2357         emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
2358         emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
2359     
2360         emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
2361         if(size == 4) {
2362             wassert(0);
2363         }
2364         emitLabel(tlbl->key+100);
2365         return TRUE;
2366     }
2367 #endif
2368
2369     /* if decrement 16 bits in register */
2370     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2371         (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
2372         while (icount--)
2373             emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2374         return TRUE;
2375     }
2376
2377     /* If result is a pair */
2378     if (isPair(AOP(IC_RESULT(ic)))) {
2379         movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
2380         movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
2381         while (icount--)
2382             emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
2383         return TRUE;
2384     }
2385
2386     /* if the sizes are greater than 1 then we cannot */
2387     if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2388         AOP_SIZE(IC_LEFT(ic)) > 1   )
2389         return FALSE ;
2390
2391     /* we can if the aops of the left & result match or if they are in
2392        registers and the registers are the same */
2393     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
2394         while (icount--) 
2395             emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
2396         return TRUE ;
2397     }
2398
2399     return FALSE ;
2400 }
2401
2402 /*-----------------------------------------------------------------*/
2403 /* genMinus - generates code for subtraction                       */
2404 /*-----------------------------------------------------------------*/
2405 static void genMinus (iCode *ic)
2406 {
2407     int size, offset = 0;
2408     unsigned long lit = 0L;
2409
2410     aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
2411     aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2412     aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
2413
2414     /* special cases :- */
2415     /* if both left & right are in bit space */
2416     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2417         AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2418         wassert(0);
2419         goto release ;
2420     }
2421
2422     /* if I can do an decrement instead of subtract then GOOD for ME */
2423     if (genMinusDec (ic) == TRUE)
2424         goto release;   
2425
2426     size = getDataSize(IC_RESULT(ic));   
2427
2428     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
2429     }
2430     else{
2431         lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
2432         lit = - (long)lit;
2433     }
2434
2435     /* Same logic as genPlus */
2436     if (IS_GB) {
2437         if (AOP_TYPE(IC_LEFT(ic)) == AOP_STK ||
2438             AOP_TYPE(IC_RIGHT(ic)) == AOP_STK ||
2439             AOP_TYPE(IC_RESULT(ic)) == AOP_STK) {
2440             if ((AOP_SIZE(IC_LEFT(ic)) == 2 ||
2441                 AOP_SIZE(IC_RIGHT(ic)) == 2) &&
2442                 (AOP_SIZE(IC_LEFT(ic)) <= 2 &&
2443                  AOP_SIZE(IC_RIGHT(ic)) <= 2)) {
2444                 PAIR_ID left = getPairId(AOP(IC_LEFT(ic)));
2445                 PAIR_ID right = getPairId(AOP(IC_RIGHT(ic)));
2446
2447                 if (left == PAIR_INVALID && right == PAIR_INVALID) {
2448                     left = PAIR_DE;
2449                     right = PAIR_HL;
2450                 }
2451                 else if (right == PAIR_INVALID)
2452                     right = PAIR_DE;
2453                 else if (left == PAIR_INVALID)
2454                     left = PAIR_DE;
2455                 
2456                 fetchPair(left, AOP(IC_LEFT(ic)));
2457                 /* Order is important.  Right may be HL */
2458                 fetchPair(right, AOP(IC_RIGHT(ic)));
2459
2460                 emit2("ld a,%s", _pairs[left].l);
2461                 emit2("sub a,%s", _pairs[right].l);
2462                 emit2("ld e,a");
2463                 emit2("ld a,%s", _pairs[left].h);
2464                 emit2("sbc a,%s", _pairs[right].h);
2465
2466                 aopPut(AOP(IC_RESULT(ic)), "a", 1);
2467                 aopPut(AOP(IC_RESULT(ic)), "e", 0);
2468                 goto release;
2469             }
2470             else if (size == 4) {
2471                 emit2("; WARNING: This sub is probably broken.\n");
2472             }
2473         }
2474     }
2475     
2476     /* if literal, add a,#-lit, else normal subb */
2477     while (size--) {
2478         MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));    
2479         if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
2480             if (!offset)
2481                 emitcode("sub","a,%s",
2482                          aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2483             else
2484                 emitcode("sbc","a,%s",
2485                          aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
2486         }
2487         else{
2488             /* first add without previous c */
2489             if (!offset)
2490                 emit2("add a,!immedbyte", (unsigned int)(lit & 0x0FFL));
2491             else
2492                 emit2("adc a,!immedbyte", (unsigned int)((lit >> (offset*8)) & 0x0FFL));
2493         }
2494         aopPut(AOP(IC_RESULT(ic)),"a",offset++);      
2495     }
2496     
2497     if (AOP_SIZE(IC_RESULT(ic)) == 3 && 
2498         AOP_SIZE(IC_LEFT(ic)) == 3   &&
2499         !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2500         wassert(0);
2501
2502 release:
2503     freeAsmop(IC_LEFT(ic),NULL,ic);
2504     freeAsmop(IC_RIGHT(ic),NULL,ic);
2505     freeAsmop(IC_RESULT(ic),NULL,ic);
2506 }
2507
2508 /*-----------------------------------------------------------------*/
2509 /* genMult - generates code for multiplication                     */
2510 /*-----------------------------------------------------------------*/
2511 static void genMult (iCode *ic)
2512 {
2513     /* Shouldn't occur - all done through function calls */
2514     wassert(0);
2515 }
2516
2517 /*-----------------------------------------------------------------*/
2518 /* genDiv - generates code for division                            */
2519 /*-----------------------------------------------------------------*/
2520 static void genDiv (iCode *ic)
2521 {
2522     /* Shouldn't occur - all done through function calls */
2523     wassert(0);
2524 }
2525
2526 /*-----------------------------------------------------------------*/
2527 /* genMod - generates code for division                            */
2528 /*-----------------------------------------------------------------*/
2529 static void genMod (iCode *ic)
2530 {
2531     /* Shouldn't occur - all done through function calls */
2532     wassert(0);
2533 }
2534
2535 /*-----------------------------------------------------------------*/
2536 /* genIfxJump :- will create a jump depending on the ifx           */
2537 /*-----------------------------------------------------------------*/
2538 static void genIfxJump (iCode *ic, char *jval)
2539 {
2540     symbol *jlbl ;
2541     const char *inst;
2542
2543     /* if true label then we jump if condition
2544     supplied is true */
2545     if ( IC_TRUE(ic) ) {
2546         jlbl = IC_TRUE(ic);
2547         if (!strcmp(jval, "a")) {
2548             inst = "nz";
2549         }
2550         else if (!strcmp(jval, "c")) {
2551             inst = "c";
2552         }
2553         else {
2554             /* The buffer contains the bit on A that we should test */
2555             inst = "nz";
2556         }
2557     }
2558     else {
2559         /* false label is present */
2560         jlbl = IC_FALSE(ic) ;
2561         if (!strcmp(jval, "a")) {
2562             inst = "z";
2563         }
2564         else if (!strcmp(jval, "c")) {
2565             inst = "nc";
2566         }
2567         else {
2568             /* The buffer contains the bit on A that we should test */
2569             inst = "z";
2570         }
2571     }
2572     /* Z80 can do a conditional long jump */
2573     if (!strcmp(jval, "a")) {
2574         emitcode("or", "a,a");
2575     }
2576     else if (!strcmp(jval, "c")) {
2577     }
2578     else {
2579         emitcode("bit", "%s,a", jval);
2580     }
2581     emit2("jp %s,!tlabel", inst, jlbl->key+100);
2582
2583     /* mark the icode as generated */
2584     ic->generated = 1;
2585 }
2586
2587 /** Generic compare for > or <
2588  */
2589 static void genCmp (operand *left,operand *right,
2590                     operand *result, iCode *ifx, int sign)
2591 {
2592     int size, offset = 0 ;
2593     unsigned long lit = 0L;
2594
2595     /* if left & right are bit variables */
2596     if (AOP_TYPE(left) == AOP_CRY &&
2597         AOP_TYPE(right) == AOP_CRY ) {
2598         /* Cant happen on the Z80 */
2599         wassert(0);
2600     } else {
2601         /* subtract right from left if at the
2602         end the carry flag is set then we know that
2603         left is greater than right */
2604         size = max(AOP_SIZE(left),AOP_SIZE(right));
2605
2606         /* if unsigned char cmp with lit, just compare */
2607         if((size == 1) && 
2608            (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
2609             emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2610             if (sign) {
2611                 emit2("xor a,!immedbyte", 0x80);
2612                 emit2("cp %s^!constbyte", aopGet(AOP(right), offset, FALSE), 0x80);
2613             }
2614             else 
2615                 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
2616         } 
2617         else {
2618             if(AOP_TYPE(right) == AOP_LIT) {
2619                 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2620                 /* optimize if(x < 0) or if(x >= 0) */
2621                 if (lit == 0L){
2622                     if (!sign) {
2623                         /* No sign so it's always false */
2624                         CLRC;
2625                     }
2626                     else{
2627                         /* Just load in the top most bit */
2628                         MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
2629                         if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
2630                             genIfxJump (ifx,"7");
2631                             return;
2632                         }
2633                         else    
2634                             emitcode("rlc","a");
2635                     }
2636                     goto release;
2637                 }
2638             }
2639             if (sign) {
2640                 /* First setup h and l contaning the top most bytes XORed */
2641                 bool fDidXor = FALSE;
2642                 if (AOP_TYPE(left) == AOP_LIT){
2643                     unsigned long lit = (unsigned long)
2644                         floatFromVal(AOP(left)->aopu.aop_lit);
2645                     emit2("ld %s,!immedbyte", _fTmp[0],
2646                              0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2647                 }
2648                 else {
2649                     emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2650                     emit2("xor a,!immedbyte", 0x80);
2651                     emitcode("ld", "%s,a", _fTmp[0]);
2652                     fDidXor = TRUE;
2653                 }
2654                 if (AOP_TYPE(right) == AOP_LIT) {
2655                     unsigned long lit = (unsigned long)
2656                         floatFromVal(AOP(right)->aopu.aop_lit);
2657                     emit2("ld %s,!immedbyte", _fTmp[1],
2658                              0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2659                 }
2660                 else {
2661                     emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2662                     emit2("xor a,!immedbyte", 0x80);
2663                     emitcode("ld", "%s,a", _fTmp[1]);
2664                     fDidXor = TRUE;
2665                 }
2666                 if (!fDidXor)
2667                     CLRC;
2668             }
2669             else {
2670                 CLRC;
2671             }
2672             while (size--) {
2673                 /* Do a long subtract */
2674                 if (!sign || size ) {
2675                     MOVA(aopGet(AOP(left),offset,FALSE));
2676                 }
2677                 if (sign && size == 0) {
2678                     emitcode("ld", "a,%s", _fTmp[0]);
2679                     emitcode("sbc", "a,%s", _fTmp[1]);
2680                 }
2681                 else {
2682                     /* Subtract through, propagating the carry */
2683                     emitcode("sbc","a,%s ; 2",aopGet(AOP(right),offset++,FALSE));
2684                 }
2685             }
2686         }
2687     }
2688
2689 release:
2690     if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2691         outBitC(result);
2692     } else {
2693         /* if the result is used in the next
2694         ifx conditional branch then generate
2695         code a little differently */
2696         if (ifx )
2697             genIfxJump (ifx,"c");
2698         else
2699             outBitC(result);
2700         /* leave the result in acc */
2701     }
2702 }
2703
2704 /*-----------------------------------------------------------------*/
2705 /* genCmpGt :- greater than comparison                             */
2706 /*-----------------------------------------------------------------*/
2707 static void genCmpGt (iCode *ic, iCode *ifx)
2708 {
2709     operand *left, *right, *result;
2710     link *letype , *retype;
2711     int sign ;
2712
2713     left = IC_LEFT(ic);
2714     right= IC_RIGHT(ic);
2715     result = IC_RESULT(ic);
2716
2717     letype = getSpec(operandType(left));
2718     retype =getSpec(operandType(right));
2719     sign =  !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2720     /* assign the amsops */
2721     aopOp (left,ic,FALSE, FALSE);
2722     aopOp (right,ic,FALSE, FALSE);
2723     aopOp (result,ic,TRUE, FALSE);
2724
2725     genCmp(right, left, result, ifx, sign);
2726
2727     freeAsmop(left,NULL,ic);
2728     freeAsmop(right,NULL,ic);
2729     freeAsmop(result,NULL,ic);
2730 }
2731
2732 /*-----------------------------------------------------------------*/
2733 /* genCmpLt - less than comparisons                                */
2734 /*-----------------------------------------------------------------*/
2735 static void genCmpLt (iCode *ic, iCode *ifx)
2736 {
2737     operand *left, *right, *result;
2738     link *letype , *retype;
2739     int sign ;
2740
2741     left = IC_LEFT(ic);
2742     right= IC_RIGHT(ic);
2743     result = IC_RESULT(ic);
2744
2745     letype = getSpec(operandType(left));
2746     retype =getSpec(operandType(right));
2747     sign =  !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2748
2749     /* assign the amsops */
2750     aopOp (left,ic,FALSE, FALSE);
2751     aopOp (right,ic,FALSE, FALSE);
2752     aopOp (result,ic,TRUE, FALSE);
2753
2754     genCmp(left, right, result, ifx, sign);
2755
2756     freeAsmop(left,NULL,ic);
2757     freeAsmop(right,NULL,ic);
2758     freeAsmop(result,NULL,ic);
2759 }
2760
2761 /*-----------------------------------------------------------------*/
2762 /* gencjneshort - compare and jump if not equal                    */
2763 /*-----------------------------------------------------------------*/
2764 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2765 {
2766     int size = max(AOP_SIZE(left),AOP_SIZE(right));
2767     int offset = 0;
2768     unsigned long lit = 0L;
2769
2770     /* Swap the left and right if it makes the computation easier */
2771     if (AOP_TYPE(left) == AOP_LIT) {
2772         operand *t = right;
2773         right = left;
2774         left = t;
2775     }
2776
2777     if(AOP_TYPE(right) == AOP_LIT)
2778         lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2779
2780     /* if the right side is a literal then anything goes */
2781     if (AOP_TYPE(right) == AOP_LIT &&
2782         AOP_TYPE(left) != AOP_DIR ) {
2783         if (lit == 0) {
2784             emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
2785             if (size > 1) {
2786                 size--;
2787                 offset++;
2788                 while (size--) {
2789                     emitcode("or", "a,%s", aopGet(AOP(left), offset, FALSE));
2790                 }
2791             }
2792             else {
2793                 emitcode("or", "a,a");
2794             }
2795             emit2("jp nz,!tlabel", lbl->key+100);
2796         }
2797         else {
2798             while (size--) {
2799                 emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2800                 if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2801                     emitcode("or", "a,a");
2802                 else 
2803                     emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2804                 emit2("jp nz,!tlabel", lbl->key+100);
2805                 offset++;
2806             }
2807         }
2808     }
2809     /* if the right side is in a register or in direct space or
2810     if the left is a pointer register & right is not */    
2811     else if (AOP_TYPE(right) == AOP_REG ||
2812              AOP_TYPE(right) == AOP_DIR || 
2813              (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2814         while (size--) {
2815             MOVA(aopGet(AOP(left),offset,FALSE));
2816             if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2817                ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2818                 /* PENDING */
2819                 emit2("jp nz,!tlabel", lbl->key+100);
2820             else {
2821                 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2822                 emit2("jp nz,!tlabel", lbl->key+100);
2823             }
2824             offset++;
2825         }
2826     } else {
2827         /* right is a pointer reg need both a & b */
2828         /* PENDING: is this required? */
2829         while(size--) {
2830             MOVA(aopGet(AOP(right),offset,FALSE));
2831             emitcode("cp", "%s ; 5", aopGet(AOP(left), offset, FALSE));
2832             emit2("!shortjp nz,!tlabel", lbl->key+100);
2833             offset++;
2834         }
2835     }
2836 }
2837
2838 /*-----------------------------------------------------------------*/
2839 /* gencjne - compare and jump if not equal                         */
2840 /*-----------------------------------------------------------------*/
2841 static void gencjne(operand *left, operand *right, symbol *lbl)
2842 {
2843     symbol *tlbl  = newiTempLabel(NULL);
2844
2845     gencjneshort(left, right, lbl);
2846
2847     /* PENDING: ?? */
2848     emit2("ld a,!one");
2849     emit2("!shortjp !tlabel", tlbl->key+100);
2850     emitLabel(lbl->key+100);
2851     emitcode("xor","a,a");
2852     emitLabel(tlbl->key+100);
2853 }
2854
2855 /*-----------------------------------------------------------------*/
2856 /* genCmpEq - generates code for equal to                          */
2857 /*-----------------------------------------------------------------*/
2858 static void genCmpEq (iCode *ic, iCode *ifx)
2859 {
2860     operand *left, *right, *result;
2861
2862     aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
2863     aopOp((right=IC_RIGHT(ic)),ic,FALSE, FALSE);
2864     aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
2865
2866     /* Swap operands if it makes the operation easier. ie if:
2867        1.  Left is a literal.
2868     */
2869     if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2870         operand *t = IC_RIGHT(ic);
2871         IC_RIGHT(ic) = IC_LEFT(ic);
2872         IC_LEFT(ic) = t;
2873     }
2874
2875     if (ifx && !AOP_SIZE(result)){
2876         symbol *tlbl;
2877         /* if they are both bit variables */
2878         if (AOP_TYPE(left) == AOP_CRY &&
2879             ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2880             wassert(0);
2881         } else {
2882             tlbl = newiTempLabel(NULL);
2883             gencjneshort(left, right, tlbl);
2884             if ( IC_TRUE(ifx) ) {
2885                 emit2("jp !tlabel", IC_TRUE(ifx)->key+100);
2886                 emitLabel(tlbl->key+100);
2887             } else {
2888                 /* PENDING: do this better */
2889                 symbol *lbl = newiTempLabel(NULL);
2890                 emit2("!shortjp !tlabel", lbl->key+100);
2891                 emitLabel(tlbl->key+100);
2892                 emit2("jp !tlabel", IC_FALSE(ifx)->key+100);
2893                 emitLabel(lbl->key+100);             
2894             }
2895         }
2896         /* mark the icode as generated */
2897         ifx->generated = 1;
2898         goto release ;
2899     }
2900
2901     /* if they are both bit variables */
2902     if (AOP_TYPE(left) == AOP_CRY &&
2903         ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2904         wassert(0);
2905     } else {
2906         gencjne(left,right,newiTempLabel(NULL));    
2907         if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2908             wassert(0);
2909         }
2910         if (ifx) {
2911             genIfxJump(ifx,"a");
2912             goto release;
2913         }
2914         /* if the result is used in an arithmetic operation
2915         then put the result in place */
2916         if (AOP_TYPE(result) != AOP_CRY) {
2917             outAcc(result);
2918         }
2919         /* leave the result in acc */
2920     }
2921
2922 release:
2923     freeAsmop(left,NULL,ic);
2924     freeAsmop(right,NULL,ic);
2925     freeAsmop(result,NULL,ic);
2926 }
2927
2928 /*-----------------------------------------------------------------*/
2929 /* ifxForOp - returns the icode containing the ifx for operand     */
2930 /*-----------------------------------------------------------------*/
2931 static iCode *ifxForOp ( operand *op, iCode *ic )
2932 {
2933     /* if true symbol then needs to be assigned */
2934     if (IS_TRUE_SYMOP(op))
2935         return NULL ;
2936
2937     /* if this has register type condition and
2938     the next instruction is ifx with the same operand
2939     and live to of the operand is upto the ifx only then */
2940     if (ic->next &&
2941         ic->next->op == IFX &&
2942         IC_COND(ic->next)->key == op->key &&
2943         OP_SYMBOL(op)->liveTo <= ic->next->seq )
2944         return ic->next;
2945
2946     return NULL;
2947 }
2948
2949 /*-----------------------------------------------------------------*/
2950 /* genAndOp - for && operation                                     */
2951 /*-----------------------------------------------------------------*/
2952 static void genAndOp (iCode *ic)
2953 {
2954     operand *left,*right, *result;
2955     symbol *tlbl;
2956
2957     /* note here that && operations that are in an if statement are
2958        taken away by backPatchLabels only those used in arthmetic
2959        operations remain */
2960     aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2961     aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2962     aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2963
2964     /* if both are bit variables */
2965     if (AOP_TYPE(left) == AOP_CRY &&
2966         AOP_TYPE(right) == AOP_CRY ) {
2967         wassert(0);
2968     } else {
2969         tlbl = newiTempLabel(NULL);
2970         toBoolean(left);    
2971         emit2("!shortjp z,!tlabel", tlbl->key+100);
2972         toBoolean(right);
2973         emitLabel(tlbl->key+100);
2974         outBitAcc(result);
2975     }
2976
2977     freeAsmop(left,NULL,ic);
2978     freeAsmop(right,NULL,ic);
2979     freeAsmop(result,NULL,ic);
2980 }
2981
2982 /*-----------------------------------------------------------------*/
2983 /* genOrOp - for || operation                                      */
2984 /*-----------------------------------------------------------------*/
2985 static void genOrOp (iCode *ic)
2986 {
2987     operand *left,*right, *result;
2988     symbol *tlbl;
2989
2990     /* note here that || operations that are in an
2991        if statement are taken away by backPatchLabels
2992        only those used in arthmetic operations remain */
2993     aopOp((left=IC_LEFT(ic)),ic,FALSE, TRUE);
2994     aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
2995     aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
2996
2997     /* if both are bit variables */
2998     if (AOP_TYPE(left) == AOP_CRY &&
2999         AOP_TYPE(right) == AOP_CRY ) {
3000         wassert(0);
3001     } else {
3002         tlbl = newiTempLabel(NULL);
3003         toBoolean(left);
3004         emit2("!shortjp nz,!tlabel", tlbl->key+100);
3005         toBoolean(right);
3006         emitLabel(tlbl->key+100);
3007         outBitAcc(result);
3008     }
3009
3010     freeAsmop(left,NULL,ic);
3011     freeAsmop(right,NULL,ic);
3012     freeAsmop(result,NULL,ic);
3013 }
3014
3015 /*-----------------------------------------------------------------*/
3016 /* isLiteralBit - test if lit == 2^n                               */
3017 /*-----------------------------------------------------------------*/
3018 int isLiteralBit(unsigned long lit)
3019 {
3020     unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
3021     0x100L,0x200L,0x400L,0x800L,
3022     0x1000L,0x2000L,0x4000L,0x8000L,
3023     0x10000L,0x20000L,0x40000L,0x80000L,
3024     0x100000L,0x200000L,0x400000L,0x800000L,
3025     0x1000000L,0x2000000L,0x4000000L,0x8000000L,
3026     0x10000000L,0x20000000L,0x40000000L,0x80000000L};
3027     int idx;
3028     
3029     for(idx = 0; idx < 32; idx++)
3030         if(lit == pw[idx])
3031             return idx+1;
3032     return 0;
3033 }
3034
3035 /*-----------------------------------------------------------------*/
3036 /* jmpTrueOrFalse -                                                */
3037 /*-----------------------------------------------------------------*/
3038 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
3039 {
3040     // ugly but optimized by peephole
3041     if(IC_TRUE(ic)){
3042         symbol *nlbl = newiTempLabel(NULL);
3043         emit2("jp !tlabel", nlbl->key+100);                 
3044         emitLabel(tlbl->key+100);
3045         emit2("jp !tlabel", IC_TRUE(ic)->key+100);
3046         emitLabel(nlbl->key+100);
3047     }
3048     else{
3049         emit2("jp !tlabel", IC_FALSE(ic)->key+100);
3050         emitLabel(tlbl->key+100);
3051     }
3052     ic->generated = 1;
3053 }
3054
3055 /*-----------------------------------------------------------------*/
3056 /* genAnd  - code for and                                          */
3057 /*-----------------------------------------------------------------*/
3058 static void genAnd (iCode *ic, iCode *ifx)
3059 {
3060     operand *left, *right, *result;
3061     int size, offset=0;  
3062     unsigned long lit = 0L;
3063     int bytelit = 0;
3064
3065     aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3066     aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3067     aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3068
3069 #ifdef DEBUG_TYPE
3070     emitcode("","; Type res[%d] = l[%d]&r[%d]",
3071              AOP_TYPE(result),
3072              AOP_TYPE(left), AOP_TYPE(right));
3073     emitcode("","; Size res[%d] = l[%d]&r[%d]",
3074              AOP_SIZE(result),
3075              AOP_SIZE(left), AOP_SIZE(right));
3076 #endif
3077
3078     /* if left is a literal & right is not then exchange them */
3079     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3080         AOP_NEEDSACC(left)) {
3081         operand *tmp = right ;
3082         right = left;
3083         left = tmp;
3084     }
3085
3086     /* if result = right then exchange them */
3087     if(sameRegs(AOP(result),AOP(right))){
3088         operand *tmp = right ;
3089         right = left;
3090         left = tmp;
3091     }
3092
3093     /* if right is bit then exchange them */
3094     if (AOP_TYPE(right) == AOP_CRY &&
3095         AOP_TYPE(left) != AOP_CRY){
3096         operand *tmp = right ;
3097         right = left;
3098         left = tmp;
3099     }
3100     if(AOP_TYPE(right) == AOP_LIT)
3101         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3102
3103     size = AOP_SIZE(result);
3104
3105     if (AOP_TYPE(left) == AOP_CRY){
3106         wassert(0);
3107         goto release ;
3108     }
3109
3110     // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
3111     // bit = val & 0xZZ     - size = 1, ifx = FALSE -
3112     if((AOP_TYPE(right) == AOP_LIT) &&
3113        (AOP_TYPE(result) == AOP_CRY) &&
3114        (AOP_TYPE(left) != AOP_CRY)) {
3115         int posbit = isLiteralBit(lit);
3116         /* left &  2^n */
3117         if(posbit){
3118             posbit--;
3119             MOVA(aopGet(AOP(left),posbit>>3,FALSE));
3120             // bit = left & 2^n
3121             if(size) {
3122                 wassert(0);
3123                 emitcode("mov","c,acc.%d",posbit&0x07);
3124             }
3125             // if(left &  2^n)
3126             else{
3127                 if (ifx) {
3128                     sprintf(buffer, "%d", posbit&0x07);
3129                     genIfxJump(ifx, buffer);
3130                 }
3131                 else {
3132                     wassert(0);
3133                 }
3134                 goto release;
3135             }
3136         } else {
3137             symbol *tlbl = newiTempLabel(NULL);
3138             int sizel = AOP_SIZE(left);
3139             if(size) {
3140                 wassert(0);
3141                 emitcode("setb","c");
3142             }
3143             while(sizel--){
3144                 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
3145                     MOVA( aopGet(AOP(left),offset,FALSE));
3146                     // byte ==  2^n ?
3147                     if((posbit = isLiteralBit(bytelit)) != 0) {
3148                         wassert(0);
3149                         emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
3150                     }
3151                     else{
3152                         if(bytelit != 0x0FFL)
3153                             emitcode("and","a,%s",
3154                                      aopGet(AOP(right),offset,FALSE));
3155                         else
3156                             /* For the flags */
3157                             emit2("or a,a");
3158                         emit2("!shortjp nz,!tlabel", tlbl->key+100);
3159                     }
3160                 }
3161                 offset++;
3162             }
3163             // bit = left & literal
3164             if (size){
3165                 emitcode("clr","c");
3166                 emit2("!tlabeldef", tlbl->key+100);
3167             }
3168             // if(left & literal)
3169             else{
3170                 if(ifx)
3171                     jmpTrueOrFalse(ifx, tlbl);
3172                 goto release ;
3173             }
3174         }
3175         outBitC(result);
3176         goto release ;
3177     }
3178
3179     /* if left is same as result */
3180     if(sameRegs(AOP(result),AOP(left))){
3181         for(;size--; offset++) {
3182             if(AOP_TYPE(right) == AOP_LIT){
3183                 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
3184                     continue;
3185                 else {
3186                     if (bytelit == 0)
3187                         aopPut(AOP(result),zero,offset);
3188                     else {
3189                         MOVA(aopGet(AOP(left),offset,FALSE));
3190                         emitcode("and","a,%s",
3191                                  aopGet(AOP(right),offset,FALSE));
3192                         aopPut(AOP(left), "a", offset);
3193                     }
3194                 }
3195
3196             } else {
3197                 if (AOP_TYPE(left) == AOP_ACC) {
3198                     wassert(0);
3199                 }
3200                 else {
3201                     MOVA(aopGet(AOP(left),offset,FALSE));
3202                     emitcode("and","a,%s",
3203                              aopGet(AOP(right),offset,FALSE));
3204                     aopPut(AOP(left), "a", offset);
3205                 }
3206             }
3207         }
3208     } else {
3209         // left & result in different registers
3210         if(AOP_TYPE(result) == AOP_CRY){
3211             wassert(0);
3212         } else {
3213             for(;(size--);offset++) {
3214                 // normal case
3215                 // result = left & right
3216                 if(AOP_TYPE(right) == AOP_LIT){
3217                     if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
3218                         aopPut(AOP(result),
3219                                aopGet(AOP(left),offset,FALSE),
3220                                offset);
3221                         continue;
3222                     } else if(bytelit == 0){
3223                         aopPut(AOP(result),zero,offset);
3224                         continue;
3225                     }
3226                 }
3227                 // faster than result <- left, anl result,right
3228                 // and better if result is SFR
3229                 if (AOP_TYPE(left) == AOP_ACC) 
3230                     emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
3231                 else {
3232                     MOVA(aopGet(AOP(left),offset,FALSE));
3233                     emitcode("and","a,%s",
3234                              aopGet(AOP(right),offset,FALSE));
3235                 }
3236                 aopPut(AOP(result),"a",offset);
3237             }
3238         }
3239
3240     }
3241
3242 release :
3243     freeAsmop(left,NULL,ic);
3244     freeAsmop(right,NULL,ic);
3245     freeAsmop(result,NULL,ic);
3246 }
3247
3248 /*-----------------------------------------------------------------*/
3249 /* genOr  - code for or                                            */
3250 /*-----------------------------------------------------------------*/
3251 static void genOr (iCode *ic, iCode *ifx)
3252 {
3253     operand *left, *right, *result;
3254     int size, offset=0;
3255     unsigned long lit = 0L;
3256
3257     aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3258     aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3259     aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3260
3261 #if 1
3262     emitcode("","; Type res[%d] = l[%d]&r[%d]",
3263              AOP_TYPE(result),
3264              AOP_TYPE(left), AOP_TYPE(right));
3265     emitcode("","; Size res[%d] = l[%d]&r[%d]",
3266              AOP_SIZE(result),
3267              AOP_SIZE(left), AOP_SIZE(right));
3268 #endif
3269
3270     /* if left is a literal & right is not then exchange them */
3271     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3272         AOP_NEEDSACC(left)) {
3273         operand *tmp = right ;
3274         right = left;
3275         left = tmp;
3276     }
3277
3278     /* if result = right then exchange them */
3279     if(sameRegs(AOP(result),AOP(right))){
3280         operand *tmp = right ;
3281         right = left;
3282         left = tmp;
3283     }
3284
3285     /* if right is bit then exchange them */
3286     if (AOP_TYPE(right) == AOP_CRY &&
3287         AOP_TYPE(left) != AOP_CRY){
3288         operand *tmp = right ;
3289         right = left;
3290         left = tmp;
3291     }
3292     if(AOP_TYPE(right) == AOP_LIT)
3293         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3294
3295     size = AOP_SIZE(result);
3296
3297     if (AOP_TYPE(left) == AOP_CRY){
3298         wassert(0);
3299         goto release ;
3300     }
3301
3302     if((AOP_TYPE(right) == AOP_LIT) &&
3303        (AOP_TYPE(result) == AOP_CRY) &&
3304        (AOP_TYPE(left) != AOP_CRY)){
3305         wassert(0);
3306         goto release ;
3307     }
3308
3309     /* if left is same as result */
3310     if(sameRegs(AOP(result),AOP(left))){
3311         for(;size--; offset++) {
3312             if(AOP_TYPE(right) == AOP_LIT){
3313                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3314                     continue;
3315                 else {
3316                     MOVA(aopGet(AOP(left),offset,FALSE));
3317                     emitcode("or","a,%s",
3318                              aopGet(AOP(right),offset,FALSE));
3319                     aopPut(AOP(result),"a", offset);
3320                 }
3321             } else {
3322                 if (AOP_TYPE(left) == AOP_ACC) 
3323                     emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3324                 else {              
3325                     MOVA(aopGet(AOP(left),offset,FALSE));
3326                     emitcode("or","a,%s",
3327                              aopGet(AOP(right),offset,FALSE));
3328                     aopPut(AOP(result),"a", offset);
3329                 }
3330             }
3331         }
3332     } else {
3333         // left & result in different registers
3334         if(AOP_TYPE(result) == AOP_CRY){
3335             wassert(0);
3336         } else for(;(size--);offset++){
3337             // normal case
3338             // result = left & right
3339             if(AOP_TYPE(right) == AOP_LIT){
3340                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3341                     aopPut(AOP(result),
3342                            aopGet(AOP(left),offset,FALSE),
3343                            offset);
3344                     continue;
3345                 }
3346             }
3347             // faster than result <- left, anl result,right
3348             // and better if result is SFR
3349             if (AOP_TYPE(left) == AOP_ACC) 
3350                 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
3351             else {
3352                 MOVA(aopGet(AOP(left),offset,FALSE));
3353                 emitcode("or","a,%s",
3354                          aopGet(AOP(right),offset,FALSE));
3355             }
3356             aopPut(AOP(result),"a",offset);                     
3357             /* PENDING: something weird is going on here.  Add exception. */
3358             if (AOP_TYPE(result) == AOP_ACC)
3359                 break;
3360         }
3361     }
3362
3363 release :
3364     freeAsmop(left,NULL,ic);
3365     freeAsmop(right,NULL,ic);
3366     freeAsmop(result,NULL,ic);
3367 }
3368
3369 /*-----------------------------------------------------------------*/
3370 /* genXor - code for xclusive or                                   */
3371 /*-----------------------------------------------------------------*/
3372 static void genXor (iCode *ic, iCode *ifx)
3373 {
3374     operand *left, *right, *result;
3375     int size, offset=0;
3376     unsigned long lit = 0L;
3377
3378     aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
3379     aopOp((right= IC_RIGHT(ic)),ic,FALSE, FALSE);
3380     aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
3381
3382     /* if left is a literal & right is not then exchange them */
3383     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
3384         AOP_NEEDSACC(left)) {
3385         operand *tmp = right ;
3386         right = left;
3387         left = tmp;
3388     }
3389
3390     /* if result = right then exchange them */
3391     if(sameRegs(AOP(result),AOP(right))){
3392         operand *tmp = right ;
3393         right = left;
3394         left = tmp;
3395     }
3396
3397     /* if right is bit then exchange them */
3398     if (AOP_TYPE(right) == AOP_CRY &&
3399         AOP_TYPE(left) != AOP_CRY){
3400         operand *tmp = right ;
3401         right = left;
3402         left = tmp;
3403     }
3404     if(AOP_TYPE(right) == AOP_LIT)
3405         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
3406
3407     size = AOP_SIZE(result);
3408
3409     if (AOP_TYPE(left) == AOP_CRY){
3410         wassert(0);
3411         goto release ;
3412     }
3413
3414     if((AOP_TYPE(right) == AOP_LIT) &&
3415        (AOP_TYPE(result) == AOP_CRY) &&
3416        (AOP_TYPE(left) != AOP_CRY)){
3417         wassert(0);
3418         goto release ;
3419     }
3420
3421     /* if left is same as result */
3422     if(sameRegs(AOP(result),AOP(left))){
3423         for(;size--; offset++) {
3424             if(AOP_TYPE(right) == AOP_LIT){
3425                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
3426                     continue;
3427                 else {
3428                     MOVA(aopGet(AOP(right),offset,FALSE));
3429                     emitcode("xor","a,%s",
3430                              aopGet(AOP(left),offset,FALSE));
3431                     aopPut(AOP(result),"a",0);
3432                 }
3433             } else {
3434                 if (AOP_TYPE(left) == AOP_ACC) 
3435                     emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3436                 else {              
3437                     MOVA(aopGet(AOP(right),offset,FALSE));
3438                     emitcode("xor","a,%s",
3439                              aopGet(AOP(left),offset,FALSE));
3440                     aopPut(AOP(result),"a",0);
3441                 }
3442             }
3443         }
3444     } else {
3445         // left & result in different registers
3446         if(AOP_TYPE(result) == AOP_CRY){
3447             wassert(0);
3448         } else for(;(size--);offset++){
3449             // normal case
3450             // result = left & right
3451             if(AOP_TYPE(right) == AOP_LIT){
3452                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
3453                     aopPut(AOP(result),
3454                            aopGet(AOP(left),offset,FALSE),
3455                            offset);
3456                     continue;
3457                 }
3458             }
3459             // faster than result <- left, anl result,right
3460             // and better if result is SFR
3461             if (AOP_TYPE(left) == AOP_ACC) 
3462                 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
3463             else {
3464                 MOVA(aopGet(AOP(right),offset,FALSE));
3465                 emitcode("xor","a,%s",
3466                          aopGet(AOP(left),offset,FALSE));
3467                 aopPut(AOP(result),"a",0);
3468             }
3469             aopPut(AOP(result),"a",offset);                     
3470         }
3471     }
3472
3473 release :
3474     freeAsmop(left,NULL,ic);
3475     freeAsmop(right,NULL,ic);
3476     freeAsmop(result,NULL,ic);
3477 }
3478
3479 /*-----------------------------------------------------------------*/
3480 /* genInline - write the inline code out                           */
3481 /*-----------------------------------------------------------------*/
3482 static void genInline (iCode *ic)
3483 {
3484     char buffer[MAX_INLINEASM];
3485     char *bp = buffer;
3486     char *bp1= buffer;
3487     
3488     inLine += (!options.asmpeep);
3489     strcpy(buffer,IC_INLINE(ic));
3490
3491     /* emit each line as a code */
3492     while (*bp) {
3493         if (*bp == '\n') {
3494             *bp++ = '\0';
3495             emitcode(bp1,"");
3496             bp1 = bp;
3497         } else {
3498             if (*bp == ':') {
3499                 bp++;
3500                 *bp = '\0';
3501                 bp++;
3502                 emitcode(bp1,"");
3503                 bp1 = bp;
3504             } else
3505                 bp++;
3506         }
3507     }
3508     if (bp1 != bp)
3509         emitcode(bp1,"");
3510     /*     emitcode("",buffer); */
3511     inLine -= (!options.asmpeep);
3512 }
3513
3514 /*-----------------------------------------------------------------*/
3515 /* genRRC - rotate right with carry                                */
3516 /*-----------------------------------------------------------------*/
3517 static void genRRC (iCode *ic)
3518 {
3519     wassert(0);
3520 }
3521
3522 /*-----------------------------------------------------------------*/
3523 /* genRLC - generate code for rotate left with carry               */
3524 /*-----------------------------------------------------------------*/
3525 static void genRLC (iCode *ic)
3526 {    
3527     wassert(0);
3528 }
3529
3530 /*-----------------------------------------------------------------*/
3531 /* shiftR2Left2Result - shift right two bytes from left to result  */
3532 /*-----------------------------------------------------------------*/
3533 static void shiftR2Left2Result (operand *left, int offl,
3534                                 operand *result, int offr,
3535                                 int shCount, int sign)
3536 {
3537     movLeft2Result(left, offl, result, offr, 0);
3538     movLeft2Result(left, offl+1, result, offr+1, 0);
3539
3540     if (sign) {
3541         wassert(0);
3542     }
3543     else {
3544         /*      if (AOP(result)->type == AOP_REG) {*/
3545             int size = 2;
3546             int offset = 0;
3547             symbol *tlbl , *tlbl1;
3548             char *l;
3549
3550             tlbl = newiTempLabel(NULL);
3551             tlbl1 = newiTempLabel(NULL);
3552                 
3553             /* Left is already in result - so now do the shift */
3554             if (shCount>1) {
3555                 emit2("ld a,!immedbyte+1", shCount);
3556                 emit2("!shortjp !tlabel", tlbl1->key+100); 
3557                 emitLabel(tlbl->key+100);    
3558             }
3559
3560             emitcode("or", "a,a");
3561             offset = size;
3562             while (size--) {
3563                 l = aopGet(AOP(result), --offset, FALSE);
3564                 emitcode("rr","%s", l);         
3565             }
3566             if (shCount>1) {
3567                 emitLabel(tlbl1->key+100);
3568                 emitcode("dec", "a");
3569                 emit2("!shortjp nz,!tlabel", tlbl->key+100);
3570             }
3571     }
3572 }
3573
3574 /*-----------------------------------------------------------------*/
3575 /* shiftL2Left2Result - shift left two bytes from left to result   */
3576 /*-----------------------------------------------------------------*/
3577 static void shiftL2Left2Result (operand *left, int offl,
3578                                 operand *result, int offr, int shCount)
3579 {
3580     if(sameRegs(AOP(result), AOP(left)) &&
3581        ((offl + MSB16) == offr)){
3582         wassert(0);
3583     } else {
3584         /* Copy left into result */
3585         movLeft2Result(left, offl, result, offr, 0);
3586         movLeft2Result(left, offl+1, result, offr+1, 0);
3587     }
3588     /* PENDING: for now just see if it'll work. */
3589     /*if (AOP(result)->type == AOP_REG) { */
3590     {
3591         int size = 2;
3592         int offset = 0;
3593         symbol *tlbl , *tlbl1;
3594         char *l;
3595
3596         tlbl = newiTempLabel(NULL);
3597         tlbl1 = newiTempLabel(NULL);
3598
3599         /* Left is already in result - so now do the shift */
3600         if (shCount>1) {
3601             emit2("ld a,!immedbyte+1", shCount);
3602             emit2("!shortjp !tlabel", tlbl1->key+100); 
3603             emitLabel(tlbl->key+100);    
3604         }
3605
3606         emitcode("or", "a,a");
3607         while (size--) {
3608             l = aopGet(AOP(result),offset++,FALSE);
3609             emitcode("rl","%s", l);         
3610         }
3611         if (shCount>1) {
3612             emitLabel(tlbl1->key+100);
3613             emitcode("dec", "a");
3614             emit2("!shortjp nz,!tlabel", tlbl->key+100);
3615         }
3616     }
3617 }
3618
3619 /*-----------------------------------------------------------------*/
3620 /* AccRol - rotate left accumulator by known count                 */
3621 /*-----------------------------------------------------------------*/
3622 static void AccRol (int shCount)
3623 {
3624     shCount &= 0x0007;              // shCount : 0..7
3625     switch(shCount){
3626         case 0 :
3627             break;
3628         case 1 :
3629             emitcode("rl","a");
3630             break;
3631         case 2 :
3632             emitcode("rl","a");
3633             emitcode("rl","a");
3634             break;
3635         case 3 :
3636             emitcode("rl","a");
3637             emitcode("rl","a");
3638             emitcode("rl","a");
3639             break;
3640         case 4 :
3641             emitcode("rl","a");
3642             emitcode("rl","a");
3643             emitcode("rl","a");
3644             emitcode("rl","a");
3645             break;
3646         case 5 :
3647             emitcode("rr","a");
3648             emitcode("rr","a");
3649             emitcode("rr","a");
3650             break;
3651         case 6 :
3652             emitcode("rr","a");
3653             emitcode("rr","a");
3654             break;
3655         case 7 :
3656             emitcode("rr","a");
3657             break;
3658     }
3659 }
3660
3661 /*-----------------------------------------------------------------*/
3662 /* AccLsh - left shift accumulator by known count                  */
3663 /*-----------------------------------------------------------------*/
3664 static void AccLsh (int shCount)
3665 {
3666     if(shCount != 0) {
3667         if(shCount == 1) {
3668             emitcode("add","a,a");
3669         }
3670         else if(shCount == 2) {
3671             emitcode("add","a,a");
3672             emitcode("add","a,a");
3673         } else {
3674             /* rotate left accumulator */
3675             AccRol(shCount);
3676             /* and kill the lower order bits */
3677             emit2("and a,!immedbyte", SLMask[shCount]);
3678         }
3679     }
3680 }
3681
3682 /*-----------------------------------------------------------------*/
3683 /* shiftL1Left2Result - shift left one byte from left to result    */
3684 /*-----------------------------------------------------------------*/
3685 static void shiftL1Left2Result (operand *left, int offl,
3686                                 operand *result, int offr, int shCount)
3687 {
3688     char *l;
3689     l = aopGet(AOP(left),offl,FALSE);
3690     MOVA(l);
3691     /* shift left accumulator */
3692     AccLsh(shCount);
3693     aopPut(AOP(result),"a",offr);
3694 }
3695
3696
3697 /*-----------------------------------------------------------------*/
3698 /* genlshTwo - left shift two bytes by known amount != 0           */
3699 /*-----------------------------------------------------------------*/
3700 static void genlshTwo (operand *result,operand *left, int shCount)
3701 {
3702     int size = AOP_SIZE(result);
3703
3704     wassert(size==2);
3705
3706     /* if shCount >= 8 */
3707     if (shCount >= 8) {
3708         shCount -= 8 ;
3709         if (size > 1){
3710             if (shCount) {
3711                 movLeft2Result(left, LSB, result, MSB16, 0);
3712                 aopPut(AOP(result),zero, 0);   
3713                 shiftL1Left2Result(left, MSB16, result, MSB16, shCount);
3714             }
3715             else {
3716                 movLeft2Result(left, LSB, result, MSB16, 0);
3717                 aopPut(AOP(result),zero, 0);   
3718             }
3719         }
3720         else {
3721             aopPut(AOP(result),zero,LSB);   
3722         }
3723     }
3724     /*  1 <= shCount <= 7 */
3725     else {  
3726         if(size == 1) {
3727             wassert(0);
3728         }
3729         else {
3730             shiftL2Left2Result(left, LSB, result, LSB, shCount);
3731         }
3732     }
3733 }
3734
3735 /*-----------------------------------------------------------------*/
3736 /* genlshOne - left shift a one byte quantity by known count       */
3737 /*-----------------------------------------------------------------*/
3738 static void genlshOne (operand *result, operand *left, int shCount)
3739 {       
3740     shiftL1Left2Result(left, LSB, result, LSB, shCount);
3741 }
3742
3743 /*-----------------------------------------------------------------*/
3744 /* genLeftShiftLiteral - left shifting by known count              */
3745 /*-----------------------------------------------------------------*/
3746 static void genLeftShiftLiteral (operand *left,
3747                                  operand *right,
3748                                  operand *result,
3749                                  iCode *ic)
3750 {    
3751     int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3752     int size;
3753
3754     freeAsmop(right,NULL,ic);
3755
3756     aopOp(left,ic,FALSE, FALSE);
3757     aopOp(result,ic,FALSE, FALSE);
3758
3759     size = getSize(operandType(result));
3760
3761 #if VIEW_SIZE
3762     emitcode("; shift left ","result %d, left %d",size,
3763              AOP_SIZE(left));
3764 #endif
3765
3766     /* I suppose that the left size >= result size */
3767     if (shCount == 0) {
3768         wassert(0);
3769     }
3770
3771     else if(shCount >= (size * 8))
3772         while(size--)
3773             aopPut(AOP(result),zero,size);
3774     else{
3775         switch (size) {
3776         case 1:
3777             genlshOne (result,left,shCount);
3778             break;
3779         case 2:
3780             genlshTwo (result,left,shCount);
3781             break;
3782         case 4:
3783             wassert(0);
3784             break;
3785         default:
3786             wassert(0);
3787         }
3788     }
3789     freeAsmop(left,NULL,ic);
3790     freeAsmop(result,NULL,ic);
3791 }
3792
3793 /*-----------------------------------------------------------------*/
3794 /* genLeftShift - generates code for left shifting                 */
3795 /*-----------------------------------------------------------------*/
3796 static void genLeftShift (iCode *ic)
3797 {
3798     int size, offset;
3799     char *l;
3800     symbol *tlbl , *tlbl1;
3801     operand *left,*right, *result;
3802
3803     right = IC_RIGHT(ic);
3804     left  = IC_LEFT(ic);
3805     result = IC_RESULT(ic);
3806
3807     aopOp(right,ic,FALSE, FALSE);
3808
3809     /* if the shift count is known then do it 
3810     as efficiently as possible */
3811     if (AOP_TYPE(right) == AOP_LIT) {
3812         genLeftShiftLiteral (left,right,result,ic);
3813         return ;
3814     }
3815
3816     /* shift count is unknown then we have to form a loop get the loop
3817        count in B : Note: we take only the lower order byte since
3818        shifting more that 32 bits make no sense anyway, ( the largest
3819        size of an object can be only 32 bits ) */
3820     emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3821     emitcode("inc","a");
3822     freeAsmop (right,NULL,ic);
3823     aopOp(left,ic,FALSE, FALSE);
3824     aopOp(result,ic,FALSE, FALSE);
3825
3826     /* now move the left to the result if they are not the
3827        same */
3828 #if 1
3829     if (!sameRegs(AOP(left),AOP(result))) {
3830
3831         size = AOP_SIZE(result);
3832         offset = 0;
3833         while (size--) {
3834             l = aopGet(AOP(left),offset,FALSE);
3835             aopPut(AOP(result),l,offset);
3836             offset++;
3837         }
3838     }
3839 #else
3840     size = AOP_SIZE(result);
3841     offset = 0;
3842     while (size--) {
3843         l = aopGet(AOP(left),offset,FALSE);
3844         aopPut(AOP(result),l,offset);
3845         offset++;
3846     }
3847 #endif
3848
3849
3850     tlbl = newiTempLabel(NULL);
3851     size = AOP_SIZE(result);
3852     offset = 0 ;   
3853     tlbl1 = newiTempLabel(NULL);
3854
3855     emit2("!shortjp !tlabel", tlbl1->key+100); 
3856     emitLabel(tlbl->key+100);    
3857     l = aopGet(AOP(result),offset,FALSE);
3858     emitcode("or", "a,a");
3859     while (size--) {
3860         l = aopGet(AOP(result),offset++,FALSE);
3861         emitcode("rl","%s", l);         
3862     }
3863     emitLabel(tlbl1->key+100);
3864     emitcode("dec", "a");
3865     emit2("!shortjp nz,!tlabel", tlbl->key+100);
3866
3867     freeAsmop(left,NULL,ic);
3868     freeAsmop(result,NULL,ic);
3869 }
3870
3871 /*-----------------------------------------------------------------*/
3872 /* genrshOne - left shift two bytes by known amount != 0           */
3873 /*-----------------------------------------------------------------*/
3874 static void genrshOne (operand *result,operand *left, int shCount)
3875 {
3876     /* Errk */
3877     int size = AOP_SIZE(result);
3878     char *l;
3879
3880     wassert(size==1);
3881     wassert(shCount<8);
3882
3883     l = aopGet(AOP(left),0,FALSE);
3884     if (AOP(result)->type == AOP_REG) {
3885         aopPut(AOP(result), l, 0);
3886         l = aopGet(AOP(result), 0, FALSE);
3887         while (shCount--) 
3888             emitcode("srl", "%s", l);
3889     }
3890     else {
3891         MOVA(l);
3892         while (shCount--) {
3893             emitcode("srl", "a");
3894         }
3895         aopPut(AOP(result),"a",0);
3896     }
3897 }
3898
3899 /*-----------------------------------------------------------------*/
3900 /* AccRsh - right shift accumulator by known count                 */
3901 /*-----------------------------------------------------------------*/
3902 static void AccRsh (int shCount)
3903 {
3904     if(shCount != 0){
3905         /* rotate right accumulator */
3906         AccRol(8 - shCount);
3907         /* and kill the higher order bits */
3908         emit2("and a,!immedbyte", SRMask[shCount]);
3909     }
3910 }
3911
3912 /*-----------------------------------------------------------------*/
3913 /* shiftR1Left2Result - shift right one byte from left to result   */
3914 /*-----------------------------------------------------------------*/
3915 static void shiftR1Left2Result (operand *left, int offl,
3916                                 operand *result, int offr,
3917                                 int shCount, int sign)
3918 {
3919     MOVA(aopGet(AOP(left),offl,FALSE));
3920     if (sign) {
3921         wassert(0);
3922     }
3923     else {
3924         AccRsh(shCount);
3925     }
3926     aopPut(AOP(result),"a",offr);
3927 }
3928
3929 /*-----------------------------------------------------------------*/
3930 /* genrshTwo - right shift two bytes by known amount != 0          */
3931 /*-----------------------------------------------------------------*/
3932 static void genrshTwo (operand *result,operand *left,
3933                        int shCount, int sign)
3934 {
3935     /* if shCount >= 8 */
3936     if (shCount >= 8) {
3937         shCount -= 8;
3938         if (shCount) {
3939             shiftR1Left2Result(left, MSB16, result, LSB,
3940                                shCount, sign);
3941         }
3942         else {
3943             movLeft2Result(left, MSB16, result, LSB, sign);
3944         }
3945         aopPut(AOP(result),zero,1);
3946     }
3947     /*  1 <= shCount <= 7 */
3948     else {
3949         shiftR2Left2Result(left, LSB, result, LSB, shCount, sign); 
3950     }
3951 }
3952
3953 /*-----------------------------------------------------------------*/
3954 /* genRightShiftLiteral - left shifting by known count              */
3955 /*-----------------------------------------------------------------*/
3956 static void genRightShiftLiteral (operand *left,
3957                                  operand *right,
3958                                  operand *result,
3959                                  iCode *ic)
3960 {    
3961     int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3962     int size;
3963
3964     freeAsmop(right,NULL,ic);
3965
3966     aopOp(left,ic,FALSE, FALSE);
3967     aopOp(result,ic,FALSE, FALSE);
3968
3969     size = getSize(operandType(result));
3970
3971     emitcode("; shift right ","result %d, left %d",size,
3972              AOP_SIZE(left));
3973
3974     /* I suppose that the left size >= result size */
3975     if (shCount == 0) {
3976         wassert(0);
3977     }
3978
3979     else if(shCount >= (size * 8))
3980         while(size--)
3981             aopPut(AOP(result),zero,size);
3982     else{
3983         switch (size) {
3984         case 1:
3985             genrshOne(result, left, shCount);
3986             break;
3987         case 2:
3988             /* PENDING: sign support */
3989             genrshTwo(result, left, shCount, FALSE);
3990             break;
3991         case 4:
3992             wassert(0);
3993             break;
3994         default:
3995             wassert(0);
3996         }
3997     }
3998     freeAsmop(left,NULL,ic);
3999     freeAsmop(result,NULL,ic);
4000 }
4001
4002 /*-----------------------------------------------------------------*/
4003 /* genRightShift - generate code for right shifting                */
4004 /*-----------------------------------------------------------------*/
4005 static void genRightShift (iCode *ic)
4006 {
4007     operand *right, *left, *result;
4008     link *retype ;
4009     int size, offset, first = 1;
4010     char *l;
4011     bool is_signed;
4012
4013     symbol *tlbl, *tlbl1 ;
4014
4015     /* if signed then we do it the hard way preserve the
4016     sign bit moving it inwards */
4017     retype = getSpec(operandType(IC_RESULT(ic)));
4018
4019     is_signed = !SPEC_USIGN(retype);
4020
4021     /* signed & unsigned types are treated the same : i.e. the
4022     signed is NOT propagated inwards : quoting from the
4023     ANSI - standard : "for E1 >> E2, is equivalent to division
4024     by 2**E2 if unsigned or if it has a non-negative value,
4025     otherwise the result is implementation defined ", MY definition
4026     is that the sign does not get propagated */
4027
4028     right = IC_RIGHT(ic);
4029     left  = IC_LEFT(ic);
4030     result = IC_RESULT(ic);
4031
4032     aopOp(right,ic,FALSE, FALSE);
4033
4034     /* if the shift count is known then do it 
4035     as efficiently as possible */
4036     if (AOP_TYPE(right) == AOP_LIT) {
4037         genRightShiftLiteral(left,right,result,ic);
4038         return;
4039     }
4040
4041     aopOp(left,ic,FALSE, FALSE);
4042     aopOp(result,ic,FALSE, FALSE);
4043
4044     /* now move the left to the result if they are not the
4045     same */
4046     if (!sameRegs(AOP(left),AOP(result)) && 
4047         AOP_SIZE(result) > 1) {
4048
4049         size = AOP_SIZE(result);
4050         offset=0;
4051         while (size--) {
4052             l = aopGet(AOP(left),offset,FALSE);
4053             aopPut(AOP(result),l,offset);
4054             offset++;
4055         }
4056     }
4057
4058     emitcode("ld", "a,%s",aopGet(AOP(right),0,FALSE));
4059     emitcode("inc","a");
4060     freeAsmop (right, NULL, ic);
4061
4062     tlbl = newiTempLabel(NULL);
4063     tlbl1= newiTempLabel(NULL);
4064     size = AOP_SIZE(result);
4065     offset = size - 1;
4066
4067     emit2("!shortjp !tlabel", tlbl1->key+100);
4068     emitLabel(tlbl->key+100);
4069     while (size--) {
4070         l = aopGet(AOP(result),offset--,FALSE);
4071         if (first) {
4072             if (is_signed)
4073                 emitcode("sra", "%s", l);
4074             else
4075                 emitcode("srl", "%s", l);
4076             first = 0;
4077         }
4078         else
4079             emitcode("rr", "%s", l);
4080     }
4081     emitLabel(tlbl1->key+100);
4082     emitcode("dec", "a");
4083     emit2("!shortjp nz,!tlabel", tlbl->key+100);
4084
4085     freeAsmop(left,NULL,ic);
4086     freeAsmop(result,NULL,ic);
4087 }
4088
4089 /*-----------------------------------------------------------------*/
4090 /* genGenPointerGet -  get value from generic pointer space        */
4091 /*-----------------------------------------------------------------*/
4092 static void genGenPointerGet (operand *left,
4093                               operand *result, iCode *ic)
4094 {
4095     int size, offset ;
4096     link *retype = getSpec(operandType(result));
4097     int pair = PAIR_HL;
4098
4099     if (IS_GB)
4100         pair = PAIR_DE;
4101
4102     aopOp(left,ic,FALSE, FALSE);
4103     aopOp(result,ic,FALSE, FALSE);
4104     
4105     if (isPair(AOP(left)) && AOP_SIZE(result)==1) {
4106         /* Just do it */
4107         if (isPtrPair(AOP(left))) 
4108             {
4109                 tsprintf(buffer, "!*pair", getPairName(AOP(left)));
4110                 aopPut(AOP(result), buffer, 0);
4111             }
4112         else {
4113             emit2("ld a,!*pair", getPairName(AOP(left)));
4114             aopPut(AOP(result),"a", 0);
4115         }
4116         freeAsmop(left,NULL,ic);
4117         goto release;
4118     }
4119
4120     /* For now we always load into IY */
4121     /* if this is remateriazable */
4122     fetchPair(pair, AOP(left));
4123
4124     /* so iy now contains the address */
4125     freeAsmop(left,NULL,ic);
4126
4127     /* if bit then unpack */
4128     if (IS_BITVAR(retype)) {
4129         wassert(0);
4130     }
4131     else {
4132         size = AOP_SIZE(result);
4133         offset = 0 ;
4134
4135         while (size--) {
4136             /* PENDING: make this better */
4137             if (!IS_GB && AOP(result)->type == AOP_REG) {
4138                 aopPut(AOP(result), "!*hl", offset++);
4139             }
4140             else {
4141                 emit2("ld a,!*pair", _pairs[pair].name);
4142                 aopPut(AOP(result),"a",offset++);
4143             }
4144             if (size) {
4145                 emit2("inc %s", _pairs[pair].name);
4146                 _G.pairs[pair].offset++;
4147             }
4148         }
4149     }
4150
4151  release:
4152     freeAsmop(result,NULL,ic);
4153 }
4154
4155 /*-----------------------------------------------------------------*/
4156 /* genPointerGet - generate code for pointer get                   */
4157 /*-----------------------------------------------------------------*/
4158 static void genPointerGet (iCode *ic)
4159 {
4160     operand *left, *result ;
4161     link *type, *etype;
4162
4163     left = IC_LEFT(ic);
4164     result = IC_RESULT(ic) ;
4165
4166     /* depending on the type of pointer we need to
4167     move it to the correct pointer register */
4168     type = operandType(left);
4169     etype = getSpec(type);
4170
4171     genGenPointerGet (left,result,ic);
4172 }
4173
4174 bool isRegOrLit(asmop *aop)
4175 {
4176     if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
4177         return TRUE;
4178     return FALSE;
4179 }
4180
4181 /*-----------------------------------------------------------------*/
4182 /* genGenPointerSet - stores the value into a pointer location        */
4183 /*-----------------------------------------------------------------*/
4184 static void genGenPointerSet (operand *right,
4185                               operand *result, iCode *ic)
4186 {    
4187     int size, offset ;
4188     link *retype = getSpec(operandType(right));
4189     PAIR_ID pairId = PAIR_HL;
4190
4191     aopOp(result,ic,FALSE, FALSE);
4192     aopOp(right,ic,FALSE, FALSE);
4193
4194     if (IS_GB)
4195         pairId = PAIR_DE;
4196
4197     /* Handle the exceptions first */
4198     if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
4199         /* Just do it */
4200         char *l = aopGet(AOP(right), 0, FALSE);
4201         const char *pair = getPairName(AOP(result));
4202         if (canAssignToPtr(l) && isPtr(pair)) {
4203             emit2("ld !*pair,%s", pair, l);
4204         }
4205         else {
4206             MOVA(l);
4207             emit2("ld !*pair,a", pair);
4208         }
4209         goto release;
4210     }
4211         
4212     /* if the operand is already in dptr 
4213        then we do nothing else we move the value to dptr */
4214     if (AOP_TYPE(result) != AOP_STR) {
4215         fetchPair(pairId, AOP(result));
4216     }
4217     /* so hl know contains the address */
4218     freeAsmop(result,NULL,ic);
4219
4220     /* if bit then unpack */
4221     if (IS_BITVAR(retype)) {
4222         wassert(0);
4223     }
4224     else {
4225         size = AOP_SIZE(right);
4226         offset = 0 ;
4227
4228         while (size--) {
4229             char *l = aopGet(AOP(right),offset,FALSE);
4230             if (isRegOrLit(AOP(right)) && !IS_GB) {
4231                 emit2("ld !*pair,%s", _pairs[pairId].name, l);
4232             }
4233             else {
4234                 MOVA(l);
4235                 emit2("ld !*pair,a", _pairs[pairId].name);
4236             }
4237             if (size) {
4238                 emitcode("inc", _pairs[pairId].name);
4239                 _G.pairs[pairId].offset++;
4240             }
4241             offset++;
4242         }
4243     }
4244     release:
4245     freeAsmop(right,NULL,ic);
4246 }
4247
4248 /*-----------------------------------------------------------------*/
4249 /* genPointerSet - stores the value into a pointer location        */
4250 /*-----------------------------------------------------------------*/
4251 static void genPointerSet (iCode *ic)
4252 {    
4253     operand *right, *result ;
4254     link *type, *etype;
4255
4256     right = IC_RIGHT(ic);
4257     result = IC_RESULT(ic) ;
4258
4259     /* depending on the type of pointer we need to
4260     move it to the correct pointer register */
4261     type = operandType(result);
4262     etype = getSpec(type);
4263     
4264     genGenPointerSet (right,result,ic);
4265 }
4266
4267 /*-----------------------------------------------------------------*/
4268 /* genIfx - generate code for Ifx statement                        */
4269 /*-----------------------------------------------------------------*/
4270 static void genIfx (iCode *ic, iCode *popIc)
4271 {
4272     operand *cond = IC_COND(ic);
4273     int isbit =0;
4274
4275     aopOp(cond,ic,FALSE, TRUE);
4276
4277     /* get the value into acc */
4278     if (AOP_TYPE(cond) != AOP_CRY)
4279         toBoolean(cond);
4280     else
4281         isbit = 1;
4282     /* the result is now in the accumulator */
4283     freeAsmop(cond,NULL,ic);
4284
4285     /* if there was something to be popped then do it */
4286     if (popIc)
4287         genIpop(popIc);
4288
4289     /* if the condition is  a bit variable */
4290     if (isbit && IS_ITEMP(cond) && 
4291         SPIL_LOC(cond))
4292         genIfxJump(ic,SPIL_LOC(cond)->rname);
4293     else
4294         if (isbit && !IS_ITEMP(cond))
4295             genIfxJump(ic,OP_SYMBOL(cond)->rname);
4296         else
4297             genIfxJump(ic,"a");
4298
4299     ic->generated = 1;
4300 }
4301
4302 /*-----------------------------------------------------------------*/
4303 /* genAddrOf - generates code for address of                       */
4304 /*-----------------------------------------------------------------*/
4305 static void genAddrOf (iCode *ic)
4306 {
4307     symbol *sym = OP_SYMBOL(IC_LEFT(ic));
4308
4309     aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
4310
4311     /* if the operand is on the stack then we 
4312     need to get the stack offset of this
4313     variable */
4314     if (IS_GB) {
4315         if (sym->onStack) {
4316             spillCached();
4317             if (sym->stack <= 0) {
4318                 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
4319             }
4320             else {
4321                 emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
4322             }
4323             emitcode("ld", "d,h");
4324             emitcode("ld", "e,l");
4325         }
4326         else {
4327             emit2("ld de,!hashedstr", sym->rname);
4328         }
4329         aopPut(AOP(IC_RESULT(ic)), "e", 0);
4330         aopPut(AOP(IC_RESULT(ic)), "d", 1);
4331     }
4332     else {
4333         spillCached();
4334         if (sym->onStack) {
4335             /* if it has an offset  then we need to compute it */
4336             emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
4337             emitcode("add", "hl,sp");
4338         }
4339         else {
4340             emitcode("ld", "hl,#%s", sym->rname);
4341         }
4342         aopPut(AOP(IC_RESULT(ic)), "l", 0);
4343         aopPut(AOP(IC_RESULT(ic)), "h", 1);
4344     }
4345     freeAsmop(IC_RESULT(ic),NULL,ic);
4346 }
4347
4348 /*-----------------------------------------------------------------*/
4349 /* genAssign - generate code for assignment                        */
4350 /*-----------------------------------------------------------------*/
4351 static void genAssign (iCode *ic)
4352 {
4353     operand *result, *right;
4354     int size, offset ;
4355     unsigned long lit = 0L;
4356
4357     result = IC_RESULT(ic);
4358     right  = IC_RIGHT(ic) ;
4359
4360 #if 1
4361     /* Dont bother assigning if they are the same */
4362     if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
4363         emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
4364         return;
4365     }
4366 #endif
4367
4368     aopOp(right,ic,FALSE, FALSE);
4369     aopOp(result,ic,TRUE, FALSE);
4370
4371     /* if they are the same registers */
4372     if (sameRegs(AOP(right),AOP(result))) {
4373         emitcode("", "; (registers are the same)");
4374         goto release;
4375     }
4376
4377     /* if the result is a bit */
4378     if (AOP_TYPE(result) == AOP_CRY) {
4379         wassert(0);
4380     }
4381
4382     /* general case */
4383     size = AOP_SIZE(result);
4384     offset = 0;
4385
4386     if(AOP_TYPE(right) == AOP_LIT)
4387         lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4388     if (isPair(AOP(result))) {
4389         fetchPair(getPairId(AOP(result)), AOP(right));
4390     }
4391     else if((size > 1) &&
4392        (AOP_TYPE(result) != AOP_REG) &&
4393        (AOP_TYPE(right) == AOP_LIT) &&
4394        !IS_FLOAT(operandType(right)) &&
4395        (lit < 256L)) {
4396         bool fXored = FALSE;
4397         offset = 0;
4398         /* Work from the top down.
4399            Done this way so that we can use the cached copy of 0
4400            in A for a fast clear */
4401         while (size--) {
4402             if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
4403                 if (!fXored && size>1) {
4404                     emitcode("xor", "a,a");
4405                     fXored = TRUE;
4406                 }
4407                 if (fXored) {
4408                     aopPut(AOP(result),"a",offset);
4409                 }
4410                 else {
4411                     aopPut(AOP(result), zero, offset);
4412                 }
4413             }
4414             else
4415                 aopPut(AOP(result),
4416                        aopGet(AOP(right),offset,FALSE),
4417                        offset);
4418             offset++;
4419         }
4420     }
4421     else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result)) && IS_GB) {
4422         /* Special case.  Load into a and d, then load out. */
4423         MOVA(aopGet(AOP(right), 0, FALSE));
4424         emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
4425         aopPut(AOP(result), "a", 0);
4426         aopPut(AOP(result), "e", 1);
4427     } else {
4428         while (size--) {
4429             /* PENDING: do this check better */
4430             if (requiresHL(AOP(right)) && requiresHL(AOP(result))) {
4431                 MOVA(aopGet(AOP(right), offset, FALSE));
4432                 aopPut(AOP(result), "a", offset);
4433             }
4434             else 
4435                 aopPut(AOP(result),
4436                        aopGet(AOP(right),offset,FALSE),
4437                        offset);
4438             offset++;
4439         }
4440     }
4441     
4442 release:
4443     freeAsmop(right,NULL,ic);
4444     freeAsmop(result,NULL,ic);
4445 }   
4446
4447 /*-----------------------------------------------------------------*/
4448 /* genJumpTab - genrates code for jump table                       */
4449 /*-----------------------------------------------------------------*/
4450 static void genJumpTab (iCode *ic)
4451 {
4452     symbol *jtab;
4453     char *l;
4454
4455     aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
4456     /* get the condition into accumulator */
4457     l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
4458     if (!IS_GB)
4459         emitcode("push", "de");
4460     emitcode("ld", "e,%s", l);
4461     emit2("ld d,!zero");
4462     jtab = newiTempLabel(NULL);
4463     spillCached();
4464     emit2("ld hl,!immed!tlabel", jtab->key+100);
4465     emitcode("add", "hl,de");
4466     emitcode("add", "hl,de");
4467     emitcode("add", "hl,de");
4468     freeAsmop(IC_JTCOND(ic),NULL,ic);
4469     if (!IS_GB)
4470         emitcode("pop", "de");
4471     emit2("jp !*hl");
4472     emitLabel(jtab->key+100);
4473     /* now generate the jump labels */
4474     for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4475          jtab = setNextItem(IC_JTLABELS(ic)))
4476         emit2("jp !tlabel", jtab->key+100);
4477 }
4478
4479 /*-----------------------------------------------------------------*/
4480 /* genCast - gen code for casting                                  */
4481 /*-----------------------------------------------------------------*/
4482 static void genCast (iCode *ic)
4483 {
4484     operand *result = IC_RESULT(ic);
4485     link *ctype = operandType(IC_LEFT(ic));
4486     operand *right = IC_RIGHT(ic);
4487     int size, offset ;
4488
4489     /* if they are equivalent then do nothing */
4490     if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4491         return ;
4492
4493     aopOp(right,ic,FALSE, FALSE);
4494     aopOp(result,ic,FALSE, FALSE);
4495
4496     /* if the result is a bit */
4497     if (AOP_TYPE(result) == AOP_CRY) {
4498         wassert(0);
4499     }
4500
4501     /* if they are the same size : or less */
4502     if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4503
4504         /* if they are in the same place */
4505         if (sameRegs(AOP(right),AOP(result)))
4506             goto release;
4507
4508         /* if they in different places then copy */
4509         size = AOP_SIZE(result);
4510         offset = 0 ;
4511         while (size--) {
4512             aopPut(AOP(result),
4513                    aopGet(AOP(right),offset,FALSE),
4514                    offset);
4515             offset++;
4516         }
4517         goto release;
4518     }
4519
4520     /* PENDING: should be OK. */
4521 #if 0
4522     /* if the result is of type pointer */
4523     if (IS_PTR(ctype)) {
4524         wassert(0);
4525     }
4526 #endif
4527     
4528     /* so we now know that the size of destination is greater
4529     than the size of the source */
4530     /* we move to result for the size of source */
4531     size = AOP_SIZE(right);
4532     offset = 0 ;
4533     while (size--) {
4534         aopPut(AOP(result),
4535                aopGet(AOP(right),offset,FALSE),
4536                offset);
4537         offset++;
4538     }
4539
4540     /* now depending on the sign of the destination */
4541     size = AOP_SIZE(result) - AOP_SIZE(right);
4542     /* Unsigned or not an integral type - right fill with zeros */
4543     if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
4544         while (size--)
4545             aopPut(AOP(result),zero,offset++);
4546     } else {
4547         /* we need to extend the sign :{ */
4548         char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
4549                          FALSE);
4550         MOVA(l);
4551         emitcode("", "; genCast: sign extend untested.");
4552         emitcode("rla", "");
4553         emitcode("sbc", "a,a");
4554         while (size--)
4555             aopPut(AOP(result),"a",offset++);   
4556     }
4557
4558 release:
4559     freeAsmop(right, NULL, ic);
4560     freeAsmop(result, NULL, ic);
4561 }
4562
4563 /*-----------------------------------------------------------------*/
4564 /* genReceive - generate code for a receive iCode                  */
4565 /*-----------------------------------------------------------------*/
4566 static void genReceive (iCode *ic)
4567 {    
4568     if (isOperandInFarSpace(IC_RESULT(ic)) && 
4569         ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
4570           IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
4571         wassert(0);
4572     } else {
4573         accInUse++;
4574         aopOp(IC_RESULT(ic),ic,FALSE, FALSE);  
4575         accInUse--;
4576         assignResultValue(IC_RESULT(ic));       
4577     }
4578
4579     freeAsmop(IC_RESULT(ic),NULL,ic);
4580 }
4581
4582 /*-----------------------------------------------------------------*/
4583 /* genZ80Code - generate code for Z80 based controllers            */
4584 /*-----------------------------------------------------------------*/
4585 void genZ80Code (iCode *lic)
4586 {
4587     iCode *ic;
4588     int cln = 0;
4589
4590     /* HACK */
4591     if (IS_GB) {
4592         _fReturn = _gbz80_return;
4593         _fTmp = _gbz80_return;
4594     }
4595     else {
4596         _fReturn = _z80_return;
4597         _fTmp = _z80_return;
4598     }
4599     tsprintf(zero, "!zero");
4600
4601     lineHead = lineCurr = NULL;
4602
4603     /* if debug information required */
4604     if (options.debug && currFunc) { 
4605         cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4606         debugLine = 1;
4607         if (IS_STATIC(currFunc->etype))
4608             emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name); 
4609         else
4610             emitcode("","G$%s$0$0 ==.",currFunc->name);
4611         debugLine = 0;
4612     }
4613     /* stack pointer name */
4614     spname = "sp";
4615     
4616  
4617     for (ic = lic ; ic ; ic = ic->next ) {
4618         
4619         if ( cln != ic->lineno ) {
4620             if ( options.debug ) {
4621                 debugLine = 1;
4622                 emitcode("","C$%s$%d$%d$%d ==.",
4623                          ic->filename,ic->lineno,
4624                          ic->level,ic->block);
4625                 debugLine = 0;
4626             }
4627             emitcode(";","%s %d",ic->filename,ic->lineno);
4628             cln = ic->lineno ;
4629         }
4630         /* if the result is marked as
4631            spilt and rematerializable or code for
4632            this has already been generated then
4633            do nothing */
4634         if (resultRemat(ic) || ic->generated ) 
4635             continue ;
4636         
4637         /* depending on the operation */
4638         switch (ic->op) {
4639         case '!' :
4640             emitcode("", "; genNot");
4641             genNot(ic);
4642             break;
4643             
4644         case '~' :
4645             emitcode("", "; genCpl");
4646             genCpl(ic);
4647             break;
4648             
4649         case UNARYMINUS:
4650             emitcode("", "; genUminus");
4651             genUminus (ic);
4652             break;
4653             
4654         case IPUSH:
4655             emitcode("", "; genIpush");
4656             genIpush (ic);
4657             break;
4658             
4659         case IPOP:
4660             /* IPOP happens only when trying to restore a 
4661                spilt live range, if there is an ifx statement
4662                following this pop then the if statement might
4663                be using some of the registers being popped which
4664                would destory the contents of the register so
4665                we need to check for this condition and handle it */
4666             if (ic->next            && 
4667                 ic->next->op == IFX &&
4668                 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
4669                 emitcode("", "; genIfx");
4670                 genIfx (ic->next,ic);
4671             }
4672             else {
4673                 emitcode("", "; genIpop");
4674                 genIpop (ic);
4675             }
4676             break; 
4677             
4678         case CALL:
4679             emitcode("", "; genCall");
4680             genCall (ic);
4681             break;
4682             
4683         case PCALL:
4684             emitcode("", "; genPcall");
4685             genPcall (ic);
4686             break;
4687             
4688         case FUNCTION:
4689             emitcode("", "; genFunction");
4690             genFunction (ic);
4691             break;
4692             
4693         case ENDFUNCTION:
4694             emitcode("", "; genEndFunction");
4695             genEndFunction (ic);
4696             break;
4697             
4698         case RETURN:
4699             emitcode("", "; genRet");
4700             genRet (ic);
4701             break;
4702             
4703         case LABEL:
4704             emitcode("", "; genLabel");
4705             genLabel (ic);
4706             break;
4707             
4708         case GOTO:
4709             emitcode("", "; genGoto");
4710             genGoto (ic);
4711             break;
4712             
4713         case '+' :
4714             emitcode("", "; genPlus");
4715             genPlus (ic) ;
4716             break;
4717             
4718         case '-' :
4719             emitcode("", "; genMinus");
4720             genMinus (ic);
4721             break;
4722             
4723         case '*' :
4724             emitcode("", "; genMult");
4725             genMult (ic);
4726             break;
4727             
4728         case '/' :
4729             emitcode("", "; genDiv");
4730             genDiv (ic) ;
4731             break;
4732             
4733         case '%' :
4734             emitcode("", "; genMod");
4735             genMod (ic);
4736             break;
4737             
4738         case '>' :
4739             emitcode("", "; genCmpGt");
4740             genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));                 
4741             break;
4742             
4743         case '<' :
4744             emitcode("", "; genCmpLt");
4745             genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4746             break;
4747             
4748         case LE_OP:
4749         case GE_OP:
4750         case NE_OP:
4751             
4752             /* note these two are xlated by algebraic equivalence
4753                during parsing SDCC.y */
4754             werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4755                    "got '>=' or '<=' shouldn't have come here");
4756             break;      
4757             
4758         case EQ_OP:
4759             emitcode("", "; genCmpEq");
4760             genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4761             break;          
4762             
4763         case AND_OP:
4764             emitcode("", "; genAndOp");
4765             genAndOp (ic);
4766             break;
4767             
4768         case OR_OP:
4769             emitcode("", "; genOrOp");
4770             genOrOp (ic);
4771             break;
4772             
4773         case '^' :
4774             emitcode("", "; genXor");
4775             genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4776             break;
4777             
4778         case '|' :
4779             emitcode("", "; genOr");
4780             genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4781             break;
4782             
4783         case BITWISEAND:
4784             emitcode("", "; genAnd");
4785             genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4786             break;
4787             
4788         case INLINEASM:
4789             emitcode("", "; genInline");
4790             genInline (ic);
4791             break;
4792             
4793         case RRC:
4794             emitcode("", "; genRRC");
4795             genRRC (ic);
4796             break;
4797             
4798         case RLC:
4799             emitcode("", "; genRLC");
4800             genRLC (ic);
4801             break;
4802             
4803         case GETHBIT:
4804             emitcode("", "; genHBIT");
4805             wassert(0);
4806             
4807         case LEFT_OP:
4808             emitcode("", "; genLeftShift");
4809             genLeftShift (ic);
4810             break;
4811             
4812         case RIGHT_OP:
4813             emitcode("", "; genRightShift");
4814             genRightShift (ic);
4815             break;
4816             
4817         case GET_VALUE_AT_ADDRESS:
4818             emitcode("", "; genPointerGet");
4819             genPointerGet(ic);
4820             break;
4821             
4822         case '=' :
4823
4824             if (POINTER_SET(ic)) {
4825                 emitcode("", "; genAssign (pointer)");
4826                 genPointerSet(ic);
4827             }
4828             else {
4829                 emitcode("", "; genAssign");
4830                 genAssign(ic);
4831             }
4832             break;
4833             
4834         case IFX:
4835             emitcode("", "; genIfx");
4836             genIfx (ic,NULL);
4837             break;
4838             
4839         case ADDRESS_OF:
4840             emitcode("", "; genAddrOf");
4841             genAddrOf (ic);
4842             break;
4843             
4844         case JUMPTABLE:
4845             emitcode("", "; genJumpTab");
4846             genJumpTab (ic);
4847             break;
4848             
4849         case CAST:
4850             emitcode("", "; genCast");
4851             genCast (ic);
4852             break;
4853             
4854         case RECEIVE:
4855             emitcode("", "; genReceive");
4856             genReceive(ic);
4857             break;
4858             
4859         case SEND:
4860             emitcode("", "; addSet");
4861             addSet(&sendSet,ic);
4862             break;
4863
4864         default :
4865             ic = ic;
4866             /*      piCode(ic,stdout); */
4867             
4868         }
4869     }
4870     
4871
4872     /* now we are ready to call the 
4873        peep hole optimizer */
4874     if (!options.nopeep)
4875         peepHole (&lineHead);
4876
4877     /* This is unfortunate */
4878     /* now do the actual printing */
4879     {
4880         FILE *fp = codeOutFile;
4881         if (isInHome() && codeOutFile == code->oFile)
4882             codeOutFile = home->oFile;
4883         printLine (lineHead, codeOutFile);
4884         if (_G.flush_statics) {
4885             flushStatics();
4886             _G.flush_statics = 0;
4887         }
4888         codeOutFile = fp;
4889     }
4890 }