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