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