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