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