* device/lib/_gptrget.c,
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   SDCCgen51.c - source file for code generation for 8051
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25
26   Notes:
27   000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
28       Made everything static
29 -------------------------------------------------------------------------*/
30
31 //#define D(x)
32 #define D(x) x
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include "SDCCglobl.h"
39 #include "newalloc.h"
40
41 #include "common.h"
42 #include "SDCCpeeph.h"
43 #include "ralloc.h"
44 #include "gen.h"
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0x00";
55 static char *one = "#0x01";
56 static char *spname;
57
58 char *fReturn8051[] =
59 {"dpl", "dph", "b", "a"};
60 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
61 char **fReturn = fReturn8051;
62 static char *accUse[] =
63 {"a", "b"};
64
65 static unsigned short rbank = -1;
66
67 static struct
68   {
69     short r0Pushed;
70     short r1Pushed;
71     short r0InB;
72     short r1InB;
73     short accInUse;
74     short inLine;
75     short debugLine;
76     short nRegsSaved;
77     set *sendSet;
78     iCode *current_iCode;
79     symbol *currentFunc;
80   }
81 _G;
82
83 static char *rb1regs[] = {
84     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
85 };
86
87 extern int mcs51_ptrRegReq;
88 extern int mcs51_nRegs;
89 extern FILE *codeOutFile;
90 static void saveRBank (int, iCode *, bool);
91 #define RESULTONSTACK(x) \
92                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
93                          IC_RESULT(x)->aop->type == AOP_STK )
94
95 #define MOVA(x) mova(x)  /* use function to avoid multiple eval */
96 #define CLRC    emitcode("clr","c")
97 #define SETC    emitcode("setb","c")
98
99 static lineNode *lineHead = NULL;
100 static lineNode *lineCurr = NULL;
101
102 static unsigned char SLMask[] =
103 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
104  0xE0, 0xC0, 0x80, 0x00};
105 static unsigned char SRMask[] =
106 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
107  0x07, 0x03, 0x01, 0x00};
108
109 #define LSB     0
110 #define MSB16   1
111 #define MSB24   2
112 #define MSB32   3
113
114 /*-----------------------------------------------------------------*/
115 /* emitcode - writes the code into a file : for now it is simple    */
116 /*-----------------------------------------------------------------*/
117 static void
118 emitcode (char *inst, const char *fmt,...)
119 {
120   va_list ap;
121   char lb[INITIAL_INLINEASM];
122   char *lbp = lb;
123
124   va_start (ap, fmt);
125
126   if (inst && *inst)
127     {
128       if (fmt && *fmt)
129         SNPRINTF (lb, sizeof(lb), "%s\t", inst);
130       else
131         SNPRINTF (lb, sizeof(lb), "%s", inst);
132       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
133     }
134   else
135     tvsprintf (lb, sizeof(lb), fmt, ap);
136
137   while (isspace (*lbp))
138     lbp++;
139
140   if (lbp && *lbp)
141     lineCurr = (lineCurr ?
142                 connectLine (lineCurr, newLineNode (lb)) :
143                 (lineHead = newLineNode (lb)));
144   lineCurr->isInline = _G.inLine;
145   lineCurr->isDebug = _G.debugLine;
146   lineCurr->ic = _G.current_iCode;
147   lineCurr->isComment = (*lbp==';');
148   va_end (ap);
149 }
150
151 /*-----------------------------------------------------------------*/
152 /* mcs51_emitDebuggerSymbol - associate the current code location  */
153 /*   with a debugger symbol                                        */
154 /*-----------------------------------------------------------------*/
155 void
156 mcs51_emitDebuggerSymbol (char * debugSym)
157 {
158   _G.debugLine = 1;
159   emitcode ("", "%s ==.", debugSym);
160   _G.debugLine = 0;
161 }
162
163 /*-----------------------------------------------------------------*/
164 /* mova - moves specified value into accumulator                   */
165 /*-----------------------------------------------------------------*/
166 static void
167 mova (const char *x)
168 {
169   /* do some early peephole optimization */
170   if (!strcmp(x, "a") || !strcmp(x, "acc"))
171     return;
172
173   emitcode("mov","a,%s", x);
174 }
175
176 /*-----------------------------------------------------------------*/
177 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
178 /*-----------------------------------------------------------------*/
179 static regs *
180 getFreePtr (iCode * ic, asmop ** aopp, bool result)
181 {
182   bool r0iu, r1iu;
183   bool r0ou, r1ou;
184
185   /* the logic: if r0 & r1 used in the instruction
186      then we are in trouble otherwise */
187
188   /* first check if r0 & r1 are used by this
189      instruction, in which case we are in trouble */
190   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
191   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
192   if (r0iu && r1iu) {
193       goto endOfWorld;
194     }
195
196   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
197   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
198
199   /* if no usage of r0 then return it */
200   if (!r0iu && !r0ou)
201     {
202       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
203       (*aopp)->type = AOP_R0;
204
205       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
206     }
207
208   /* if no usage of r1 then return it */
209   if (!r1iu && !r1ou)
210     {
211       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
212       (*aopp)->type = AOP_R1;
213
214       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
215     }
216
217   /* now we know they both have usage */
218   /* if r0 not used in this instruction */
219   if (!r0iu)
220     {
221       /* push it if not already pushed */
222       if (ic->op == IPUSH)
223         {
224           emitcode ("mov", "b,%s",
225                     mcs51_regWithIdx (R0_IDX)->dname);
226           _G.r0InB++;
227         }
228       else if (!_G.r0Pushed)
229         {
230           emitcode ("push", "%s",
231                     mcs51_regWithIdx (R0_IDX)->dname);
232           _G.r0Pushed++;
233         }
234
235       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
236       (*aopp)->type = AOP_R0;
237
238       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
239     }
240
241   /* if r1 not used then */
242
243   if (!r1iu)
244     {
245       /* push it if not already pushed */
246       if (ic->op == IPUSH)
247         {
248           emitcode ("mov", "b,%s",
249                     mcs51_regWithIdx (R1_IDX)->dname);
250           _G.r1InB++;
251         }
252       else if (!_G.r1Pushed)
253         {
254           emitcode ("push", "%s",
255                     mcs51_regWithIdx (R1_IDX)->dname);
256           _G.r1Pushed++;
257         }
258
259       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
260       (*aopp)->type = AOP_R1;
261       return mcs51_regWithIdx (R1_IDX);
262     }
263 endOfWorld:
264   /* I said end of world, but not quite end of world yet */
265   if (result) {
266     /* we can push it on the stack */
267     (*aopp)->type = AOP_STK;
268     return NULL;
269   } else {
270     /* in the case that result AND left AND right needs a pointer reg
271        we can safely use the result's */
272     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
273       (*aopp)->type = AOP_R0;
274       return mcs51_regWithIdx (R0_IDX);
275     }
276     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
277       (*aopp)->type = AOP_R1;
278       return mcs51_regWithIdx (R1_IDX);
279     }
280   }
281
282   /* now this is REALLY the end of the world */
283   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
284           "getFreePtr should never reach here");
285   exit (1);
286 }
287
288
289 /*-----------------------------------------------------------------*/
290 /* getTempRegs - initialize an array of pointers to GPR registers */
291 /*               that are not in use. Returns 1 if the requested   */
292 /*               number of registers were available, 0 otherwise.  */
293 /*-----------------------------------------------------------------*/
294 int
295 getTempRegs(regs **tempRegs, int size, iCode *ic)
296 {
297   bitVect * freeRegs;
298   int i;
299   int offset;
300
301   if (!ic)
302     ic = _G.current_iCode;
303   if (!ic)
304     return 0;
305   if (!_G.currentFunc)
306     return 0;
307
308   freeRegs = newBitVect(8);
309   bitVectSetBit (freeRegs, R2_IDX);
310   bitVectSetBit (freeRegs, R3_IDX);
311   bitVectSetBit (freeRegs, R4_IDX);
312   bitVectSetBit (freeRegs, R5_IDX);
313   bitVectSetBit (freeRegs, R6_IDX);
314   bitVectSetBit (freeRegs, R7_IDX);
315
316   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
317     {
318       bitVect * newfreeRegs;
319       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
320       freeBitVect(freeRegs);
321       freeRegs = newfreeRegs;
322     }
323   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
324
325   offset = 0;
326   for (i=0; i<freeRegs->size; i++)
327     {
328       if (bitVectBitValue(freeRegs,i))
329         tempRegs[offset++] = mcs51_regWithIdx(i);
330       if (offset>=size)
331         {
332           freeBitVect(freeRegs);
333           return 1;
334         }
335     }
336
337   freeBitVect(freeRegs);
338   return 1;
339 }
340
341
342 /*-----------------------------------------------------------------*/
343 /* newAsmop - creates a new asmOp                                  */
344 /*-----------------------------------------------------------------*/
345 static asmop *
346 newAsmop (short type)
347 {
348   asmop *aop;
349
350   aop = Safe_calloc (1, sizeof (asmop));
351   aop->type = type;
352   return aop;
353 }
354
355 /*-----------------------------------------------------------------*/
356 /* pointerCode - returns the code for a pointer type               */
357 /*-----------------------------------------------------------------*/
358 static int
359 pointerCode (sym_link * etype)
360 {
361
362   return PTR_TYPE (SPEC_OCLS (etype));
363
364 }
365
366
367 /*-----------------------------------------------------------------*/
368 /* leftRightUseAcc - returns size of accumulator use by operands   */
369 /*-----------------------------------------------------------------*/
370 static int
371 leftRightUseAcc(iCode *ic)
372 {
373   operand *op;
374   int size;
375   int accuseSize = 0;
376   int accuse = 0;
377
378   if (!ic)
379     {
380       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
381               "null iCode pointer");
382       return 0;
383     }
384
385   if (ic->op == IFX)
386     {
387       op = IC_COND (ic);
388       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
389         {
390           accuse = 1;
391           size = getSize (OP_SYMBOL (op)->type);
392           if (size>accuseSize)
393             accuseSize = size;
394         }
395     }
396   else if (ic->op == JUMPTABLE)
397     {
398       op = IC_JTCOND (ic);
399       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
400         {
401           accuse = 1;
402           size = getSize (OP_SYMBOL (op)->type);
403           if (size>accuseSize)
404             accuseSize = size;
405         }
406     }
407   else
408     {
409       op = IC_LEFT (ic);
410       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
411         {
412           accuse = 1;
413           size = getSize (OP_SYMBOL (op)->type);
414           if (size>accuseSize)
415             accuseSize = size;
416         }
417       op = IC_RIGHT (ic);
418       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
419         {
420           accuse = 1;
421           size = getSize (OP_SYMBOL (op)->type);
422           if (size>accuseSize)
423             accuseSize = size;
424         }
425     }
426
427   if (accuseSize)
428     return accuseSize;
429   else
430     return accuse;
431 }
432
433
434 /*-----------------------------------------------------------------*/
435 /* aopForSym - for a true symbol                                   */
436 /*-----------------------------------------------------------------*/
437 static asmop *
438 aopForSym (iCode * ic, symbol * sym, bool result)
439 {
440   asmop *aop;
441   memmap *space;
442
443   wassertl (ic != NULL, "Got a null iCode");
444   wassertl (sym != NULL, "Got a null symbol");
445
446   space = SPEC_OCLS (sym->etype);
447
448   /* if already has one */
449   if (sym->aop)
450     return sym->aop;
451
452   /* assign depending on the storage class */
453   /* if it is on the stack or indirectly addressable */
454   /* space we need to assign either r0 or r1 to it   */
455   if (sym->onStack || sym->iaccess)
456     {
457       sym->aop = aop = newAsmop (0);
458       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
459       aop->size = getSize (sym->type);
460
461       /* now assign the address of the variable to
462          the pointer register */
463       if (aop->type != AOP_STK)
464         {
465
466           if (sym->onStack)
467             {
468               if (_G.accInUse || leftRightUseAcc (ic))
469                 emitcode ("push", "acc");
470
471               emitcode ("mov", "a,_bp");
472               emitcode ("add", "a,#0x%02x",
473                         ((sym->stack < 0) ?
474                          ((char) (sym->stack - _G.nRegsSaved)) :
475                          ((char) sym->stack)) & 0xff);
476               emitcode ("mov", "%s,a",
477                         aop->aopu.aop_ptr->name);
478
479               if (_G.accInUse || leftRightUseAcc (ic))
480                 emitcode ("pop", "acc");
481             }
482           else
483             emitcode ("mov", "%s,#%s",
484                       aop->aopu.aop_ptr->name,
485                       sym->rname);
486           aop->paged = space->paged;
487         }
488       else
489         aop->aopu.aop_stk = sym->stack;
490       return aop;
491     }
492
493   /* if in bit space */
494   if (IN_BITSPACE (space))
495     {
496       sym->aop = aop = newAsmop (AOP_CRY);
497       aop->aopu.aop_dir = sym->rname;
498       aop->size = getSize (sym->type);
499       return aop;
500     }
501   /* if it is in direct space */
502   if (IN_DIRSPACE (space))
503     {
504       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
505       //printTypeChainRaw(sym->type, NULL);
506       //printf("space = %s\n", space ? space->sname : "NULL");
507       sym->aop = aop = newAsmop (AOP_DIR);
508       aop->aopu.aop_dir = sym->rname;
509       aop->size = getSize (sym->type);
510       return aop;
511     }
512
513   /* special case for a function */
514   if (IS_FUNC (sym->type))
515     {
516       sym->aop = aop = newAsmop (AOP_IMMD);
517       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
518       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
519       aop->size = FPTRSIZE;
520       return aop;
521     }
522
523   /* only remaining is far space */
524   /* in which case DPTR gets the address */
525   sym->aop = aop = newAsmop (AOP_DPTR);
526   emitcode ("mov", "dptr,#%s", sym->rname);
527   aop->size = getSize (sym->type);
528
529   /* if it is in code space */
530   if (IN_CODESPACE (space))
531     aop->code = 1;
532
533   return aop;
534 }
535
536 /*-----------------------------------------------------------------*/
537 /* aopForRemat - rematerialzes an object                           */
538 /*-----------------------------------------------------------------*/
539 static asmop *
540 aopForRemat (symbol * sym)
541 {
542   iCode *ic = sym->rematiCode;
543   asmop *aop = newAsmop (AOP_IMMD);
544   int ptr_type=0;
545   int val = 0;
546
547   for (;;)
548     {
549       if (ic->op == '+')
550         val += (int) operandLitValue (IC_RIGHT (ic));
551       else if (ic->op == '-')
552         val -= (int) operandLitValue (IC_RIGHT (ic));
553       else if (IS_CAST_ICODE(ic)) {
554               sym_link *from_type = operandType(IC_RIGHT(ic));
555               aop->aopu.aop_immd.from_cast_remat = 1;
556               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
557               ptr_type = DCL_TYPE(from_type);
558               if (ptr_type == IPOINTER) {
559                 // bug #481053
560                 ptr_type = POINTER;
561               }
562               continue ;
563       } else break;
564
565       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
566     }
567
568   if (val)
569     sprintf (buffer, "(%s %c 0x%04x)",
570              OP_SYMBOL (IC_LEFT (ic))->rname,
571              val >= 0 ? '+' : '-',
572              abs (val) & 0xffff);
573   else
574     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
575
576   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
577   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
578   /* set immd2 field if required */
579   if (aop->aopu.aop_immd.from_cast_remat) {
580           sprintf(buffer,"#0x%02x",ptr_type);
581           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
582           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
583   }
584
585   return aop;
586 }
587
588 /*-----------------------------------------------------------------*/
589 /* regsInCommon - two operands have some registers in common       */
590 /*-----------------------------------------------------------------*/
591 static bool
592 regsInCommon (operand * op1, operand * op2)
593 {
594   symbol *sym1, *sym2;
595   int i;
596
597   /* if they have registers in common */
598   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
599     return FALSE;
600
601   sym1 = OP_SYMBOL (op1);
602   sym2 = OP_SYMBOL (op2);
603
604   if (sym1->nRegs == 0 || sym2->nRegs == 0)
605     return FALSE;
606
607   for (i = 0; i < sym1->nRegs; i++)
608     {
609       int j;
610       if (!sym1->regs[i])
611         continue;
612
613       for (j = 0; j < sym2->nRegs; j++)
614         {
615           if (!sym2->regs[j])
616             continue;
617
618           if (sym2->regs[j] == sym1->regs[i])
619             return TRUE;
620         }
621     }
622
623   return FALSE;
624 }
625
626 /*-----------------------------------------------------------------*/
627 /* operandsEqu - equivalent                                        */
628 /*-----------------------------------------------------------------*/
629 static bool
630 operandsEqu (operand * op1, operand * op2)
631 {
632   symbol *sym1, *sym2;
633
634   /* if they're not symbols */
635   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
636     return FALSE;
637
638   sym1 = OP_SYMBOL (op1);
639   sym2 = OP_SYMBOL (op2);
640
641   /* if both are itemps & one is spilt
642      and the other is not then false */
643   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
644       sym1->isspilt != sym2->isspilt)
645     return FALSE;
646
647   /* if they are the same */
648   if (sym1 == sym2)
649     return TRUE;
650
651   /* if they have the same rname */
652   if (sym1->rname[0] && sym2->rname[0]
653       && strcmp (sym1->rname, sym2->rname) == 0)
654     return TRUE;
655
656   /* if left is a tmp & right is not */
657   if (IS_ITEMP (op1) &&
658       !IS_ITEMP (op2) &&
659       sym1->isspilt &&
660       (sym1->usl.spillLoc == sym2))
661     return TRUE;
662
663   if (IS_ITEMP (op2) &&
664       !IS_ITEMP (op1) &&
665       sym2->isspilt &&
666       sym1->level > 0 &&
667       (sym2->usl.spillLoc == sym1))
668     return TRUE;
669
670   return FALSE;
671 }
672
673 /*-----------------------------------------------------------------*/
674 /* sameRegs - two asmops have the same registers                   */
675 /*-----------------------------------------------------------------*/
676 static bool
677 sameRegs (asmop * aop1, asmop * aop2)
678 {
679   int i;
680
681   if (aop1 == aop2)
682     return TRUE;
683
684   if (aop1->type != AOP_REG ||
685       aop2->type != AOP_REG)
686     return FALSE;
687
688   if (aop1->size != aop2->size)
689     return FALSE;
690
691   for (i = 0; i < aop1->size; i++)
692     if (aop1->aopu.aop_reg[i] !=
693         aop2->aopu.aop_reg[i])
694       return FALSE;
695
696   return TRUE;
697 }
698
699 /*-----------------------------------------------------------------*/
700 /* aopOp - allocates an asmop for an operand  :                    */
701 /*-----------------------------------------------------------------*/
702 static void
703 aopOp (operand * op, iCode * ic, bool result)
704 {
705   asmop *aop;
706   symbol *sym;
707   int i;
708
709   if (!op)
710     return;
711
712   /* if this a literal */
713   if (IS_OP_LITERAL (op))
714     {
715       op->aop = aop = newAsmop (AOP_LIT);
716       aop->aopu.aop_lit = op->operand.valOperand;
717       aop->size = getSize (operandType (op));
718       return;
719     }
720
721   /* if already has a asmop then continue */
722   if (op->aop )
723     return;
724
725   /* if the underlying symbol has a aop */
726   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
727     {
728       op->aop = OP_SYMBOL (op)->aop;
729       return;
730     }
731
732   /* if this is a true symbol */
733   if (IS_TRUE_SYMOP (op))
734     {
735       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
736       return;
737     }
738
739   /* this is a temporary : this has
740      only four choices :
741      a) register
742      b) spillocation
743      c) rematerialize
744      d) conditional
745      e) can be a return use only */
746
747   sym = OP_SYMBOL (op);
748
749   /* if the type is a conditional */
750   if (sym->regType == REG_CND)
751     {
752       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
753       aop->size = 0;
754       return;
755     }
756
757   /* if it is spilt then two situations
758      a) is rematerialize
759      b) has a spill location */
760   if (sym->isspilt || sym->nRegs == 0)
761     {
762
763       /* rematerialize it NOW */
764       if (sym->remat)
765         {
766           sym->aop = op->aop = aop =
767             aopForRemat (sym);
768           aop->size = getSize (sym->type);
769           return;
770         }
771
772       if (sym->accuse)
773         {
774           int i;
775           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
776           aop->size = getSize (sym->type);
777           for (i = 0; i < 2; i++)
778             aop->aopu.aop_str[i] = accUse[i];
779           return;
780         }
781
782       if (sym->ruonly)
783         {
784           unsigned i;
785
786           aop = op->aop = sym->aop = newAsmop (AOP_STR);
787           aop->size = getSize (sym->type);
788           for (i = 0; i < fReturnSizeMCS51; i++)
789             aop->aopu.aop_str[i] = fReturn[i];
790           return;
791         }
792
793       if (sym->usl.spillLoc)
794         {
795           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
796             {
797               /* force a new aop if sizes differ */
798               sym->usl.spillLoc->aop = NULL;
799             }
800           sym->aop = op->aop = aop =
801                      aopForSym (ic, sym->usl.spillLoc, result);
802           aop->size = getSize (sym->type);
803           return;
804         }
805
806       /* else must be a dummy iTemp */
807       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
808       aop->size = getSize (sym->type);
809       return;
810     }
811
812   /* must be in a register */
813   sym->aop = op->aop = aop = newAsmop (AOP_REG);
814   aop->size = sym->nRegs;
815   for (i = 0; i < sym->nRegs; i++)
816     aop->aopu.aop_reg[i] = sym->regs[i];
817 }
818
819 /*-----------------------------------------------------------------*/
820 /* freeAsmop - free up the asmop given to an operand               */
821 /*----------------------------------------------------------------*/
822 static void
823 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
824 {
825   asmop *aop;
826
827   if (!op)
828     aop = aaop;
829   else
830     aop = op->aop;
831
832   if (!aop)
833     return;
834
835   if (aop->freed)
836     goto dealloc;
837
838   aop->freed = 1;
839
840   /* depending on the asmop type only three cases need work AOP_RO
841      , AOP_R1 && AOP_STK */
842   switch (aop->type)
843     {
844     case AOP_R0:
845       if (_G.r0InB)
846         {
847           emitcode ("mov", "r0,b");
848           _G.r0InB--;
849         }
850       else if (_G.r0Pushed)
851         {
852           if (pop)
853             {
854               emitcode ("pop", "ar0");
855               _G.r0Pushed--;
856             }
857         }
858       bitVectUnSetBit (ic->rUsed, R0_IDX);
859       break;
860
861     case AOP_R1:
862       if (_G.r1InB)
863         {
864           emitcode ("mov", "r1,b");
865           _G.r1InB--;
866         }
867       if (_G.r1Pushed)
868         {
869           if (pop)
870             {
871               emitcode ("pop", "ar1");
872               _G.r1Pushed--;
873             }
874         }
875       bitVectUnSetBit (ic->rUsed, R1_IDX);
876       break;
877
878     case AOP_STK:
879       {
880         int sz = aop->size;
881         int stk = aop->aopu.aop_stk + aop->size - 1;
882         bitVectUnSetBit (ic->rUsed, R0_IDX);
883         bitVectUnSetBit (ic->rUsed, R1_IDX);
884
885         getFreePtr (ic, &aop, FALSE);
886
887         if (stk)
888           {
889             emitcode ("mov", "a,_bp");
890             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
891             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
892           }
893         else
894           {
895             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
896           }
897
898         while (sz--)
899           {
900             emitcode ("pop", "acc");
901             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
902             if (!sz)
903               break;
904             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
905           }
906         op->aop = aop;
907         freeAsmop (op, NULL, ic, TRUE);
908         if (_G.r1Pushed)
909           {
910             emitcode ("pop", "ar1");
911             _G.r1Pushed--;
912           }
913
914         if (_G.r0Pushed)
915           {
916             emitcode ("pop", "ar0");
917             _G.r0Pushed--;
918           }
919       }
920     }
921
922 dealloc:
923   /* all other cases just dealloc */
924   if (op)
925     {
926       op->aop = NULL;
927       if (IS_SYMOP (op))
928         {
929           OP_SYMBOL (op)->aop = NULL;
930           /* if the symbol has a spill */
931           if (SPIL_LOC (op))
932             SPIL_LOC (op)->aop = NULL;
933         }
934     }
935 }
936
937 /*------------------------------------------------------------------*/
938 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
939 /*                      pop r0 or r1 off stack if pushed            */
940 /*------------------------------------------------------------------*/
941 static void
942 freeForBranchAsmop (operand * op)
943 {
944   asmop *aop;
945
946   if (!op)
947     return;
948
949   aop = op->aop;
950
951   if (!aop)
952     return;
953
954   if (aop->freed)
955     return;
956
957   switch (aop->type)
958     {
959     case AOP_R0:
960       if (_G.r0InB)
961         {
962           emitcode ("mov", "r0,b");
963         }
964       else if (_G.r0Pushed)
965         {
966           emitcode ("pop", "ar0");
967         }
968       break;
969
970     case AOP_R1:
971       if (_G.r1InB)
972         {
973           emitcode ("mov", "r1,b");
974         }
975       else if (_G.r1Pushed)
976         {
977           emitcode ("pop", "ar1");
978         }
979       break;
980
981     case AOP_STK:
982       {
983         int sz = aop->size;
984         int stk = aop->aopu.aop_stk + aop->size - 1;
985
986         emitcode ("mov", "b,r0");
987         if (stk)
988           {
989             emitcode ("mov", "a,_bp");
990             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
991             emitcode ("mov", "r0,a");
992           }
993         else
994           {
995             emitcode ("mov", "r0,_bp");
996           }
997
998         while (sz--)
999           {
1000             emitcode ("pop", "acc");
1001             emitcode ("mov", "@r0,a");
1002             if (!sz)
1003               break;
1004             emitcode ("dec", "r0");
1005           }
1006         emitcode ("mov", "r0,b");
1007       }
1008     }
1009
1010 }
1011
1012 /*-----------------------------------------------------------------*/
1013 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1014 /*                 clobber the accumulator                         */
1015 /*-----------------------------------------------------------------*/
1016 static bool
1017 aopGetUsesAcc (asmop *aop, int offset)
1018 {
1019   if (offset > (aop->size - 1))
1020     return FALSE;
1021
1022   switch (aop->type)
1023     {
1024
1025     case AOP_R0:
1026     case AOP_R1:
1027       if (aop->paged)
1028         return TRUE;
1029       return FALSE;
1030     case AOP_DPTR:
1031       return TRUE;
1032     case AOP_IMMD:
1033       return FALSE;
1034     case AOP_DIR:
1035       return FALSE;
1036     case AOP_REG:
1037       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1038       return FALSE;
1039     case AOP_CRY:
1040       return TRUE;
1041     case AOP_ACC:
1042       return TRUE;
1043     case AOP_LIT:
1044       return FALSE;
1045     case AOP_STR:
1046       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1047         return TRUE;
1048       return FALSE;
1049     case AOP_DUMMY:
1050       return FALSE;
1051     default:
1052       /* Error case --- will have been caught already */
1053       wassert(0);
1054       return FALSE;
1055     }
1056 }
1057
1058 /*-----------------------------------------------------------------*/
1059 /* aopGet - for fetching value of the aop                          */
1060 /*-----------------------------------------------------------------*/
1061 static char *
1062 aopGet (asmop * aop, int offset, bool bit16, bool dname)
1063 {
1064   char *s = buffer;
1065   char *rs;
1066
1067   /* offset is greater than
1068      size then zero */
1069   if (offset > (aop->size - 1) &&
1070       aop->type != AOP_LIT)
1071     return zero;
1072
1073   /* depending on type */
1074   switch (aop->type)
1075     {
1076     case AOP_DUMMY:
1077       return zero;
1078
1079     case AOP_R0:
1080     case AOP_R1:
1081       /* if we need to increment it */
1082       while (offset > aop->coff)
1083         {
1084           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1085           aop->coff++;
1086         }
1087
1088       while (offset < aop->coff)
1089         {
1090           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1091           aop->coff--;
1092         }
1093
1094       aop->coff = offset;
1095       if (aop->paged)
1096         {
1097           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1098           return (dname ? "acc" : "a");
1099         }
1100       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1101       rs = Safe_calloc (1, strlen (s) + 1);
1102       strcpy (rs, s);
1103       return rs;
1104
1105     case AOP_DPTR:
1106       if (aop->code && aop->coff==0 && offset>=1) {
1107         emitcode ("mov", "a,#0x%02x", offset);
1108         emitcode ("movc", "a,@a+dptr");
1109         return (dname ? "acc" : "a");
1110       }
1111
1112       while (offset > aop->coff)
1113         {
1114           emitcode ("inc", "dptr");
1115           aop->coff++;
1116         }
1117
1118       while (offset < aop->coff)
1119         {
1120           emitcode ("lcall", "__decdptr");
1121           aop->coff--;
1122         }
1123
1124       aop->coff = offset;
1125       if (aop->code)
1126         {
1127           emitcode ("clr", "a");
1128           emitcode ("movc", "a,@a+dptr");
1129         }
1130       else
1131         {
1132           emitcode ("movx", "a,@dptr");
1133         }
1134       return (dname ? "acc" : "a");
1135
1136
1137     case AOP_IMMD:
1138       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1139               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1140       } else if (bit16)
1141         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1142       else if (offset)
1143         sprintf (s, "#(%s >> %d)",
1144                  aop->aopu.aop_immd.aop_immd1,
1145                  offset * 8);
1146       else
1147         sprintf (s, "#%s",
1148                  aop->aopu.aop_immd.aop_immd1);
1149       rs = Safe_calloc (1, strlen (s) + 1);
1150       strcpy (rs, s);
1151       return rs;
1152
1153     case AOP_DIR:
1154       if (offset)
1155         sprintf (s, "(%s + %d)",
1156                  aop->aopu.aop_dir,
1157                  offset);
1158       else
1159         sprintf (s, "%s", aop->aopu.aop_dir);
1160       rs = Safe_calloc (1, strlen (s) + 1);
1161       strcpy (rs, s);
1162       return rs;
1163
1164     case AOP_REG:
1165       if (dname)
1166         return aop->aopu.aop_reg[offset]->dname;
1167       else
1168         return aop->aopu.aop_reg[offset]->name;
1169
1170     case AOP_CRY:
1171       emitcode ("clr", "a");
1172       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1173       emitcode ("rlc", "a");
1174       return (dname ? "acc" : "a");
1175
1176     case AOP_ACC:
1177       if (!offset && dname)
1178         return "acc";
1179       return aop->aopu.aop_str[offset];
1180
1181     case AOP_LIT:
1182       return aopLiteral (aop->aopu.aop_lit, offset);
1183
1184     case AOP_STR:
1185       aop->coff = offset;
1186       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1187           dname)
1188         return "acc";
1189
1190       return aop->aopu.aop_str[offset];
1191
1192     }
1193
1194   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1195           "aopget got unsupported aop->type");
1196   exit (1);
1197 }
1198 /*-----------------------------------------------------------------*/
1199 /* aopPut - puts a string for a aop                                */
1200 /*-----------------------------------------------------------------*/
1201 static void
1202 aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
1203 {
1204   char *d = buffer;
1205
1206   if (aop->size && offset > (aop->size - 1))
1207     {
1208       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1209               "aopPut got offset > aop->size");
1210       exit (1);
1211     }
1212
1213   /* will assign value to value */
1214   /* depending on where it is ofcourse */
1215   switch (aop->type)
1216     {
1217     case AOP_DUMMY:
1218       MOVA (s);         /* read s in case it was volatile */
1219       break;
1220
1221     case AOP_DIR:
1222       if (offset)
1223         sprintf (d, "(%s + %d)",
1224                  aop->aopu.aop_dir, offset);
1225       else
1226         sprintf (d, "%s", aop->aopu.aop_dir);
1227
1228       if (strcmp (d, s) ||
1229           bvolatile)
1230         emitcode ("mov", "%s,%s", d, s);
1231
1232       break;
1233
1234     case AOP_REG:
1235       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1236           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1237         {
1238           if (*s == '@' ||
1239               strcmp (s, "r0") == 0 ||
1240               strcmp (s, "r1") == 0 ||
1241               strcmp (s, "r2") == 0 ||
1242               strcmp (s, "r3") == 0 ||
1243               strcmp (s, "r4") == 0 ||
1244               strcmp (s, "r5") == 0 ||
1245               strcmp (s, "r6") == 0 ||
1246               strcmp (s, "r7") == 0)
1247             emitcode ("mov", "%s,%s",
1248                       aop->aopu.aop_reg[offset]->dname, s);
1249           else
1250             emitcode ("mov", "%s,%s",
1251                       aop->aopu.aop_reg[offset]->name, s);
1252         }
1253       break;
1254
1255     case AOP_DPTR:
1256       if (aop->code)
1257         {
1258           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1259                   "aopPut writing to code space");
1260           exit (1);
1261         }
1262
1263       while (offset > aop->coff)
1264         {
1265           aop->coff++;
1266           emitcode ("inc", "dptr");
1267         }
1268
1269       while (offset < aop->coff)
1270         {
1271           aop->coff--;
1272           emitcode ("lcall", "__decdptr");
1273         }
1274
1275       aop->coff = offset;
1276
1277       /* if not in accumulater */
1278       MOVA (s);
1279
1280       emitcode ("movx", "@dptr,a");
1281       break;
1282
1283     case AOP_R0:
1284     case AOP_R1:
1285       while (offset > aop->coff)
1286         {
1287           aop->coff++;
1288           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1289         }
1290       while (offset < aop->coff)
1291         {
1292           aop->coff--;
1293           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1294         }
1295       aop->coff = offset;
1296
1297       if (aop->paged)
1298         {
1299           MOVA (s);
1300           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1301
1302         }
1303       else if (*s == '@')
1304         {
1305           MOVA (s);
1306           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1307         }
1308       else if (strcmp (s, "r0") == 0 ||
1309                strcmp (s, "r1") == 0 ||
1310                strcmp (s, "r2") == 0 ||
1311                strcmp (s, "r3") == 0 ||
1312                strcmp (s, "r4") == 0 ||
1313                strcmp (s, "r5") == 0 ||
1314                strcmp (s, "r6") == 0 ||
1315                strcmp (s, "r7") == 0)
1316         {
1317           char buffer[10];
1318           sprintf (buffer, "a%s", s);
1319           emitcode ("mov", "@%s,%s",
1320                     aop->aopu.aop_ptr->name, buffer);
1321         }
1322       else
1323         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1324
1325       break;
1326
1327     case AOP_STK:
1328       if (strcmp (s, "a") == 0)
1329         emitcode ("push", "acc");
1330       else
1331         if (*s=='@') {
1332           MOVA(s);
1333           emitcode ("push", "acc");
1334         } else {
1335           emitcode ("push", s);
1336         }
1337
1338       break;
1339
1340     case AOP_CRY:
1341       /* if bit variable */
1342       if (!aop->aopu.aop_dir)
1343         {
1344           emitcode ("clr", "a");
1345           emitcode ("rlc", "a");
1346         }
1347       else
1348         {
1349           if (s == zero)
1350             emitcode ("clr", "%s", aop->aopu.aop_dir);
1351           else if (s == one)
1352             emitcode ("setb", "%s", aop->aopu.aop_dir);
1353           else if (!strcmp (s, "c"))
1354             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1355           else
1356             {
1357               if (strcmp (s, "a"))
1358                 {
1359                   MOVA (s);
1360                 }
1361               {
1362                 /* set C, if a >= 1 */
1363                 emitcode ("add", "a,#0xff");
1364                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1365               }
1366             }
1367         }
1368       break;
1369
1370     case AOP_STR:
1371       aop->coff = offset;
1372       if (strcmp (aop->aopu.aop_str[offset], s) ||
1373           bvolatile)
1374         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1375       break;
1376
1377     case AOP_ACC:
1378       aop->coff = offset;
1379       if (!offset && (strcmp (s, "acc") == 0) &&
1380           !bvolatile)
1381         break;
1382
1383       if (strcmp (aop->aopu.aop_str[offset], s) &&
1384           !bvolatile)
1385         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1386       break;
1387
1388     default:
1389       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1390               "aopPut got unsupported aop->type");
1391       exit (1);
1392     }
1393
1394 }
1395
1396
1397 #if 0
1398 /*-----------------------------------------------------------------*/
1399 /* pointToEnd :- points to the last byte of the operand            */
1400 /*-----------------------------------------------------------------*/
1401 static void
1402 pointToEnd (asmop * aop)
1403 {
1404   int count;
1405   if (!aop)
1406     return;
1407
1408   aop->coff = count = (aop->size - 1);
1409   switch (aop->type)
1410     {
1411     case AOP_R0:
1412     case AOP_R1:
1413       while (count--)
1414         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1415       break;
1416     case AOP_DPTR:
1417       while (count--)
1418         emitcode ("inc", "dptr");
1419       break;
1420     }
1421
1422 }
1423 #endif
1424
1425 /*-----------------------------------------------------------------*/
1426 /* reAdjustPreg - points a register back to where it should        */
1427 /*-----------------------------------------------------------------*/
1428 static void
1429 reAdjustPreg (asmop * aop)
1430 {
1431   if ((aop->coff==0) || aop->size <= 1)
1432     return;
1433
1434   switch (aop->type)
1435     {
1436     case AOP_R0:
1437     case AOP_R1:
1438       while (aop->coff--)
1439         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1440       break;
1441     case AOP_DPTR:
1442       while (aop->coff--)
1443         {
1444           emitcode ("lcall", "__decdptr");
1445         }
1446       break;
1447     }
1448   aop->coff = 0;
1449 }
1450
1451 #define AOP(op) op->aop
1452 #define AOP_TYPE(op) AOP(op)->type
1453 #define AOP_SIZE(op) AOP(op)->size
1454 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1455                        AOP_TYPE(x) == AOP_R0))
1456
1457 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1458                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
1459
1460 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1461                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
1462                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
1463
1464
1465 /*-----------------------------------------------------------------*/
1466 /* opIsGptr: returns non-zero if the passed operand is       */
1467 /* a generic pointer type.             */
1468 /*-----------------------------------------------------------------*/
1469 static int
1470 opIsGptr (operand * op)
1471 {
1472   sym_link *type = operandType (op);
1473
1474   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1475     {
1476       return 1;
1477     }
1478   return 0;
1479 }
1480
1481 /*-----------------------------------------------------------------*/
1482 /* getDataSize - get the operand data size                         */
1483 /*-----------------------------------------------------------------*/
1484 static int
1485 getDataSize (operand * op)
1486 {
1487   int size;
1488   size = AOP_SIZE (op);
1489   if (size == GPTRSIZE)
1490     {
1491       sym_link *type = operandType (op);
1492       if (IS_GENPTR (type))
1493         {
1494           /* generic pointer; arithmetic operations
1495            * should ignore the high byte (pointer type).
1496            */
1497           size--;
1498         }
1499     }
1500   return size;
1501 }
1502
1503 /*-----------------------------------------------------------------*/
1504 /* outAcc - output Acc                                             */
1505 /*-----------------------------------------------------------------*/
1506 static void
1507 outAcc (operand * result)
1508 {
1509   int size, offset;
1510   size = getDataSize (result);
1511   if (size)
1512     {
1513       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
1514       size--;
1515       offset = 1;
1516       /* unsigned or positive */
1517       while (size--)
1518         {
1519           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
1520         }
1521     }
1522 }
1523
1524 /*-----------------------------------------------------------------*/
1525 /* outBitC - output a bit C                                        */
1526 /*-----------------------------------------------------------------*/
1527 static void
1528 outBitC (operand * result)
1529 {
1530   /* if the result is bit */
1531   if (AOP_TYPE (result) == AOP_CRY)
1532     aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
1533   else
1534     {
1535       emitcode ("clr", "a");
1536       emitcode ("rlc", "a");
1537       outAcc (result);
1538     }
1539 }
1540
1541 /*-----------------------------------------------------------------*/
1542 /* toBoolean - emit code for orl a,operator(sizeop)                */
1543 /*-----------------------------------------------------------------*/
1544 static void
1545 toBoolean (operand * oper)
1546 {
1547   int size = AOP_SIZE (oper) - 1;
1548   int offset = 1;
1549   MOVA (aopGet (AOP (oper), 0, FALSE, FALSE));
1550   while (size--)
1551     emitcode ("orl", "a,%s", aopGet (AOP (oper), offset++, FALSE, FALSE));
1552 }
1553
1554
1555 /*-----------------------------------------------------------------*/
1556 /* genNot - generate code for ! operation                          */
1557 /*-----------------------------------------------------------------*/
1558 static void
1559 genNot (iCode * ic)
1560 {
1561   symbol *tlbl;
1562
1563   D(emitcode (";     genNot",""));
1564
1565   /* assign asmOps to operand & result */
1566   aopOp (IC_LEFT (ic), ic, FALSE);
1567   aopOp (IC_RESULT (ic), ic, TRUE);
1568
1569   /* if in bit space then a special case */
1570   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1571     {
1572       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1573       emitcode ("cpl", "c");
1574       outBitC (IC_RESULT (ic));
1575       goto release;
1576     }
1577
1578   toBoolean (IC_LEFT (ic));
1579
1580   tlbl = newiTempLabel (NULL);
1581   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1582   emitcode ("", "%05d$:", tlbl->key + 100);
1583   outBitC (IC_RESULT (ic));
1584
1585 release:
1586   /* release the aops */
1587   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1588   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1589 }
1590
1591
1592 /*-----------------------------------------------------------------*/
1593 /* genCpl - generate code for complement                           */
1594 /*-----------------------------------------------------------------*/
1595 static void
1596 genCpl (iCode * ic)
1597 {
1598   int offset = 0;
1599   int size;
1600   symbol *tlbl;
1601
1602   D(emitcode (";     genCpl",""));
1603
1604   /* assign asmOps to operand & result */
1605   aopOp (IC_LEFT (ic), ic, FALSE);
1606   aopOp (IC_RESULT (ic), ic, TRUE);
1607
1608   /* special case if in bit space */
1609   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1610     {
1611       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1612         {
1613           /* promotion rules are responsible for this strange result: */
1614           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1615           goto release;
1616         }
1617
1618       tlbl=newiTempLabel(NULL);
1619       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC ||
1620           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1621           IS_AOP_PREG (IC_LEFT (ic)))
1622         {
1623           emitcode ("cjne", "%s,#0x01,%05d$",
1624                     aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE),
1625                     tlbl->key + 100);
1626         }
1627       else
1628         {
1629           char *l = aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE);
1630           MOVA (l);
1631           emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1632         }
1633       emitcode ("", "%05d$:", tlbl->key + 100);
1634       outBitC (IC_RESULT(ic));
1635       goto release;
1636     }
1637
1638   size = AOP_SIZE (IC_RESULT (ic));
1639   while (size--)
1640     {
1641       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1642       MOVA (l);
1643       emitcode ("cpl", "a");
1644       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1645     }
1646
1647
1648 release:
1649   /* release the aops */
1650   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1651   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1652 }
1653
1654 /*-----------------------------------------------------------------*/
1655 /* genUminusFloat - unary minus for floating points                */
1656 /*-----------------------------------------------------------------*/
1657 static void
1658 genUminusFloat (operand * op, operand * result)
1659 {
1660   int size, offset = 0;
1661   char *l;
1662
1663   D(emitcode (";     genUminusFloat",""));
1664
1665   /* for this we just copy and then flip the bit */
1666
1667   size = AOP_SIZE (op) - 1;
1668
1669   while (size--)
1670     {
1671       aopPut (AOP (result),
1672               aopGet (AOP (op), offset, FALSE, FALSE),
1673               offset,
1674               isOperandVolatile (result, FALSE));
1675       offset++;
1676     }
1677
1678   l = aopGet (AOP (op), offset, FALSE, FALSE);
1679
1680   MOVA (l);
1681
1682   emitcode ("cpl", "acc.7");
1683   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
1684 }
1685
1686 /*-----------------------------------------------------------------*/
1687 /* genUminus - unary minus code generation                         */
1688 /*-----------------------------------------------------------------*/
1689 static void
1690 genUminus (iCode * ic)
1691 {
1692   int offset, size;
1693   sym_link *optype, *rtype;
1694
1695
1696   D(emitcode (";     genUminus",""));
1697
1698   /* assign asmops */
1699   aopOp (IC_LEFT (ic), ic, FALSE);
1700   aopOp (IC_RESULT (ic), ic, TRUE);
1701
1702   /* if both in bit space then special
1703      case */
1704   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1705       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1706     {
1707
1708       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1709       emitcode ("cpl", "c");
1710       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1711       goto release;
1712     }
1713
1714   optype = operandType (IC_LEFT (ic));
1715   rtype = operandType (IC_RESULT (ic));
1716
1717   /* if float then do float stuff */
1718   if (IS_FLOAT (optype))
1719     {
1720       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1721       goto release;
1722     }
1723
1724   /* otherwise subtract from zero */
1725   size = AOP_SIZE (IC_LEFT (ic));
1726   offset = 0;
1727   //CLRC ;
1728   while (size--)
1729     {
1730       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1731       if (!strcmp (l, "a"))
1732         {
1733           if (offset == 0)
1734             SETC;
1735           emitcode ("cpl", "a");
1736           emitcode ("addc", "a,#0");
1737         }
1738       else
1739         {
1740           if (offset == 0)
1741             CLRC;
1742           emitcode ("clr", "a");
1743           emitcode ("subb", "a,%s", l);
1744         }
1745       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1746     }
1747
1748   /* if any remaining bytes in the result */
1749   /* we just need to propagate the sign   */
1750   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1751     {
1752       emitcode ("rlc", "a");
1753       emitcode ("subb", "a,acc");
1754       while (size--)
1755         aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1756     }
1757
1758 release:
1759   /* release the aops */
1760   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1761   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1762 }
1763
1764 /*-----------------------------------------------------------------*/
1765 /* saveRegisters - will look for a call and save the registers     */
1766 /*-----------------------------------------------------------------*/
1767 static void
1768 saveRegisters (iCode * lic)
1769 {
1770   int i;
1771   iCode *ic;
1772   bitVect *rsave;
1773
1774   /* look for call */
1775   for (ic = lic; ic; ic = ic->next)
1776     if (ic->op == CALL || ic->op == PCALL)
1777       break;
1778
1779   if (!ic)
1780     {
1781       fprintf (stderr, "found parameter push with no function call\n");
1782       return;
1783     }
1784
1785   /* if the registers have been saved already or don't need to be then
1786      do nothing */
1787   if (ic->regsSaved)
1788     return;
1789   if (IS_SYMOP(IC_LEFT(ic)) &&
1790       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1791        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1792     return;
1793
1794   /* safe the registers in use at this time but skip the
1795      ones for the result */
1796   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1797                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1798
1799   ic->regsSaved = 1;
1800   if (options.useXstack)
1801     {
1802       if (bitVectBitValue (rsave, R0_IDX))
1803         emitcode ("mov", "b,r0");
1804       emitcode ("mov", "r0,%s", spname);
1805       for (i = 0; i < mcs51_nRegs; i++)
1806         {
1807           if (bitVectBitValue (rsave, i))
1808             {
1809               if (i == R0_IDX)
1810                 emitcode ("mov", "a,b");
1811               else
1812                 emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1813               emitcode ("movx", "@r0,a");
1814               emitcode ("inc", "r0");
1815             }
1816         }
1817       emitcode ("mov", "%s,r0", spname);
1818       if (bitVectBitValue (rsave, R0_IDX))
1819         emitcode ("mov", "r0,b");
1820     }
1821   else
1822     for (i = 0; i < mcs51_nRegs; i++)
1823       {
1824         if (bitVectBitValue (rsave, i))
1825           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1826       }
1827 }
1828
1829 /*-----------------------------------------------------------------*/
1830 /* unsaveRegisters - pop the pushed registers                      */
1831 /*-----------------------------------------------------------------*/
1832 static void
1833 unsaveRegisters (iCode * ic)
1834 {
1835   int i;
1836   bitVect *rsave;
1837
1838   /* restore the registers in use at this time but skip the
1839      ones for the result */
1840   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1841                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1842
1843   if (options.useXstack)
1844     {
1845       emitcode ("mov", "r0,%s", spname);
1846       for (i = mcs51_nRegs; i >= 0; i--)
1847         {
1848           if (bitVectBitValue (rsave, i))
1849             {
1850               emitcode ("dec", "r0");
1851               emitcode ("movx", "a,@r0");
1852               if (i == R0_IDX)
1853                 emitcode ("mov", "b,a");
1854               else
1855                 emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1856             }
1857
1858         }
1859       emitcode ("mov", "%s,r0", spname);
1860       if (bitVectBitValue (rsave, R0_IDX))
1861         emitcode ("mov", "r0,b");
1862     }
1863   else
1864     for (i = mcs51_nRegs; i >= 0; i--)
1865       {
1866         if (bitVectBitValue (rsave, i))
1867           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
1868       }
1869
1870 }
1871
1872
1873 /*-----------------------------------------------------------------*/
1874 /* pushSide -                */
1875 /*-----------------------------------------------------------------*/
1876 static void
1877 pushSide (operand * oper, int size)
1878 {
1879   int offset = 0;
1880   while (size--)
1881     {
1882       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE);
1883       if (AOP_TYPE (oper) != AOP_REG &&
1884           AOP_TYPE (oper) != AOP_DIR &&
1885           strcmp (l, "a"))
1886         {
1887           MOVA (l);
1888           emitcode ("push", "acc");
1889         }
1890       else
1891         emitcode ("push", "%s", l);
1892     }
1893 }
1894
1895 /*-----------------------------------------------------------------*/
1896 /* assignResultValue -               */
1897 /*-----------------------------------------------------------------*/
1898 static void
1899 assignResultValue (operand * oper)
1900 {
1901   int offset = 0;
1902   int size = AOP_SIZE (oper);
1903   while (size--)
1904     {
1905       aopPut (AOP (oper), fReturn[offset], offset, isOperandVolatile (oper, FALSE));
1906       offset++;
1907     }
1908 }
1909
1910
1911 /*-----------------------------------------------------------------*/
1912 /* genXpush - pushes onto the external stack                       */
1913 /*-----------------------------------------------------------------*/
1914 static void
1915 genXpush (iCode * ic)
1916 {
1917   asmop *aop = newAsmop (0);
1918   regs *r;
1919   int size, offset = 0;
1920
1921   D(emitcode (";     genXpush",""));
1922
1923   aopOp (IC_LEFT (ic), ic, FALSE);
1924   r = getFreePtr (ic, &aop, FALSE);
1925
1926
1927   emitcode ("mov", "%s,_spx", r->name);
1928
1929   size = AOP_SIZE (IC_LEFT (ic));
1930   while (size--)
1931     {
1932
1933       char *l = aopGet (AOP (IC_LEFT (ic)),
1934                         offset++, FALSE, FALSE);
1935       MOVA (l);
1936       emitcode ("movx", "@%s,a", r->name);
1937       emitcode ("inc", "%s", r->name);
1938
1939     }
1940
1941
1942   emitcode ("mov", "_spx,%s", r->name);
1943
1944   freeAsmop (NULL, aop, ic, TRUE);
1945   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
1946 }
1947
1948 /*-----------------------------------------------------------------*/
1949 /* genIpush - genrate code for pushing this gets a little complex  */
1950 /*-----------------------------------------------------------------*/
1951 static void
1952 genIpush (iCode * ic)
1953 {
1954   int size, offset = 0;
1955   char *l;
1956
1957   D(emitcode (";     genIpush",""));
1958
1959   /* if this is not a parm push : ie. it is spill push
1960      and spill push is always done on the local stack */
1961   if (!ic->parmPush)
1962     {
1963
1964       /* and the item is spilt then do nothing */
1965       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
1966         return;
1967
1968       aopOp (IC_LEFT (ic), ic, FALSE);
1969       size = AOP_SIZE (IC_LEFT (ic));
1970       /* push it on the stack */
1971       while (size--)
1972         {
1973           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
1974           if (*l == '#')
1975             {
1976               MOVA (l);
1977               l = "acc";
1978             }
1979           emitcode ("push", "%s", l);
1980         }
1981       return;
1982     }
1983
1984   /* this is a paramter push: in this case we call
1985      the routine to find the call and save those
1986      registers that need to be saved */
1987   saveRegisters (ic);
1988
1989   /* if use external stack then call the external
1990      stack pushing routine */
1991   if (options.useXstack)
1992     {
1993       genXpush (ic);
1994       return;
1995     }
1996
1997   /* then do the push */
1998   aopOp (IC_LEFT (ic), ic, FALSE);
1999
2000
2001   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2002   size = AOP_SIZE (IC_LEFT (ic));
2003
2004   while (size--)
2005     {
2006       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2007       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2008           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2009           strcmp (l, "a"))
2010         {
2011           MOVA (l);
2012           emitcode ("push", "acc");
2013         }
2014       else
2015         emitcode ("push", "%s", l);
2016     }
2017
2018   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2019 }
2020
2021 /*-----------------------------------------------------------------*/
2022 /* genIpop - recover the registers: can happen only for spilling   */
2023 /*-----------------------------------------------------------------*/
2024 static void
2025 genIpop (iCode * ic)
2026 {
2027   int size, offset;
2028
2029   D(emitcode (";     genIpop",""));
2030
2031   /* if the temp was not pushed then */
2032   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2033     return;
2034
2035   aopOp (IC_LEFT (ic), ic, FALSE);
2036   size = AOP_SIZE (IC_LEFT (ic));
2037   offset = (size - 1);
2038   while (size--)
2039     emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2040                                    FALSE, TRUE));
2041
2042   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2043 }
2044
2045 /*-----------------------------------------------------------------*/
2046 /* unsaveRBank - restores the resgister bank from stack            */
2047 /*-----------------------------------------------------------------*/
2048 static void
2049 unsaveRBank (int bank, iCode * ic, bool popPsw)
2050 {
2051   int i;
2052   asmop *aop = NULL;
2053   regs *r = NULL;
2054
2055   if (options.useXstack)
2056   {
2057       if (!ic)
2058       {
2059           /* Assume r0 is available for use. */
2060           r = mcs51_regWithIdx (R0_IDX);;
2061       }
2062       else
2063       {
2064           aop = newAsmop (0);
2065           r = getFreePtr (ic, &aop, FALSE);
2066       }
2067       emitcode ("mov", "%s,_spx", r->name);
2068   }
2069
2070   if (popPsw)
2071     {
2072       if (options.useXstack)
2073       {
2074           emitcode ("movx", "a,@%s", r->name);
2075           emitcode ("mov", "psw,a");
2076           emitcode ("dec", "%s", r->name);
2077         }
2078       else
2079       {
2080         emitcode ("pop", "psw");
2081       }
2082     }
2083
2084   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2085     {
2086       if (options.useXstack)
2087         {
2088           emitcode ("movx", "a,@%s", r->name);
2089           emitcode ("mov", "(%s+%d),a",
2090                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2091           emitcode ("dec", "%s", r->name);
2092
2093         }
2094       else
2095         emitcode ("pop", "(%s+%d)",
2096                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2097     }
2098
2099   if (options.useXstack)
2100     {
2101       emitcode ("mov", "_spx,%s", r->name);
2102     }
2103
2104   if (aop)
2105   {
2106       freeAsmop (NULL, aop, ic, TRUE);
2107   }
2108 }
2109
2110 /*-----------------------------------------------------------------*/
2111 /* saveRBank - saves an entire register bank on the stack          */
2112 /*-----------------------------------------------------------------*/
2113 static void
2114 saveRBank (int bank, iCode * ic, bool pushPsw)
2115 {
2116   int i;
2117   asmop *aop = NULL;
2118   regs *r = NULL;
2119
2120   if (options.useXstack)
2121     {
2122       if (!ic)
2123       {
2124           /* Assume r0 is available for use. */
2125           r = mcs51_regWithIdx (R0_IDX);;
2126       }
2127       else
2128       {
2129           aop = newAsmop (0);
2130           r = getFreePtr (ic, &aop, FALSE);
2131       }
2132       emitcode ("mov", "%s,_spx", r->name);
2133     }
2134
2135   for (i = 0; i < mcs51_nRegs; i++)
2136     {
2137       if (options.useXstack)
2138         {
2139           emitcode ("inc", "%s", r->name);
2140           emitcode ("mov", "a,(%s+%d)",
2141                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2142           emitcode ("movx", "@%s,a", r->name);
2143         }
2144       else
2145         emitcode ("push", "(%s+%d)",
2146                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2147     }
2148
2149   if (pushPsw)
2150     {
2151       if (options.useXstack)
2152         {
2153           emitcode ("mov", "a,psw");
2154           emitcode ("movx", "@%s,a", r->name);
2155           emitcode ("inc", "%s", r->name);
2156           emitcode ("mov", "_spx,%s", r->name);
2157
2158         }
2159       else
2160       {
2161         emitcode ("push", "psw");
2162       }
2163
2164       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2165     }
2166
2167     if (aop)
2168     {
2169         freeAsmop (NULL, aop, ic, TRUE);
2170     }
2171
2172   if (ic)
2173   {
2174       ic->bankSaved = 1;
2175   }
2176 }
2177
2178 /*-----------------------------------------------------------------*/
2179 /* genSend - gen code for SEND                                     */
2180 /*-----------------------------------------------------------------*/
2181 static void genSend(set *sendSet)
2182 {
2183     iCode *sic;
2184     int rb1_count = 0 ;
2185
2186     for (sic = setFirstItem (sendSet); sic;
2187          sic = setNextItem (sendSet)) {
2188           int size, offset = 0;
2189           aopOp (IC_LEFT (sic), sic, FALSE);
2190           size = AOP_SIZE (IC_LEFT (sic));
2191
2192           if (sic->argreg == 1) {
2193               while (size--) {
2194                   char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2195                                     FALSE, FALSE);
2196                   if (strcmp (l, fReturn[offset]))
2197                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2198                   offset++;
2199               }
2200               rb1_count = 0;
2201           } else {
2202               while (size--) {
2203                   emitcode ("mov","b1_%d,%s",rb1_count++,
2204                             aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE));
2205               }
2206           }
2207           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2208     }
2209 }
2210
2211 /*-----------------------------------------------------------------*/
2212 /* genCall - generates a call statement                            */
2213 /*-----------------------------------------------------------------*/
2214 static void
2215 genCall (iCode * ic)
2216 {
2217   sym_link *dtype;
2218 //  bool restoreBank = FALSE;
2219   bool swapBanks = FALSE;
2220
2221   D(emitcode(";     genCall",""));
2222
2223   dtype = operandType (IC_LEFT (ic));
2224   /* if send set is not empty then assign */
2225   if (_G.sendSet)
2226     {
2227         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2228             genSend(reverseSet(_G.sendSet));
2229         } else {
2230             genSend(_G.sendSet);
2231         }
2232
2233       _G.sendSet = NULL;
2234     }
2235
2236   /* if we are calling a not _naked function that is not using
2237      the same register bank then we need to save the
2238      destination registers on the stack */
2239   dtype = operandType (IC_LEFT (ic));
2240   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2241       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2242        !IFFUNC_ISISR (dtype))
2243   {
2244       swapBanks = TRUE;
2245   }
2246
2247   /* if caller saves & we have not saved then */
2248   if (!ic->regsSaved)
2249       saveRegisters (ic);
2250
2251   if (swapBanks)
2252   {
2253         emitcode ("mov", "psw,#0x%02x",
2254            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2255   }
2256
2257   /* make the call */
2258   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2259                             OP_SYMBOL (IC_LEFT (ic))->rname :
2260                             OP_SYMBOL (IC_LEFT (ic))->name));
2261
2262   if (swapBanks)
2263   {
2264        emitcode ("mov", "psw,#0x%02x",
2265           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2266   }
2267
2268   /* if we need assign a result value */
2269   if ((IS_ITEMP (IC_RESULT (ic)) &&
2270        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2271         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2272         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2273       IS_TRUE_SYMOP (IC_RESULT (ic)))
2274     {
2275
2276       _G.accInUse++;
2277       aopOp (IC_RESULT (ic), ic, FALSE);
2278       _G.accInUse--;
2279
2280       assignResultValue (IC_RESULT (ic));
2281
2282       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2283     }
2284
2285   /* adjust the stack for parameters if
2286      required */
2287   if (ic->parmBytes)
2288     {
2289       int i;
2290       if (ic->parmBytes > 3)
2291         {
2292           emitcode ("mov", "a,%s", spname);
2293           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2294           emitcode ("mov", "%s,a", spname);
2295         }
2296       else
2297         for (i = 0; i < ic->parmBytes; i++)
2298           emitcode ("dec", "%s", spname);
2299     }
2300
2301   /* if we hade saved some registers then unsave them */
2302   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2303     unsaveRegisters (ic);
2304
2305 //  /* if register bank was saved then pop them */
2306 //  if (restoreBank)
2307 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2308 }
2309
2310 /*-----------------------------------------------------------------*/
2311 /* -10l - generates a call by pointer statement                */
2312 /*-----------------------------------------------------------------*/
2313 static void
2314 genPcall (iCode * ic)
2315 {
2316   sym_link *dtype;
2317   symbol *rlbl = newiTempLabel (NULL);
2318 //  bool restoreBank=FALSE;
2319   bool swapBanks = FALSE;
2320
2321   D(emitcode(";     genPCall",""));
2322
2323   /* if caller saves & we have not saved then */
2324   if (!ic->regsSaved)
2325     saveRegisters (ic);
2326
2327   /* if we are calling a not _naked function that is not using
2328      the same register bank then we need to save the
2329      destination registers on the stack */
2330   dtype = operandType (IC_LEFT (ic))->next;
2331   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2332       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2333       !IFFUNC_ISISR (dtype))
2334   {
2335 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2336 //    restoreBank=TRUE;
2337       swapBanks = TRUE;
2338       // need caution message to user here
2339   }
2340
2341   /* push the return address on to the stack */
2342   emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2343   emitcode ("push", "acc");
2344   emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2345   emitcode ("push", "acc");
2346
2347   /* now push the calling address */
2348   aopOp (IC_LEFT (ic), ic, FALSE);
2349
2350   pushSide (IC_LEFT (ic), FPTRSIZE);
2351
2352   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2353
2354   /* if send set is not empty the assign */
2355   if (_G.sendSet)
2356     {
2357         genSend(reverseSet(_G.sendSet));
2358         _G.sendSet = NULL;
2359     }
2360
2361   if (swapBanks)
2362   {
2363         emitcode ("mov", "psw,#0x%02x",
2364            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2365   }
2366
2367   /* make the call */
2368   emitcode ("ret", "");
2369   emitcode ("", "%05d$:", (rlbl->key + 100));
2370
2371
2372   if (swapBanks)
2373   {
2374        emitcode ("mov", "psw,#0x%02x",
2375           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2376   }
2377
2378   /* if we need assign a result value */
2379   if ((IS_ITEMP (IC_RESULT (ic)) &&
2380        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2381         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2382       IS_TRUE_SYMOP (IC_RESULT (ic)))
2383     {
2384
2385       _G.accInUse++;
2386       aopOp (IC_RESULT (ic), ic, FALSE);
2387       _G.accInUse--;
2388
2389       assignResultValue (IC_RESULT (ic));
2390
2391       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2392     }
2393
2394   /* adjust the stack for parameters if
2395      required */
2396   if (ic->parmBytes)
2397     {
2398       int i;
2399       if (ic->parmBytes > 3)
2400         {
2401           emitcode ("mov", "a,%s", spname);
2402           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2403           emitcode ("mov", "%s,a", spname);
2404         }
2405       else
2406         for (i = 0; i < ic->parmBytes; i++)
2407           emitcode ("dec", "%s", spname);
2408
2409     }
2410
2411 //  /* if register bank was saved then unsave them */
2412 //  if (restoreBank)
2413 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2414
2415   /* if we hade saved some registers then
2416      unsave them */
2417   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2418     unsaveRegisters (ic);
2419 }
2420
2421 /*-----------------------------------------------------------------*/
2422 /* resultRemat - result  is rematerializable                       */
2423 /*-----------------------------------------------------------------*/
2424 static int
2425 resultRemat (iCode * ic)
2426 {
2427   if (SKIP_IC (ic) || ic->op == IFX)
2428     return 0;
2429
2430   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2431     {
2432       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2433       if (sym->remat && !POINTER_SET (ic))
2434         return 1;
2435     }
2436
2437   return 0;
2438 }
2439
2440 #if defined(__BORLANDC__) || defined(_MSC_VER)
2441 #define STRCASECMP stricmp
2442 #else
2443 #define STRCASECMP strcasecmp
2444 #endif
2445
2446 /*-----------------------------------------------------------------*/
2447 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2448 /*-----------------------------------------------------------------*/
2449 static int
2450 regsCmp(void *p1, void *p2)
2451 {
2452   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2453 }
2454
2455 static bool
2456 inExcludeList (char *s)
2457 {
2458   const char *p = setFirstItem(options.excludeRegsSet);
2459
2460   if (p == NULL || STRCASECMP(p, "none") == 0)
2461     return FALSE;
2462
2463
2464   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2465 }
2466
2467 /*-----------------------------------------------------------------*/
2468 /* genFunction - generated code for function entry                 */
2469 /*-----------------------------------------------------------------*/
2470 static void
2471 genFunction (iCode * ic)
2472 {
2473   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2474   sym_link *ftype;
2475   bool   switchedPSW = FALSE;
2476   int calleesaves_saved_register = -1;
2477   int stackAdjust = sym->stack;
2478   int accIsFree = sym->recvSize < 4;
2479   iCode * ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2480
2481   _G.nRegsSaved = 0;
2482   /* create the function header */
2483   emitcode (";", "-----------------------------------------");
2484   emitcode (";", " function %s", sym->name);
2485   emitcode (";", "-----------------------------------------");
2486
2487   emitcode ("", "%s:", sym->rname);
2488   ftype = operandType (IC_LEFT (ic));
2489   _G.currentFunc = sym;
2490
2491   if (IFFUNC_ISNAKED(ftype))
2492   {
2493       emitcode(";", "naked function: no prologue.");
2494       return;
2495   }
2496
2497   /* here we need to generate the equates for the
2498      register bank if required */
2499   if (FUNC_REGBANK (ftype) != rbank)
2500     {
2501       int i;
2502
2503       rbank = FUNC_REGBANK (ftype);
2504       for (i = 0; i < mcs51_nRegs; i++)
2505         {
2506           if (strcmp (regs8051[i].base, "0") == 0)
2507             emitcode ("", "%s = 0x%02x",
2508                       regs8051[i].dname,
2509                       8 * rbank + regs8051[i].offset);
2510           else
2511             emitcode ("", "%s = %s + 0x%02x",
2512                       regs8051[i].dname,
2513                       regs8051[i].base,
2514                       8 * rbank + regs8051[i].offset);
2515         }
2516     }
2517
2518   /* if this is an interrupt service routine then
2519      save acc, b, dpl, dph  */
2520   if (IFFUNC_ISISR (sym->type))
2521     {
2522
2523       if (!inExcludeList ("acc"))
2524         emitcode ("push", "acc");
2525       if (!inExcludeList ("b"))
2526         emitcode ("push", "b");
2527       if (!inExcludeList ("dpl"))
2528         emitcode ("push", "dpl");
2529       if (!inExcludeList ("dph"))
2530         emitcode ("push", "dph");
2531       /* if this isr has no bank i.e. is going to
2532          run with bank 0 , then we need to save more
2533          registers :-) */
2534       if (!FUNC_REGBANK (sym->type))
2535         {
2536
2537           /* if this function does not call any other
2538              function then we can be economical and
2539              save only those registers that are used */
2540           if (!IFFUNC_HASFCALL(sym->type))
2541             {
2542               int i;
2543
2544               /* if any registers used */
2545               if (sym->regsUsed)
2546                 {
2547                   /* save the registers used */
2548                   for (i = 0; i < sym->regsUsed->size; i++)
2549                     {
2550                       if (bitVectBitValue (sym->regsUsed, i))
2551                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2552                     }
2553                 }
2554             }
2555           else
2556             {
2557
2558               /* this function has a function call. We cannot
2559                  determines register usage so we will have to push the
2560                  entire bank */
2561                 saveRBank (0, ic, FALSE);
2562                 if (options.parms_in_bank1) {
2563                     int i;
2564                     for (i=0; i < 8 ; i++ ) {
2565                         emitcode ("push","%s",rb1regs[i]);
2566                     }
2567                 }
2568             }
2569         }
2570         else
2571         {
2572             /* This ISR uses a non-zero bank.
2573              *
2574              * We assume that the bank is available for our
2575              * exclusive use.
2576              *
2577              * However, if this ISR calls a function which uses some
2578              * other bank, we must save that bank entirely.
2579              */
2580             unsigned long banksToSave = 0;
2581
2582             if (IFFUNC_HASFCALL(sym->type))
2583             {
2584
2585 #define MAX_REGISTER_BANKS 4
2586
2587                 iCode *i;
2588                 int ix;
2589
2590                 for (i = ic; i; i = i->next)
2591                 {
2592                     if (i->op == ENDFUNCTION)
2593                     {
2594                         /* we got to the end OK. */
2595                         break;
2596                     }
2597
2598                     if (i->op == CALL)
2599                     {
2600                         sym_link *dtype;
2601
2602                         dtype = operandType (IC_LEFT(i));
2603                         if (dtype
2604                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2605                         {
2606                              /* Mark this bank for saving. */
2607                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2608                              {
2609                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2610                              }
2611                              else
2612                              {
2613                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2614                              }
2615
2616                              /* And note that we don't need to do it in
2617                               * genCall.
2618                               */
2619                              i->bankSaved = 1;
2620                         }
2621                     }
2622                     if (i->op == PCALL)
2623                     {
2624                         /* This is a mess; we have no idea what
2625                          * register bank the called function might
2626                          * use.
2627                          *
2628                          * The only thing I can think of to do is
2629                          * throw a warning and hope.
2630                          */
2631                         werror(W_FUNCPTR_IN_USING_ISR);
2632                     }
2633                 }
2634
2635                 if (banksToSave && options.useXstack)
2636                 {
2637                     /* Since we aren't passing it an ic,
2638                      * saveRBank will assume r0 is available to abuse.
2639                      *
2640                      * So switch to our (trashable) bank now, so
2641                      * the caller's R0 isn't trashed.
2642                      */
2643                     emitcode ("push", "psw");
2644                     emitcode ("mov", "psw,#0x%02x",
2645                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2646                     switchedPSW = TRUE;
2647                 }
2648
2649                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2650                 {
2651                      if (banksToSave & (1 << ix))
2652                      {
2653                          saveRBank(ix, NULL, FALSE);
2654                      }
2655                 }
2656             }
2657             // TODO: this needs a closer look
2658             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2659         }
2660
2661       /* Set the register bank to the desired value if nothing else */
2662       /* has done so yet. */
2663       if (!switchedPSW)
2664         {
2665           emitcode ("push", "psw");
2666           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2667         }
2668     }
2669   else
2670     {
2671       /* This is a non-ISR function. The caller has already switched register */
2672       /* banks, if necessary, so just handle the callee-saves option. */
2673
2674       /* if callee-save to be used for this function
2675          then save the registers being used in this function */
2676       if (IFFUNC_CALLEESAVES(sym->type))
2677         {
2678           int i;
2679
2680           /* if any registers used */
2681           if (sym->regsUsed)
2682             {
2683               /* save the registers used */
2684               for (i = 0; i < sym->regsUsed->size; i++)
2685                 {
2686                   if (bitVectBitValue (sym->regsUsed, i))
2687                     {
2688                       /* remember one saved register for later usage */
2689                       if (calleesaves_saved_register < 0)
2690                         calleesaves_saved_register = i;
2691                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2692                       _G.nRegsSaved++;
2693                     }
2694                 }
2695             }
2696         }
2697     }
2698
2699
2700   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
2701     {
2702
2703       if (options.useXstack)
2704         {
2705           if (!accIsFree)
2706             emitcode ("push", "acc");
2707           emitcode ("mov", "r0,%s", spname);
2708           emitcode ("mov", "a,_bp");
2709           emitcode ("movx", "@r0,a");
2710           emitcode ("inc", "%s", spname);
2711           if (!accIsFree)
2712             emitcode ("pop", "acc");
2713         }
2714       else
2715         {
2716           /* set up the stack */
2717           emitcode ("push", "_bp");     /* save the callers stack  */
2718         }
2719       emitcode ("mov", "_bp,%s", spname);
2720     }
2721
2722   /* For some cases it is worthwhile to perform a RECEIVE iCode */
2723   /* before setting up the stack frame completely. */
2724   if (ric && ric->argreg == 1 && IC_RESULT (ric))
2725     {
2726       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
2727
2728       if (rsym->isitmp)
2729         {
2730           if (rsym && rsym->regType == REG_CND)
2731             rsym = NULL;
2732           if (rsym && (rsym->accuse || rsym->ruonly))
2733             rsym = NULL;
2734           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
2735             rsym = rsym->usl.spillLoc;
2736         }
2737
2738       /* If the RECEIVE operand immediately spills to the first entry on the */
2739       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
2740       /* rather than the usual @r0/r1 machinations. */
2741       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
2742         {
2743           int ofs;
2744
2745           _G.current_iCode = ric;
2746           D(emitcode (";     genReceive",""));
2747           for (ofs=0; ofs < sym->recvSize; ofs++)
2748             {
2749               if (!strcmp (fReturn[ofs], "a"))
2750                 emitcode ("push", "acc");
2751               else
2752                 emitcode ("push", fReturn[ofs]);
2753             }
2754           stackAdjust -= sym->recvSize;
2755           if (stackAdjust<0)
2756             {
2757               assert (stackAdjust>=0);
2758               stackAdjust = 0;
2759             }
2760           _G.current_iCode = ic;
2761           ric->generated = 1;
2762           accIsFree = 1;
2763         }
2764       /* If the RECEIVE operand is 4 registers, we can do the moves now */
2765       /* to free up the accumulator. */
2766       else if (rsym && rsym->nRegs && sym->recvSize == 4)
2767         {
2768           int ofs;
2769
2770           _G.current_iCode = ric;
2771           D(emitcode (";     genReceive",""));
2772           for (ofs=0; ofs < sym->recvSize; ofs++)
2773             {
2774               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
2775             }
2776           _G.current_iCode = ic;
2777           ric->generated = 1;
2778           accIsFree = 1;
2779         }
2780     }
2781
2782   /* adjust the stack for the function */
2783   if (stackAdjust)
2784     {
2785
2786       int i = stackAdjust;
2787       if (i > 256)
2788         werror (W_STACK_OVERFLOW, sym->name);
2789
2790       if (i > 3 && accIsFree)
2791         {
2792
2793           emitcode ("mov", "a,sp");
2794           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2795           emitcode ("mov", "sp,a");
2796
2797         }
2798       else if (i > 5)
2799         {
2800           /* The accumulator is not free, so we will need another register */
2801           /* to clobber. No need to worry about a possible conflict with */
2802           /* the above early RECEIVE optimizations since they would have */
2803           /* freed the accumulator if they were generated. */
2804
2805           if (IFFUNC_CALLEESAVES(sym->type))
2806             {
2807               /* if it's a callee-saves function we need a saved register */
2808               if (calleesaves_saved_register >= 0)
2809                 {
2810                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2811                   emitcode ("mov", "a,sp");
2812                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2813                   emitcode ("mov", "sp,a");
2814                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2815                 }
2816               else
2817                 /* do it the hard way */
2818                 while (i--)
2819                   emitcode ("inc", "sp");
2820             }
2821           else
2822             {
2823               /* not callee-saves, we can clobber r0 */
2824               emitcode ("mov", "r0,a");
2825               emitcode ("mov", "a,sp");
2826               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2827               emitcode ("mov", "sp,a");
2828               emitcode ("mov", "a,r0");
2829             }
2830         }
2831       else
2832         while (i--)
2833           emitcode ("inc", "sp");
2834     }
2835
2836   if (sym->xstack)
2837     {
2838
2839       if (!accIsFree)
2840         emitcode ("push", "acc");
2841       emitcode ("mov", "a,_spx");
2842       emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff));
2843       emitcode ("mov", "_spx,a");
2844       if (!accIsFree)
2845         emitcode ("pop", "acc");
2846     }
2847
2848   /* if critical function then turn interrupts off */
2849   if (IFFUNC_ISCRITICAL (ftype))
2850     {
2851       symbol *tlbl = newiTempLabel (NULL);
2852       emitcode ("setb", "c");
2853       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
2854       emitcode ("clr", "c");
2855       emitcode ("", "%05d$:", (tlbl->key + 100));
2856       emitcode ("push", "psw"); /* save old ea via c in psw */
2857     }
2858 }
2859
2860 /*-----------------------------------------------------------------*/
2861 /* genEndFunction - generates epilogue for functions               */
2862 /*-----------------------------------------------------------------*/
2863 static void
2864 genEndFunction (iCode * ic)
2865 {
2866   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2867   lineNode *lnp = lineCurr;
2868   bitVect *regsUsed;
2869   bitVect *regsUsedPrologue;
2870   bitVect *regsUnneeded;
2871   int idx;
2872
2873   _G.currentFunc = NULL;
2874   if (IFFUNC_ISNAKED(sym->type))
2875   {
2876       emitcode(";", "naked function: no epilogue.");
2877       if (options.debug && currFunc)
2878         debugFile->writeEndFunction (currFunc, ic, 0);
2879       return;
2880   }
2881
2882   if (IFFUNC_ISCRITICAL (sym->type))
2883     {
2884       emitcode ("pop", "psw"); /* restore ea via c in psw */
2885       emitcode ("mov", "ea,c");
2886     }
2887
2888   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
2889     {
2890       emitcode ("mov", "%s,_bp", spname);
2891     }
2892
2893   /* if use external stack but some variables were
2894      added to the local stack then decrement the
2895      local stack */
2896   if (options.useXstack && sym->stack)
2897     {
2898       emitcode ("mov", "a,sp");
2899       emitcode ("add", "a,#0x%02x", ((char) -sym->stack) & 0xff);
2900       emitcode ("mov", "sp,a");
2901     }
2902
2903
2904   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
2905     {
2906       if (options.useXstack)
2907         {
2908           emitcode ("mov", "r0,%s", spname);
2909           emitcode ("movx", "a,@r0");
2910           emitcode ("mov", "_bp,a");
2911           emitcode ("dec", "%s", spname);
2912         }
2913       else
2914         {
2915           emitcode ("pop", "_bp");
2916         }
2917     }
2918
2919   /* restore the register bank  */
2920   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
2921   {
2922     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
2923      || !options.useXstack)
2924     {
2925         /* Special case of ISR using non-zero bank with useXstack
2926          * is handled below.
2927          */
2928         emitcode ("pop", "psw");
2929     }
2930   }
2931
2932   if (IFFUNC_ISISR (sym->type))
2933     {
2934
2935       /* now we need to restore the registers */
2936       /* if this isr has no bank i.e. is going to
2937          run with bank 0 , then we need to save more
2938          registers :-) */
2939       if (!FUNC_REGBANK (sym->type))
2940         {
2941           /* if this function does not call any other
2942              function then we can be economical and
2943              save only those registers that are used */
2944           if (!IFFUNC_HASFCALL(sym->type))
2945             {
2946               int i;
2947
2948               /* if any registers used */
2949               if (sym->regsUsed)
2950                 {
2951                   /* save the registers used */
2952                   for (i = sym->regsUsed->size; i >= 0; i--)
2953                     {
2954                       if (bitVectBitValue (sym->regsUsed, i))
2955                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2956                     }
2957                 }
2958             }
2959           else
2960             {
2961               if (options.parms_in_bank1) {
2962                   int i;
2963                   for (i = 7 ; i >= 0 ; i-- ) {
2964                       emitcode ("pop","%s",rb1regs[i]);
2965                   }
2966               }
2967               /* this function has  a function call cannot
2968                  determines register usage so we will have to pop the
2969                  entire bank */
2970               unsaveRBank (0, ic, FALSE);
2971             }
2972         }
2973         else
2974         {
2975             /* This ISR uses a non-zero bank.
2976              *
2977              * Restore any register banks saved by genFunction
2978              * in reverse order.
2979              */
2980             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
2981             int ix;
2982
2983             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
2984             {
2985                 if (savedBanks & (1 << ix))
2986                 {
2987                     unsaveRBank(ix, NULL, FALSE);
2988                 }
2989             }
2990
2991             if (options.useXstack)
2992             {
2993                 /* Restore bank AFTER calling unsaveRBank,
2994                  * since it can trash r0.
2995                  */
2996                 emitcode ("pop", "psw");
2997             }
2998         }
2999
3000       if (!inExcludeList ("dph"))
3001         emitcode ("pop", "dph");
3002       if (!inExcludeList ("dpl"))
3003         emitcode ("pop", "dpl");
3004       if (!inExcludeList ("b"))
3005         emitcode ("pop", "b");
3006       if (!inExcludeList ("acc"))
3007         emitcode ("pop", "acc");
3008
3009       /* if debug then send end of function */
3010       if (options.debug && currFunc)
3011         {
3012           debugFile->writeEndFunction (currFunc, ic, 1);
3013         }
3014
3015       emitcode ("reti", "");
3016     }
3017   else
3018     {
3019       if (IFFUNC_CALLEESAVES(sym->type))
3020         {
3021           int i;
3022
3023           /* if any registers used */
3024           if (sym->regsUsed)
3025             {
3026               /* save the registers used */
3027               for (i = sym->regsUsed->size; i >= 0; i--)
3028                 {
3029                   if (bitVectBitValue (sym->regsUsed, i) ||
3030                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3031                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3032                 }
3033             }
3034           else if (mcs51_ptrRegReq)
3035             {
3036               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3037               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3038             }
3039
3040         }
3041
3042       /* if debug then send end of function */
3043       if (options.debug && currFunc)
3044         {
3045           debugFile->writeEndFunction (currFunc, ic, 1);
3046         }
3047
3048       emitcode ("ret", "");
3049     }
3050
3051   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3052     return;
3053
3054   /* If this was an interrupt handler using bank 0 that called another */
3055   /* function, then all registers must be saved; nothing to optimized. */
3056   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3057       && !FUNC_REGBANK(sym->type))
3058     return;
3059
3060   /* There are no push/pops to optimize if not callee-saves or ISR */
3061   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3062     return;
3063
3064   /* If there were stack parameters, we cannot optimize without also    */
3065   /* fixing all of the stack offsets; this is too dificult to consider. */
3066   if (FUNC_HASSTACKPARM(sym->type))
3067     return;
3068
3069   /* Compute the registers actually used */
3070   regsUsed = newBitVect (mcs51_nRegs);
3071   regsUsedPrologue = newBitVect (mcs51_nRegs);
3072   while (lnp)
3073     {
3074       if (lnp->ic && lnp->ic->op == FUNCTION)
3075         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3076       else
3077         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3078
3079       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3080           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3081         break;
3082       if (!lnp->prev)
3083         break;
3084       lnp = lnp->prev;
3085     }
3086
3087   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3088       && !bitVectBitValue (regsUsed, CND_IDX))
3089     {
3090       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3091       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3092           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3093         bitVectUnSetBit (regsUsed, CND_IDX);
3094     }
3095   else
3096     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3097
3098   /* If this was an interrupt handler that called another function */
3099   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3100   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3101     {
3102       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3103       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3104       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3105       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3106       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3107     }
3108
3109   /* Remove the unneeded push/pops */
3110   regsUnneeded = newBitVect (mcs51_nRegs);
3111   while (lnp)
3112     {
3113       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3114         {
3115           if (!strncmp(lnp->line, "push", 4))
3116             {
3117               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3118               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3119                 {
3120                   connectLine (lnp->prev, lnp->next);
3121                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3122                 }
3123             }
3124           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3125             {
3126               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3127               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3128                 {
3129                   connectLine (lnp->prev, lnp->next);
3130                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3131                 }
3132             }
3133         }
3134       lnp = lnp->next;
3135     }
3136
3137   for (idx = 0; idx < regsUnneeded->size; idx++)
3138     if (bitVectBitValue (regsUnneeded, idx))
3139       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3140
3141   freeBitVect (regsUnneeded);
3142   freeBitVect (regsUsed);
3143   freeBitVect (regsUsedPrologue);
3144 }
3145
3146 /*-----------------------------------------------------------------*/
3147 /* genRet - generate code for return statement                     */
3148 /*-----------------------------------------------------------------*/
3149 static void
3150 genRet (iCode * ic)
3151 {
3152   int size, offset = 0, pushed = 0;
3153
3154   D(emitcode (";     genRet",""));
3155
3156   /* if we have no return value then
3157      just generate the "ret" */
3158   if (!IC_LEFT (ic))
3159     goto jumpret;
3160
3161   /* we have something to return then
3162      move the return value into place */
3163   aopOp (IC_LEFT (ic), ic, FALSE);
3164   size = AOP_SIZE (IC_LEFT (ic));
3165
3166   while (size--)
3167     {
3168       char *l;
3169       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3170         {
3171           /* #NOCHANGE */
3172           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3173                       FALSE, TRUE);
3174           emitcode ("push", "%s", l);
3175           pushed++;
3176         }
3177       else
3178         {
3179           l = aopGet (AOP (IC_LEFT (ic)), offset,
3180                       FALSE, FALSE);
3181           if (strcmp (fReturn[offset], l))
3182             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3183         }
3184     }
3185
3186   if (pushed)
3187     {
3188       while (pushed)
3189         {
3190           pushed--;
3191           if (strcmp (fReturn[pushed], "a"))
3192             emitcode ("pop", fReturn[pushed]);
3193           else
3194             emitcode ("pop", "acc");
3195         }
3196     }
3197   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3198
3199 jumpret:
3200   /* generate a jump to the return label
3201      if the next is not the return statement */
3202   if (!(ic->next && ic->next->op == LABEL &&
3203         IC_LABEL (ic->next) == returnLabel))
3204
3205     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3206
3207 }
3208
3209 /*-----------------------------------------------------------------*/
3210 /* genLabel - generates a label                                    */
3211 /*-----------------------------------------------------------------*/
3212 static void
3213 genLabel (iCode * ic)
3214 {
3215   /* special case never generate */
3216   if (IC_LABEL (ic) == entryLabel)
3217     return;
3218
3219   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3220 }
3221
3222 /*-----------------------------------------------------------------*/
3223 /* genGoto - generates a ljmp                                      */
3224 /*-----------------------------------------------------------------*/
3225 static void
3226 genGoto (iCode * ic)
3227 {
3228   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3229 }
3230
3231 /*-----------------------------------------------------------------*/
3232 /* findLabelBackwards: walks back through the iCode chain looking  */
3233 /* for the given label. Returns number of iCode instructions     */
3234 /* between that label and given ic.          */
3235 /* Returns zero if label not found.          */
3236 /*-----------------------------------------------------------------*/
3237 static int
3238 findLabelBackwards (iCode * ic, int key)
3239 {
3240   int count = 0;
3241
3242   while (ic->prev)
3243     {
3244       ic = ic->prev;
3245       count++;
3246
3247       /* If we have any pushes or pops, we cannot predict the distance.
3248          I don't like this at all, this should be dealt with in the
3249          back-end */
3250       if (ic->op == IPUSH || ic->op == IPOP) {
3251         return 0;
3252       }
3253
3254       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3255         {
3256           return count;
3257         }
3258     }
3259
3260   return 0;
3261 }
3262
3263 /*-----------------------------------------------------------------*/
3264 /* genPlusIncr :- does addition with increment if possible         */
3265 /*-----------------------------------------------------------------*/
3266 static bool
3267 genPlusIncr (iCode * ic)
3268 {
3269   unsigned int icount;
3270   unsigned int size = getDataSize (IC_RESULT (ic));
3271
3272   /* will try to generate an increment */
3273   /* if the right side is not a literal
3274      we cannot */
3275   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3276     return FALSE;
3277
3278   /* if the literal value of the right hand side
3279      is greater than 4 then it is not worth it */
3280   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3281     return FALSE;
3282
3283   D(emitcode (";     genPlusIncr",""));
3284
3285   /* if increment >=16 bits in register or direct space */
3286   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3287       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3288       (size > 1) &&
3289       (icount == 1))
3290     {
3291       symbol *tlbl;
3292       int emitTlbl;
3293       int labelRange;
3294
3295       /* If the next instruction is a goto and the goto target
3296        * is < 10 instructions previous to this, we can generate
3297        * jumps straight to that target.
3298        */
3299       if (ic->next && ic->next->op == GOTO
3300           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3301           && labelRange <= 10)
3302         {
3303           emitcode (";", "tail increment optimized");
3304           tlbl = IC_LABEL (ic->next);
3305           emitTlbl = 0;
3306         }
3307       else
3308         {
3309           tlbl = newiTempLabel (NULL);
3310           emitTlbl = 1;
3311         }
3312       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3313       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3314           IS_AOP_PREG (IC_RESULT (ic)))
3315         emitcode ("cjne", "%s,#0x00,%05d$",
3316                   aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3317                   tlbl->key + 100);
3318       else
3319         {
3320           emitcode ("clr", "a");
3321           emitcode ("cjne", "a,%s,%05d$",
3322                     aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3323                     tlbl->key + 100);
3324         }
3325
3326       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3327       if (size > 2)
3328         {
3329           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3330               IS_AOP_PREG (IC_RESULT (ic)))
3331             emitcode ("cjne", "%s,#0x00,%05d$",
3332                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3333                       tlbl->key + 100);
3334           else
3335             emitcode ("cjne", "a,%s,%05d$",
3336                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3337                       tlbl->key + 100);
3338
3339           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3340         }
3341       if (size > 3)
3342         {
3343           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3344               IS_AOP_PREG (IC_RESULT (ic)))
3345             emitcode ("cjne", "%s,#0x00,%05d$",
3346                       aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3347                       tlbl->key + 100);
3348           else
3349             {
3350               emitcode ("cjne", "a,%s,%05d$",
3351                         aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3352                         tlbl->key + 100);
3353             }
3354           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3355         }
3356
3357       if (emitTlbl)
3358         {
3359           emitcode ("", "%05d$:", tlbl->key + 100);
3360         }
3361       return TRUE;
3362     }
3363
3364   /* if the sizes are greater than 1 then we cannot */
3365   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3366       AOP_SIZE (IC_LEFT (ic)) > 1)
3367     return FALSE;
3368
3369   /* we can if the aops of the left & result match or
3370      if they are in registers and the registers are the
3371      same */
3372   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3373     {
3374
3375       if (icount > 3)
3376         {
3377           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3378           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3379           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3380         }
3381       else
3382         {
3383
3384           while (icount--)
3385             emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3386         }
3387
3388       return TRUE;
3389     }
3390
3391   return FALSE;
3392 }
3393
3394 /*-----------------------------------------------------------------*/
3395 /* outBitAcc - output a bit in acc                                 */
3396 /*-----------------------------------------------------------------*/
3397 static void
3398 outBitAcc (operand * result)
3399 {
3400   symbol *tlbl = newiTempLabel (NULL);
3401   /* if the result is a bit */
3402   if (AOP_TYPE (result) == AOP_CRY)
3403     {
3404       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
3405     }
3406   else
3407     {
3408       emitcode ("jz", "%05d$", tlbl->key + 100);
3409       emitcode ("mov", "a,%s", one);
3410       emitcode ("", "%05d$:", tlbl->key + 100);
3411       outAcc (result);
3412     }
3413 }
3414
3415 /*-----------------------------------------------------------------*/
3416 /* genPlusBits - generates code for addition of two bits           */
3417 /*-----------------------------------------------------------------*/
3418 static void
3419 genPlusBits (iCode * ic)
3420 {
3421   D(emitcode (";     genPlusBits",""));
3422
3423   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3424     {
3425       symbol *lbl = newiTempLabel (NULL);
3426       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3427       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3428       emitcode ("cpl", "c");
3429       emitcode ("", "%05d$:", (lbl->key + 100));
3430       outBitC (IC_RESULT (ic));
3431     }
3432   else
3433     {
3434       emitcode ("clr", "a");
3435       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3436       emitcode ("rlc", "a");
3437       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3438       emitcode ("addc", "a,#0x00");
3439       outAcc (IC_RESULT (ic));
3440     }
3441 }
3442
3443 #if 0
3444 /* This is the original version of this code.
3445
3446  * This is being kept around for reference,
3447  * because I am not entirely sure I got it right...
3448  */
3449 static void
3450 adjustArithmeticResult (iCode * ic)
3451 {
3452   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3453       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3454       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3455     aopPut (AOP (IC_RESULT (ic)),
3456             aopGet (AOP (IC_LEFT (ic)), 2, FALSE, FALSE),
3457             2,
3458             isOperandVolatile (IC_RESULT (ic), FALSE));
3459
3460   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3461       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3462       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3463     aopPut (AOP (IC_RESULT (ic)),
3464             aopGet (AOP (IC_RIGHT (ic)), 2, FALSE, FALSE),
3465             2,
3466             isOperandVolatile (IC_RESULT (ic), FALSE));
3467
3468   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3469       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3470       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3471       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3472       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3473     {
3474       char buffer[5];
3475       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3476       aopPut (AOP (IC_RESULT (ic)), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3477     }
3478 }
3479 #else
3480 /* This is the pure and virtuous version of this code.
3481  * I'm pretty certain it's right, but not enough to toss the old
3482  * code just yet...
3483  */
3484 static void
3485 adjustArithmeticResult (iCode * ic)
3486 {
3487   if (opIsGptr (IC_RESULT (ic)) &&
3488       opIsGptr (IC_LEFT (ic)) &&
3489       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3490     {
3491       aopPut (AOP (IC_RESULT (ic)),
3492               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3493               GPTRSIZE - 1,
3494               isOperandVolatile (IC_RESULT (ic), FALSE));
3495     }
3496
3497   if (opIsGptr (IC_RESULT (ic)) &&
3498       opIsGptr (IC_RIGHT (ic)) &&
3499       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3500     {
3501       aopPut (AOP (IC_RESULT (ic)),
3502               aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3503               GPTRSIZE - 1,
3504               isOperandVolatile (IC_RESULT (ic), FALSE));
3505     }
3506
3507   if (opIsGptr (IC_RESULT (ic)) &&
3508       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3509       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3510       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3511       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3512     {
3513       char buffer[5];
3514       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3515       aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3516     }
3517 }
3518 #endif
3519
3520 /*-----------------------------------------------------------------*/
3521 /* genPlus - generates code for addition                           */
3522 /*-----------------------------------------------------------------*/
3523 static void
3524 genPlus (iCode * ic)
3525 {
3526   int size, offset = 0;
3527   int skip_bytes = 0;
3528   char *add = "add";
3529   asmop *leftOp, *rightOp;
3530   operand * op;
3531
3532   /* special cases :- */
3533
3534   D(emitcode (";     genPlus",""));
3535
3536   aopOp (IC_LEFT (ic), ic, FALSE);
3537   aopOp (IC_RIGHT (ic), ic, FALSE);
3538   aopOp (IC_RESULT (ic), ic, TRUE);
3539
3540   /* if literal, literal on the right or
3541      if left requires ACC or right is already
3542      in ACC */
3543   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3544       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3545       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3546     {
3547       operand *t = IC_RIGHT (ic);
3548       IC_RIGHT (ic) = IC_LEFT (ic);
3549       IC_LEFT (ic) = t;
3550     }
3551
3552   /* if both left & right are in bit
3553      space */
3554   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3555       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3556     {
3557       genPlusBits (ic);
3558       goto release;
3559     }
3560
3561   /* if left in bit space & right literal */
3562   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3563       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3564     {
3565       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3566       /* if result in bit space */
3567       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3568         {
3569           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3570             emitcode ("cpl", "c");
3571           outBitC (IC_RESULT (ic));
3572         }
3573       else
3574         {
3575           size = getDataSize (IC_RESULT (ic));
3576           while (size--)
3577             {
3578               MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE));
3579               emitcode ("addc", "a,#00");
3580               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3581             }
3582         }
3583       goto release;
3584     }
3585
3586   /* if I can do an increment instead
3587      of add then GOOD for ME */
3588   if (genPlusIncr (ic) == TRUE)
3589     goto release;
3590
3591   size = getDataSize (IC_RESULT (ic));
3592   leftOp = AOP(IC_LEFT(ic));
3593   rightOp = AOP(IC_RIGHT(ic));
3594   op=IC_LEFT(ic);
3595
3596   /* if this is an add for an array access
3597      at a 256 byte boundary */
3598   if ( 2 == size
3599        && AOP_TYPE (op) == AOP_IMMD
3600        && IS_SYMOP (op)
3601        && IS_SPEC (OP_SYM_ETYPE (op))
3602        && SPEC_ABSA (OP_SYM_ETYPE (op))
3603        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3604      )
3605     {
3606       D(emitcode (";     genPlus aligned array",""));
3607       aopPut (AOP (IC_RESULT (ic)),
3608               aopGet (rightOp, 0, FALSE, FALSE),
3609               0,
3610               isOperandVolatile (IC_RESULT (ic), FALSE));
3611
3612       if( 1 == getDataSize (IC_RIGHT (ic)) )
3613         {
3614           aopPut (AOP (IC_RESULT (ic)),
3615                   aopGet (leftOp, 1, FALSE, FALSE),
3616                   1,
3617                   isOperandVolatile (IC_RESULT (ic), FALSE));
3618         }
3619       else
3620         {
3621           MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
3622           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3623           aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3624         }
3625       goto release;
3626     }
3627
3628   /* if the lower bytes of a literal are zero skip the addition */
3629   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3630     {
3631        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3632               (skip_bytes+1 < size))
3633          {
3634            skip_bytes++;
3635          }
3636        if (skip_bytes)
3637          D(emitcode (";     genPlus shortcut",""));
3638     }
3639
3640   while (size--)
3641     {
3642       if( offset >= skip_bytes )
3643         {
3644           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3645             {
3646               emitcode("mov", "b,a");
3647               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3648               emitcode("xch", "a,b");
3649               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3650               emitcode (add, "a,b");
3651             }
3652           else if (aopGetUsesAcc (leftOp, offset))
3653             {
3654               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3655               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3656             }
3657           else
3658             {
3659               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3660               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3661             }
3662           aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3663           add = "addc";  /* further adds must propagate carry */
3664         }
3665       else
3666         {
3667           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3668               isOperandVolatile (IC_RESULT (ic), FALSE))
3669             {
3670               /* just move */
3671               aopPut (AOP (IC_RESULT (ic)),
3672                       aopGet (leftOp, offset, FALSE, FALSE),
3673                       offset,
3674                       isOperandVolatile (IC_RESULT (ic), FALSE));
3675             }
3676         }
3677       offset++;
3678     }
3679
3680   adjustArithmeticResult (ic);
3681
3682 release:
3683   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3684   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3685   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3686 }
3687
3688 /*-----------------------------------------------------------------*/
3689 /* genMinusDec :- does subtraction with deccrement if possible     */
3690 /*-----------------------------------------------------------------*/
3691 static bool
3692 genMinusDec (iCode * ic)
3693 {
3694   unsigned int icount;
3695   unsigned int size = getDataSize (IC_RESULT (ic));
3696
3697   /* will try to generate an increment */
3698   /* if the right side is not a literal
3699      we cannot */
3700   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3701     return FALSE;
3702
3703   /* if the literal value of the right hand side
3704      is greater than 4 then it is not worth it */
3705   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3706     return FALSE;
3707
3708   D(emitcode (";     genMinusDec",""));
3709
3710   /* if decrement >=16 bits in register or direct space */
3711   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3712       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3713       (size > 1) &&
3714       (icount == 1))
3715     {
3716       symbol *tlbl;
3717       int emitTlbl;
3718       int labelRange;
3719
3720       /* If the next instruction is a goto and the goto target
3721        * is <= 10 instructions previous to this, we can generate
3722        * jumps straight to that target.
3723        */
3724       if (ic->next && ic->next->op == GOTO
3725           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3726           && labelRange <= 10)
3727         {
3728           emitcode (";", "tail decrement optimized");
3729           tlbl = IC_LABEL (ic->next);
3730           emitTlbl = 0;
3731         }
3732       else
3733         {
3734           tlbl = newiTempLabel (NULL);
3735           emitTlbl = 1;
3736         }
3737
3738       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3739       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3740           IS_AOP_PREG (IC_RESULT (ic)))
3741         emitcode ("cjne", "%s,#0xff,%05d$"
3742                   ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3743                   ,tlbl->key + 100);
3744       else
3745         {
3746           emitcode ("mov", "a,#0xff");
3747           emitcode ("cjne", "a,%s,%05d$"
3748                     ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3749                     ,tlbl->key + 100);
3750         }
3751       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3752       if (size > 2)
3753         {
3754           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3755               IS_AOP_PREG (IC_RESULT (ic)))
3756             emitcode ("cjne", "%s,#0xff,%05d$"
3757                       ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3758                       ,tlbl->key + 100);
3759           else
3760             {
3761               emitcode ("cjne", "a,%s,%05d$"
3762                         ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3763                         ,tlbl->key + 100);
3764             }
3765           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3766         }
3767       if (size > 3)
3768         {
3769           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3770               IS_AOP_PREG (IC_RESULT (ic)))
3771             emitcode ("cjne", "%s,#0xff,%05d$"
3772                       ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3773                       ,tlbl->key + 100);
3774           else
3775             {
3776               emitcode ("cjne", "a,%s,%05d$"
3777                         ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3778                         ,tlbl->key + 100);
3779             }
3780           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3781         }
3782       if (emitTlbl)
3783         {
3784           emitcode ("", "%05d$:", tlbl->key + 100);
3785         }
3786       return TRUE;
3787     }
3788
3789   /* if the sizes are greater than 1 then we cannot */
3790   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3791       AOP_SIZE (IC_LEFT (ic)) > 1)
3792     return FALSE;
3793
3794   /* we can if the aops of the left & result match or
3795      if they are in registers and the registers are the
3796      same */
3797   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3798     {
3799
3800       while (icount--)
3801         emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
3802
3803       return TRUE;
3804     }
3805
3806   return FALSE;
3807 }
3808
3809 /*-----------------------------------------------------------------*/
3810 /* addSign - complete with sign                                    */
3811 /*-----------------------------------------------------------------*/
3812 static void
3813 addSign (operand * result, int offset, int sign)
3814 {
3815   int size = (getDataSize (result) - offset);
3816   if (size > 0)
3817     {
3818       if (sign)
3819         {
3820           emitcode ("rlc", "a");
3821           emitcode ("subb", "a,acc");
3822           while (size--)
3823             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
3824         }
3825       else
3826         while (size--)
3827           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
3828     }
3829 }
3830
3831 /*-----------------------------------------------------------------*/
3832 /* genMinusBits - generates code for subtraction  of two bits      */
3833 /*-----------------------------------------------------------------*/
3834 static void
3835 genMinusBits (iCode * ic)
3836 {
3837   symbol *lbl = newiTempLabel (NULL);
3838
3839   D(emitcode (";     genMinusBits",""));
3840
3841   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3842     {
3843       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3844       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3845       emitcode ("cpl", "c");
3846       emitcode ("", "%05d$:", (lbl->key + 100));
3847       outBitC (IC_RESULT (ic));
3848     }
3849   else
3850     {
3851       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3852       emitcode ("subb", "a,acc");
3853       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
3854       emitcode ("inc", "a");
3855       emitcode ("", "%05d$:", (lbl->key + 100));
3856       aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3857       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
3858     }
3859 }
3860
3861 /*-----------------------------------------------------------------*/
3862 /* genMinus - generates code for subtraction                       */
3863 /*-----------------------------------------------------------------*/
3864 static void
3865 genMinus (iCode * ic)
3866 {
3867   int size, offset = 0;
3868
3869   D(emitcode (";     genMinus",""));
3870
3871   aopOp (IC_LEFT (ic), ic, FALSE);
3872   aopOp (IC_RIGHT (ic), ic, FALSE);
3873   aopOp (IC_RESULT (ic), ic, TRUE);
3874
3875   /* special cases :- */
3876   /* if both left & right are in bit space */
3877   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3878       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3879     {
3880       genMinusBits (ic);
3881       goto release;
3882     }
3883
3884   /* if I can do an decrement instead
3885      of subtract then GOOD for ME */
3886   if (genMinusDec (ic) == TRUE)
3887     goto release;
3888
3889   size = getDataSize (IC_RESULT (ic));
3890
3891   /* if literal, add a,#-lit, else normal subb */
3892   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3893     {
3894       unsigned long lit = 0L;
3895
3896       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3897       lit = -(long) lit;
3898
3899       while (size--)
3900         {
3901           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE));
3902           /* first add without previous c */
3903           if (!offset) {
3904             if (!size && lit== (unsigned long) -1) {
3905               emitcode ("dec", "a");
3906             } else {
3907               emitcode ("add", "a,#0x%02x",
3908                         (unsigned int) (lit & 0x0FFL));
3909             }
3910           } else {
3911             emitcode ("addc", "a,#0x%02x",
3912                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3913           }
3914           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3915         }
3916     }
3917   else
3918     {
3919       asmop *leftOp, *rightOp;
3920
3921       leftOp = AOP(IC_LEFT(ic));
3922       rightOp = AOP(IC_RIGHT(ic));
3923
3924       while (size--)
3925         {
3926           if (aopGetUsesAcc(rightOp, offset)) {
3927             wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
3928             MOVA (aopGet(rightOp, offset, FALSE, TRUE));
3929             if (offset == 0) {
3930               emitcode( "setb", "c");
3931             }
3932             emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
3933             emitcode("cpl", "a");
3934           } else {
3935             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
3936             if (offset == 0)
3937               CLRC;
3938             emitcode ("subb", "a,%s",
3939                       aopGet(rightOp, offset, FALSE, TRUE));
3940           }
3941
3942           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3943         }
3944     }
3945
3946
3947   adjustArithmeticResult (ic);
3948
3949 release:
3950   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3951   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3952   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3953 }
3954
3955
3956 /*-----------------------------------------------------------------*/
3957 /* genMultbits :- multiplication of bits                           */
3958 /*-----------------------------------------------------------------*/
3959 static void
3960 genMultbits (operand * left,
3961              operand * right,
3962              operand * result)
3963 {
3964   D(emitcode (";     genMultbits",""));
3965
3966   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
3967   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
3968   outBitC (result);
3969 }
3970
3971 /*-----------------------------------------------------------------*/
3972 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
3973 /*-----------------------------------------------------------------*/
3974 static void
3975 genMultOneByte (operand * left,
3976                 operand * right,
3977                 operand * result)
3978 {
3979   symbol *lbl;
3980   int size = AOP_SIZE (result);
3981   bool runtimeSign, compiletimeSign;
3982   bool lUnsigned, rUnsigned;
3983
3984   D(emitcode (";     genMultOneByte",""));
3985
3986   if (size < 1 || size > 2)
3987     {
3988       /* this should never happen */
3989       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
3990                AOP_SIZE(result), __FILE__, lineno);
3991       exit (1);
3992     }
3993
3994   /* (if two literals: the value is computed before) */
3995   /* if one literal, literal on the right */
3996   if (AOP_TYPE (left) == AOP_LIT)
3997     {
3998       operand *t = right;
3999       right = left;
4000       left = t;
4001       /* emitcode (";", "swapped left and right"); */
4002     }
4003   /* if no literal, unsigned on the right: shorter code */
4004   if (   AOP_TYPE (right) != AOP_LIT
4005       && SPEC_USIGN (getSpec (operandType (left))))
4006     {
4007       operand *t = right;
4008       right = left;
4009       left = t;
4010     }
4011
4012   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4013   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4014
4015   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4016                    no need to take care about the signedness! */
4017       || (lUnsigned && rUnsigned))
4018     {
4019       /* just an unsigned 8 * 8 = 8 multiply
4020          or 8u * 8u = 16u */
4021       /* emitcode (";","unsigned"); */
4022       /* TODO: check for accumulator clash between left & right aops? */
4023
4024       if (AOP_TYPE (right) == AOP_LIT)
4025         {
4026           /* moving to accumulator first helps peepholes */
4027           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4028           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4029         }
4030       else
4031         {
4032           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4033           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4034         }
4035
4036       emitcode ("mul", "ab");
4037       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4038       if (size == 2)
4039         aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4040       return;
4041     }
4042
4043   /* we have to do a signed multiply */
4044   /* emitcode (";", "signed"); */
4045
4046   /* now sign adjust for both left & right */
4047
4048   /* let's see what's needed: */
4049   /* apply negative sign during runtime */
4050   runtimeSign = FALSE;
4051   /* negative sign from literals */
4052   compiletimeSign = FALSE;
4053
4054   if (!lUnsigned)
4055     {
4056       if (AOP_TYPE(left) == AOP_LIT)
4057         {
4058           /* signed literal */
4059           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4060           if (val < 0)
4061             compiletimeSign = TRUE;
4062         }
4063       else
4064         /* signed but not literal */
4065         runtimeSign = TRUE;
4066     }
4067
4068   if (!rUnsigned)
4069     {
4070       if (AOP_TYPE(right) == AOP_LIT)
4071         {
4072           /* signed literal */
4073           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4074           if (val < 0)
4075             compiletimeSign ^= TRUE;
4076         }
4077       else
4078         /* signed but not literal */
4079         runtimeSign = TRUE;
4080     }
4081
4082   /* initialize F0, which stores the runtime sign */
4083   if (runtimeSign)
4084     {
4085       if (compiletimeSign)
4086         emitcode ("setb", "F0"); /* set sign flag */
4087       else
4088         emitcode ("clr", "F0"); /* reset sign flag */
4089     }
4090
4091   /* save the signs of the operands */
4092   if (AOP_TYPE(right) == AOP_LIT)
4093     {
4094       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4095
4096       if (!rUnsigned && val < 0)
4097         emitcode ("mov", "b,#0x%02x", -val);
4098       else
4099         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4100     }
4101   else /* ! literal */
4102     {
4103       if (rUnsigned)  /* emitcode (";", "signed"); */
4104
4105         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4106       else
4107         {
4108           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4109           lbl = newiTempLabel (NULL);
4110           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4111           emitcode ("cpl", "F0"); /* complement sign flag */
4112           emitcode ("cpl", "a");  /* 2's complement */
4113           emitcode ("inc", "a");
4114           emitcode ("", "%05d$:", (lbl->key + 100));
4115           emitcode ("mov", "b,a");
4116         }
4117     }
4118
4119   if (AOP_TYPE(left) == AOP_LIT)
4120     {
4121       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4122
4123       if (!lUnsigned && val < 0)
4124         emitcode ("mov", "a,#0x%02x", -val);
4125       else
4126         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4127     }
4128   else /* ! literal */
4129     {
4130       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4131
4132       if (!lUnsigned)
4133         {
4134           lbl = newiTempLabel (NULL);
4135           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4136           emitcode ("cpl", "F0"); /* complement sign flag */
4137           emitcode ("cpl", "a"); /* 2's complement */
4138           emitcode ("inc", "a");
4139           emitcode ("", "%05d$:", (lbl->key + 100));
4140         }
4141     }
4142
4143   /* now the multiplication */
4144   emitcode ("mul", "ab");
4145   if (runtimeSign || compiletimeSign)
4146     {
4147       lbl = newiTempLabel (NULL);
4148       if (runtimeSign)
4149         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4150       emitcode ("cpl", "a"); /* lsb 2's complement */
4151       if (size != 2)
4152         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4153       else
4154         {
4155           emitcode ("add", "a,#1"); /* this sets carry flag */
4156           emitcode ("xch", "a,b");
4157           emitcode ("cpl", "a"); /* msb 2's complement */
4158           emitcode ("addc", "a,#0");
4159           emitcode ("xch", "a,b");
4160         }
4161       emitcode ("", "%05d$:", (lbl->key + 100));
4162     }
4163   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4164   if (size == 2)
4165     aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4166 }
4167
4168 /*-----------------------------------------------------------------*/
4169 /* genMult - generates code for multiplication                     */
4170 /*-----------------------------------------------------------------*/
4171 static void
4172 genMult (iCode * ic)
4173 {
4174   operand *left = IC_LEFT (ic);
4175   operand *right = IC_RIGHT (ic);
4176   operand *result = IC_RESULT (ic);
4177
4178   D(emitcode (";     genMult",""));
4179
4180   /* assign the amsops */
4181   aopOp (left, ic, FALSE);
4182   aopOp (right, ic, FALSE);
4183   aopOp (result, ic, TRUE);
4184
4185   /* special cases first */
4186   /* both are bits */
4187   if (AOP_TYPE (left) == AOP_CRY &&
4188       AOP_TYPE (right) == AOP_CRY)
4189     {
4190       genMultbits (left, right, result);
4191       goto release;
4192     }
4193
4194   /* if both are of size == 1 */
4195 #if 0 // one of them can be a sloc shared with the result
4196     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4197 #else
4198   if (getSize(operandType(left)) == 1 &&
4199       getSize(operandType(right)) == 1)
4200 #endif
4201     {
4202       genMultOneByte (left, right, result);
4203       goto release;
4204     }
4205
4206   /* should have been converted to function call */
4207     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4208              getSize(OP_SYMBOL(right)->type));
4209   assert (0);
4210
4211 release:
4212   freeAsmop (result, NULL, ic, TRUE);
4213   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4214   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4215 }
4216
4217 /*-----------------------------------------------------------------*/
4218 /* genDivbits :- division of bits                                  */
4219 /*-----------------------------------------------------------------*/
4220 static void
4221 genDivbits (operand * left,
4222             operand * right,
4223             operand * result)
4224 {
4225
4226   char *l;
4227
4228   D(emitcode (";     genDivbits",""));
4229
4230   /* the result must be bit */
4231   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4232   l = aopGet (AOP (left), 0, FALSE, FALSE);
4233
4234   MOVA (l);
4235
4236   emitcode ("div", "ab");
4237   emitcode ("rrc", "a");
4238   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4239 }
4240
4241 /*-----------------------------------------------------------------*/
4242 /* genDivOneByte : 8 bit division                                  */
4243 /*-----------------------------------------------------------------*/
4244 static void
4245 genDivOneByte (operand * left,
4246                operand * right,
4247                operand * result)
4248 {
4249   bool lUnsigned, rUnsigned;
4250   bool runtimeSign, compiletimeSign;
4251   symbol *lbl;
4252   int size, offset;
4253
4254   D(emitcode (";     genDivOneByte",""));
4255
4256   /* Why is it necessary that genDivOneByte() can return an int result?
4257      Have a look at:
4258
4259         volatile unsigned char uc;
4260         volatile signed char sc1, sc2;
4261         volatile int i;
4262
4263         uc  = 255;
4264         sc1 = -1;
4265         i = uc / sc1;
4266
4267      Or:
4268
4269         sc1 = -128;
4270         sc2 = -1;
4271         i = sc1 / sc2;
4272
4273      In all cases a one byte result would overflow, the following cast to int
4274      would return the wrong result.
4275
4276      Two possible solution:
4277         a) cast operands to int, if ((unsigned) / (signed)) or
4278            ((signed) / (signed))
4279         b) return an 16 bit signed int; this is what we're doing here!
4280   */
4281
4282   size = AOP_SIZE (result) - 1;
4283   offset = 1;
4284   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4285   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4286
4287   /* signed or unsigned */
4288   if (lUnsigned && rUnsigned)
4289     {
4290       /* unsigned is easy */
4291       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4292       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4293       emitcode ("div", "ab");
4294       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4295       while (size--)
4296         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4297       return;
4298     }
4299
4300   /* signed is a little bit more difficult */
4301
4302   /* now sign adjust for both left & right */
4303
4304   /* let's see what's needed: */
4305   /* apply negative sign during runtime */
4306   runtimeSign = FALSE;
4307   /* negative sign from literals */
4308   compiletimeSign = FALSE;
4309
4310   if (!lUnsigned)
4311     {
4312       if (AOP_TYPE(left) == AOP_LIT)
4313         {
4314           /* signed literal */
4315           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4316           if (val < 0)
4317             compiletimeSign = TRUE;
4318         }
4319       else
4320         /* signed but not literal */
4321         runtimeSign = TRUE;
4322     }
4323
4324   if (!rUnsigned)
4325     {
4326       if (AOP_TYPE(right) == AOP_LIT)
4327         {
4328           /* signed literal */
4329           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4330           if (val < 0)
4331             compiletimeSign ^= TRUE;
4332         }
4333       else
4334         /* signed but not literal */
4335         runtimeSign = TRUE;
4336     }
4337
4338   /* initialize F0, which stores the runtime sign */
4339   if (runtimeSign)
4340     {
4341       if (compiletimeSign)
4342         emitcode ("setb", "F0"); /* set sign flag */
4343       else
4344         emitcode ("clr", "F0"); /* reset sign flag */
4345     }
4346
4347   /* save the signs of the operands */
4348   if (AOP_TYPE(right) == AOP_LIT)
4349     {
4350       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4351
4352       if (!rUnsigned && val < 0)
4353         emitcode ("mov", "b,#0x%02x", -val);
4354       else
4355         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4356     }
4357   else /* ! literal */
4358     {
4359       if (rUnsigned)
4360         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4361       else
4362         {
4363           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4364           lbl = newiTempLabel (NULL);
4365           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4366           emitcode ("cpl", "F0"); /* complement sign flag */
4367           emitcode ("cpl", "a");  /* 2's complement */
4368           emitcode ("inc", "a");
4369           emitcode ("", "%05d$:", (lbl->key + 100));
4370           emitcode ("mov", "b,a");
4371         }
4372     }
4373
4374   if (AOP_TYPE(left) == AOP_LIT)
4375     {
4376       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4377
4378       if (!lUnsigned && val < 0)
4379         emitcode ("mov", "a,#0x%02x", -val);
4380       else
4381         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4382     }
4383   else /* ! literal */
4384     {
4385       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4386
4387       if (!lUnsigned)
4388         {
4389           lbl = newiTempLabel (NULL);
4390           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4391           emitcode ("cpl", "F0"); /* complement sign flag */
4392           emitcode ("cpl", "a");  /* 2's complement */
4393           emitcode ("inc", "a");
4394           emitcode ("", "%05d$:", (lbl->key + 100));
4395         }
4396     }
4397
4398   /* now the division */
4399   emitcode ("div", "ab");
4400
4401   if (runtimeSign || compiletimeSign)
4402     {
4403       lbl = newiTempLabel (NULL);
4404       if (runtimeSign)
4405         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4406       emitcode ("cpl", "a"); /* lsb 2's complement */
4407       emitcode ("inc", "a");
4408       emitcode ("", "%05d$:", (lbl->key + 100));
4409
4410       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4411       if (size > 0)
4412         {
4413           /* msb is 0x00 or 0xff depending on the sign */
4414           if (runtimeSign)
4415             {
4416               emitcode ("mov", "c,F0");
4417               emitcode ("subb", "a,acc");
4418               while (size--)
4419                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4420             }
4421           else /* compiletimeSign */
4422             while (size--)
4423               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4424         }
4425     }
4426   else
4427     {
4428       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4429       while (size--)
4430         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4431     }
4432 }
4433
4434 /*-----------------------------------------------------------------*/
4435 /* genDiv - generates code for division                            */
4436 /*-----------------------------------------------------------------*/
4437 static void
4438 genDiv (iCode * ic)
4439 {
4440   operand *left = IC_LEFT (ic);
4441   operand *right = IC_RIGHT (ic);
4442   operand *result = IC_RESULT (ic);
4443
4444   D(emitcode (";     genDiv",""));
4445
4446   /* assign the amsops */
4447   aopOp (left, ic, FALSE);
4448   aopOp (right, ic, FALSE);
4449   aopOp (result, ic, TRUE);
4450
4451   /* special cases first */
4452   /* both are bits */
4453   if (AOP_TYPE (left) == AOP_CRY &&
4454       AOP_TYPE (right) == AOP_CRY)
4455     {
4456       genDivbits (left, right, result);
4457       goto release;
4458     }
4459
4460   /* if both are of size == 1 */
4461   if (AOP_SIZE (left) == 1 &&
4462       AOP_SIZE (right) == 1)
4463     {
4464       genDivOneByte (left, right, result);
4465       goto release;
4466     }
4467
4468   /* should have been converted to function call */
4469   assert (0);
4470 release:
4471   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4472   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4473   freeAsmop (result, NULL, ic, TRUE);
4474 }
4475
4476 /*-----------------------------------------------------------------*/
4477 /* genModbits :- modulus of bits                                   */
4478 /*-----------------------------------------------------------------*/
4479 static void
4480 genModbits (operand * left,
4481             operand * right,
4482             operand * result)
4483 {
4484
4485   char *l;
4486
4487   D(emitcode (";     genModbits",""));
4488
4489   /* the result must be bit */
4490   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4491   l = aopGet (AOP (left), 0, FALSE, FALSE);
4492
4493   MOVA (l);
4494
4495   emitcode ("div", "ab");
4496   emitcode ("mov", "a,b");
4497   emitcode ("rrc", "a");
4498   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4499 }
4500
4501 /*-----------------------------------------------------------------*/
4502 /* genModOneByte : 8 bit modulus                                   */
4503 /*-----------------------------------------------------------------*/
4504 static void
4505 genModOneByte (operand * left,
4506                operand * right,
4507                operand * result)
4508 {
4509   bool lUnsigned, rUnsigned;
4510   bool runtimeSign, compiletimeSign;
4511   symbol *lbl;
4512   int size, offset;
4513
4514   D(emitcode (";     genModOneByte",""));
4515
4516   size = AOP_SIZE (result) - 1;
4517   offset = 1;
4518   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4519   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4520
4521   /* signed or unsigned */
4522   if (lUnsigned && rUnsigned)
4523     {
4524       /* unsigned is easy */
4525       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4526       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4527       emitcode ("div", "ab");
4528       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4529       while (size--)
4530         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4531       return;
4532     }
4533
4534   /* signed is a little bit more difficult */
4535
4536   /* now sign adjust for both left & right */
4537
4538   /* modulus: sign of the right operand has no influence on the result! */
4539   if (AOP_TYPE(right) == AOP_LIT)
4540     {
4541       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4542
4543       if (!rUnsigned && val < 0)
4544         emitcode ("mov", "b,#0x%02x", -val);
4545       else
4546         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4547     }
4548   else /* not literal */
4549     {
4550       if (rUnsigned)
4551         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4552       else
4553         {
4554           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4555           lbl = newiTempLabel (NULL);
4556           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4557           emitcode ("cpl", "a"); /* 2's complement */
4558           emitcode ("inc", "a");
4559           emitcode ("", "%05d$:", (lbl->key + 100));
4560           emitcode ("mov", "b,a");
4561         }
4562     }
4563
4564   /* let's see what's needed: */
4565   /* apply negative sign during runtime */
4566   runtimeSign = FALSE;
4567   /* negative sign from literals */
4568   compiletimeSign = FALSE;
4569
4570   /* sign adjust left side */
4571   if (AOP_TYPE(left) == AOP_LIT)
4572     {
4573       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4574
4575       if (!lUnsigned && val < 0)
4576         {
4577           compiletimeSign = TRUE; /* set sign flag */
4578           emitcode ("mov", "a,#0x%02x", -val);
4579         }
4580       else
4581         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4582     }
4583   else /* ! literal */
4584     {
4585       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4586
4587       if (!lUnsigned)
4588         {
4589           runtimeSign = TRUE;
4590           emitcode ("clr", "F0"); /* clear sign flag */
4591
4592           lbl = newiTempLabel (NULL);
4593           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4594           emitcode ("setb", "F0"); /* set sign flag */
4595           emitcode ("cpl", "a");   /* 2's complement */
4596           emitcode ("inc", "a");
4597           emitcode ("", "%05d$:", (lbl->key + 100));
4598         }
4599     }
4600
4601   /* now the modulus */
4602   emitcode ("div", "ab");
4603
4604   if (runtimeSign || compiletimeSign)
4605     {
4606       emitcode ("mov", "a,b");
4607       lbl = newiTempLabel (NULL);
4608       if (runtimeSign)
4609         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4610       emitcode ("cpl", "a"); /* 2's complement */
4611       emitcode ("inc", "a");
4612       emitcode ("", "%05d$:", (lbl->key + 100));
4613
4614       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4615       if (size > 0)
4616         {
4617           /* msb is 0x00 or 0xff depending on the sign */
4618           if (runtimeSign)
4619             {
4620               emitcode ("mov", "c,F0");
4621               emitcode ("subb", "a,acc");
4622               while (size--)
4623                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4624             }
4625           else /* compiletimeSign */
4626             while (size--)
4627               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4628         }
4629     }
4630   else
4631     {
4632       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4633       while (size--)
4634         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4635     }
4636 }
4637
4638 /*-----------------------------------------------------------------*/
4639 /* genMod - generates code for division                            */
4640 /*-----------------------------------------------------------------*/
4641 static void
4642 genMod (iCode * ic)
4643 {
4644   operand *left = IC_LEFT (ic);
4645   operand *right = IC_RIGHT (ic);
4646   operand *result = IC_RESULT (ic);
4647
4648   D(emitcode (";     genMod",""));
4649
4650   /* assign the amsops */
4651   aopOp (left, ic, FALSE);
4652   aopOp (right, ic, FALSE);
4653   aopOp (result, ic, TRUE);
4654
4655   /* special cases first */
4656   /* both are bits */
4657   if (AOP_TYPE (left) == AOP_CRY &&
4658       AOP_TYPE (right) == AOP_CRY)
4659     {
4660       genModbits (left, right, result);
4661       goto release;
4662     }
4663
4664   /* if both are of size == 1 */
4665   if (AOP_SIZE (left) == 1 &&
4666       AOP_SIZE (right) == 1)
4667     {
4668       genModOneByte (left, right, result);
4669       goto release;
4670     }
4671
4672   /* should have been converted to function call */
4673   assert (0);
4674
4675 release:
4676   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4677   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4678   freeAsmop (result, NULL, ic, TRUE);
4679 }
4680
4681 /*-----------------------------------------------------------------*/
4682 /* genIfxJump :- will create a jump depending on the ifx           */
4683 /*-----------------------------------------------------------------*/
4684 static void
4685 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
4686 {
4687   symbol *jlbl;
4688   symbol *tlbl = newiTempLabel (NULL);
4689   char *inst;
4690
4691   D(emitcode (";     genIfxJump",""));
4692
4693   /* if true label then we jump if condition
4694      supplied is true */
4695   if (IC_TRUE (ic))
4696     {
4697       jlbl = IC_TRUE (ic);
4698       inst = ((strcmp (jval, "a") == 0 ? "jz" :
4699                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
4700     }
4701   else
4702     {
4703       /* false label is present */
4704       jlbl = IC_FALSE (ic);
4705       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
4706                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
4707     }
4708   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
4709     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
4710   else
4711     emitcode (inst, "%05d$", tlbl->key + 100);
4712   freeForBranchAsmop (result);
4713   freeForBranchAsmop (right);
4714   freeForBranchAsmop (left);
4715   emitcode ("ljmp", "%05d$", jlbl->key + 100);
4716   emitcode ("", "%05d$:", tlbl->key + 100);
4717
4718   /* mark the icode as generated */
4719   ic->generated = 1;
4720 }
4721
4722 /*-----------------------------------------------------------------*/
4723 /* genCmp :- greater or less than comparison                       */
4724 /*-----------------------------------------------------------------*/
4725 static void
4726 genCmp (operand * left, operand * right,
4727         operand * result, iCode * ifx, int sign, iCode *ic)
4728 {
4729   int size, offset = 0;
4730   unsigned long lit = 0L;
4731   bool rightInB;
4732
4733   D(emitcode (";     genCmp",""));
4734
4735   /* if left & right are bit variables */
4736   if (AOP_TYPE (left) == AOP_CRY &&
4737       AOP_TYPE (right) == AOP_CRY)
4738     {
4739       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
4740       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
4741     }
4742   else
4743     {
4744       /* subtract right from left if at the
4745          end the carry flag is set then we know that
4746          left is greater than right */
4747       size = max (AOP_SIZE (left), AOP_SIZE (right));
4748
4749       /* if unsigned char cmp with lit, do cjne left,#right,zz */
4750       if ((size == 1) && !sign &&
4751           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4752         {
4753           symbol *lbl = newiTempLabel (NULL);
4754           emitcode ("cjne", "%s,%s,%05d$",
4755                     aopGet (AOP (left), offset, FALSE, FALSE),
4756                     aopGet (AOP (right), offset, FALSE, FALSE),
4757                     lbl->key + 100);
4758           emitcode ("", "%05d$:", lbl->key + 100);
4759         }
4760       else
4761         {
4762           if (AOP_TYPE (right) == AOP_LIT)
4763             {
4764               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4765               /* optimize if(x < 0) or if(x >= 0) */
4766               if (lit == 0L)
4767                 {
4768                   if (!sign)
4769                     {
4770                       CLRC;
4771                     }
4772                   else
4773                     {
4774                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
4775                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4776                         {
4777                           genIfxJump (ifx, "acc.7", left, right, result);
4778                           freeAsmop (right, NULL, ic, TRUE);
4779                           freeAsmop (left, NULL, ic, TRUE);
4780
4781                           return;
4782                         }
4783                       else
4784                         emitcode ("rlc", "a");
4785                     }
4786                   goto release;
4787                 }
4788             }
4789           CLRC;
4790           while (size--)
4791             {
4792               rightInB = aopGetUsesAcc(AOP (right), offset);
4793               if (rightInB)
4794                 emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4795               MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4796               if (sign && size == 0)
4797                 {
4798                   emitcode ("xrl", "a,#0x80");
4799                   if (AOP_TYPE (right) == AOP_LIT)
4800                     {
4801                       unsigned long lit = (unsigned long)
4802                       floatFromVal (AOP (right)->aopu.aop_lit);
4803                       emitcode ("subb", "a,#0x%02x",
4804                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4805                     }
4806                   else
4807                     {
4808                       if (!rightInB)
4809                         emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4810                       emitcode ("xrl", "b,#0x80");
4811                       emitcode ("subb", "a,b");
4812                     }
4813                 }
4814               else
4815                 {
4816                   if (rightInB)
4817                     emitcode ("subb", "a,b");
4818                   else
4819                     emitcode ("subb", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4820                 }
4821               offset++;
4822             }
4823         }
4824     }
4825
4826 release:
4827   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4828   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4829   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4830     {
4831       outBitC (result);
4832     }
4833   else
4834     {
4835       /* if the result is used in the next
4836          ifx conditional branch then generate
4837          code a little differently */
4838       if (ifx)
4839         genIfxJump (ifx, "c", NULL, NULL, result);
4840       else
4841         outBitC (result);
4842       /* leave the result in acc */
4843     }
4844 }
4845
4846 /*-----------------------------------------------------------------*/
4847 /* genCmpGt :- greater than comparison                             */
4848 /*-----------------------------------------------------------------*/
4849 static void
4850 genCmpGt (iCode * ic, iCode * ifx)
4851 {
4852   operand *left, *right, *result;
4853   sym_link *letype, *retype;
4854   int sign;
4855
4856   D(emitcode (";     genCmpGt",""));
4857
4858   left = IC_LEFT (ic);
4859   right = IC_RIGHT (ic);
4860   result = IC_RESULT (ic);
4861
4862   letype = getSpec (operandType (left));
4863   retype = getSpec (operandType (right));
4864   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4865            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4866   /* assign the amsops */
4867   aopOp (left, ic, FALSE);
4868   aopOp (right, ic, FALSE);
4869   aopOp (result, ic, TRUE);
4870
4871   genCmp (right, left, result, ifx, sign,ic);
4872
4873   freeAsmop (result, NULL, ic, TRUE);
4874 }
4875
4876 /*-----------------------------------------------------------------*/
4877 /* genCmpLt - less than comparisons                                */
4878 /*-----------------------------------------------------------------*/
4879 static void
4880 genCmpLt (iCode * ic, iCode * ifx)
4881 {
4882   operand *left, *right, *result;
4883   sym_link *letype, *retype;
4884   int sign;
4885
4886   D(emitcode (";     genCmpLt",""));
4887
4888   left = IC_LEFT (ic);
4889   right = IC_RIGHT (ic);
4890   result = IC_RESULT (ic);
4891
4892   letype = getSpec (operandType (left));
4893   retype = getSpec (operandType (right));
4894   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4895            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4896   /* assign the amsops */
4897   aopOp (left, ic, FALSE);
4898   aopOp (right, ic, FALSE);
4899   aopOp (result, ic, TRUE);
4900
4901   genCmp (left, right, result, ifx, sign,ic);
4902
4903   freeAsmop (result, NULL, ic, TRUE);
4904 }
4905
4906 /*-----------------------------------------------------------------*/
4907 /* gencjneshort - compare and jump if not equal                    */
4908 /*-----------------------------------------------------------------*/
4909 static void
4910 gencjneshort (operand * left, operand * right, symbol * lbl)
4911 {
4912   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4913   int offset = 0;
4914   unsigned long lit = 0L;
4915
4916   /* if the left side is a literal or
4917      if the right is in a pointer register and left
4918      is not */
4919   if ((AOP_TYPE (left) == AOP_LIT) ||
4920       (AOP_TYPE (left) == AOP_IMMD) ||
4921       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
4922     {
4923       operand *t = right;
4924       right = left;
4925       left = t;
4926     }
4927
4928   if (AOP_TYPE (right) == AOP_LIT)
4929     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4930
4931   /* if the right side is a literal then anything goes */
4932   if (AOP_TYPE (right) == AOP_LIT &&
4933       AOP_TYPE (left) != AOP_DIR  &&
4934       AOP_TYPE (left) != AOP_IMMD)
4935     {
4936       while (size--)
4937         {
4938           emitcode ("cjne", "%s,%s,%05d$",
4939                     aopGet (AOP (left), offset, FALSE, FALSE),
4940                     aopGet (AOP (right), offset, FALSE, FALSE),
4941                     lbl->key + 100);
4942           offset++;
4943         }
4944     }
4945
4946   /* if the right side is in a register or in direct space or
4947      if the left is a pointer register & right is not */
4948   else if (AOP_TYPE (right) == AOP_REG ||
4949            AOP_TYPE (right) == AOP_DIR ||
4950            AOP_TYPE (right) == AOP_LIT ||
4951            AOP_TYPE (right) == AOP_IMMD ||
4952            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
4953            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
4954     {
4955       while (size--)
4956         {
4957           MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4958           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4959               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4960             emitcode ("jnz", "%05d$", lbl->key + 100);
4961           else
4962             emitcode ("cjne", "a,%s,%05d$",
4963                       aopGet (AOP (right), offset, FALSE, TRUE),
4964                       lbl->key + 100);
4965           offset++;
4966         }
4967     }
4968   else
4969     {
4970       /* right is a pointer reg need both a & b */
4971       while (size--)
4972         {
4973           char *l = aopGet (AOP (left), offset, FALSE, FALSE);
4974           if (strcmp (l, "b"))
4975             emitcode ("mov", "b,%s", l);
4976           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
4977           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
4978           offset++;
4979         }
4980     }
4981 }
4982
4983 /*-----------------------------------------------------------------*/
4984 /* gencjne - compare and jump if not equal                         */
4985 /*-----------------------------------------------------------------*/
4986 static void
4987 gencjne (operand * left, operand * right, symbol * lbl)
4988 {
4989   symbol *tlbl = newiTempLabel (NULL);
4990
4991   gencjneshort (left, right, lbl);
4992
4993   emitcode ("mov", "a,%s", one);
4994   emitcode ("sjmp", "%05d$", tlbl->key + 100);
4995   emitcode ("", "%05d$:", lbl->key + 100);
4996   emitcode ("clr", "a");
4997   emitcode ("", "%05d$:", tlbl->key + 100);
4998 }
4999
5000 /*-----------------------------------------------------------------*/
5001 /* genCmpEq - generates code for equal to                          */
5002 /*-----------------------------------------------------------------*/
5003 static void
5004 genCmpEq (iCode * ic, iCode * ifx)
5005 {
5006   operand *left, *right, *result;
5007
5008   D(emitcode (";     genCmpEq",""));
5009
5010   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5011   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5012   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5013
5014   /* if literal, literal on the right or
5015      if the right is in a pointer register and left
5016      is not */
5017   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5018       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5019     {
5020       operand *t = IC_RIGHT (ic);
5021       IC_RIGHT (ic) = IC_LEFT (ic);
5022       IC_LEFT (ic) = t;
5023     }
5024
5025   if (ifx && !AOP_SIZE (result))
5026     {
5027       symbol *tlbl;
5028       /* if they are both bit variables */
5029       if (AOP_TYPE (left) == AOP_CRY &&
5030           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5031         {
5032           if (AOP_TYPE (right) == AOP_LIT)
5033             {
5034               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5035               if (lit == 0L)
5036                 {
5037                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5038                   emitcode ("cpl", "c");
5039                 }
5040               else if (lit == 1L)
5041                 {
5042                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5043                 }
5044               else
5045                 {
5046                   emitcode ("clr", "c");
5047                 }
5048               /* AOP_TYPE(right) == AOP_CRY */
5049             }
5050           else
5051             {
5052               symbol *lbl = newiTempLabel (NULL);
5053               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5054               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5055               emitcode ("cpl", "c");
5056               emitcode ("", "%05d$:", (lbl->key + 100));
5057             }
5058           /* if true label then we jump if condition
5059              supplied is true */
5060           tlbl = newiTempLabel (NULL);
5061           if (IC_TRUE (ifx))
5062             {
5063               emitcode ("jnc", "%05d$", tlbl->key + 100);
5064               freeForBranchAsmop (result);
5065               freeForBranchAsmop (right);
5066               freeForBranchAsmop (left);
5067               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5068             }
5069           else
5070             {
5071               emitcode ("jc", "%05d$", tlbl->key + 100);
5072               freeForBranchAsmop (result);
5073               freeForBranchAsmop (right);
5074               freeForBranchAsmop (left);
5075               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5076             }
5077           emitcode ("", "%05d$:", tlbl->key + 100);
5078         }
5079       else
5080         {
5081           tlbl = newiTempLabel (NULL);
5082           gencjneshort (left, right, tlbl);
5083           if (IC_TRUE (ifx))
5084             {
5085               freeForBranchAsmop (result);
5086               freeForBranchAsmop (right);
5087               freeForBranchAsmop (left);
5088               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5089               emitcode ("", "%05d$:", tlbl->key + 100);
5090             }
5091           else
5092             {
5093               symbol *lbl = newiTempLabel (NULL);
5094               emitcode ("sjmp", "%05d$", lbl->key + 100);
5095               emitcode ("", "%05d$:", tlbl->key + 100);
5096               freeForBranchAsmop (result);
5097               freeForBranchAsmop (right);
5098               freeForBranchAsmop (left);
5099               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5100               emitcode ("", "%05d$:", lbl->key + 100);
5101             }
5102         }
5103       /* mark the icode as generated */
5104       ifx->generated = 1;
5105       goto release;
5106     }
5107
5108   /* if they are both bit variables */
5109   if (AOP_TYPE (left) == AOP_CRY &&
5110       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5111     {
5112       if (AOP_TYPE (right) == AOP_LIT)
5113         {
5114           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5115           if (lit == 0L)
5116             {
5117               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5118               emitcode ("cpl", "c");
5119             }
5120           else if (lit == 1L)
5121             {
5122               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5123             }
5124           else
5125             {
5126               emitcode ("clr", "c");
5127             }
5128           /* AOP_TYPE(right) == AOP_CRY */
5129         }
5130       else
5131         {
5132           symbol *lbl = newiTempLabel (NULL);
5133           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5134           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5135           emitcode ("cpl", "c");
5136           emitcode ("", "%05d$:", (lbl->key + 100));
5137         }
5138       /* c = 1 if egal */
5139       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5140         {
5141           outBitC (result);
5142           goto release;
5143         }
5144       if (ifx)
5145         {
5146           genIfxJump (ifx, "c", left, right, result);
5147           goto release;
5148         }
5149       /* if the result is used in an arithmetic operation
5150          then put the result in place */
5151       outBitC (result);
5152     }
5153   else
5154     {
5155       gencjne (left, right, newiTempLabel (NULL));
5156       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5157         {
5158           aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
5159           goto release;
5160         }
5161       if (ifx)
5162         {
5163           genIfxJump (ifx, "a", left, right, result);
5164           goto release;
5165         }
5166       /* if the result is used in an arithmetic operation
5167          then put the result in place */
5168       if (AOP_TYPE (result) != AOP_CRY)
5169         outAcc (result);
5170       /* leave the result in acc */
5171     }
5172
5173 release:
5174   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5175   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5176   freeAsmop (result, NULL, ic, TRUE);
5177 }
5178
5179 /*-----------------------------------------------------------------*/
5180 /* ifxForOp - returns the icode containing the ifx for operand     */
5181 /*-----------------------------------------------------------------*/
5182 static iCode *
5183 ifxForOp (operand * op, iCode * ic)
5184 {
5185   /* if true symbol then needs to be assigned */
5186   if (IS_TRUE_SYMOP (op))
5187     return NULL;
5188
5189   /* if this has register type condition and
5190      the next instruction is ifx with the same operand
5191      and live to of the operand is upto the ifx only then */
5192   if (ic->next &&
5193       ic->next->op == IFX &&
5194       IC_COND (ic->next)->key == op->key &&
5195       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5196     return ic->next;
5197
5198   return NULL;
5199 }
5200
5201 /*-----------------------------------------------------------------*/
5202 /* hasInc - operand is incremented before any other use            */
5203 /*-----------------------------------------------------------------*/
5204 static iCode *
5205 hasInc (operand *op, iCode *ic,int osize)
5206 {
5207   sym_link *type = operandType(op);
5208   sym_link *retype = getSpec (type);
5209   iCode *lic = ic->next;
5210   int isize ;
5211
5212   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5213   if (!IS_SYMOP(op)) return NULL;
5214
5215   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5216   if (IS_AGGREGATE(type->next)) return NULL;
5217   if (osize != (isize = getSize(type->next))) return NULL;
5218
5219   while (lic) {
5220     /* if operand of the form op = op + <sizeof *op> */
5221     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5222         isOperandEqual(IC_RESULT(lic),op) &&
5223         isOperandLiteral(IC_RIGHT(lic)) &&
5224         operandLitValue(IC_RIGHT(lic)) == isize) {
5225       return lic;
5226     }
5227     /* if the operand used or deffed */
5228     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5229       return NULL;
5230     }
5231     /* if GOTO or IFX */
5232     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5233     lic = lic->next;
5234   }
5235   return NULL;
5236 }
5237
5238 /*-----------------------------------------------------------------*/
5239 /* genAndOp - for && operation                                     */
5240 /*-----------------------------------------------------------------*/
5241 static void
5242 genAndOp (iCode * ic)
5243 {
5244   operand *left, *right, *result;
5245   symbol *tlbl;
5246
5247   D(emitcode (";     genAndOp",""));
5248
5249   /* note here that && operations that are in an
5250      if statement are taken away by backPatchLabels
5251      only those used in arthmetic operations remain */
5252   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5253   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5254   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5255
5256   /* if both are bit variables */
5257   if (AOP_TYPE (left) == AOP_CRY &&
5258       AOP_TYPE (right) == AOP_CRY)
5259     {
5260       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5261       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5262       outBitC (result);
5263     }
5264   else
5265     {
5266       tlbl = newiTempLabel (NULL);
5267       toBoolean (left);
5268       emitcode ("jz", "%05d$", tlbl->key + 100);
5269       toBoolean (right);
5270       emitcode ("", "%05d$:", tlbl->key + 100);
5271       outBitAcc (result);
5272     }
5273
5274   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5275   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5276   freeAsmop (result, NULL, ic, TRUE);
5277 }
5278
5279
5280 /*-----------------------------------------------------------------*/
5281 /* genOrOp - for || operation                                      */
5282 /*-----------------------------------------------------------------*/
5283 static void
5284 genOrOp (iCode * ic)
5285 {
5286   operand *left, *right, *result;
5287   symbol *tlbl;
5288
5289   D(emitcode (";     genOrOp",""));
5290
5291   /* note here that || operations that are in an
5292      if statement are taken away by backPatchLabels
5293      only those used in arthmetic operations remain */
5294   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5295   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5296   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5297
5298   /* if both are bit variables */
5299   if (AOP_TYPE (left) == AOP_CRY &&
5300       AOP_TYPE (right) == AOP_CRY)
5301     {
5302       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5303       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5304       outBitC (result);
5305     }
5306   else
5307     {
5308       tlbl = newiTempLabel (NULL);
5309       toBoolean (left);
5310       emitcode ("jnz", "%05d$", tlbl->key + 100);
5311       toBoolean (right);
5312       emitcode ("", "%05d$:", tlbl->key + 100);
5313       outBitAcc (result);
5314     }
5315
5316   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5317   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5318   freeAsmop (result, NULL, ic, TRUE);
5319 }
5320
5321 /*-----------------------------------------------------------------*/
5322 /* isLiteralBit - test if lit == 2^n                               */
5323 /*-----------------------------------------------------------------*/
5324 static int
5325 isLiteralBit (unsigned long lit)
5326 {
5327   unsigned long pw[32] =
5328   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5329    0x100L, 0x200L, 0x400L, 0x800L,
5330    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5331    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5332    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5333    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5334    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5335   int idx;
5336
5337   for (idx = 0; idx < 32; idx++)
5338     if (lit == pw[idx])
5339       return idx + 1;
5340   return 0;
5341 }
5342
5343 /*-----------------------------------------------------------------*/
5344 /* continueIfTrue -                                                */
5345 /*-----------------------------------------------------------------*/
5346 static void
5347 continueIfTrue (iCode * ic)
5348 {
5349   if (IC_TRUE (ic))
5350     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5351   ic->generated = 1;
5352 }
5353
5354 /*-----------------------------------------------------------------*/
5355 /* jmpIfTrue -                                                     */
5356 /*-----------------------------------------------------------------*/
5357 static void
5358 jumpIfTrue (iCode * ic)
5359 {
5360   if (!IC_TRUE (ic))
5361     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5362   ic->generated = 1;
5363 }
5364
5365 /*-----------------------------------------------------------------*/
5366 /* jmpTrueOrFalse -                                                */
5367 /*-----------------------------------------------------------------*/
5368 static void
5369 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5370 {
5371   // ugly but optimized by peephole
5372   if (IC_TRUE (ic))
5373     {
5374       symbol *nlbl = newiTempLabel (NULL);
5375       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5376       emitcode ("", "%05d$:", tlbl->key + 100);
5377       freeForBranchAsmop (result);
5378       freeForBranchAsmop (right);
5379       freeForBranchAsmop (left);
5380       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5381       emitcode ("", "%05d$:", nlbl->key + 100);
5382     }
5383   else
5384     {
5385       freeForBranchAsmop (result);
5386       freeForBranchAsmop (right);
5387       freeForBranchAsmop (left);
5388       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5389       emitcode ("", "%05d$:", tlbl->key + 100);
5390     }
5391   ic->generated = 1;
5392 }
5393
5394 /*-----------------------------------------------------------------*/
5395 /* genAnd  - code for and                                          */
5396 /*-----------------------------------------------------------------*/
5397 static void
5398 genAnd (iCode * ic, iCode * ifx)
5399 {
5400   operand *left, *right, *result;
5401   int size, offset = 0;
5402   unsigned long lit = 0L;
5403   int bytelit = 0;
5404   char buffer[10];
5405
5406   D(emitcode (";     genAnd",""));
5407
5408   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5409   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5410   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5411
5412 #ifdef DEBUG_TYPE
5413   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5414             AOP_TYPE (result),
5415             AOP_TYPE (left), AOP_TYPE (right));
5416   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5417             AOP_SIZE (result),
5418             AOP_SIZE (left), AOP_SIZE (right));
5419 #endif
5420
5421   /* if left is a literal & right is not then exchange them */
5422   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5423       AOP_NEEDSACC (left))
5424     {
5425       operand *tmp = right;
5426       right = left;
5427       left = tmp;
5428     }
5429
5430   /* if result = right then exchange left and right */
5431   if (sameRegs (AOP (result), AOP (right)))
5432     {
5433       operand *tmp = right;
5434       right = left;
5435       left = tmp;
5436     }
5437
5438   /* if right is bit then exchange them */
5439   if (AOP_TYPE (right) == AOP_CRY &&
5440       AOP_TYPE (left) != AOP_CRY)
5441     {
5442       operand *tmp = right;
5443       right = left;
5444       left = tmp;
5445     }
5446   if (AOP_TYPE (right) == AOP_LIT)
5447     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5448
5449   size = AOP_SIZE (result);
5450
5451   // if(bit & yy)
5452   // result = bit & yy;
5453   if (AOP_TYPE (left) == AOP_CRY)
5454     {
5455       // c = bit & literal;
5456       if (AOP_TYPE (right) == AOP_LIT)
5457         {
5458           if (lit & 1)
5459             {
5460               if (size && sameRegs (AOP (result), AOP (left)))
5461                 // no change
5462                 goto release;
5463               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5464             }
5465           else
5466             {
5467               // bit(result) = 0;
5468               if (size && (AOP_TYPE (result) == AOP_CRY))
5469                 {
5470                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5471                   goto release;
5472                 }
5473               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5474                 {
5475                   jumpIfTrue (ifx);
5476                   goto release;
5477                 }
5478               emitcode ("clr", "c");
5479             }
5480         }
5481       else
5482         {
5483           if (AOP_TYPE (right) == AOP_CRY)
5484             {
5485               // c = bit & bit;
5486               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5487               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5488             }
5489           else
5490             {
5491               // c = bit & val;
5492               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
5493               // c = lsb
5494               emitcode ("rrc", "a");
5495               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5496             }
5497         }
5498       // bit = c
5499       // val = c
5500       if (size)
5501         outBitC (result);
5502       // if(bit & ...)
5503       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5504         genIfxJump (ifx, "c", left, right, result);
5505       goto release;
5506     }
5507
5508   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5509   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5510   if ((AOP_TYPE (right) == AOP_LIT) &&
5511       (AOP_TYPE (result) == AOP_CRY) &&
5512       (AOP_TYPE (left) != AOP_CRY))
5513     {
5514       int posbit = isLiteralBit (lit);
5515       /* left &  2^n */
5516       if (posbit)
5517         {
5518           posbit--;
5519           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE));
5520           // bit = left & 2^n
5521           if (size)
5522             emitcode ("mov", "c,acc.%d", posbit & 0x07);
5523           // if(left &  2^n)
5524           else
5525             {
5526               if (ifx)
5527                 {
5528                   SNPRINTF (buffer, sizeof(buffer),
5529                             "acc.%d", posbit & 0x07);
5530                   genIfxJump (ifx, buffer, left, right, result);
5531                 }
5532               else 
5533                 {// what is this case? just found it in ds390/gen.c
5534                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
5535                 }
5536               goto release;
5537             }
5538         }
5539       else
5540         {
5541           symbol *tlbl = newiTempLabel (NULL);
5542           int sizel = AOP_SIZE (left);
5543           if (size)
5544             emitcode ("setb", "c");
5545           while (sizel--)
5546             {
5547               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5548                 {
5549                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5550                   // byte ==  2^n ?
5551                   if ((posbit = isLiteralBit (bytelit)) != 0)
5552                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5553                   else
5554                     {
5555                       if (bytelit != 0x0FFL)
5556                         emitcode ("anl", "a,%s",
5557                                   aopGet (AOP (right), offset, FALSE, TRUE));
5558                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5559                     }
5560                 }
5561               offset++;
5562             }
5563           // bit = left & literal
5564           if (size)
5565             {
5566               emitcode ("clr", "c");
5567               emitcode ("", "%05d$:", tlbl->key + 100);
5568             }
5569           // if(left & literal)
5570           else
5571             {
5572               if (ifx)
5573                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5574               else
5575                 emitcode ("", "%05d$:", tlbl->key + 100);
5576               goto release;
5577             }
5578         }
5579       outBitC (result);
5580       goto release;
5581     }
5582
5583   /* if left is same as result */
5584   if (sameRegs (AOP (result), AOP (left)))
5585     {
5586       for (; size--; offset++)
5587         {
5588           if (AOP_TYPE (right) == AOP_LIT)
5589             {
5590               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5591               if (bytelit == 0x0FF)
5592                 {
5593                   /* dummy read of volatile operand */
5594                   if (isOperandVolatile (left, FALSE))
5595                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5596                   else
5597                 continue;
5598                 }
5599               else if (bytelit == 0)
5600                 {
5601                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5602                 }
5603               else if (IS_AOP_PREG (result))
5604                 {
5605                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5606                   emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5607                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5608                 }
5609               else
5610                 emitcode ("anl", "%s,%s",
5611                           aopGet (AOP (left), offset, FALSE, TRUE),
5612                           aopGet (AOP (right), offset, FALSE, FALSE));
5613             }
5614           else
5615             {
5616               if (AOP_TYPE (left) == AOP_ACC)
5617                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5618               else
5619                 {
5620                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5621                   if (IS_AOP_PREG (result))
5622                     {
5623                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5624                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5625                     }
5626                   else
5627                     emitcode ("anl", "%s,a",
5628                               aopGet (AOP (left), offset, FALSE, TRUE));
5629                 }
5630             }
5631         }
5632     }
5633   else
5634     {
5635       // left & result in different registers
5636       if (AOP_TYPE (result) == AOP_CRY)
5637         {
5638           // result = bit
5639           // if(size), result in bit
5640           // if(!size && ifx), conditional oper: if(left & right)
5641           symbol *tlbl = newiTempLabel (NULL);
5642           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5643           if (size)
5644             emitcode ("setb", "c");
5645           while (sizer--)
5646             {
5647               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5648                 emitcode ("anl", "a,%s",
5649                           aopGet (AOP (right), offset, FALSE, FALSE));
5650               } else {
5651                 if (AOP_TYPE(left)==AOP_ACC) {
5652                   emitcode("mov", "b,a");
5653                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5654                   emitcode("anl", "a,b");
5655                 }else {
5656                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5657                   emitcode ("anl", "a,%s",
5658                             aopGet (AOP (left), offset, FALSE, FALSE));
5659                 }
5660               }
5661               emitcode ("jnz", "%05d$", tlbl->key + 100);
5662               offset++;
5663             }
5664           if (size)
5665             {
5666               CLRC;
5667               emitcode ("", "%05d$:", tlbl->key + 100);
5668               outBitC (result);
5669             }
5670           else if (ifx)
5671             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5672           else
5673             emitcode ("", "%05d$:", tlbl->key + 100);
5674         }
5675       else
5676         {
5677           for (; (size--); offset++)
5678             {
5679               // normal case
5680               // result = left & right
5681               if (AOP_TYPE (right) == AOP_LIT)
5682                 {
5683                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5684                   if (bytelit == 0x0FF)
5685                     {
5686                       aopPut (AOP (result),
5687                               aopGet (AOP (left), offset, FALSE, FALSE),
5688                               offset,
5689                               isOperandVolatile (result, FALSE));
5690                       continue;
5691                     }
5692                   else if (bytelit == 0)
5693                     {
5694                       /* dummy read of volatile operand */
5695                       if (isOperandVolatile (left, FALSE))
5696                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5697                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5698                       continue;
5699                     }
5700                 }
5701               // faster than result <- left, anl result,right
5702               // and better if result is SFR
5703               if (AOP_TYPE (left) == AOP_ACC)
5704                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5705               else
5706                 {
5707                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5708                   emitcode ("anl", "a,%s",
5709                             aopGet (AOP (left), offset, FALSE, FALSE));
5710                 }
5711               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5712             }
5713         }
5714     }
5715
5716 release:
5717   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5718   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5719   freeAsmop (result, NULL, ic, TRUE);
5720 }
5721
5722 /*-----------------------------------------------------------------*/
5723 /* genOr  - code for or                                            */
5724 /*-----------------------------------------------------------------*/
5725 static void
5726 genOr (iCode * ic, iCode * ifx)
5727 {
5728   operand *left, *right, *result;
5729   int size, offset = 0;
5730   unsigned long lit = 0L;
5731   int bytelit = 0;
5732
5733   D(emitcode (";     genOr",""));
5734
5735   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5736   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5737   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5738
5739 #ifdef DEBUG_TYPE
5740   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5741             AOP_TYPE (result),
5742             AOP_TYPE (left), AOP_TYPE (right));
5743   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5744             AOP_SIZE (result),
5745             AOP_SIZE (left), AOP_SIZE (right));
5746 #endif
5747
5748   /* if left is a literal & right is not then exchange them */
5749   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5750       AOP_NEEDSACC (left))
5751     {
5752       operand *tmp = right;
5753       right = left;
5754       left = tmp;
5755     }
5756
5757   /* if result = right then exchange them */
5758   if (sameRegs (AOP (result), AOP (right)))
5759     {
5760       operand *tmp = right;
5761       right = left;
5762       left = tmp;
5763     }
5764
5765   /* if right is bit then exchange them */
5766   if (AOP_TYPE (right) == AOP_CRY &&
5767       AOP_TYPE (left) != AOP_CRY)
5768     {
5769       operand *tmp = right;
5770       right = left;
5771       left = tmp;
5772     }
5773   if (AOP_TYPE (right) == AOP_LIT)
5774     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5775
5776   size = AOP_SIZE (result);
5777
5778   // if(bit | yy)
5779   // xx = bit | yy;
5780   if (AOP_TYPE (left) == AOP_CRY)
5781     {
5782       if (AOP_TYPE (right) == AOP_LIT)
5783         {
5784           // c = bit | literal;
5785           if (lit)
5786             {
5787               // lit != 0 => result = 1
5788               if (AOP_TYPE (result) == AOP_CRY)
5789                 {
5790                   if (size)
5791                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5792                   else if (ifx)
5793                     continueIfTrue (ifx);
5794                   goto release;
5795                 }
5796               emitcode ("setb", "c");
5797             }
5798           else
5799             {
5800               // lit == 0 => result = left
5801               if (size && sameRegs (AOP (result), AOP (left)))
5802                 goto release;
5803               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5804             }
5805         }
5806       else
5807         {
5808           if (AOP_TYPE (right) == AOP_CRY)
5809             {
5810               // c = bit | bit;
5811               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5812               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
5813             }
5814           else
5815             {
5816               // c = bit | val;
5817               symbol *tlbl = newiTempLabel (NULL);
5818               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
5819                 emitcode ("setb", "c");
5820               emitcode ("jb", "%s,%05d$",
5821                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
5822               toBoolean (right);
5823               emitcode ("jnz", "%05d$", tlbl->key + 100);
5824               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5825                 {
5826                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
5827                   goto release;
5828                 }
5829               else
5830                 {
5831                   CLRC;
5832                   emitcode ("", "%05d$:", tlbl->key + 100);
5833                 }
5834             }
5835         }
5836       // bit = c
5837       // val = c
5838       if (size)
5839         outBitC (result);
5840       // if(bit | ...)
5841       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5842         genIfxJump (ifx, "c", left, right, result);
5843       goto release;
5844     }
5845
5846   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5847   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5848   if ((AOP_TYPE (right) == AOP_LIT) &&
5849       (AOP_TYPE (result) == AOP_CRY) &&
5850       (AOP_TYPE (left) != AOP_CRY))
5851     {
5852       if (lit)
5853         {
5854           // result = 1
5855           if (size)
5856             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5857           else
5858             continueIfTrue (ifx);
5859           goto release;
5860         }
5861       else
5862         {
5863           // lit = 0, result = boolean(left)
5864           if (size)
5865             emitcode ("setb", "c");
5866           toBoolean (right);
5867           if (size)
5868             {
5869               symbol *tlbl = newiTempLabel (NULL);
5870               emitcode ("jnz", "%05d$", tlbl->key + 100);
5871               CLRC;
5872               emitcode ("", "%05d$:", tlbl->key + 100);
5873             }
5874           else
5875             {
5876               genIfxJump (ifx, "a", left, right, result);
5877               goto release;
5878             }
5879         }
5880       outBitC (result);
5881       goto release;
5882     }
5883
5884   /* if left is same as result */
5885   if (sameRegs (AOP (result), AOP (left)))
5886     {
5887       for (; size--; offset++)
5888         {
5889           if (AOP_TYPE (right) == AOP_LIT)
5890             {
5891               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5892               if (bytelit == 0)
5893                 {
5894                   /* dummy read of volatile operand */
5895                   if (isOperandVolatile (left, FALSE))
5896                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5897                   else
5898                     continue;
5899                 }
5900               else if (bytelit == 0x0FF)
5901                 {
5902                   aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
5903                 }
5904               else if (IS_AOP_PREG (left))
5905                 {
5906                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5907                   emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5908                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5909                 }
5910               else
5911                 {
5912                   emitcode ("orl", "%s,%s",
5913                             aopGet (AOP (left), offset, FALSE, TRUE),
5914                             aopGet (AOP (right), offset, FALSE, FALSE));
5915                 }
5916             }
5917           else
5918             {
5919               if (AOP_TYPE (left) == AOP_ACC)
5920                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5921               else
5922                 {
5923                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5924                   if (IS_AOP_PREG (left))
5925                     {
5926                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5927                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5928                     }
5929                   else
5930                     {
5931                       emitcode ("orl", "%s,a",
5932                                 aopGet (AOP (left), offset, FALSE, TRUE));
5933                     }
5934                 }
5935             }
5936         }
5937     }
5938   else
5939     {
5940       // left & result in different registers
5941       if (AOP_TYPE (result) == AOP_CRY)
5942         {
5943           // result = bit
5944           // if(size), result in bit
5945           // if(!size && ifx), conditional oper: if(left | right)
5946           symbol *tlbl = newiTempLabel (NULL);
5947           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
5948           if (size)
5949             emitcode ("setb", "c");
5950           while (sizer--)
5951             {
5952               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5953                 emitcode ("orl", "a,%s",
5954                           aopGet (AOP (right), offset, FALSE, FALSE));
5955               } else {
5956                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5957                 emitcode ("orl", "a,%s",
5958                           aopGet (AOP (left), offset, FALSE, FALSE));
5959               }
5960               emitcode ("jnz", "%05d$", tlbl->key + 100);
5961               offset++;
5962             }
5963           if (size)
5964             {
5965               CLRC;
5966               emitcode ("", "%05d$:", tlbl->key + 100);
5967               outBitC (result);
5968             }
5969           else if (ifx)
5970             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5971           else
5972             emitcode ("", "%05d$:", tlbl->key + 100);
5973         }
5974       else
5975         {
5976           for (; (size--); offset++)
5977             {
5978               // normal case
5979               // result = left | right
5980               if (AOP_TYPE (right) == AOP_LIT)
5981                 {
5982                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5983                   if (bytelit == 0)
5984                     {
5985                       aopPut (AOP (result),
5986                               aopGet (AOP (left), offset, FALSE, FALSE),
5987                               offset,
5988                               isOperandVolatile (result, FALSE));
5989                       continue;
5990                     }
5991                   else if (bytelit == 0x0FF)
5992                     {
5993                       /* dummy read of volatile operand */
5994                       if (isOperandVolatile (left, FALSE))
5995                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5996                       aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
5997                       continue;
5998                     }
5999                 }
6000               // faster than result <- left, anl result,right
6001               // and better if result is SFR
6002               if (AOP_TYPE (left) == AOP_ACC)
6003                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6004               else
6005                 {
6006                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6007                   emitcode ("orl", "a,%s",
6008                             aopGet (AOP (left), offset, FALSE, FALSE));
6009                 }
6010               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6011             }
6012         }
6013     }
6014
6015 release:
6016   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6017   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6018   freeAsmop (result, NULL, ic, TRUE);
6019 }
6020
6021 /*-----------------------------------------------------------------*/
6022 /* genXor - code for xclusive or                                   */
6023 /*-----------------------------------------------------------------*/
6024 static void
6025 genXor (iCode * ic, iCode * ifx)
6026 {
6027   operand *left, *right, *result;
6028   int size, offset = 0;
6029   unsigned long lit = 0L;
6030   int bytelit = 0;
6031
6032   D(emitcode (";     genXor",""));
6033
6034   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6035   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6036   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6037
6038 #ifdef DEBUG_TYPE
6039   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6040             AOP_TYPE (result),
6041             AOP_TYPE (left), AOP_TYPE (right));
6042   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6043             AOP_SIZE (result),
6044             AOP_SIZE (left), AOP_SIZE (right));
6045 #endif
6046
6047   /* if left is a literal & right is not ||
6048      if left needs acc & right does not */
6049   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6050       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6051     {
6052       operand *tmp = right;
6053       right = left;
6054       left = tmp;
6055     }
6056
6057   /* if result = right then exchange them */
6058   if (sameRegs (AOP (result), AOP (right)))
6059     {
6060       operand *tmp = right;
6061       right = left;
6062       left = tmp;
6063     }
6064
6065   /* if right is bit then exchange them */
6066   if (AOP_TYPE (right) == AOP_CRY &&
6067       AOP_TYPE (left) != AOP_CRY)
6068     {
6069       operand *tmp = right;
6070       right = left;
6071       left = tmp;
6072     }
6073   if (AOP_TYPE (right) == AOP_LIT)
6074     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6075
6076   size = AOP_SIZE (result);
6077
6078   // if(bit ^ yy)
6079   // xx = bit ^ yy;
6080   if (AOP_TYPE (left) == AOP_CRY)
6081     {
6082       if (AOP_TYPE (right) == AOP_LIT)
6083         {
6084           // c = bit & literal;
6085           if (lit >> 1)
6086             {
6087               // lit>>1  != 0 => result = 1
6088               if (AOP_TYPE (result) == AOP_CRY)
6089                 {
6090                   if (size)
6091                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6092                   else if (ifx)
6093                     continueIfTrue (ifx);
6094                   goto release;
6095                 }
6096               emitcode ("setb", "c");
6097             }
6098           else
6099             {
6100               // lit == (0 or 1)
6101               if (lit == 0)
6102                 {
6103                   // lit == 0, result = left
6104                   if (size && sameRegs (AOP (result), AOP (left)))
6105                     goto release;
6106                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6107                 }
6108               else
6109                 {
6110                   // lit == 1, result = not(left)
6111                   if (size && sameRegs (AOP (result), AOP (left)))
6112                     {
6113                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6114                       goto release;
6115                     }
6116                   else
6117                     {
6118                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6119                       emitcode ("cpl", "c");
6120                     }
6121                 }
6122             }
6123
6124         }
6125       else
6126         {
6127           // right != literal
6128           symbol *tlbl = newiTempLabel (NULL);
6129           if (AOP_TYPE (right) == AOP_CRY)
6130             {
6131               // c = bit ^ bit;
6132               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6133             }
6134           else
6135             {
6136               int sizer = AOP_SIZE (right);
6137               // c = bit ^ val
6138               // if val>>1 != 0, result = 1
6139               emitcode ("setb", "c");
6140               while (sizer)
6141                 {
6142                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
6143                   if (sizer == 1)
6144                     // test the msb of the lsb
6145                     emitcode ("anl", "a,#0xfe");
6146                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6147                   sizer--;
6148                 }
6149               // val = (0,1)
6150               emitcode ("rrc", "a");
6151             }
6152           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6153           emitcode ("cpl", "c");
6154           emitcode ("", "%05d$:", (tlbl->key + 100));
6155         }
6156       // bit = c
6157       // val = c
6158       if (size)
6159         outBitC (result);
6160       // if(bit | ...)
6161       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6162         genIfxJump (ifx, "c", left, right, result);
6163       goto release;
6164     }
6165
6166   /* if left is same as result */
6167   if (sameRegs (AOP (result), AOP (left)))
6168     {
6169       for (; size--; offset++)
6170         {
6171           if (AOP_TYPE (right) == AOP_LIT)
6172             {
6173               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6174               if (bytelit == 0)
6175                 {
6176                   /* dummy read of volatile operand */
6177                   if (isOperandVolatile (left, FALSE))
6178                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6179                   else
6180                 continue;
6181                 }
6182               else if (IS_AOP_PREG (left))
6183                 {
6184                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6185                   emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6186                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6187                 }
6188               else
6189                 {
6190                   emitcode ("xrl", "%s,%s",
6191                             aopGet (AOP (left), offset, FALSE, TRUE),
6192                             aopGet (AOP (right), offset, FALSE, FALSE));
6193                 }
6194             }
6195           else
6196             {
6197               if (AOP_TYPE (left) == AOP_ACC)
6198                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6199               else
6200                 {
6201                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6202                   if (IS_AOP_PREG (left))
6203                     {
6204                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6205                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6206                     }
6207                   else
6208                     emitcode ("xrl", "%s,a",
6209                               aopGet (AOP (left), offset, FALSE, TRUE));
6210                 }
6211             }
6212         }
6213     }
6214   else
6215     {
6216       // left & result in different registers
6217       if (AOP_TYPE (result) == AOP_CRY)
6218         {
6219           // result = bit
6220           // if(size), result in bit
6221           // if(!size && ifx), conditional oper: if(left ^ right)
6222           symbol *tlbl = newiTempLabel (NULL);
6223           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6224           if (size)
6225             emitcode ("setb", "c");
6226           while (sizer--)
6227             {
6228               if ((AOP_TYPE (right) == AOP_LIT) &&
6229                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6230                 {
6231                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6232                 }
6233               else
6234                 {
6235                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6236                     emitcode ("xrl", "a,%s",
6237                               aopGet (AOP (right), offset, FALSE, FALSE));
6238                   } else {
6239                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6240                     emitcode ("xrl", "a,%s",
6241                               aopGet (AOP (left), offset, FALSE, FALSE));
6242                   }
6243                 }
6244               emitcode ("jnz", "%05d$", tlbl->key + 100);
6245               offset++;
6246             }
6247           if (size)
6248             {
6249               CLRC;
6250               emitcode ("", "%05d$:", tlbl->key + 100);
6251               outBitC (result);
6252             }
6253           else if (ifx)
6254             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6255         }
6256       else
6257         {
6258           for (; (size--); offset++)
6259             {
6260               // normal case
6261               // result = left & right
6262               if (AOP_TYPE (right) == AOP_LIT)
6263                 {
6264                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6265                   if (bytelit == 0)
6266                     {
6267                       aopPut (AOP (result),
6268                               aopGet (AOP (left), offset, FALSE, FALSE),
6269                               offset,
6270                               isOperandVolatile (result, FALSE));
6271                       continue;
6272                     }
6273                 }
6274               // faster than result <- left, anl result,right
6275               // and better if result is SFR
6276               if (AOP_TYPE (left) == AOP_ACC)
6277                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6278               else
6279                 {
6280                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6281                   emitcode ("xrl", "a,%s",
6282                             aopGet (AOP (left), offset, FALSE, TRUE));
6283                 }
6284               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6285             }
6286         }
6287     }
6288
6289 release:
6290   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6291   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6292   freeAsmop (result, NULL, ic, TRUE);
6293 }
6294
6295 /*-----------------------------------------------------------------*/
6296 /* genInline - write the inline code out                           */
6297 /*-----------------------------------------------------------------*/
6298 static void
6299 genInline (iCode * ic)
6300 {
6301   char *buffer, *bp, *bp1;
6302
6303   D(emitcode (";     genInline",""));
6304
6305   _G.inLine += (!options.asmpeep);
6306
6307   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6308   strcpy (buffer, IC_INLINE (ic));
6309
6310   /* emit each line as a code */
6311   while (*bp)
6312     {
6313       if (*bp == '\n')
6314         {
6315           *bp++ = '\0';
6316           emitcode (bp1, "");
6317           bp1 = bp;
6318         }
6319       else
6320         {
6321           /* Add \n for labels, not dirs such as c:\mydir */
6322           if ( (*bp == ':') && (isspace(bp[1])) )
6323             {
6324               bp++;
6325               *bp = '\0';
6326               bp++;
6327               emitcode (bp1, "");
6328               bp1 = bp;
6329             }
6330           else
6331             bp++;
6332         }
6333     }
6334   if (bp1 != bp)
6335     emitcode (bp1, "");
6336   /*     emitcode("",buffer); */
6337   _G.inLine -= (!options.asmpeep);
6338 }
6339
6340 /*-----------------------------------------------------------------*/
6341 /* genRRC - rotate right with carry                                */
6342 /*-----------------------------------------------------------------*/
6343 static void
6344 genRRC (iCode * ic)
6345 {
6346   operand *left, *result;
6347   int size, offset = 0;
6348   char *l;
6349
6350   D(emitcode (";     genRRC",""));
6351
6352   /* rotate right with carry */
6353   left = IC_LEFT (ic);
6354   result = IC_RESULT (ic);
6355   aopOp (left, ic, FALSE);
6356   aopOp (result, ic, FALSE);
6357
6358   /* move it to the result */
6359   size = AOP_SIZE (result);
6360   offset = size - 1;
6361   if (size == 1) { /* special case for 1 byte */
6362       l = aopGet (AOP (left), offset, FALSE, FALSE);
6363       MOVA (l);
6364       emitcode ("rr", "a");
6365       goto release;
6366   }
6367   CLRC;
6368   while (size--)
6369     {
6370       l = aopGet (AOP (left), offset, FALSE, FALSE);
6371       MOVA (l);
6372       emitcode ("rrc", "a");
6373       if (AOP_SIZE (result) > 1)
6374         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6375     }
6376   /* now we need to put the carry into the
6377      highest order byte of the result */
6378   if (AOP_SIZE (result) > 1)
6379     {
6380       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6381       MOVA (l);
6382     }
6383   emitcode ("mov", "acc.7,c");
6384  release:
6385   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6386   freeAsmop (left, NULL, ic, TRUE);
6387   freeAsmop (result, NULL, ic, TRUE);
6388 }
6389
6390 /*-----------------------------------------------------------------*/
6391 /* genRLC - generate code for rotate left with carry               */
6392 /*-----------------------------------------------------------------*/
6393 static void
6394 genRLC (iCode * ic)
6395 {
6396   operand *left, *result;
6397   int size, offset = 0;
6398   char *l;
6399
6400   D(emitcode (";     genRLC",""));
6401
6402   /* rotate right with carry */
6403   left = IC_LEFT (ic);
6404   result = IC_RESULT (ic);
6405   aopOp (left, ic, FALSE);
6406   aopOp (result, ic, FALSE);
6407
6408   /* move it to the result */
6409   size = AOP_SIZE (result);
6410   offset = 0;
6411   if (size--)
6412     {
6413       l = aopGet (AOP (left), offset, FALSE, FALSE);
6414       MOVA (l);
6415       if (size == 0) { /* special case for 1 byte */
6416               emitcode("rl","a");
6417               goto release;
6418       }
6419       emitcode ("add", "a,acc");
6420       if (AOP_SIZE (result) > 1)
6421         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6422       while (size--)
6423         {
6424           l = aopGet (AOP (left), offset, FALSE, FALSE);
6425           MOVA (l);
6426           emitcode ("rlc", "a");
6427           if (AOP_SIZE (result) > 1)
6428             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6429         }
6430     }
6431   /* now we need to put the carry into the
6432      highest order byte of the result */
6433   if (AOP_SIZE (result) > 1)
6434     {
6435       l = aopGet (AOP (result), 0, FALSE, FALSE);
6436       MOVA (l);
6437     }
6438   emitcode ("mov", "acc.0,c");
6439  release:
6440   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6441   freeAsmop (left, NULL, ic, TRUE);
6442   freeAsmop (result, NULL, ic, TRUE);
6443 }
6444
6445 /*-----------------------------------------------------------------*/
6446 /* genGetHbit - generates code get highest order bit               */
6447 /*-----------------------------------------------------------------*/
6448 static void
6449 genGetHbit (iCode * ic)
6450 {
6451   operand *left, *result;
6452
6453   D(emitcode (";     genGetHbit",""));
6454
6455   left = IC_LEFT (ic);
6456   result = IC_RESULT (ic);
6457   aopOp (left, ic, FALSE);
6458   aopOp (result, ic, FALSE);
6459
6460   /* get the highest order byte into a */
6461   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6462   if (AOP_TYPE (result) == AOP_CRY)
6463     {
6464       emitcode ("rlc", "a");
6465       outBitC (result);
6466     }
6467   else
6468     {
6469       emitcode ("rl", "a");
6470       emitcode ("anl", "a,#0x01");
6471       outAcc (result);
6472     }
6473
6474
6475   freeAsmop (left, NULL, ic, TRUE);
6476   freeAsmop (result, NULL, ic, TRUE);
6477 }
6478
6479 /*-----------------------------------------------------------------*/
6480 /* genSwap - generates code to swap nibbles or bytes               */
6481 /*-----------------------------------------------------------------*/
6482 static void
6483 genSwap (iCode * ic)
6484 {
6485   operand *left, *result;
6486
6487   D(emitcode (";     genSwap",""));
6488
6489   left = IC_LEFT (ic);
6490   result = IC_RESULT (ic);
6491   aopOp (left, ic, FALSE);
6492   aopOp (result, ic, FALSE);
6493
6494   switch (AOP_SIZE (left))
6495     {
6496     case 1: /* swap nibbles in byte */
6497       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6498       emitcode ("swap", "a");
6499       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6500       break;
6501     case 2: /* swap bytes in word */
6502       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6503         {
6504           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6505           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6506                   0, isOperandVolatile (result, FALSE));
6507           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6508         }
6509       else if (operandsEqu (left, result))
6510         {
6511           char * reg = "a";
6512           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6513           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6514             {
6515               emitcode ("mov", "b,a");
6516               reg = "b";
6517             }
6518           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6519                   0, isOperandVolatile (result, FALSE));
6520           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6521         }
6522       else
6523         {
6524           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6525                   0, isOperandVolatile (result, FALSE));
6526           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6527                   1, isOperandVolatile (result, FALSE));
6528         }
6529       break;
6530     default:
6531       wassertl(FALSE, "unsupported SWAP operand size");
6532     }
6533
6534   freeAsmop (left, NULL, ic, TRUE);
6535   freeAsmop (result, NULL, ic, TRUE);
6536 }
6537
6538
6539 /*-----------------------------------------------------------------*/
6540 /* AccRol - rotate left accumulator by known count                 */
6541 /*-----------------------------------------------------------------*/
6542 static void
6543 AccRol (int shCount)
6544 {
6545   shCount &= 0x0007;            // shCount : 0..7
6546
6547   switch (shCount)
6548     {
6549     case 0:
6550       break;
6551     case 1:
6552       emitcode ("rl", "a");
6553       break;
6554     case 2:
6555       emitcode ("rl", "a");
6556       emitcode ("rl", "a");
6557       break;
6558     case 3:
6559       emitcode ("swap", "a");
6560       emitcode ("rr", "a");
6561       break;
6562     case 4:
6563       emitcode ("swap", "a");
6564       break;
6565     case 5:
6566       emitcode ("swap", "a");
6567       emitcode ("rl", "a");
6568       break;
6569     case 6:
6570       emitcode ("rr", "a");
6571       emitcode ("rr", "a");
6572       break;
6573     case 7:
6574       emitcode ("rr", "a");
6575       break;
6576     }
6577 }
6578
6579 /*-----------------------------------------------------------------*/
6580 /* AccLsh - left shift accumulator by known count                  */
6581 /*-----------------------------------------------------------------*/
6582 static void
6583 AccLsh (int shCount)
6584 {
6585   if (shCount != 0)
6586     {
6587       if (shCount == 1)
6588         emitcode ("add", "a,acc");
6589       else if (shCount == 2)
6590         {
6591           emitcode ("add", "a,acc");
6592           emitcode ("add", "a,acc");
6593         }
6594       else
6595         {
6596           /* rotate left accumulator */
6597           AccRol (shCount);
6598           /* and kill the lower order bits */
6599           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6600         }
6601     }
6602 }
6603
6604 /*-----------------------------------------------------------------*/
6605 /* AccRsh - right shift accumulator by known count                 */
6606 /*-----------------------------------------------------------------*/
6607 static void
6608 AccRsh (int shCount)
6609 {
6610   if (shCount != 0)
6611     {
6612       if (shCount == 1)
6613         {
6614           CLRC;
6615           emitcode ("rrc", "a");
6616         }
6617       else
6618         {
6619           /* rotate right accumulator */
6620           AccRol (8 - shCount);
6621           /* and kill the higher order bits */
6622           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6623         }
6624     }
6625 }
6626
6627 /*-----------------------------------------------------------------*/
6628 /* AccSRsh - signed right shift accumulator by known count                 */
6629 /*-----------------------------------------------------------------*/
6630 static void
6631 AccSRsh (int shCount)
6632 {
6633   symbol *tlbl;
6634   if (shCount != 0)
6635     {
6636       if (shCount == 1)
6637         {
6638           emitcode ("mov", "c,acc.7");
6639           emitcode ("rrc", "a");
6640         }
6641       else if (shCount == 2)
6642         {
6643           emitcode ("mov", "c,acc.7");
6644           emitcode ("rrc", "a");
6645           emitcode ("mov", "c,acc.7");
6646           emitcode ("rrc", "a");
6647         }
6648       else
6649         {
6650           tlbl = newiTempLabel (NULL);
6651           /* rotate right accumulator */
6652           AccRol (8 - shCount);
6653           /* and kill the higher order bits */
6654           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6655           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6656           emitcode ("orl", "a,#0x%02x",
6657                     (unsigned char) ~SRMask[shCount]);
6658           emitcode ("", "%05d$:", tlbl->key + 100);
6659         }
6660     }
6661 }
6662
6663 /*-----------------------------------------------------------------*/
6664 /* shiftR1Left2Result - shift right one byte from left to result   */
6665 /*-----------------------------------------------------------------*/
6666 static void
6667 shiftR1Left2Result (operand * left, int offl,
6668                     operand * result, int offr,
6669                     int shCount, int sign)
6670 {
6671   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6672   /* shift right accumulator */
6673   if (sign)
6674     AccSRsh (shCount);
6675   else
6676     AccRsh (shCount);
6677   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6678 }
6679
6680 /*-----------------------------------------------------------------*/
6681 /* shiftL1Left2Result - shift left one byte from left to result    */
6682 /*-----------------------------------------------------------------*/
6683 static void
6684 shiftL1Left2Result (operand * left, int offl,
6685                     operand * result, int offr, int shCount)
6686 {
6687   char *l;
6688   l = aopGet (AOP (left), offl, FALSE, FALSE);
6689   MOVA (l);
6690   /* shift left accumulator */
6691   AccLsh (shCount);
6692   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6693 }
6694
6695 /*-----------------------------------------------------------------*/
6696 /* movLeft2Result - move byte from left to result                  */
6697 /*-----------------------------------------------------------------*/
6698 static void
6699 movLeft2Result (operand * left, int offl,
6700                 operand * result, int offr, int sign)
6701 {
6702   char *l;
6703   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
6704     {
6705       l = aopGet (AOP (left), offl, FALSE, FALSE);
6706
6707       if (*l == '@' && (IS_AOP_PREG (result)))
6708         {
6709           emitcode ("mov", "a,%s", l);
6710           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6711         }
6712       else
6713         {
6714           if (!sign)
6715             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
6716           else
6717             {
6718               /* MSB sign in acc.7 ! */
6719               if (getDataSize (left) == offl + 1)
6720                 {
6721                   emitcode ("mov", "a,%s", l);
6722                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6723                 }
6724             }
6725         }
6726     }
6727 }
6728
6729 /*-----------------------------------------------------------------*/
6730 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
6731 /*-----------------------------------------------------------------*/
6732 static void
6733 AccAXRrl1 (char *x)
6734 {
6735   emitcode ("rrc", "a");
6736   emitcode ("xch", "a,%s", x);
6737   emitcode ("rrc", "a");
6738   emitcode ("xch", "a,%s", x);
6739 }
6740
6741 /*-----------------------------------------------------------------*/
6742 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
6743 /*-----------------------------------------------------------------*/
6744 static void
6745 AccAXLrl1 (char *x)
6746 {
6747   emitcode ("xch", "a,%s", x);
6748   emitcode ("rlc", "a");
6749   emitcode ("xch", "a,%s", x);
6750   emitcode ("rlc", "a");
6751 }
6752
6753 /*-----------------------------------------------------------------*/
6754 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
6755 /*-----------------------------------------------------------------*/
6756 static void
6757 AccAXLsh1 (char *x)
6758 {
6759   emitcode ("xch", "a,%s", x);
6760   emitcode ("add", "a,acc");
6761   emitcode ("xch", "a,%s", x);
6762   emitcode ("rlc", "a");
6763 }
6764
6765 /*-----------------------------------------------------------------*/
6766 /* AccAXLsh - left shift a:x by known count (0..7)                 */
6767 /*-----------------------------------------------------------------*/
6768 static void
6769 AccAXLsh (char *x, int shCount)
6770 {
6771   switch (shCount)
6772     {
6773     case 0:
6774       break;
6775     case 1:
6776       AccAXLsh1 (x);
6777       break;
6778     case 2:
6779       AccAXLsh1 (x);
6780       AccAXLsh1 (x);
6781       break;
6782     case 3:
6783     case 4:
6784     case 5:                     // AAAAABBB:CCCCCDDD
6785
6786       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
6787
6788       emitcode ("anl", "a,#0x%02x",
6789                 SLMask[shCount]);       // BBB00000:CCCCCDDD
6790
6791       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
6792
6793       AccRol (shCount);         // DDDCCCCC:BBB00000
6794
6795       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
6796
6797       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
6798
6799       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
6800
6801       emitcode ("anl", "a,#0x%02x",
6802                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
6803
6804       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
6805
6806       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
6807
6808       break;
6809     case 6:                     // AAAAAABB:CCCCCCDD
6810       emitcode ("anl", "a,#0x%02x",
6811                 SRMask[shCount]);       // 000000BB:CCCCCCDD
6812       emitcode ("mov", "c,acc.0");      // c = B
6813       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
6814 #if 0 // REMOVE ME
6815       AccAXRrl1 (x);            // BCCCCCCD:D000000B
6816       AccAXRrl1 (x);            // BBCCCCCC:DD000000
6817 #else
6818       emitcode("rrc","a");
6819       emitcode("xch","a,%s", x);
6820       emitcode("rrc","a");
6821       emitcode("mov","c,acc.0"); //<< get correct bit
6822       emitcode("xch","a,%s", x);
6823
6824       emitcode("rrc","a");
6825       emitcode("xch","a,%s", x);
6826       emitcode("rrc","a");
6827       emitcode("xch","a,%s", x);
6828 #endif
6829       break;
6830     case 7:                     // a:x <<= 7
6831
6832       emitcode ("anl", "a,#0x%02x",
6833                 SRMask[shCount]);       // 0000000B:CCCCCCCD
6834
6835       emitcode ("mov", "c,acc.0");      // c = B
6836
6837       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
6838
6839       AccAXRrl1 (x);            // BCCCCCCC:D0000000
6840
6841       break;
6842     default:
6843       break;
6844     }
6845 }
6846
6847 /*-----------------------------------------------------------------*/
6848 /* AccAXRsh - right shift a:x known count (0..7)                   */
6849 /*-----------------------------------------------------------------*/
6850 static void
6851 AccAXRsh (char *x, int shCount)
6852 {
6853   switch (shCount)
6854     {
6855     case 0:
6856       break;
6857     case 1:
6858       CLRC;
6859       AccAXRrl1 (x);            // 0->a:x
6860
6861       break;
6862     case 2:
6863       CLRC;
6864       AccAXRrl1 (x);            // 0->a:x
6865
6866       CLRC;
6867       AccAXRrl1 (x);            // 0->a:x
6868
6869       break;
6870     case 3:
6871     case 4:
6872     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6873
6874       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
6875
6876       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6877
6878       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6879
6880       emitcode ("anl", "a,#0x%02x",
6881                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6882
6883       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6884
6885       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6886
6887       emitcode ("anl", "a,#0x%02x",
6888                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6889
6890       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6891
6892       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6893
6894       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
6895
6896       break;
6897     case 6:                     // AABBBBBB:CCDDDDDD
6898
6899       emitcode ("mov", "c,acc.7");
6900       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6901
6902       emitcode ("mov", "c,acc.7");
6903       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6904
6905       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6906
6907       emitcode ("anl", "a,#0x%02x",
6908                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6909
6910       break;
6911     case 7:                     // ABBBBBBB:CDDDDDDD
6912
6913       emitcode ("mov", "c,acc.7");      // c = A
6914
6915       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
6916
6917       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
6918
6919       emitcode ("anl", "a,#0x%02x",
6920                 SRMask[shCount]);       // 0000000A:BBBBBBBC
6921
6922       break;
6923     default:
6924       break;
6925     }
6926 }
6927
6928 /*-----------------------------------------------------------------*/
6929 /* AccAXRshS - right shift signed a:x known count (0..7)           */
6930 /*-----------------------------------------------------------------*/
6931 static void
6932 AccAXRshS (char *x, int shCount)
6933 {
6934   symbol *tlbl;
6935   switch (shCount)
6936     {
6937     case 0:
6938       break;
6939     case 1:
6940       emitcode ("mov", "c,acc.7");
6941       AccAXRrl1 (x);            // s->a:x
6942
6943       break;
6944     case 2:
6945       emitcode ("mov", "c,acc.7");
6946       AccAXRrl1 (x);            // s->a:x
6947
6948       emitcode ("mov", "c,acc.7");
6949       AccAXRrl1 (x);            // s->a:x
6950
6951       break;
6952     case 3:
6953     case 4:
6954     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6955
6956       tlbl = newiTempLabel (NULL);
6957       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
6958
6959       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6960
6961       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6962
6963       emitcode ("anl", "a,#0x%02x",
6964                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6965
6966       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6967
6968       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6969
6970       emitcode ("anl", "a,#0x%02x",
6971                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6972
6973       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6974
6975       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6976
6977       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
6978
6979       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6980       emitcode ("orl", "a,#0x%02x",
6981                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
6982
6983       emitcode ("", "%05d$:", tlbl->key + 100);
6984       break;                    // SSSSAAAA:BBBCCCCC
6985
6986     case 6:                     // AABBBBBB:CCDDDDDD
6987
6988       tlbl = newiTempLabel (NULL);
6989       emitcode ("mov", "c,acc.7");
6990       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6991
6992       emitcode ("mov", "c,acc.7");
6993       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6994
6995       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6996
6997       emitcode ("anl", "a,#0x%02x",
6998                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6999
7000       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7001       emitcode ("orl", "a,#0x%02x",
7002                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7003
7004       emitcode ("", "%05d$:", tlbl->key + 100);
7005       break;
7006     case 7:                     // ABBBBBBB:CDDDDDDD
7007
7008       tlbl = newiTempLabel (NULL);
7009       emitcode ("mov", "c,acc.7");      // c = A
7010
7011       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7012
7013       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7014
7015       emitcode ("anl", "a,#0x%02x",
7016                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7017
7018       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7019       emitcode ("orl", "a,#0x%02x",
7020                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7021
7022       emitcode ("", "%05d$:", tlbl->key + 100);
7023       break;
7024     default:
7025       break;
7026     }
7027 }
7028
7029 /*-----------------------------------------------------------------*/
7030 /* shiftL2Left2Result - shift left two bytes from left to result   */
7031 /*-----------------------------------------------------------------*/
7032 static void
7033 shiftL2Left2Result (operand * left, int offl,
7034                     operand * result, int offr, int shCount)
7035 {
7036   if (sameRegs (AOP (result), AOP (left)) &&
7037       ((offl + MSB16) == offr))
7038     {
7039       /* don't crash result[offr] */
7040       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7041       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7042     }
7043   else
7044     {
7045       movLeft2Result (left, offl, result, offr, 0);
7046       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7047     }
7048   /* ax << shCount (x = lsb(result)) */
7049   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7050   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7051 }
7052
7053
7054 /*-----------------------------------------------------------------*/
7055 /* shiftR2Left2Result - shift right two bytes from left to result  */
7056 /*-----------------------------------------------------------------*/
7057 static void
7058 shiftR2Left2Result (operand * left, int offl,
7059                     operand * result, int offr,
7060                     int shCount, int sign)
7061 {
7062   if (sameRegs (AOP (result), AOP (left)) &&
7063       ((offl + MSB16) == offr))
7064     {
7065       /* don't crash result[offr] */
7066       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7067       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7068     }
7069   else
7070     {
7071       movLeft2Result (left, offl, result, offr, 0);
7072       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7073     }
7074   /* a:x >> shCount (x = lsb(result)) */
7075   if (sign)
7076     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7077   else
7078     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7079   if (getDataSize (result) > 1)
7080     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7081 }
7082
7083 /*-----------------------------------------------------------------*/
7084 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7085 /*-----------------------------------------------------------------*/
7086 static void
7087 shiftLLeftOrResult (operand * left, int offl,
7088                     operand * result, int offr, int shCount)
7089 {
7090   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7091   /* shift left accumulator */
7092   AccLsh (shCount);
7093   /* or with result */
7094   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7095   /* back to result */
7096   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7097 }
7098
7099 /*-----------------------------------------------------------------*/
7100 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7101 /*-----------------------------------------------------------------*/
7102 static void
7103 shiftRLeftOrResult (operand * left, int offl,
7104                     operand * result, int offr, int shCount)
7105 {
7106   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7107   /* shift right accumulator */
7108   AccRsh (shCount);
7109   /* or with result */
7110   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7111   /* back to result */
7112   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7113 }
7114
7115 /*-----------------------------------------------------------------*/
7116 /* genlshOne - left shift a one byte quantity by known count       */
7117 /*-----------------------------------------------------------------*/
7118 static void
7119 genlshOne (operand * result, operand * left, int shCount)
7120 {
7121   D(emitcode (";     genlshOne",""));
7122
7123   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7124 }
7125
7126 /*-----------------------------------------------------------------*/
7127 /* genlshTwo - left shift two bytes by known amount != 0           */
7128 /*-----------------------------------------------------------------*/
7129 static void
7130 genlshTwo (operand * result, operand * left, int shCount)
7131 {
7132   int size;
7133
7134   D(emitcode (";     genlshTwo",""));
7135
7136   size = getDataSize (result);
7137
7138   /* if shCount >= 8 */
7139   if (shCount >= 8)
7140     {
7141       shCount -= 8;
7142
7143       if (size > 1)
7144         {
7145           if (shCount)
7146             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7147           else
7148             movLeft2Result (left, LSB, result, MSB16, 0);
7149         }
7150       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7151     }
7152
7153   /*  1 <= shCount <= 7 */
7154   else
7155     {
7156       if (size == 1)
7157         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7158       else
7159         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7160     }
7161 }
7162
7163 /*-----------------------------------------------------------------*/
7164 /* shiftLLong - shift left one long from left to result            */
7165 /* offl = LSB or MSB16                                             */
7166 /*-----------------------------------------------------------------*/
7167 static void
7168 shiftLLong (operand * left, operand * result, int offr)
7169 {
7170   char *l;
7171   int size = AOP_SIZE (result);
7172
7173   if (size >= LSB + offr)
7174     {
7175       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7176       MOVA (l);
7177       emitcode ("add", "a,acc");
7178       if (sameRegs (AOP (left), AOP (result)) &&
7179           size >= MSB16 + offr && offr != LSB)
7180         emitcode ("xch", "a,%s",
7181                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7182       else
7183         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7184     }
7185
7186   if (size >= MSB16 + offr)
7187     {
7188       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7189         {
7190           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7191           MOVA (l);
7192         }
7193       emitcode ("rlc", "a");
7194       if (sameRegs (AOP (left), AOP (result)) &&
7195           size >= MSB24 + offr && offr != LSB)
7196         emitcode ("xch", "a,%s",
7197                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7198       else
7199         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7200     }
7201
7202   if (size >= MSB24 + offr)
7203     {
7204       if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7205         {
7206           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7207           MOVA (l);
7208         }
7209       emitcode ("rlc", "a");
7210       if (sameRegs (AOP (left), AOP (result)) &&
7211           size >= MSB32 + offr && offr != LSB)
7212         emitcode ("xch", "a,%s",
7213                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7214       else
7215         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7216     }
7217
7218   if (size > MSB32 + offr)
7219     {
7220       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7221         {
7222           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7223           MOVA (l);
7224         }
7225       emitcode ("rlc", "a");
7226       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7227     }
7228   if (offr != LSB)
7229     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7230 }
7231
7232 /*-----------------------------------------------------------------*/
7233 /* genlshFour - shift four byte by a known amount != 0             */
7234 /*-----------------------------------------------------------------*/
7235 static void
7236 genlshFour (operand * result, operand * left, int shCount)
7237 {
7238   int size;
7239
7240   D(emitcode (";     genlshFour",""));
7241
7242   size = AOP_SIZE (result);
7243
7244   /* if shifting more that 3 bytes */
7245   if (shCount >= 24)
7246     {
7247       shCount -= 24;
7248       if (shCount)
7249         /* lowest order of left goes to the highest
7250            order of the destination */
7251         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7252       else
7253         movLeft2Result (left, LSB, result, MSB32, 0);
7254       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7255       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7256       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7257       return;
7258     }
7259
7260   /* more than two bytes */
7261   else if (shCount >= 16)
7262     {
7263       /* lower order two bytes goes to higher order two bytes */
7264       shCount -= 16;
7265       /* if some more remaining */
7266       if (shCount)
7267         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7268       else
7269         {
7270           movLeft2Result (left, MSB16, result, MSB32, 0);
7271           movLeft2Result (left, LSB, result, MSB24, 0);
7272         }
7273       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7274       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7275       return;
7276     }
7277
7278   /* if more than 1 byte */
7279   else if (shCount >= 8)
7280     {
7281       /* lower order three bytes goes to higher order  three bytes */
7282       shCount -= 8;
7283       if (size == 2)
7284         {
7285           if (shCount)
7286             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7287           else
7288             movLeft2Result (left, LSB, result, MSB16, 0);
7289         }
7290       else
7291         {                       /* size = 4 */
7292           if (shCount == 0)
7293             {
7294               movLeft2Result (left, MSB24, result, MSB32, 0);
7295               movLeft2Result (left, MSB16, result, MSB24, 0);
7296               movLeft2Result (left, LSB, result, MSB16, 0);
7297               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7298             }
7299           else if (shCount == 1)
7300             shiftLLong (left, result, MSB16);
7301           else
7302             {
7303               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7304               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7305               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7306               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7307             }
7308         }
7309     }
7310
7311   /* 1 <= shCount <= 7 */
7312   else if (shCount <= 2)
7313     {
7314       shiftLLong (left, result, LSB);
7315       if (shCount == 2)
7316         shiftLLong (result, result, LSB);
7317     }
7318   /* 3 <= shCount <= 7, optimize */
7319   else
7320     {
7321       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7322       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7323       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7324     }
7325 }
7326
7327 /*-----------------------------------------------------------------*/
7328 /* genLeftShiftLiteral - left shifting by known count              */
7329 /*-----------------------------------------------------------------*/
7330 static void
7331 genLeftShiftLiteral (operand * left,
7332                      operand * right,
7333                      operand * result,
7334                      iCode * ic)
7335 {
7336   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7337   int size;
7338
7339   D(emitcode (";     genLeftShiftLiteral",""));
7340
7341   freeAsmop (right, NULL, ic, TRUE);
7342
7343   aopOp (left, ic, FALSE);
7344   aopOp (result, ic, FALSE);
7345
7346   size = getSize (operandType (result));
7347
7348 #if VIEW_SIZE
7349   emitcode ("; shift left ", "result %d, left %d", size,
7350             AOP_SIZE (left));
7351 #endif
7352
7353   /* I suppose that the left size >= result size */
7354   if (shCount == 0)
7355     {
7356       while (size--)
7357         {
7358           movLeft2Result (left, size, result, size, 0);
7359         }
7360     }
7361
7362   else if (shCount >= (size * 8))
7363     while (size--)
7364       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7365   else
7366     {
7367       switch (size)
7368         {
7369         case 1:
7370           genlshOne (result, left, shCount);
7371           break;
7372
7373         case 2:
7374           genlshTwo (result, left, shCount);
7375           break;
7376
7377         case 4:
7378           genlshFour (result, left, shCount);
7379           break;
7380         default:
7381           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7382                   "*** ack! mystery literal shift!\n");
7383           break;
7384         }
7385     }
7386   freeAsmop (left, NULL, ic, TRUE);
7387   freeAsmop (result, NULL, ic, TRUE);
7388 }
7389
7390 /*-----------------------------------------------------------------*/
7391 /* genLeftShift - generates code for left shifting                 */
7392 /*-----------------------------------------------------------------*/
7393 static void
7394 genLeftShift (iCode * ic)
7395 {
7396   operand *left, *right, *result;
7397   int size, offset;
7398   char *l;
7399   symbol *tlbl, *tlbl1;
7400
7401   D(emitcode (";     genLeftShift",""));
7402
7403   right = IC_RIGHT (ic);
7404   left = IC_LEFT (ic);
7405   result = IC_RESULT (ic);
7406
7407   aopOp (right, ic, FALSE);
7408
7409   /* if the shift count is known then do it
7410      as efficiently as possible */
7411   if (AOP_TYPE (right) == AOP_LIT)
7412     {
7413       genLeftShiftLiteral (left, right, result, ic);
7414       return;
7415     }
7416
7417   /* shift count is unknown then we have to form
7418      a loop get the loop count in B : Note: we take
7419      only the lower order byte since shifting
7420      more that 32 bits make no sense anyway, ( the
7421      largest size of an object can be only 32 bits ) */
7422
7423   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7424   emitcode ("inc", "b");
7425   freeAsmop (right, NULL, ic, TRUE);
7426   aopOp (left, ic, FALSE);
7427   aopOp (result, ic, FALSE);
7428
7429   /* now move the left to the result if they are not the
7430      same */
7431   if (!sameRegs (AOP (left), AOP (result)) &&
7432       AOP_SIZE (result) > 1)
7433     {
7434
7435       size = AOP_SIZE (result);
7436       offset = 0;
7437       while (size--)
7438         {
7439           l = aopGet (AOP (left), offset, FALSE, TRUE);
7440           if (*l == '@' && (IS_AOP_PREG (result)))
7441             {
7442
7443               emitcode ("mov", "a,%s", l);
7444               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7445             }
7446           else
7447             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7448           offset++;
7449         }
7450     }
7451
7452   tlbl = newiTempLabel (NULL);
7453   size = AOP_SIZE (result);
7454   offset = 0;
7455   tlbl1 = newiTempLabel (NULL);
7456
7457   /* if it is only one byte then */
7458   if (size == 1)
7459     {
7460       symbol *tlbl1 = newiTempLabel (NULL);
7461
7462       l = aopGet (AOP (left), 0, FALSE, FALSE);
7463       MOVA (l);
7464       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7465       emitcode ("", "%05d$:", tlbl->key + 100);
7466       emitcode ("add", "a,acc");
7467       emitcode ("", "%05d$:", tlbl1->key + 100);
7468       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7469       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7470       goto release;
7471     }
7472
7473   reAdjustPreg (AOP (result));
7474
7475   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7476   emitcode ("", "%05d$:", tlbl->key + 100);
7477   l = aopGet (AOP (result), offset, FALSE, FALSE);
7478   MOVA (l);
7479   emitcode ("add", "a,acc");
7480   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7481   while (--size)
7482     {
7483       l = aopGet (AOP (result), offset, FALSE, FALSE);
7484       MOVA (l);
7485       emitcode ("rlc", "a");
7486       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7487     }
7488   reAdjustPreg (AOP (result));
7489
7490   emitcode ("", "%05d$:", tlbl1->key + 100);
7491   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7492 release:
7493   freeAsmop (left, NULL, ic, TRUE);
7494   freeAsmop (result, NULL, ic, TRUE);
7495 }
7496
7497 /*-----------------------------------------------------------------*/
7498 /* genrshOne - right shift a one byte quantity by known count      */
7499 /*-----------------------------------------------------------------*/
7500 static void
7501 genrshOne (operand * result, operand * left,
7502            int shCount, int sign)
7503 {
7504   D(emitcode (";     genrshOne",""));
7505
7506   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7507 }
7508
7509 /*-----------------------------------------------------------------*/
7510 /* genrshTwo - right shift two bytes by known amount != 0          */
7511 /*-----------------------------------------------------------------*/
7512 static void
7513 genrshTwo (operand * result, operand * left,
7514            int shCount, int sign)
7515 {
7516   D(emitcode (";     genrshTwo",""));
7517
7518   /* if shCount >= 8 */
7519   if (shCount >= 8)
7520     {
7521       shCount -= 8;
7522       if (shCount)
7523         shiftR1Left2Result (left, MSB16, result, LSB,
7524                             shCount, sign);
7525       else
7526         movLeft2Result (left, MSB16, result, LSB, sign);
7527       addSign (result, MSB16, sign);
7528     }
7529
7530   /*  1 <= shCount <= 7 */
7531   else
7532     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7533 }
7534
7535 /*-----------------------------------------------------------------*/
7536 /* shiftRLong - shift right one long from left to result           */
7537 /* offl = LSB or MSB16                                             */
7538 /*-----------------------------------------------------------------*/
7539 static void
7540 shiftRLong (operand * left, int offl,
7541             operand * result, int sign)
7542 {
7543   int isSameRegs=sameRegs(AOP(left),AOP(result));
7544
7545   if (isSameRegs && offl>1) {
7546     // we are in big trouble, but this shouldn't happen
7547     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7548   }
7549
7550   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7551
7552   if (offl==MSB16) {
7553     // shift is > 8
7554     if (sign) {
7555       emitcode ("rlc", "a");
7556       emitcode ("subb", "a,acc");
7557       if (isSameRegs)
7558         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7559       else {
7560         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7561         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7562       }
7563     } else {
7564       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7565     }
7566   }
7567
7568   if (!sign) {
7569     emitcode ("clr", "c");
7570   } else {
7571     emitcode ("mov", "c,acc.7");
7572   }
7573
7574   emitcode ("rrc", "a");
7575
7576   if (isSameRegs && offl==MSB16) {
7577     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7578   } else {
7579     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7580     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7581   }
7582
7583   emitcode ("rrc", "a");
7584   if (isSameRegs && offl==1) {
7585     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7586   } else {
7587     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7588     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7589   }
7590   emitcode ("rrc", "a");
7591   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7592
7593   if (offl == LSB)
7594     {
7595       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7596       emitcode ("rrc", "a");
7597       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7598     }
7599 }
7600
7601 /*-----------------------------------------------------------------*/
7602 /* genrshFour - shift four byte by a known amount != 0             */
7603 /*-----------------------------------------------------------------*/
7604 static void
7605 genrshFour (operand * result, operand * left,
7606             int shCount, int sign)
7607 {
7608   D(emitcode (";     genrshFour",""));
7609
7610   /* if shifting more that 3 bytes */
7611   if (shCount >= 24)
7612     {
7613       shCount -= 24;
7614       if (shCount)
7615         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7616       else
7617         movLeft2Result (left, MSB32, result, LSB, sign);
7618       addSign (result, MSB16, sign);
7619     }
7620   else if (shCount >= 16)
7621     {
7622       shCount -= 16;
7623       if (shCount)
7624         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7625       else
7626         {
7627           movLeft2Result (left, MSB24, result, LSB, 0);
7628           movLeft2Result (left, MSB32, result, MSB16, sign);
7629         }
7630       addSign (result, MSB24, sign);
7631     }
7632   else if (shCount >= 8)
7633     {
7634       shCount -= 8;
7635       if (shCount == 1)
7636         shiftRLong (left, MSB16, result, sign);
7637       else if (shCount == 0)
7638         {
7639           movLeft2Result (left, MSB16, result, LSB, 0);
7640           movLeft2Result (left, MSB24, result, MSB16, 0);
7641           movLeft2Result (left, MSB32, result, MSB24, sign);
7642           addSign (result, MSB32, sign);
7643         }
7644       else
7645         {
7646           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
7647           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
7648           /* the last shift is signed */
7649           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
7650           addSign (result, MSB32, sign);
7651         }
7652     }
7653   else
7654     {                           /* 1 <= shCount <= 7 */
7655       if (shCount <= 2)
7656         {
7657           shiftRLong (left, LSB, result, sign);
7658           if (shCount == 2)
7659             shiftRLong (result, LSB, result, sign);
7660         }
7661       else
7662         {
7663           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
7664           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
7665           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
7666         }
7667     }
7668 }
7669
7670 /*-----------------------------------------------------------------*/
7671 /* genRightShiftLiteral - right shifting by known count            */
7672 /*-----------------------------------------------------------------*/
7673 static void
7674 genRightShiftLiteral (operand * left,
7675                       operand * right,
7676                       operand * result,
7677                       iCode * ic,
7678                       int sign)
7679 {
7680   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7681   int size;
7682
7683   D(emitcode (";     genRightShiftLiteral",""));
7684
7685   freeAsmop (right, NULL, ic, TRUE);
7686
7687   aopOp (left, ic, FALSE);
7688   aopOp (result, ic, FALSE);
7689
7690 #if VIEW_SIZE
7691   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
7692             AOP_SIZE (left));
7693 #endif
7694
7695   size = getDataSize (left);
7696   /* test the LEFT size !!! */
7697
7698   /* I suppose that the left size >= result size */
7699   if (shCount == 0)
7700     {
7701       size = getDataSize (result);
7702       while (size--)
7703         movLeft2Result (left, size, result, size, 0);
7704     }
7705
7706   else if (shCount >= (size * 8))
7707     {
7708       if (sign) {
7709         /* get sign in acc.7 */
7710         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
7711       }
7712       addSign (result, LSB, sign);
7713     }
7714   else
7715     {
7716       switch (size)
7717         {
7718         case 1:
7719           genrshOne (result, left, shCount, sign);
7720           break;
7721
7722         case 2:
7723           genrshTwo (result, left, shCount, sign);
7724           break;
7725
7726         case 4:
7727           genrshFour (result, left, shCount, sign);
7728           break;
7729         default:
7730           break;
7731         }
7732     }
7733   freeAsmop (left, NULL, ic, TRUE);
7734   freeAsmop (result, NULL, ic, TRUE);
7735 }
7736
7737 /*-----------------------------------------------------------------*/
7738 /* genSignedRightShift - right shift of signed number              */
7739 /*-----------------------------------------------------------------*/
7740 static void
7741 genSignedRightShift (iCode * ic)
7742 {
7743   operand *right, *left, *result;
7744   int size, offset;
7745   char *l;
7746   symbol *tlbl, *tlbl1;
7747
7748   D(emitcode (";     genSignedRightShift",""));
7749
7750   /* we do it the hard way put the shift count in b
7751      and loop thru preserving the sign */
7752
7753   right = IC_RIGHT (ic);
7754   left = IC_LEFT (ic);
7755   result = IC_RESULT (ic);
7756
7757   aopOp (right, ic, FALSE);
7758
7759
7760   if (AOP_TYPE (right) == AOP_LIT)
7761     {
7762       genRightShiftLiteral (left, right, result, ic, 1);
7763       return;
7764     }
7765   /* shift count is unknown then we have to form
7766      a loop get the loop count in B : Note: we take
7767      only the lower order byte since shifting
7768      more that 32 bits make no sense anyway, ( the
7769      largest size of an object can be only 32 bits ) */
7770
7771   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7772   emitcode ("inc", "b");
7773   freeAsmop (right, NULL, ic, TRUE);
7774   aopOp (left, ic, FALSE);
7775   aopOp (result, ic, FALSE);
7776
7777   /* now move the left to the result if they are not the
7778      same */
7779   if (!sameRegs (AOP (left), AOP (result)) &&
7780       AOP_SIZE (result) > 1)
7781     {
7782
7783       size = AOP_SIZE (result);
7784       offset = 0;
7785       while (size--)
7786         {
7787           l = aopGet (AOP (left), offset, FALSE, TRUE);
7788           if (*l == '@' && IS_AOP_PREG (result))
7789             {
7790
7791               emitcode ("mov", "a,%s", l);
7792               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7793             }
7794           else
7795             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7796           offset++;
7797         }
7798     }
7799
7800   /* mov the highest order bit to OVR */
7801   tlbl = newiTempLabel (NULL);
7802   tlbl1 = newiTempLabel (NULL);
7803
7804   size = AOP_SIZE (result);
7805   offset = size - 1;
7806   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
7807   emitcode ("rlc", "a");
7808   emitcode ("mov", "ov,c");
7809   /* if it is only one byte then */
7810   if (size == 1)
7811     {
7812       l = aopGet (AOP (left), 0, FALSE, FALSE);
7813       MOVA (l);
7814       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7815       emitcode ("", "%05d$:", tlbl->key + 100);
7816       emitcode ("mov", "c,ov");
7817       emitcode ("rrc", "a");
7818       emitcode ("", "%05d$:", tlbl1->key + 100);
7819       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7820       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7821       goto release;
7822     }
7823
7824   reAdjustPreg (AOP (result));
7825   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7826   emitcode ("", "%05d$:", tlbl->key + 100);
7827   emitcode ("mov", "c,ov");
7828   while (size--)
7829     {
7830       l = aopGet (AOP (result), offset, FALSE, FALSE);
7831       MOVA (l);
7832       emitcode ("rrc", "a");
7833       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7834     }
7835   reAdjustPreg (AOP (result));
7836   emitcode ("", "%05d$:", tlbl1->key + 100);
7837   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7838
7839 release:
7840   freeAsmop (left, NULL, ic, TRUE);
7841   freeAsmop (result, NULL, ic, TRUE);
7842 }
7843
7844 /*-----------------------------------------------------------------*/
7845 /* genRightShift - generate code for right shifting                */
7846 /*-----------------------------------------------------------------*/
7847 static void
7848 genRightShift (iCode * ic)
7849 {
7850   operand *right, *left, *result;
7851   sym_link *letype;
7852   int size, offset;
7853   char *l;
7854   symbol *tlbl, *tlbl1;
7855
7856   D(emitcode (";     genRightShift",""));
7857
7858   /* if signed then we do it the hard way preserve the
7859      sign bit moving it inwards */
7860   letype = getSpec (operandType (IC_LEFT (ic)));
7861
7862   if (!SPEC_USIGN (letype))
7863     {
7864       genSignedRightShift (ic);
7865       return;
7866     }
7867
7868   /* signed & unsigned types are treated the same : i.e. the
7869      signed is NOT propagated inwards : quoting from the
7870      ANSI - standard : "for E1 >> E2, is equivalent to division
7871      by 2**E2 if unsigned or if it has a non-negative value,
7872      otherwise the result is implementation defined ", MY definition
7873      is that the sign does not get propagated */
7874
7875   right = IC_RIGHT (ic);
7876   left = IC_LEFT (ic);
7877   result = IC_RESULT (ic);
7878
7879   aopOp (right, ic, FALSE);
7880
7881   /* if the shift count is known then do it
7882      as efficiently as possible */
7883   if (AOP_TYPE (right) == AOP_LIT)
7884     {
7885       genRightShiftLiteral (left, right, result, ic, 0);
7886       return;
7887     }
7888
7889   /* shift count is unknown then we have to form
7890      a loop get the loop count in B : Note: we take
7891      only the lower order byte since shifting
7892      more that 32 bits make no sense anyway, ( the
7893      largest size of an object can be only 32 bits ) */
7894
7895   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7896   emitcode ("inc", "b");
7897   freeAsmop (right, NULL, ic, TRUE);
7898   aopOp (left, ic, FALSE);
7899   aopOp (result, ic, FALSE);
7900
7901   /* now move the left to the result if they are not the
7902      same */
7903   if (!sameRegs (AOP (left), AOP (result)) &&
7904       AOP_SIZE (result) > 1)
7905     {
7906
7907       size = AOP_SIZE (result);
7908       offset = 0;
7909       while (size--)
7910         {
7911           l = aopGet (AOP (left), offset, FALSE, TRUE);
7912           if (*l == '@' && IS_AOP_PREG (result))
7913             {
7914
7915               emitcode ("mov", "a,%s", l);
7916               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7917             }
7918           else
7919             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7920           offset++;
7921         }
7922     }
7923
7924   tlbl = newiTempLabel (NULL);
7925   tlbl1 = newiTempLabel (NULL);
7926   size = AOP_SIZE (result);
7927   offset = size - 1;
7928
7929   /* if it is only one byte then */
7930   if (size == 1)
7931     {
7932       l = aopGet (AOP (left), 0, FALSE, FALSE);
7933       MOVA (l);
7934       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7935       emitcode ("", "%05d$:", tlbl->key + 100);
7936       CLRC;
7937       emitcode ("rrc", "a");
7938       emitcode ("", "%05d$:", tlbl1->key + 100);
7939       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7940       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7941       goto release;
7942     }
7943
7944   reAdjustPreg (AOP (result));
7945   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7946   emitcode ("", "%05d$:", tlbl->key + 100);
7947   CLRC;
7948   while (size--)
7949     {
7950       l = aopGet (AOP (result), offset, FALSE, FALSE);
7951       MOVA (l);
7952       emitcode ("rrc", "a");
7953       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7954     }
7955   reAdjustPreg (AOP (result));
7956
7957   emitcode ("", "%05d$:", tlbl1->key + 100);
7958   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7959
7960 release:
7961   freeAsmop (left, NULL, ic, TRUE);
7962   freeAsmop (result, NULL, ic, TRUE);
7963 }
7964
7965 /*-----------------------------------------------------------------*/
7966 /* emitPtrByteGet - emits code to get a byte into A through a      */
7967 /*                  pointer register (R0, R1, or DPTR). The        */
7968 /*                  original value of A can be preserved in B.     */
7969 /*-----------------------------------------------------------------*/
7970 static void
7971 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
7972 {
7973   switch (p_type)
7974     {
7975     case IPOINTER:
7976     case POINTER:
7977       if (preserveAinB)
7978         emitcode ("mov", "b,a");
7979       emitcode ("mov", "a,@%s", rname);
7980       break;
7981
7982     case PPOINTER:
7983       if (preserveAinB)
7984         emitcode ("mov", "b,a");
7985       emitcode ("movx", "a,@%s", rname);
7986       break;
7987
7988     case FPOINTER:
7989       if (preserveAinB)
7990         emitcode ("mov", "b,a");
7991       emitcode ("movx", "a,@dptr");
7992       break;
7993
7994     case CPOINTER:
7995       if (preserveAinB)
7996         emitcode ("mov", "b,a");
7997       emitcode ("clr", "a");
7998       emitcode ("movc", "a,@a+dptr");
7999       break;
8000
8001     case GPOINTER:
8002       if (preserveAinB)
8003         {
8004           emitcode ("push", "b");
8005           emitcode ("push", "acc");
8006         }
8007       emitcode ("lcall", "__gptrget");
8008       if (preserveAinB)
8009         emitcode ("pop", "b");
8010       break;
8011     }
8012 }
8013
8014 /*-----------------------------------------------------------------*/
8015 /* emitPtrByteSet - emits code to set a byte from src through a    */
8016 /*                  pointer register (R0, R1, or DPTR).            */
8017 /*-----------------------------------------------------------------*/
8018 static void
8019 emitPtrByteSet (char *rname, int p_type, char *src)
8020 {
8021   switch (p_type)
8022     {
8023     case IPOINTER:
8024     case POINTER:
8025       if (*src=='@')
8026         {
8027           MOVA (src);
8028           emitcode ("mov", "@%s,a", rname);
8029         }
8030       else
8031         emitcode ("mov", "@%s,%s", rname, src);
8032       break;
8033
8034     case PPOINTER:
8035       MOVA (src);
8036       emitcode ("movx", "@%s,a", rname);
8037       break;
8038
8039     case FPOINTER:
8040       MOVA (src);
8041       emitcode ("movx", "@dptr,a");
8042       break;
8043
8044     case GPOINTER:
8045       MOVA (src);
8046       emitcode ("lcall", "__gptrput");
8047       break;
8048     }
8049 }
8050
8051 /*-----------------------------------------------------------------*/
8052 /* genUnpackBits - generates code for unpacking bits               */
8053 /*-----------------------------------------------------------------*/
8054 static void
8055 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8056 {
8057   int offset = 0;       /* result byte offset */
8058   int rsize;            /* result size */
8059   int rlen = 0;         /* remaining bitfield length */
8060   sym_link *etype;      /* bitfield type information */
8061   int blen;             /* bitfield length */
8062   int bstr;             /* bitfield starting bit within byte */
8063   char buffer[10];
8064
8065   D(emitcode (";     genUnpackBits",""));
8066
8067   etype = getSpec (operandType (result));
8068   rsize = getSize (operandType (result));
8069   blen = SPEC_BLEN (etype);
8070   bstr = SPEC_BSTR (etype);
8071
8072   if (ifx && blen <= 8)
8073     {
8074       emitPtrByteGet (rname, ptype, FALSE);
8075       if (blen == 1)
8076         {
8077           SNPRINTF (buffer, sizeof(buffer),
8078                     "acc.%d", bstr);
8079           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8080         }
8081       else
8082         {
8083           if (blen < 8)
8084             emitcode ("anl", "a,#0x%02x",
8085                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8086           genIfxJump (ifx, "a", NULL, NULL, NULL);
8087         }
8088       return;
8089     }
8090   wassert (!ifx);
8091   
8092   /* If the bitfield length is less than a byte */
8093   if (blen < 8)
8094     {
8095       emitPtrByteGet (rname, ptype, FALSE);
8096       AccRsh (bstr);
8097       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8098       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8099       goto finish;
8100     }
8101
8102   /* Bit field did not fit in a byte. Copy all
8103      but the partial byte at the end.  */
8104   for (rlen=blen;rlen>=8;rlen-=8)
8105     {
8106       emitPtrByteGet (rname, ptype, FALSE);
8107       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8108       if (rlen>8)
8109         emitcode ("inc", "%s", rname);
8110     }
8111
8112   /* Handle the partial byte at the end */
8113   if (rlen)
8114     {
8115       emitPtrByteGet (rname, ptype, FALSE);
8116       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8117       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8118     }
8119
8120 finish:
8121   if (offset < rsize)
8122     {
8123       rsize -= offset;
8124       while (rsize--)
8125         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
8126     }
8127 }
8128
8129
8130 /*-----------------------------------------------------------------*/
8131 /* genDataPointerGet - generates code when ptr offset is known     */
8132 /*-----------------------------------------------------------------*/
8133 static void
8134 genDataPointerGet (operand * left,
8135                    operand * result,
8136                    iCode * ic)
8137 {
8138   char *l;
8139   char buffer[256];
8140   int size, offset = 0;
8141
8142   D(emitcode (";     genDataPointerGet",""));
8143
8144   aopOp (result, ic, TRUE);
8145
8146   /* get the string representation of the name */
8147   l = aopGet (AOP (left), 0, FALSE, TRUE);
8148   size = AOP_SIZE (result);
8149   while (size--)
8150     {
8151       if (offset)
8152         sprintf (buffer, "(%s + %d)", l + 1, offset);
8153       else
8154         sprintf (buffer, "%s", l + 1);
8155       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
8156     }
8157
8158   freeAsmop (left, NULL, ic, TRUE);
8159   freeAsmop (result, NULL, ic, TRUE);
8160 }
8161
8162 /*-----------------------------------------------------------------*/
8163 /* genNearPointerGet - emitcode for near pointer fetch             */
8164 /*-----------------------------------------------------------------*/
8165 static void
8166 genNearPointerGet (operand * left,
8167                    operand * result,
8168                    iCode * ic,
8169                    iCode * pi,
8170                    iCode * ifx)
8171 {
8172   asmop *aop = NULL;
8173   regs *preg = NULL;
8174   char *rname;
8175   sym_link *rtype, *retype;
8176   sym_link *ltype = operandType (left);
8177   char buffer[80];
8178
8179   D(emitcode (";     genNearPointerGet",""));
8180
8181   rtype = operandType (result);
8182   retype = getSpec (rtype);
8183
8184   aopOp (left, ic, FALSE);
8185
8186   /* if left is rematerialisable and
8187      result is not bitfield variable type and
8188      the left is pointer to data space i.e
8189      lower 128 bytes of space */
8190   if (AOP_TYPE (left) == AOP_IMMD &&
8191       !IS_BITFIELD (retype) &&
8192       DCL_TYPE (ltype) == POINTER)
8193     {
8194       genDataPointerGet (left, result, ic);
8195       return;
8196     }
8197
8198  /* if the value is already in a pointer register
8199      then don't need anything more */
8200   if (!AOP_INPREG (AOP (left)))
8201     {
8202       if (IS_AOP_PREG (left))
8203         {
8204           // Aha, it is a pointer, just in disguise.
8205           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8206           if (*rname != '@')
8207             {
8208               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8209                       __FILE__, __LINE__);
8210             }
8211           else
8212             {
8213               // Expected case.
8214               emitcode ("mov", "a%s,%s", rname + 1, rname);
8215               rname++;  // skip the '@'.
8216             }
8217         }
8218       else
8219         {
8220           /* otherwise get a free pointer register */
8221           aop = newAsmop (0);
8222           preg = getFreePtr (ic, &aop, FALSE);
8223           emitcode ("mov", "%s,%s",
8224                     preg->name,
8225                     aopGet (AOP (left), 0, FALSE, TRUE));
8226           rname = preg->name;
8227         }
8228     }
8229   else
8230     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8231
8232   //aopOp (result, ic, FALSE);
8233   aopOp (result, ic, result?TRUE:FALSE);
8234
8235   /* if bitfield then unpack the bits */
8236   if (IS_BITFIELD (retype))
8237     genUnpackBits (result, rname, POINTER, ifx);
8238   else
8239     {
8240       /* we have can just get the values */
8241       int size = AOP_SIZE (result);
8242       int offset = 0;
8243
8244       while (size--)
8245         {
8246           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8247             {
8248
8249               emitcode ("mov", "a,@%s", rname);
8250               if (!ifx)
8251                 aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8252             }
8253           else
8254             {
8255               sprintf (buffer, "@%s", rname);
8256               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8257             }
8258           offset++;
8259           if (size || pi)
8260             emitcode ("inc", "%s", rname);
8261         }
8262     }
8263
8264   /* now some housekeeping stuff */
8265   if (aop)       /* we had to allocate for this iCode */
8266     {
8267       if (pi) { /* post increment present */
8268         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8269       }
8270       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8271     }
8272   else
8273     {
8274       /* we did not allocate which means left
8275          already in a pointer register, then
8276          if size > 0 && this could be used again
8277          we have to point it back to where it
8278          belongs */
8279       if ((AOP_SIZE (result) > 1 &&
8280            !OP_SYMBOL (left)->remat &&
8281            (OP_SYMBOL (left)->liveTo > ic->seq ||
8282             ic->depth)) &&
8283           !pi)
8284         {
8285           int size = AOP_SIZE (result) - 1;
8286           while (size--)
8287             emitcode ("dec", "%s", rname);
8288         }
8289     }
8290   
8291   if (ifx && !ifx->generated)
8292     {
8293       genIfxJump (ifx, "a", left, NULL, result);
8294     }
8295
8296   /* done */
8297   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8298   freeAsmop (left, NULL, ic, TRUE);
8299   if (pi) pi->generated = 1;
8300 }
8301
8302 /*-----------------------------------------------------------------*/
8303 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8304 /*-----------------------------------------------------------------*/
8305 static void
8306 genPagedPointerGet (operand * left,
8307                     operand * result,
8308                     iCode * ic,
8309                     iCode *pi,
8310                     iCode *ifx)
8311 {
8312   asmop *aop = NULL;
8313   regs *preg = NULL;
8314   char *rname;
8315   sym_link *rtype, *retype;
8316
8317   D(emitcode (";     genPagedPointerGet",""));
8318
8319   rtype = operandType (result);
8320   retype = getSpec (rtype);
8321
8322   aopOp (left, ic, FALSE);
8323
8324   /* if the value is already in a pointer register
8325      then don't need anything more */
8326   if (!AOP_INPREG (AOP (left)))
8327     {
8328       /* otherwise get a free pointer register */
8329       aop = newAsmop (0);
8330       preg = getFreePtr (ic, &aop, FALSE);
8331       emitcode ("mov", "%s,%s",
8332                 preg->name,
8333                 aopGet (AOP (left), 0, FALSE, TRUE));
8334       rname = preg->name;
8335     }
8336   else
8337     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8338
8339   aopOp (result, ic, FALSE);
8340
8341   /* if bitfield then unpack the bits */
8342   if (IS_BITFIELD (retype))
8343     genUnpackBits (result, rname, PPOINTER, ifx);
8344   else
8345     {
8346       /* we have can just get the values */
8347       int size = AOP_SIZE (result);
8348       int offset = 0;
8349
8350       while (size--)
8351         {
8352
8353           emitcode ("movx", "a,@%s", rname);
8354           if (!ifx)
8355             aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8356
8357           offset++;
8358
8359           if (size || pi)
8360             emitcode ("inc", "%s", rname);
8361         }
8362     }
8363
8364   /* now some housekeeping stuff */
8365   if (aop) /* we had to allocate for this iCode */
8366     {
8367       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8368       freeAsmop (NULL, aop, ic, TRUE);
8369     }
8370   else
8371     {
8372       /* we did not allocate which means left
8373          already in a pointer register, then
8374          if size > 0 && this could be used again
8375          we have to point it back to where it
8376          belongs */
8377       if ((AOP_SIZE (result) > 1 &&
8378            !OP_SYMBOL (left)->remat &&
8379            (OP_SYMBOL (left)->liveTo > ic->seq ||
8380             ic->depth)) &&
8381           !pi)
8382         {
8383           int size = AOP_SIZE (result) - 1;
8384           while (size--)
8385             emitcode ("dec", "%s", rname);
8386         }
8387     }
8388
8389   if (ifx && !ifx->generated)
8390     {
8391       genIfxJump (ifx, "a", left, NULL, result);
8392     }
8393
8394   /* done */
8395   freeAsmop (left, NULL, ic, TRUE);
8396   freeAsmop (result, NULL, ic, TRUE);
8397   if (pi) pi->generated = 1;
8398
8399 }
8400
8401 /*--------------------------------------------------------------------*/
8402 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8403 /*--------------------------------------------------------------------*/
8404 static void
8405 loadDptrFromOperand (operand *op, bool loadBToo)
8406 {
8407   if (AOP_TYPE (op) != AOP_STR)
8408     {
8409       /* if this is remateriazable */
8410       if (AOP_TYPE (op) == AOP_IMMD)
8411         {
8412           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8413           if (loadBToo)
8414             {
8415               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8416                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8417               else
8418                 {
8419                   wassertl(FALSE, "need pointerCode");
8420                   emitcode ("", "; mov b,???");
8421                   /* genPointerGet and genPointerSet originally did different
8422                   ** things for this case. Both seem wrong.
8423                   ** from genPointerGet:
8424                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8425                   ** from genPointerSet:
8426                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8427                   */
8428                 }
8429             }
8430         }
8431       else if (AOP_TYPE (op) == AOP_DPTR)
8432         {
8433           if (loadBToo)
8434             {
8435               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8436               emitcode ("push", "acc");
8437               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8438               emitcode ("push", "acc");
8439               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8440               emitcode ("pop", "dph");
8441               emitcode ("pop", "dpl");
8442             }
8443           else
8444             {
8445               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8446               emitcode ("push", "acc");
8447               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8448               emitcode ("pop", "dpl");
8449             }
8450         }
8451       else
8452         {                       /* we need to get it byte by byte */
8453           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8454           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8455           if (loadBToo)
8456             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8457         }
8458     }
8459 }
8460
8461 /*-----------------------------------------------------------------*/
8462 /* genFarPointerGet - gget value from far space                    */
8463 /*-----------------------------------------------------------------*/
8464 static void
8465 genFarPointerGet (operand * left,
8466                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
8467 {
8468   int size, offset;
8469   sym_link *retype = getSpec (operandType (result));
8470
8471   D(emitcode (";     genFarPointerGet",""));
8472
8473   aopOp (left, ic, FALSE);
8474   loadDptrFromOperand (left, FALSE);
8475
8476   /* so dptr now contains the address */
8477   aopOp (result, ic, FALSE);
8478
8479   /* if bit then unpack */
8480   if (IS_BITFIELD (retype))
8481     genUnpackBits (result, "dptr", FPOINTER, ifx);
8482   else
8483     {
8484       size = AOP_SIZE (result);
8485       offset = 0;
8486
8487       while (size--)
8488         {
8489           emitcode ("movx", "a,@dptr");
8490           if (!ifx)
8491             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8492           if (size || pi)
8493             emitcode ("inc", "dptr");
8494         }
8495
8496     }
8497   
8498   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8499     {
8500       aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8501       aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8502       pi->generated = 1;
8503     }
8504
8505   if (ifx && !ifx->generated)
8506     {
8507       genIfxJump (ifx, "a", left, NULL, result);
8508     }
8509
8510   freeAsmop (left, NULL, ic, TRUE);
8511   freeAsmop (result, NULL, ic, TRUE);
8512 }
8513
8514 /*-----------------------------------------------------------------*/
8515 /* genCodePointerGet - gget value from code space                  */
8516 /*-----------------------------------------------------------------*/
8517 static void
8518 genCodePointerGet (operand * left,
8519                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
8520 {
8521   int size, offset;
8522   sym_link *retype = getSpec (operandType (result));
8523
8524   D(emitcode (";     genCodePointerGet",""));
8525
8526   aopOp (left, ic, FALSE);
8527   loadDptrFromOperand (left, FALSE);
8528
8529   /* so dptr now contains the address */
8530   aopOp (result, ic, FALSE);
8531
8532   /* if bit then unpack */
8533   if (IS_BITFIELD (retype))
8534     genUnpackBits (result, "dptr", CPOINTER, ifx);
8535   else
8536     {
8537       size = AOP_SIZE (result);
8538       offset = 0;
8539
8540       while (size--)
8541         {
8542           if (pi)
8543             {
8544               emitcode ("clr", "a");
8545               emitcode ("movc", "a,@a+dptr");
8546               if (!ifx)
8547                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8548               emitcode ("inc", "dptr");
8549             }
8550           else
8551             {
8552               emitcode ("mov", "a,#0x%02x", offset);
8553               emitcode ("movc", "a,@a+dptr");
8554               if (!ifx)
8555                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8556             }
8557         }
8558     }
8559
8560   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8561     {
8562       aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8563       aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8564       pi->generated = 1;
8565     }
8566
8567   if (ifx && !ifx->generated)
8568     {
8569       genIfxJump (ifx, "a", left, NULL, result);
8570     }
8571
8572   freeAsmop (left, NULL, ic, TRUE);
8573   freeAsmop (result, NULL, ic, TRUE);
8574 }
8575
8576 /*-----------------------------------------------------------------*/
8577 /* genGenPointerGet - gget value from generic pointer space        */
8578 /*-----------------------------------------------------------------*/
8579 static void
8580 genGenPointerGet (operand * left,
8581                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
8582 {
8583   int size, offset;
8584   sym_link *retype = getSpec (operandType (result));
8585
8586   D(emitcode (";     genGenPointerGet",""));
8587
8588   aopOp (left, ic, FALSE);
8589   loadDptrFromOperand (left, TRUE);
8590
8591   /* so dptr know contains the address */
8592   aopOp (result, ic, FALSE);
8593
8594   /* if bit then unpack */
8595   if (IS_BITFIELD (retype))
8596     genUnpackBits (result, "dptr", GPOINTER, ifx);
8597   else
8598     {
8599       size = AOP_SIZE (result);
8600       offset = 0;
8601
8602       while (size--)
8603         {
8604           emitcode ("lcall", "__gptrget");
8605           if (!ifx)
8606             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8607           if (size || pi)
8608             emitcode ("inc", "dptr");
8609         }
8610     }
8611
8612   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8613     {
8614       aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8615       aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8616       pi->generated = 1;
8617     }
8618
8619   if (ifx && !ifx->generated)
8620     {
8621       genIfxJump (ifx, "a", left, NULL, result);
8622     }
8623
8624     
8625   freeAsmop (left, NULL, ic, TRUE);
8626   freeAsmop (result, NULL, ic, TRUE);
8627 }
8628
8629 /*-----------------------------------------------------------------*/
8630 /* genPointerGet - generate code for pointer get                   */
8631 /*-----------------------------------------------------------------*/
8632 static void
8633 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
8634 {
8635   operand *left, *result;
8636   sym_link *type, *etype;
8637   int p_type;
8638
8639   D(emitcode (";     genPointerGet",""));
8640
8641   left = IC_LEFT (ic);
8642   result = IC_RESULT (ic);
8643   
8644   if (getSize (operandType (result))>1)
8645     ifx = NULL;
8646
8647   /* depending on the type of pointer we need to
8648      move it to the correct pointer register */
8649   type = operandType (left);
8650   etype = getSpec (type);
8651   /* if left is of type of pointer then it is simple */
8652   if (IS_PTR (type) && !IS_FUNC (type->next))
8653     p_type = DCL_TYPE (type);
8654   else
8655     {
8656       /* we have to go by the storage class */
8657       p_type = PTR_TYPE (SPEC_OCLS (etype));
8658     }
8659
8660   /* special case when cast remat */
8661   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
8662       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
8663           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
8664           type = operandType (left);
8665           p_type = DCL_TYPE (type);
8666   }
8667   /* now that we have the pointer type we assign
8668      the pointer values */
8669   switch (p_type)
8670     {
8671
8672     case POINTER:
8673     case IPOINTER:
8674       genNearPointerGet (left, result, ic, pi, ifx);
8675       break;
8676
8677     case PPOINTER:
8678       genPagedPointerGet (left, result, ic, pi, ifx);
8679       break;
8680
8681     case FPOINTER:
8682       genFarPointerGet (left, result, ic, pi, ifx);
8683       break;
8684
8685     case CPOINTER:
8686       genCodePointerGet (left, result, ic, pi, ifx);
8687       break;
8688
8689     case GPOINTER:
8690       genGenPointerGet (left, result, ic, pi, ifx);
8691       break;
8692     }
8693
8694 }
8695
8696
8697
8698 /*-----------------------------------------------------------------*/
8699 /* genPackBits - generates code for packed bit storage             */
8700 /*-----------------------------------------------------------------*/
8701 static void
8702 genPackBits (sym_link * etype,
8703              operand * right,
8704              char *rname, int p_type)
8705 {
8706   int offset = 0;       /* source byte offset */
8707   int rlen = 0;         /* remaining bitfield length */
8708   int blen;             /* bitfield length */
8709   int bstr;             /* bitfield starting bit within byte */
8710   int litval;           /* source literal value (if AOP_LIT) */
8711   unsigned char mask;   /* bitmask within current byte */
8712
8713   D(emitcode (";     genPackBits",""));
8714
8715   blen = SPEC_BLEN (etype);
8716   bstr = SPEC_BSTR (etype);
8717
8718   /* If the bitfield length is less than a byte */
8719   if (blen < 8)
8720     {
8721       mask = ((unsigned char) (0xFF << (blen + bstr)) |
8722               (unsigned char) (0xFF >> (8 - bstr)));
8723
8724       if (AOP_TYPE (right) == AOP_LIT)
8725         {
8726           /* Case with a bitfield length <8 and literal source
8727           */
8728           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8729           litval <<= bstr;
8730           litval &= (~mask) & 0xff;
8731           emitPtrByteGet (rname, p_type, FALSE);
8732           if ((mask|litval)!=0xff)
8733             emitcode ("anl","a,#0x%02x", mask);
8734           if (litval)
8735             emitcode ("orl","a,#0x%02x", litval);
8736         }
8737       else
8738         {
8739           if ((blen==1) && (p_type!=GPOINTER))
8740             {
8741               /* Case with a bitfield length == 1 and no generic pointer
8742               */
8743               if (AOP_TYPE (right) == AOP_CRY)
8744                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
8745               else
8746                 {
8747                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8748                   emitcode ("rrc","a");
8749                 }
8750               emitPtrByteGet (rname, p_type, FALSE);
8751               emitcode ("mov","acc.%d,c",bstr);
8752             }
8753           else
8754             {
8755               /* Case with a bitfield length < 8 and arbitrary source
8756               */
8757               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8758               /* shift and mask source value */
8759               AccLsh (bstr);
8760               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8761
8762               /* transfer A to B and get next byte */
8763               emitPtrByteGet (rname, p_type, TRUE);
8764
8765               emitcode ("anl", "a,#0x%02x", mask);
8766               emitcode ("orl", "a,b");
8767               if (p_type == GPOINTER)
8768                 emitcode ("pop", "b");
8769            }
8770         }
8771
8772       emitPtrByteSet (rname, p_type, "a");
8773       return;
8774     }
8775
8776   /* Bit length is greater than 7 bits. In this case, copy  */
8777   /* all except the partial byte at the end                 */
8778   for (rlen=blen;rlen>=8;rlen-=8)
8779     {
8780       emitPtrByteSet (rname, p_type,
8781                       aopGet (AOP (right), offset++, FALSE, TRUE) );
8782       if (rlen>8)
8783         emitcode ("inc", "%s", rname);
8784     }
8785
8786   /* If there was a partial byte at the end */
8787   if (rlen)
8788     {
8789       mask = (((unsigned char) -1 << rlen) & 0xff);
8790
8791       if (AOP_TYPE (right) == AOP_LIT)
8792         {
8793           /* Case with partial byte and literal source
8794           */
8795           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8796           litval >>= (blen-rlen);
8797           litval &= (~mask) & 0xff;
8798           emitPtrByteGet (rname, p_type, FALSE);
8799           if ((mask|litval)!=0xff)
8800             emitcode ("anl","a,#0x%02x", mask);
8801           if (litval)
8802             emitcode ("orl","a,#0x%02x", litval);
8803         }
8804       else
8805         {
8806           /* Case with partial byte and arbitrary source
8807           */
8808           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
8809           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8810
8811           /* transfer A to B and get next byte */
8812           emitPtrByteGet (rname, p_type, TRUE);
8813
8814           emitcode ("anl", "a,#0x%02x", mask);
8815           emitcode ("orl", "a,b");
8816           if (p_type == GPOINTER)
8817             emitcode ("pop", "b");
8818         }
8819       emitPtrByteSet (rname, p_type, "a");
8820     }
8821
8822 }
8823
8824
8825 /*-----------------------------------------------------------------*/
8826 /* genDataPointerSet - remat pointer to data space                 */
8827 /*-----------------------------------------------------------------*/
8828 static void
8829 genDataPointerSet (operand * right,
8830                    operand * result,
8831                    iCode * ic)
8832 {
8833   int size, offset = 0;
8834   char *l, buffer[256];
8835
8836   D(emitcode (";     genDataPointerSet",""));
8837
8838   aopOp (right, ic, FALSE);
8839
8840   l = aopGet (AOP (result), 0, FALSE, TRUE);
8841   size = AOP_SIZE (right);
8842   while (size--)
8843     {
8844       if (offset)
8845         sprintf (buffer, "(%s + %d)", l + 1, offset);
8846       else
8847         sprintf (buffer, "%s", l + 1);
8848       emitcode ("mov", "%s,%s", buffer,
8849                 aopGet (AOP (right), offset++, FALSE, FALSE));
8850     }
8851
8852   freeAsmop (right, NULL, ic, TRUE);
8853   freeAsmop (result, NULL, ic, TRUE);
8854 }
8855
8856 /*-----------------------------------------------------------------*/
8857 /* genNearPointerSet - emitcode for near pointer put                */
8858 /*-----------------------------------------------------------------*/
8859 static void
8860 genNearPointerSet (operand * right,
8861                    operand * result,
8862                    iCode * ic,
8863                    iCode * pi)
8864 {
8865   asmop *aop = NULL;
8866   regs *preg = NULL;
8867   char *rname, *l;
8868   sym_link *retype, *letype;
8869   sym_link *ptype = operandType (result);
8870
8871   D(emitcode (";     genNearPointerSet",""));
8872
8873   retype = getSpec (operandType (right));
8874   letype = getSpec (ptype);
8875   aopOp (result, ic, FALSE);
8876
8877   /* if the result is rematerializable &
8878      in data space & not a bit variable */
8879   if (AOP_TYPE (result) == AOP_IMMD &&
8880       DCL_TYPE (ptype) == POINTER &&
8881       !IS_BITVAR (retype) &&
8882       !IS_BITVAR (letype))
8883     {
8884       genDataPointerSet (right, result, ic);
8885       return;
8886     }
8887
8888   /* if the value is already in a pointer register
8889      then don't need anything more */
8890   if (!AOP_INPREG (AOP (result)))
8891     {
8892         if (
8893             //AOP_TYPE (result) == AOP_STK
8894             IS_AOP_PREG(result)
8895             )
8896         {
8897             // Aha, it is a pointer, just in disguise.
8898             rname = aopGet (AOP (result), 0, FALSE, FALSE);
8899             if (*rname != '@')
8900             {
8901                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8902                         __FILE__, __LINE__);
8903             }
8904             else
8905             {
8906                 // Expected case.
8907                 emitcode ("mov", "a%s,%s", rname + 1, rname);
8908                 rname++;  // skip the '@'.
8909             }
8910         }
8911         else
8912         {
8913             /* otherwise get a free pointer register */
8914             aop = newAsmop (0);
8915             preg = getFreePtr (ic, &aop, FALSE);
8916             emitcode ("mov", "%s,%s",
8917                       preg->name,
8918                       aopGet (AOP (result), 0, FALSE, TRUE));
8919             rname = preg->name;
8920         }
8921     }
8922     else
8923     {
8924         rname = aopGet (AOP (result), 0, FALSE, FALSE);
8925     }
8926
8927   aopOp (right, ic, FALSE);
8928
8929   /* if bitfield then unpack the bits */
8930   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8931     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
8932   else
8933     {
8934       /* we have can just get the values */
8935       int size = AOP_SIZE (right);
8936       int offset = 0;
8937
8938       while (size--)
8939         {
8940           l = aopGet (AOP (right), offset, FALSE, TRUE);
8941           if (*l == '@')
8942             {
8943               MOVA (l);
8944               emitcode ("mov", "@%s,a", rname);
8945             }
8946           else
8947             emitcode ("mov", "@%s,%s", rname, l);
8948           if (size || pi)
8949             emitcode ("inc", "%s", rname);
8950           offset++;
8951         }
8952     }
8953
8954   /* now some housekeeping stuff */
8955   if (aop) /* we had to allocate for this iCode */
8956     {
8957       if (pi)
8958         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
8959       freeAsmop (NULL, aop, ic, TRUE);
8960     }
8961   else
8962     {
8963       /* we did not allocate which means left
8964          already in a pointer register, then
8965          if size > 0 && this could be used again
8966          we have to point it back to where it
8967          belongs */
8968       if ((AOP_SIZE (right) > 1 &&
8969            !OP_SYMBOL (result)->remat &&
8970            (OP_SYMBOL (result)->liveTo > ic->seq ||
8971             ic->depth)) &&
8972           !pi)
8973         {
8974           int size = AOP_SIZE (right) - 1;
8975           while (size--)
8976             emitcode ("dec", "%s", rname);
8977         }
8978     }
8979
8980   /* done */
8981   if (pi) pi->generated = 1;
8982   freeAsmop (result, NULL, ic, TRUE);
8983   freeAsmop (right, NULL, ic, TRUE);
8984 }
8985
8986 /*-----------------------------------------------------------------*/
8987 /* genPagedPointerSet - emitcode for Paged pointer put             */
8988 /*-----------------------------------------------------------------*/
8989 static void
8990 genPagedPointerSet (operand * right,
8991                     operand * result,
8992                     iCode * ic,
8993                     iCode * pi)
8994 {
8995   asmop *aop = NULL;
8996   regs *preg = NULL;
8997   char *rname, *l;
8998   sym_link *retype, *letype;
8999
9000   D(emitcode (";     genPagedPointerSet",""));
9001
9002   retype = getSpec (operandType (right));
9003   letype = getSpec (operandType (result));
9004
9005   aopOp (result, ic, FALSE);
9006
9007   /* if the value is already in a pointer register
9008      then don't need anything more */
9009   if (!AOP_INPREG (AOP (result)))
9010     {
9011       /* otherwise get a free pointer register */
9012       aop = newAsmop (0);
9013       preg = getFreePtr (ic, &aop, FALSE);
9014       emitcode ("mov", "%s,%s",
9015                 preg->name,
9016                 aopGet (AOP (result), 0, FALSE, TRUE));
9017       rname = preg->name;
9018     }
9019   else
9020     rname = aopGet (AOP (result), 0, FALSE, FALSE);
9021
9022   aopOp (right, ic, FALSE);
9023
9024   /* if bitfield then unpack the bits */
9025   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9026     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9027   else
9028     {
9029       /* we have can just get the values */
9030       int size = AOP_SIZE (right);
9031       int offset = 0;
9032
9033       while (size--)
9034         {
9035           l = aopGet (AOP (right), offset, FALSE, TRUE);
9036
9037           MOVA (l);
9038           emitcode ("movx", "@%s,a", rname);
9039
9040           if (size || pi)
9041             emitcode ("inc", "%s", rname);
9042
9043           offset++;
9044         }
9045     }
9046
9047   /* now some housekeeping stuff */
9048   if (aop) /* we had to allocate for this iCode */
9049     {
9050       if (pi)
9051         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9052       freeAsmop (NULL, aop, ic, TRUE);
9053     }
9054   else
9055     {
9056       /* we did not allocate which means left
9057          already in a pointer register, then
9058          if size > 0 && this could be used again
9059          we have to point it back to where it
9060          belongs */
9061       if (AOP_SIZE (right) > 1 &&
9062           !OP_SYMBOL (result)->remat &&
9063           (OP_SYMBOL (result)->liveTo > ic->seq ||
9064            ic->depth))
9065         {
9066           int size = AOP_SIZE (right) - 1;
9067           while (size--)
9068             emitcode ("dec", "%s", rname);
9069         }
9070     }
9071
9072   /* done */
9073   if (pi) pi->generated = 1;
9074   freeAsmop (result, NULL, ic, TRUE);
9075   freeAsmop (right, NULL, ic, TRUE);
9076
9077
9078 }
9079
9080 /*-----------------------------------------------------------------*/
9081 /* genFarPointerSet - set value from far space                     */
9082 /*-----------------------------------------------------------------*/
9083 static void
9084 genFarPointerSet (operand * right,
9085                   operand * result, iCode * ic, iCode * pi)
9086 {
9087   int size, offset;
9088   sym_link *retype = getSpec (operandType (right));
9089   sym_link *letype = getSpec (operandType (result));
9090
9091   D(emitcode (";     genFarPointerSet",""));
9092
9093   aopOp (result, ic, FALSE);
9094   loadDptrFromOperand (result, FALSE);
9095
9096   /* so dptr know contains the address */
9097   aopOp (right, ic, FALSE);
9098
9099   /* if bit then unpack */
9100   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9101     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9102   else
9103     {
9104       size = AOP_SIZE (right);
9105       offset = 0;
9106
9107       while (size--)
9108         {
9109           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9110           MOVA (l);
9111           emitcode ("movx", "@dptr,a");
9112           if (size || pi)
9113             emitcode ("inc", "dptr");
9114         }
9115     }
9116   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9117     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9118     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9119     pi->generated=1;
9120   }
9121   freeAsmop (result, NULL, ic, TRUE);
9122   freeAsmop (right, NULL, ic, TRUE);
9123 }
9124
9125 /*-----------------------------------------------------------------*/
9126 /* genGenPointerSet - set value from generic pointer space         */
9127 /*-----------------------------------------------------------------*/
9128 static void
9129 genGenPointerSet (operand * right,
9130                   operand * result, iCode * ic, iCode * pi)
9131 {
9132   int size, offset;
9133   sym_link *retype = getSpec (operandType (right));
9134   sym_link *letype = getSpec (operandType (result));
9135
9136   D(emitcode (";     genGenPointerSet",""));
9137
9138   aopOp (result, ic, FALSE);
9139   loadDptrFromOperand (result, TRUE);
9140
9141   /* so dptr know contains the address */
9142   aopOp (right, ic, FALSE);
9143
9144   /* if bit then unpack */
9145   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9146     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9147   else
9148     {
9149       size = AOP_SIZE (right);
9150       offset = 0;
9151
9152       while (size--)
9153         {
9154           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9155           MOVA (l);
9156           emitcode ("lcall", "__gptrput");
9157           if (size || pi)
9158             emitcode ("inc", "dptr");
9159         }
9160     }
9161
9162   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9163     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9164     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9165     pi->generated=1;
9166   }
9167   freeAsmop (result, NULL, ic, TRUE);
9168   freeAsmop (right, NULL, ic, TRUE);
9169 }
9170
9171 /*-----------------------------------------------------------------*/
9172 /* genPointerSet - stores the value into a pointer location        */
9173 /*-----------------------------------------------------------------*/
9174 static void
9175 genPointerSet (iCode * ic, iCode *pi)
9176 {
9177   operand *right, *result;
9178   sym_link *type, *etype;
9179   int p_type;
9180
9181   D(emitcode (";     genPointerSet",""));
9182
9183   right = IC_RIGHT (ic);
9184   result = IC_RESULT (ic);
9185
9186   /* depending on the type of pointer we need to
9187      move it to the correct pointer register */
9188   type = operandType (result);
9189   etype = getSpec (type);
9190   /* if left is of type of pointer then it is simple */
9191   if (IS_PTR (type) && !IS_FUNC (type->next))
9192     {
9193       p_type = DCL_TYPE (type);
9194     }
9195   else
9196     {
9197       /* we have to go by the storage class */
9198       p_type = PTR_TYPE (SPEC_OCLS (etype));
9199     }
9200
9201   /* special case when cast remat */
9202   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9203       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9204           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9205           type = operandType (result);
9206           p_type = DCL_TYPE (type);
9207   }
9208   /* now that we have the pointer type we assign
9209      the pointer values */
9210   switch (p_type)
9211     {
9212
9213     case POINTER:
9214     case IPOINTER:
9215       genNearPointerSet (right, result, ic, pi);
9216       break;
9217
9218     case PPOINTER:
9219       genPagedPointerSet (right, result, ic, pi);
9220       break;
9221
9222     case FPOINTER:
9223       genFarPointerSet (right, result, ic, pi);
9224       break;
9225
9226     case GPOINTER:
9227       genGenPointerSet (right, result, ic, pi);
9228       break;
9229
9230     default:
9231       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9232               "genPointerSet: illegal pointer type");
9233     }
9234
9235 }
9236
9237 /*-----------------------------------------------------------------*/
9238 /* genIfx - generate code for Ifx statement                        */
9239 /*-----------------------------------------------------------------*/
9240 static void
9241 genIfx (iCode * ic, iCode * popIc)
9242 {
9243   operand *cond = IC_COND (ic);
9244   int isbit = 0;
9245
9246   D(emitcode (";     genIfx",""));
9247
9248   aopOp (cond, ic, FALSE);
9249
9250   /* get the value into acc */
9251   if (AOP_TYPE (cond) != AOP_CRY)
9252     toBoolean (cond);
9253   else
9254     isbit = 1;
9255   /* the result is now in the accumulator */
9256   freeAsmop (cond, NULL, ic, TRUE);
9257
9258   /* if there was something to be popped then do it */
9259   if (popIc)
9260     genIpop (popIc);
9261
9262   /* if the condition is  a bit variable */
9263   if (isbit && IS_ITEMP (cond) &&
9264       SPIL_LOC (cond))
9265     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9266   else if (isbit && !IS_ITEMP (cond))
9267     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9268   else
9269     genIfxJump (ic, "a", NULL, NULL, NULL);
9270
9271   ic->generated = 1;
9272 }
9273
9274 /*-----------------------------------------------------------------*/
9275 /* genAddrOf - generates code for address of                       */
9276 /*-----------------------------------------------------------------*/
9277 static void
9278 genAddrOf (iCode * ic)
9279 {
9280   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9281   int size, offset;
9282
9283   D(emitcode (";     genAddrOf",""));
9284
9285   aopOp (IC_RESULT (ic), ic, FALSE);
9286
9287   /* if the operand is on the stack then we
9288      need to get the stack offset of this
9289      variable */
9290   if (sym->onStack)
9291     {
9292       /* if it has an offset then we need to compute
9293          it */
9294       if (sym->stack)
9295         {
9296           emitcode ("mov", "a,_bp");
9297           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9298                                          ((char) (sym->stack - _G.nRegsSaved)) :
9299                                          ((char) sym->stack)) & 0xff);
9300           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9301         }
9302       else
9303         {
9304           /* we can just move _bp */
9305           aopPut (AOP (IC_RESULT (ic)), "_bp", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9306         }
9307       /* fill the result with zero */
9308       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9309
9310       offset = 1;
9311       while (size--)
9312         {
9313           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9314         }
9315
9316       goto release;
9317     }
9318
9319   /* object not on stack then we need the name */
9320   size = AOP_SIZE (IC_RESULT (ic));
9321   offset = 0;
9322
9323   while (size--)
9324     {
9325       char s[SDCC_NAME_MAX];
9326       if (offset)
9327         sprintf (s, "#(%s >> %d)",
9328                  sym->rname,
9329                  offset * 8);
9330       else
9331         sprintf (s, "#%s", sym->rname);
9332       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9333     }
9334
9335 release:
9336   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9337
9338 }
9339
9340 /*-----------------------------------------------------------------*/
9341 /* genFarFarAssign - assignment when both are in far space         */
9342 /*-----------------------------------------------------------------*/
9343 static void
9344 genFarFarAssign (operand * result, operand * right, iCode * ic)
9345 {
9346   int size = AOP_SIZE (right);
9347   int offset = 0;
9348   char *l;
9349
9350   D(emitcode (";     genFarFarAssign",""));
9351
9352   /* first push the right side on to the stack */
9353   while (size--)
9354     {
9355       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9356       MOVA (l);
9357       emitcode ("push", "acc");
9358     }
9359
9360   freeAsmop (right, NULL, ic, FALSE);
9361   /* now assign DPTR to result */
9362   aopOp (result, ic, FALSE);
9363   size = AOP_SIZE (result);
9364   while (size--)
9365     {
9366       emitcode ("pop", "acc");
9367       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9368     }
9369   freeAsmop (result, NULL, ic, FALSE);
9370
9371 }
9372
9373 /*-----------------------------------------------------------------*/
9374 /* genAssign - generate code for assignment                        */
9375 /*-----------------------------------------------------------------*/
9376 static void
9377 genAssign (iCode * ic)
9378 {
9379   operand *result, *right;
9380   int size, offset;
9381   unsigned long lit = 0L;
9382
9383   D(emitcode(";     genAssign",""));
9384
9385   result = IC_RESULT (ic);
9386   right = IC_RIGHT (ic);
9387
9388   /* if they are the same */
9389   if (operandsEqu (result, right) &&
9390       !isOperandVolatile (result, FALSE) &&
9391       !isOperandVolatile (right, FALSE))
9392     return;
9393
9394   aopOp (right, ic, FALSE);
9395
9396   /* special case both in far space */
9397   if (AOP_TYPE (right) == AOP_DPTR &&
9398       IS_TRUE_SYMOP (result) &&
9399       isOperandInFarSpace (result))
9400     {
9401
9402       genFarFarAssign (result, right, ic);
9403       return;
9404     }
9405
9406   aopOp (result, ic, TRUE);
9407
9408   /* if they are the same registers */
9409   if (sameRegs (AOP (right), AOP (result)) &&
9410       !isOperandVolatile (result, FALSE) &&
9411       !isOperandVolatile (right, FALSE))
9412     goto release;
9413
9414   /* if the result is a bit */
9415   if (AOP_TYPE (result) == AOP_CRY)
9416     {
9417
9418       /* if the right size is a literal then
9419          we know what the value is */
9420       if (AOP_TYPE (right) == AOP_LIT)
9421         {
9422           if (((int) operandLitValue (right)))
9423             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9424           else
9425             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9426           goto release;
9427         }
9428
9429       /* the right is also a bit variable */
9430       if (AOP_TYPE (right) == AOP_CRY)
9431         {
9432           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9433           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9434           goto release;
9435         }
9436
9437       /* we need to or */
9438       toBoolean (right);
9439       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9440       goto release;
9441     }
9442
9443   /* bit variables done */
9444   /* general case */
9445   size = AOP_SIZE (result);
9446   offset = 0;
9447   if (AOP_TYPE (right) == AOP_LIT)
9448     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9449   if ((size > 1) &&
9450       (AOP_TYPE (result) != AOP_REG) &&
9451       (AOP_TYPE (right) == AOP_LIT) &&
9452       !IS_FLOAT (operandType (right)) &&
9453       (lit < 256L))
9454     {
9455       emitcode ("clr", "a");
9456       while (size--)
9457         {
9458           if ((unsigned int) ((lit >> (size * 8)) & 0x0FFL) == 0)
9459             aopPut (AOP (result), "a", size, isOperandVolatile (result, FALSE));
9460           else
9461             aopPut (AOP (result),
9462                     aopGet (AOP (right), size, FALSE, FALSE),
9463                     size,
9464                     isOperandVolatile (result, FALSE));
9465         }
9466     }
9467   else
9468     {
9469       while (size--)
9470         {
9471           aopPut (AOP (result),
9472                   aopGet (AOP (right), offset, FALSE, FALSE),
9473                   offset,
9474                   isOperandVolatile (result, FALSE));
9475           offset++;
9476         }
9477     }
9478
9479 release:
9480   freeAsmop (right, NULL, ic, TRUE);
9481   freeAsmop (result, NULL, ic, TRUE);
9482 }
9483
9484 /*-----------------------------------------------------------------*/
9485 /* genJumpTab - genrates code for jump table                       */
9486 /*-----------------------------------------------------------------*/
9487 static void
9488 genJumpTab (iCode * ic)
9489 {
9490   symbol *jtab,*jtablo,*jtabhi;
9491   char *l;
9492   unsigned int count;
9493
9494   D(emitcode (";     genJumpTab",""));
9495
9496   count = elementsInSet( IC_JTLABELS (ic) );
9497
9498   if( count <= 16 )
9499     {
9500       /* this algorithm needs 9 cycles and 7 + 3*n bytes 
9501          if the switch argument is in an register. 
9502          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */ 
9503       aopOp (IC_JTCOND (ic), ic, FALSE);
9504       /* get the condition into accumulator */
9505       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9506       MOVA (l);
9507       /* multiply by three */
9508       emitcode ("add", "a,acc");
9509       emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9510       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9511
9512       jtab = newiTempLabel (NULL);
9513       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9514       emitcode ("jmp", "@a+dptr");
9515       emitcode ("", "%05d$:", jtab->key + 100);
9516       /* now generate the jump labels */
9517       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9518            jtab = setNextItem (IC_JTLABELS (ic)))
9519         emitcode ("ljmp", "%05d$", jtab->key + 100);
9520     }
9521   else
9522     {
9523       /* this algorithm needs 14 cycles and 13 + 2*n bytes 
9524          if the switch argument is in an register. 
9525          For n>6 this algorithm may be more compact */ 
9526       jtablo = newiTempLabel (NULL);
9527       jtabhi = newiTempLabel (NULL);
9528
9529       /* get the condition into accumulator.
9530          Using b as temporary storage, if register push/pop is needed */ 
9531       aopOp (IC_JTCOND (ic), ic, FALSE);
9532       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9533       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
9534           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
9535         {
9536           emitcode ("mov", "b,%s", l);
9537           l = "b";
9538         }
9539       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);            
9540       MOVA (l);      
9541       if( count <= 112 )
9542         {
9543           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
9544           emitcode ("movc", "a,@a+pc");
9545           emitcode ("push", "acc");
9546
9547           MOVA (l);
9548           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
9549           emitcode ("movc", "a,@a+pc");
9550           emitcode ("push", "acc");
9551         }
9552       else      
9553         {
9554           /* this scales up to n<=255, but needs two more bytes
9555              and changes dptr */
9556           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
9557           emitcode ("movc", "a,@a+dptr");
9558           emitcode ("push", "acc");
9559
9560           MOVA (l);
9561           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
9562           emitcode ("movc", "a,@a+dptr");
9563           emitcode ("push", "acc");
9564         }
9565
9566       emitcode ("ret", "");
9567
9568       /* now generate jump table, LSB */
9569       emitcode ("", "%05d$:", jtablo->key + 100);
9570       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9571            jtab = setNextItem (IC_JTLABELS (ic)))
9572         emitcode (".db", "%05d$", jtab->key + 100);
9573
9574       /* now generate jump table, MSB */
9575       emitcode ("", "%05d$:", jtabhi->key + 100);
9576       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9577            jtab = setNextItem (IC_JTLABELS (ic)))
9578          emitcode (".db", "%05d$>>8", jtab->key + 100);
9579     
9580     }  
9581
9582 }
9583
9584 /*-----------------------------------------------------------------*/
9585 /* genCast - gen code for casting                                  */
9586 /*-----------------------------------------------------------------*/
9587 static void
9588 genCast (iCode * ic)
9589 {
9590   operand *result = IC_RESULT (ic);
9591   sym_link *ctype = operandType (IC_LEFT (ic));
9592   sym_link *rtype = operandType (IC_RIGHT (ic));
9593   operand *right = IC_RIGHT (ic);
9594   int size, offset;
9595
9596   D(emitcode(";     genCast",""));
9597
9598   /* if they are equivalent then do nothing */
9599   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9600     return;
9601
9602   aopOp (right, ic, FALSE);
9603   aopOp (result, ic, FALSE);
9604
9605   /* if the result is a bit (and not a bitfield) */
9606   // if (AOP_TYPE (result) == AOP_CRY)
9607   if (IS_BITVAR (OP_SYMBOL (result)->type)
9608       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
9609     {
9610       /* if the right size is a literal then
9611          we know what the value is */
9612       if (AOP_TYPE (right) == AOP_LIT)
9613         {
9614           if (((int) operandLitValue (right)))
9615             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9616           else
9617             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9618
9619           goto release;
9620         }
9621
9622       /* the right is also a bit variable */
9623       if (AOP_TYPE (right) == AOP_CRY)
9624         {
9625           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9626           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9627           goto release;
9628         }
9629
9630       /* we need to or */
9631       toBoolean (right);
9632       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9633       goto release;
9634     }
9635
9636
9637   /* if they are the same size : or less */
9638   if (AOP_SIZE (result) <= AOP_SIZE (right))
9639     {
9640
9641       /* if they are in the same place */
9642       if (sameRegs (AOP (right), AOP (result)))
9643         goto release;
9644
9645       /* if they in different places then copy */
9646       size = AOP_SIZE (result);
9647       offset = 0;
9648       while (size--)
9649         {
9650           aopPut (AOP (result),
9651                   aopGet (AOP (right), offset, FALSE, FALSE),
9652                   offset,
9653                   isOperandVolatile (result, FALSE));
9654           offset++;
9655         }
9656       goto release;
9657     }
9658
9659
9660   /* if the result is of type pointer */
9661   if (IS_PTR (ctype))
9662     {
9663
9664       int p_type;
9665       sym_link *type = operandType (right);
9666       sym_link *etype = getSpec (type);
9667
9668       /* pointer to generic pointer */
9669       if (IS_GENPTR (ctype))
9670         {
9671           if (IS_PTR (type))
9672             p_type = DCL_TYPE (type);
9673           else
9674             {
9675               if (SPEC_SCLS(etype)==S_REGISTER) {
9676                 // let's assume it is a generic pointer
9677                 p_type=GPOINTER;
9678               } else {
9679                 /* we have to go by the storage class */
9680                 p_type = PTR_TYPE (SPEC_OCLS (etype));
9681               }
9682             }
9683
9684           /* the first two bytes are known */
9685           size = GPTRSIZE - 1;
9686           offset = 0;
9687           while (size--)
9688             {
9689               aopPut (AOP (result),
9690                       aopGet (AOP (right), offset, FALSE, FALSE),
9691                       offset,
9692                       isOperandVolatile (result, FALSE));
9693               offset++;
9694             }
9695           /* the last byte depending on type */
9696             {
9697                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
9698                 char gpValStr[10];
9699
9700                 if (gpVal == -1)
9701                 {
9702                     // pointerTypeToGPByte will have bitched.
9703                     exit(1);
9704                 }
9705
9706                 sprintf(gpValStr, "#0x%d", gpVal);
9707                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
9708             }
9709           goto release;
9710         }
9711
9712       /* just copy the pointers */
9713       size = AOP_SIZE (result);
9714       offset = 0;
9715       while (size--)
9716         {
9717           aopPut (AOP (result),
9718                   aopGet (AOP (right), offset, FALSE, FALSE),
9719                   offset,
9720                   isOperandVolatile (result, FALSE));
9721           offset++;
9722         }
9723       goto release;
9724     }
9725
9726   /* so we now know that the size of destination is greater
9727      than the size of the source */
9728   /* we move to result for the size of source */
9729   size = AOP_SIZE (right);
9730   offset = 0;
9731   while (size--)
9732     {
9733       aopPut (AOP (result),
9734               aopGet (AOP (right), offset, FALSE, FALSE),
9735               offset,
9736               isOperandVolatile (result, FALSE));
9737       offset++;
9738     }
9739
9740   /* now depending on the sign of the source && destination */
9741   size = AOP_SIZE (result) - AOP_SIZE (right);
9742   /* if unsigned or not an integral type */
9743   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
9744     {
9745       while (size--)
9746         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
9747     }
9748   else
9749     {
9750       /* we need to extend the sign :{ */
9751       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
9752                         FALSE, FALSE);
9753       MOVA (l);
9754       emitcode ("rlc", "a");
9755       emitcode ("subb", "a,acc");
9756       while (size--)
9757         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
9758     }
9759
9760   /* we are done hurray !!!! */
9761
9762 release:
9763   freeAsmop (right, NULL, ic, TRUE);
9764   freeAsmop (result, NULL, ic, TRUE);
9765
9766 }
9767
9768 /*-----------------------------------------------------------------*/
9769 /* genDjnz - generate decrement & jump if not zero instrucion      */
9770 /*-----------------------------------------------------------------*/
9771 static int
9772 genDjnz (iCode * ic, iCode * ifx)
9773 {
9774   symbol *lbl, *lbl1;
9775   if (!ifx)
9776     return 0;
9777
9778   D(emitcode (";     genDjnz",""));
9779
9780   /* if the if condition has a false label
9781      then we cannot save */
9782   if (IC_FALSE (ifx))
9783     return 0;
9784
9785   /* if the minus is not of the form
9786      a = a - 1 */
9787   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
9788       !IS_OP_LITERAL (IC_RIGHT (ic)))
9789     return 0;
9790
9791   if (operandLitValue (IC_RIGHT (ic)) != 1)
9792     return 0;
9793
9794   /* if the size of this greater than one then no
9795      saving */
9796   if (getSize (operandType (IC_RESULT (ic))) > 1)
9797     return 0;
9798
9799   /* otherwise we can save BIG */
9800   lbl = newiTempLabel (NULL);
9801   lbl1 = newiTempLabel (NULL);
9802
9803   aopOp (IC_RESULT (ic), ic, FALSE);
9804
9805   if (AOP_NEEDSACC(IC_RESULT(ic)))
9806   {
9807       /* If the result is accessed indirectly via
9808        * the accumulator, we must explicitly write
9809        * it back after the decrement.
9810        */
9811       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
9812
9813       if (strcmp(rByte, "a"))
9814       {
9815            /* Something is hopelessly wrong */
9816            fprintf(stderr, "*** warning: internal error at %s:%d\n",
9817                    __FILE__, __LINE__);
9818            /* We can just give up; the generated code will be inefficient,
9819             * but what the hey.
9820             */
9821            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9822            return 0;
9823       }
9824       emitcode ("dec", "%s", rByte);
9825       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9826       emitcode ("jnz", "%05d$", lbl->key + 100);
9827   }
9828   else if (IS_AOP_PREG (IC_RESULT (ic)))
9829     {
9830       emitcode ("dec", "%s",
9831                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9832       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9833       emitcode ("jnz", "%05d$", lbl->key + 100);
9834     }
9835   else
9836     {
9837       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
9838                 lbl->key + 100);
9839     }
9840   emitcode ("sjmp", "%05d$", lbl1->key + 100);
9841   emitcode ("", "%05d$:", lbl->key + 100);
9842   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
9843   emitcode ("", "%05d$:", lbl1->key + 100);
9844
9845   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9846   ifx->generated = 1;
9847   return 1;
9848 }
9849
9850 /*-----------------------------------------------------------------*/
9851 /* genReceive - generate code for a receive iCode                  */
9852 /*-----------------------------------------------------------------*/
9853 static void
9854 genReceive (iCode * ic)
9855 {
9856     int size = getSize (operandType (IC_RESULT (ic)));
9857     int offset = 0;
9858   D(emitcode (";     genReceive",""));
9859
9860   if (ic->argreg == 1) { /* first parameter */
9861       if (isOperandInFarSpace (IC_RESULT (ic)) &&
9862           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
9863            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
9864
9865           regs *tempRegs[4];
9866           int receivingA = 0;
9867           int roffset = 0;
9868
9869           for (offset = 0; offset<size; offset++)
9870             if (!strcmp (fReturn[offset], "a"))
9871               receivingA = 1;
9872
9873           if (!receivingA)
9874             {
9875               if (size==1 || getTempRegs(tempRegs, size-1, ic))
9876                 {
9877                   for (offset = size-1; offset>0; offset--)
9878                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
9879                   emitcode("mov","a,%s", fReturn[0]);
9880                   _G.accInUse++;
9881                   aopOp (IC_RESULT (ic), ic, FALSE);
9882                   _G.accInUse--;
9883                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
9884                           isOperandVolatile (IC_RESULT (ic), FALSE));
9885                   for (offset = 1; offset<size; offset++)
9886                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
9887                             isOperandVolatile (IC_RESULT (ic), FALSE));
9888                   goto release;
9889                 }
9890             }
9891           else
9892             {
9893               if (getTempRegs(tempRegs, size, ic))
9894                 {
9895                   for (offset = 0; offset<size; offset++)
9896                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
9897                   aopOp (IC_RESULT (ic), ic, FALSE);
9898                   for (offset = 0; offset<size; offset++)
9899                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
9900                             isOperandVolatile (IC_RESULT (ic), FALSE));
9901                   goto release;
9902                 }
9903             }
9904
9905           offset = fReturnSizeMCS51 - size;
9906           while (size--) {
9907               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
9908                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
9909               offset++;
9910           }
9911           aopOp (IC_RESULT (ic), ic, FALSE);
9912           size = AOP_SIZE (IC_RESULT (ic));
9913           offset = 0;
9914           while (size--) {
9915               emitcode ("pop", "acc");
9916               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9917           }
9918
9919       } else {
9920           _G.accInUse++;
9921           aopOp (IC_RESULT (ic), ic, FALSE);
9922           _G.accInUse--;
9923           assignResultValue (IC_RESULT (ic));
9924       }
9925   } else { /* second receive onwards */
9926       int rb1off ;
9927       aopOp (IC_RESULT (ic), ic, FALSE);
9928       rb1off = ic->argreg;
9929       while (size--) {
9930           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9931       }
9932   }
9933
9934 release:
9935   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9936 }
9937
9938 /*-----------------------------------------------------------------*/
9939 /* genDummyRead - generate code for dummy read of volatiles        */
9940 /*-----------------------------------------------------------------*/
9941 static void
9942 genDummyRead (iCode * ic)
9943 {
9944   operand *op;
9945   int size, offset;
9946
9947   D(emitcode(";     genDummyRead",""));
9948
9949   op = IC_RIGHT (ic);
9950   if (op && IS_SYMOP (op))
9951     {
9952       aopOp (op, ic, FALSE);
9953
9954       /* if the result is a bit */
9955       if (AOP_TYPE (op) == AOP_CRY)
9956         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9957       else
9958         {
9959           /* bit variables done */
9960           /* general case */
9961           size = AOP_SIZE (op);
9962           offset = 0;
9963           while (size--)
9964           {
9965             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9966             offset++;
9967           }
9968         }
9969
9970       freeAsmop (op, NULL, ic, TRUE);
9971     }
9972
9973   op = IC_LEFT (ic);
9974   if (op && IS_SYMOP (op))
9975     {
9976       aopOp (op, ic, FALSE);
9977
9978       /* if the result is a bit */
9979       if (AOP_TYPE (op) == AOP_CRY)
9980         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9981       else
9982         {
9983           /* bit variables done */
9984           /* general case */
9985           size = AOP_SIZE (op);
9986           offset = 0;
9987           while (size--)
9988           {
9989             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9990             offset++;
9991           }
9992         }
9993
9994       freeAsmop (op, NULL, ic, TRUE);
9995     }
9996 }
9997
9998 /*-----------------------------------------------------------------*/
9999 /* genCritical - generate code for start of a critical sequence    */
10000 /*-----------------------------------------------------------------*/
10001 static void
10002 genCritical (iCode *ic)
10003 {
10004   symbol *tlbl = newiTempLabel (NULL);
10005
10006   D(emitcode(";     genCritical",""));
10007
10008   if (IC_RESULT (ic))
10009     aopOp (IC_RESULT (ic), ic, TRUE);
10010
10011   emitcode ("setb", "c");
10012   emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10013   emitcode ("clr", "c");
10014   emitcode ("", "%05d$:", (tlbl->key + 100));
10015
10016   if (IC_RESULT (ic))
10017     outBitC (IC_RESULT (ic)); /* save old ea in an operand */
10018   else
10019     emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10020
10021   if (IC_RESULT (ic))
10022     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10023 }
10024
10025 /*-----------------------------------------------------------------*/
10026 /* genEndCritical - generate code for end of a critical sequence   */
10027 /*-----------------------------------------------------------------*/
10028 static void
10029 genEndCritical (iCode *ic)
10030 {
10031   D(emitcode(";     genEndCritical",""));
10032
10033   if (IC_RIGHT (ic))
10034     {
10035       aopOp (IC_RIGHT (ic), ic, FALSE);
10036       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10037         {
10038           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10039           emitcode ("mov", "ea,c");
10040         }
10041       else
10042         {
10043           MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
10044           emitcode ("rrc", "a");
10045           emitcode ("mov", "ea,c");
10046         }
10047       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10048     }
10049   else
10050     {
10051       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10052       emitcode ("mov", "ea,c");
10053     }
10054 }
10055
10056 /*-----------------------------------------------------------------*/
10057 /* gen51Code - generate code for 8051 based controllers            */
10058 /*-----------------------------------------------------------------*/
10059 void
10060 gen51Code (iCode * lic)
10061 {
10062   iCode *ic;
10063   int cln = 0;
10064   /* int cseq = 0; */
10065
10066   _G.currentFunc = NULL;
10067   lineHead = lineCurr = NULL;
10068
10069   /* print the allocation information */
10070   if (allocInfo && currFunc)
10071     printAllocInfo (currFunc, codeOutFile);
10072   /* if debug information required */
10073   if (options.debug && currFunc)
10074     {
10075       debugFile->writeFunction (currFunc, lic);
10076     }
10077   /* stack pointer name */
10078   if (options.useXstack)
10079     spname = "_spx";
10080   else
10081     spname = "sp";
10082
10083
10084   for (ic = lic; ic; ic = ic->next)
10085     {
10086       _G.current_iCode = ic;
10087
10088       if (ic->lineno && cln != ic->lineno)
10089         {
10090           if (options.debug)
10091             {
10092               debugFile->writeCLine(ic);
10093             }
10094           if (!options.noCcodeInAsm) {
10095             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10096                       printCLine(ic->filename, ic->lineno));
10097           }
10098           cln = ic->lineno;
10099         }
10100       #if 0
10101       if (ic->seqPoint && ic->seqPoint != cseq)
10102         {
10103           emitcode ("", "; sequence point %d", ic->seqPoint);
10104           cseq = ic->seqPoint;
10105         }
10106       #endif
10107       if (options.iCodeInAsm) {
10108         char regsInUse[80];
10109         int i;
10110
10111         for (i=0; i<8; i++) {
10112           sprintf (&regsInUse[i],
10113                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10114         }
10115         regsInUse[i]=0;
10116         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10117       }
10118       /* if the result is marked as
10119          spilt and rematerializable or code for
10120          this has already been generated then
10121          do nothing */
10122       if (resultRemat (ic) || ic->generated)
10123         continue;
10124
10125       /* depending on the operation */
10126       switch (ic->op)
10127         {
10128         case '!':
10129           genNot (ic);
10130           break;
10131
10132         case '~':
10133           genCpl (ic);
10134           break;
10135
10136         case UNARYMINUS:
10137           genUminus (ic);
10138           break;
10139
10140         case IPUSH:
10141           genIpush (ic);
10142           break;
10143
10144         case IPOP:
10145           /* IPOP happens only when trying to restore a
10146              spilt live range, if there is an ifx statement
10147              following this pop then the if statement might
10148              be using some of the registers being popped which
10149              would destory the contents of the register so
10150              we need to check for this condition and handle it */
10151           if (ic->next &&
10152               ic->next->op == IFX &&
10153               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10154             genIfx (ic->next, ic);
10155           else
10156             genIpop (ic);
10157           break;
10158
10159         case CALL:
10160           genCall (ic);
10161           break;
10162
10163         case PCALL:
10164           genPcall (ic);
10165           break;
10166
10167         case FUNCTION:
10168           genFunction (ic);
10169           break;
10170
10171         case ENDFUNCTION:
10172           genEndFunction (ic);
10173           break;
10174
10175         case RETURN:
10176           genRet (ic);
10177           break;
10178
10179         case LABEL:
10180           genLabel (ic);
10181           break;
10182
10183         case GOTO:
10184           genGoto (ic);
10185           break;
10186
10187         case '+':
10188           genPlus (ic);
10189           break;
10190
10191         case '-':
10192           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10193             genMinus (ic);
10194           break;
10195
10196         case '*':
10197           genMult (ic);
10198           break;
10199
10200         case '/':
10201           genDiv (ic);
10202           break;
10203
10204         case '%':
10205           genMod (ic);
10206           break;
10207
10208         case '>':
10209           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10210           break;
10211
10212         case '<':
10213           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10214           break;
10215
10216         case LE_OP:
10217         case GE_OP:
10218         case NE_OP:
10219
10220           /* note these two are xlated by algebraic equivalence
10221              during parsing SDCC.y */
10222           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10223                   "got '>=' or '<=' shouldn't have come here");
10224           break;
10225
10226         case EQ_OP:
10227           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10228           break;
10229
10230         case AND_OP:
10231           genAndOp (ic);
10232           break;
10233
10234         case OR_OP:
10235           genOrOp (ic);
10236           break;
10237
10238         case '^':
10239           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10240           break;
10241
10242         case '|':
10243           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10244           break;
10245
10246         case BITWISEAND:
10247           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10248           break;
10249
10250         case INLINEASM:
10251           genInline (ic);
10252           break;
10253
10254         case RRC:
10255           genRRC (ic);
10256           break;
10257
10258         case RLC:
10259           genRLC (ic);
10260           break;
10261
10262         case GETHBIT:
10263           genGetHbit (ic);
10264           break;
10265
10266         case LEFT_OP:
10267           genLeftShift (ic);
10268           break;
10269
10270         case RIGHT_OP:
10271           genRightShift (ic);
10272           break;
10273
10274         case GET_VALUE_AT_ADDRESS:
10275           genPointerGet (ic,
10276                          hasInc (IC_LEFT (ic), ic,
10277                                  getSize (operandType (IC_RESULT (ic)))),
10278                          ifxForOp (IC_RESULT (ic), ic) );
10279           break;
10280
10281         case '=':
10282           if (POINTER_SET (ic))
10283             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10284           else
10285             genAssign (ic);
10286           break;
10287
10288         case IFX:
10289           genIfx (ic, NULL);
10290           break;
10291
10292         case ADDRESS_OF:
10293           genAddrOf (ic);
10294           break;
10295
10296         case JUMPTABLE:
10297           genJumpTab (ic);
10298           break;
10299
10300         case CAST:
10301           genCast (ic);
10302           break;
10303
10304         case RECEIVE:
10305           genReceive (ic);
10306           break;
10307
10308         case SEND:
10309           addSet (&_G.sendSet, ic);
10310           break;
10311
10312         case DUMMY_READ_VOLATILE:
10313           genDummyRead (ic);
10314           break;
10315
10316         case CRITICAL:
10317           genCritical (ic);
10318           break;
10319
10320         case ENDCRITICAL:
10321           genEndCritical (ic);
10322           break;
10323
10324         case SWAP:
10325           genSwap (ic);
10326           break;
10327
10328         default:
10329           ic = ic;
10330         }
10331     }
10332
10333   _G.current_iCode = NULL;
10334
10335   /* now we are ready to call the
10336      peep hole optimizer */
10337   if (!options.nopeep)
10338     peepHole (&lineHead);
10339
10340   /* now do the actual printing */
10341   printLine (lineHead, codeOutFile);
10342   return;
10343 }