* src/ds390/gen.c (genCpl): fixed bit=~(char/bit) bugs, added warning
[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     union
72       {
73         struct
74           {
75             short r0InB : 2;//2 so we can see it overflow
76             short r1InB : 2;//2 so we can see it overflow
77             short OpInB : 2;//2 so we can see it overflow
78           } ;
79         short BInUse;
80       } ;
81     short accInUse;
82     short inLine;
83     short debugLine;
84     short nRegsSaved;
85     set *sendSet;
86     iCode *current_iCode;
87     symbol *currentFunc;
88   }
89 _G;
90
91 static char *rb1regs[] = {
92     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
93 };
94
95 extern int mcs51_ptrRegReq;
96 extern int mcs51_nRegs;
97 extern FILE *codeOutFile;
98 static void saveRBank (int, iCode *, bool);
99
100 #define RESULTONSTACK(x) \
101                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
102                          IC_RESULT(x)->aop->type == AOP_STK )
103
104 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
105 #define CLRC     emitcode("clr","c")
106 #define SETC     emitcode("setb","c")
107
108 static lineNode *lineHead = NULL;
109 static lineNode *lineCurr = NULL;
110
111 static unsigned char SLMask[] =
112 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
113  0xE0, 0xC0, 0x80, 0x00};
114 static unsigned char SRMask[] =
115 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
116  0x07, 0x03, 0x01, 0x00};
117
118 #define LSB     0
119 #define MSB16   1
120 #define MSB24   2
121 #define MSB32   3
122
123 /*-----------------------------------------------------------------*/
124 /* emitcode - writes the code into a file : for now it is simple    */
125 /*-----------------------------------------------------------------*/
126 static void
127 emitcode (char *inst, const char *fmt,...)
128 {
129   va_list ap;
130   char lb[INITIAL_INLINEASM];
131   char *lbp = lb;
132
133   va_start (ap, fmt);
134
135   if (inst && *inst)
136     {
137       if (fmt && *fmt)
138           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
139       else
140           SNPRINTF (lb, sizeof(lb), "%s", inst);
141       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
142     }
143   else
144       tvsprintf (lb, sizeof(lb), fmt, ap);
145
146   while (isspace (*lbp))
147       lbp++;
148
149   if (lbp && *lbp)
150       lineCurr = (lineCurr ?
151                   connectLine (lineCurr, newLineNode (lb)) :
152                   (lineHead = newLineNode (lb)));
153   lineCurr->isInline = _G.inLine;
154   lineCurr->isDebug = _G.debugLine;
155   lineCurr->ic = _G.current_iCode;
156   lineCurr->isComment = (*lbp==';');
157   va_end (ap);
158 }
159
160 /*-----------------------------------------------------------------*/
161 /* mcs51_emitDebuggerSymbol - associate the current code location  */
162 /*   with a debugger symbol                                        */
163 /*-----------------------------------------------------------------*/
164 void
165 mcs51_emitDebuggerSymbol (char * debugSym)
166 {
167   _G.debugLine = 1;
168   emitcode ("", "%s ==.", debugSym);
169   _G.debugLine = 0;
170 }
171
172 /*-----------------------------------------------------------------*/
173 /* mova - moves specified value into accumulator                   */
174 /*-----------------------------------------------------------------*/
175 static void
176 mova (const char *x)
177 {
178   /* do some early peephole optimization */
179   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
180     return;
181
182   emitcode("mov","a,%s", x);
183 }
184
185 /*-----------------------------------------------------------------*/
186 /* pushB - saves register B if necessary                           */
187 /*-----------------------------------------------------------------*/
188 static bool
189 pushB (void)
190 {
191   bool pushedB = FALSE;
192
193   if (_G.BInUse)
194     {
195       emitcode ("push", "b");
196 //    printf("B was in use !\n");
197       pushedB = TRUE;
198     }
199   else
200     {
201       _G.OpInB++;
202     }
203   return pushedB;
204 }
205
206 /*-----------------------------------------------------------------*/
207 /* popB - restores value of register B if necessary                */
208 /*-----------------------------------------------------------------*/
209 static void
210 popB (bool pushedB)
211 {
212   if (pushedB)
213     {
214       emitcode ("pop", "b");
215     }
216   else
217     {
218       _G.OpInB--;
219     }
220 }
221
222 /*-----------------------------------------------------------------*/
223 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
224 /*-----------------------------------------------------------------*/
225 static regs *
226 getFreePtr (iCode * ic, asmop ** aopp, bool result)
227 {
228   bool r0iu, r1iu;
229   bool r0ou, r1ou;
230
231   /* the logic: if r0 & r1 used in the instruction
232      then we are in trouble otherwise */
233
234   /* first check if r0 & r1 are used by this
235      instruction, in which case we are in trouble */
236   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
237   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
238   if (r0iu && r1iu) {
239       goto endOfWorld;
240     }
241
242   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
243   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
244
245   /* if no usage of r0 then return it */
246   if (!r0iu && !r0ou)
247     {
248       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
249       (*aopp)->type = AOP_R0;
250
251       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
252     }
253
254   /* if no usage of r1 then return it */
255   if (!r1iu && !r1ou)
256     {
257       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
258       (*aopp)->type = AOP_R1;
259
260       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
261     }
262
263   /* now we know they both have usage */
264   /* if r0 not used in this instruction */
265   if (!r0iu)
266     {
267       /* push it if not already pushed */
268       if (ic->op == IPUSH)
269         {
270           emitcode ("mov", "b,%s",
271                     mcs51_regWithIdx (R0_IDX)->dname);
272           _G.r0InB++;
273         }
274       else if (!_G.r0Pushed)
275         {
276           emitcode ("push", "%s",
277                     mcs51_regWithIdx (R0_IDX)->dname);
278           _G.r0Pushed++;
279         }
280
281       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
282       (*aopp)->type = AOP_R0;
283
284       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
285     }
286
287   /* if r1 not used then */
288
289   if (!r1iu)
290     {
291       /* push it if not already pushed */
292       if (ic->op == IPUSH)
293         {
294           emitcode ("mov", "b,%s",
295                     mcs51_regWithIdx (R1_IDX)->dname);
296           _G.r1InB++;
297         }
298       else if (!_G.r1Pushed)
299         {
300           emitcode ("push", "%s",
301                     mcs51_regWithIdx (R1_IDX)->dname);
302           _G.r1Pushed++;
303         }
304
305       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
306       (*aopp)->type = AOP_R1;
307       return mcs51_regWithIdx (R1_IDX);
308     }
309 endOfWorld:
310   /* I said end of world, but not quite end of world yet */
311   if (result) {
312     /* we can push it on the stack */
313     (*aopp)->type = AOP_STK;
314     return NULL;
315   } else {
316     /* in the case that result AND left AND right needs a pointer reg
317        we can safely use the result's */
318     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
319       (*aopp)->type = AOP_R0;
320       return mcs51_regWithIdx (R0_IDX);
321     }
322     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
323       (*aopp)->type = AOP_R1;
324       return mcs51_regWithIdx (R1_IDX);
325     }
326   }
327
328   /* now this is REALLY the end of the world */
329   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
330           "getFreePtr should never reach here");
331   exit (1);
332 }
333
334
335 /*-----------------------------------------------------------------*/
336 /* getTempRegs - initialize an array of pointers to GPR registers */
337 /*               that are not in use. Returns 1 if the requested   */
338 /*               number of registers were available, 0 otherwise.  */
339 /*-----------------------------------------------------------------*/
340 int
341 getTempRegs(regs **tempRegs, int size, iCode *ic)
342 {
343   bitVect * freeRegs;
344   int i;
345   int offset;
346
347   if (!ic)
348     ic = _G.current_iCode;
349   if (!ic)
350     return 0;
351   if (!_G.currentFunc)
352     return 0;
353
354   freeRegs = newBitVect(8);
355   bitVectSetBit (freeRegs, R2_IDX);
356   bitVectSetBit (freeRegs, R3_IDX);
357   bitVectSetBit (freeRegs, R4_IDX);
358   bitVectSetBit (freeRegs, R5_IDX);
359   bitVectSetBit (freeRegs, R6_IDX);
360   bitVectSetBit (freeRegs, R7_IDX);
361
362   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
363     {
364       bitVect * newfreeRegs;
365       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
366       freeBitVect(freeRegs);
367       freeRegs = newfreeRegs;
368     }
369   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
370
371   offset = 0;
372   for (i=0; i<freeRegs->size; i++)
373     {
374       if (bitVectBitValue(freeRegs,i))
375         tempRegs[offset++] = mcs51_regWithIdx(i);
376       if (offset>=size)
377         {
378           freeBitVect(freeRegs);
379           return 1;
380         }
381     }
382
383   freeBitVect(freeRegs);
384   return 1;
385 }
386
387
388 /*-----------------------------------------------------------------*/
389 /* newAsmop - creates a new asmOp                                  */
390 /*-----------------------------------------------------------------*/
391 static asmop *
392 newAsmop (short type)
393 {
394   asmop *aop;
395
396   aop = Safe_calloc (1, sizeof (asmop));
397   aop->type = type;
398   return aop;
399 }
400
401 /*-----------------------------------------------------------------*/
402 /* pointerCode - returns the code for a pointer type               */
403 /*-----------------------------------------------------------------*/
404 static int
405 pointerCode (sym_link * etype)
406 {
407
408   return PTR_TYPE (SPEC_OCLS (etype));
409
410 }
411
412 /*-----------------------------------------------------------------*/
413 /* leftRightUseAcc - returns size of accumulator use by operands   */
414 /*-----------------------------------------------------------------*/
415 static int
416 leftRightUseAcc(iCode *ic)
417 {
418   operand *op;
419   int size;
420   int accuseSize = 0;
421   int accuse = 0;
422
423   if (!ic)
424     {
425       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
426               "null iCode pointer");
427       return 0;
428     }
429
430   if (ic->op == IFX)
431     {
432       op = IC_COND (ic);
433       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
434         {
435           accuse = 1;
436           size = getSize (OP_SYMBOL (op)->type);
437           if (size>accuseSize)
438             accuseSize = size;
439         }
440     }
441   else if (ic->op == JUMPTABLE)
442     {
443       op = IC_JTCOND (ic);
444       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
445         {
446           accuse = 1;
447           size = getSize (OP_SYMBOL (op)->type);
448           if (size>accuseSize)
449             accuseSize = size;
450         }
451     }
452   else
453     {
454       op = IC_LEFT (ic);
455       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
456         {
457           accuse = 1;
458           size = getSize (OP_SYMBOL (op)->type);
459           if (size>accuseSize)
460             accuseSize = size;
461         }
462       op = IC_RIGHT (ic);
463       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
464         {
465           accuse = 1;
466           size = getSize (OP_SYMBOL (op)->type);
467           if (size>accuseSize)
468             accuseSize = size;
469         }
470     }
471
472   if (accuseSize)
473     return accuseSize;
474   else
475     return accuse;
476 }
477
478 /*-----------------------------------------------------------------*/
479 /* aopForSym - for a true symbol                                   */
480 /*-----------------------------------------------------------------*/
481 static asmop *
482 aopForSym (iCode * ic, symbol * sym, bool result)
483 {
484   asmop *aop;
485   memmap *space;
486
487   wassertl (ic != NULL, "Got a null iCode");
488   wassertl (sym != NULL, "Got a null symbol");
489
490   space = SPEC_OCLS (sym->etype);
491
492   /* if already has one */
493   if (sym->aop)
494     return sym->aop;
495
496   /* assign depending on the storage class */
497   /* if it is on the stack or indirectly addressable */
498   /* space we need to assign either r0 or r1 to it   */
499   if (sym->onStack || sym->iaccess)
500     {
501       sym->aop = aop = newAsmop (0);
502       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
503       aop->size = getSize (sym->type);
504
505       /* now assign the address of the variable to
506          the pointer register */
507       if (aop->type != AOP_STK)
508         {
509
510           if (sym->onStack)
511             {
512               if (_G.accInUse || leftRightUseAcc (ic))
513                 emitcode ("push", "acc");
514
515               emitcode ("mov", "a,_bp");
516               emitcode ("add", "a,#0x%02x",
517                         ((sym->stack < 0) ?
518                          ((char) (sym->stack - _G.nRegsSaved)) :
519                          ((char) sym->stack)) & 0xff);
520               emitcode ("mov", "%s,a",
521                         aop->aopu.aop_ptr->name);
522
523               if (_G.accInUse || leftRightUseAcc (ic))
524                 emitcode ("pop", "acc");
525             }
526           else
527             emitcode ("mov", "%s,#%s",
528                       aop->aopu.aop_ptr->name,
529                       sym->rname);
530           aop->paged = space->paged;
531         }
532       else
533         aop->aopu.aop_stk = sym->stack;
534       return aop;
535     }
536
537   /* if in bit space */
538   if (IN_BITSPACE (space))
539     {
540       sym->aop = aop = newAsmop (AOP_CRY);
541       aop->aopu.aop_dir = sym->rname;
542       aop->size = getSize (sym->type);
543       return aop;
544     }
545   /* if it is in direct space */
546   if (IN_DIRSPACE (space))
547     {
548       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
549       //printTypeChainRaw(sym->type, NULL);
550       //printf("space = %s\n", space ? space->sname : "NULL");
551       sym->aop = aop = newAsmop (AOP_DIR);
552       aop->aopu.aop_dir = sym->rname;
553       aop->size = getSize (sym->type);
554       return aop;
555     }
556
557   /* special case for a function */
558   if (IS_FUNC (sym->type))
559     {
560       sym->aop = aop = newAsmop (AOP_IMMD);
561       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
562       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
563       aop->size = FPTRSIZE;
564       return aop;
565     }
566
567   /* only remaining is far space */
568   /* in which case DPTR gets the address */
569   sym->aop = aop = newAsmop (AOP_DPTR);
570   emitcode ("mov", "dptr,#%s", sym->rname);
571   aop->size = getSize (sym->type);
572
573   /* if it is in code space */
574   if (IN_CODESPACE (space))
575     aop->code = 1;
576
577   return aop;
578 }
579
580 /*-----------------------------------------------------------------*/
581 /* aopForRemat - rematerialzes an object                           */
582 /*-----------------------------------------------------------------*/
583 static asmop *
584 aopForRemat (symbol * sym)
585 {
586   iCode *ic = sym->rematiCode;
587   asmop *aop = newAsmop (AOP_IMMD);
588   int ptr_type = 0;
589   int val = 0;
590
591   for (;;)
592     {
593       if (ic->op == '+')
594         val += (int) operandLitValue (IC_RIGHT (ic));
595       else if (ic->op == '-')
596         val -= (int) operandLitValue (IC_RIGHT (ic));
597       else if (IS_CAST_ICODE(ic)) {
598               sym_link *from_type = operandType(IC_RIGHT(ic));
599               aop->aopu.aop_immd.from_cast_remat = 1;
600               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
601               ptr_type = DCL_TYPE(from_type);
602               if (ptr_type == IPOINTER) {
603                 // bug #481053
604                 ptr_type = POINTER;
605               }
606               continue ;
607       } else break;
608
609       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
610     }
611
612   if (val)
613     sprintf (buffer, "(%s %c 0x%04x)",
614              OP_SYMBOL (IC_LEFT (ic))->rname,
615              val >= 0 ? '+' : '-',
616              abs (val) & 0xffff);
617   else
618     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
619
620   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
621   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
622   /* set immd2 field if required */
623   if (aop->aopu.aop_immd.from_cast_remat) {
624           sprintf(buffer,"#0x%02x",ptr_type);
625           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
626           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
627   }
628
629   return aop;
630 }
631
632 /*-----------------------------------------------------------------*/
633 /* regsInCommon - two operands have some registers in common       */
634 /*-----------------------------------------------------------------*/
635 static bool
636 regsInCommon (operand * op1, operand * op2)
637 {
638   symbol *sym1, *sym2;
639   int i;
640
641   /* if they have registers in common */
642   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
643     return FALSE;
644
645   sym1 = OP_SYMBOL (op1);
646   sym2 = OP_SYMBOL (op2);
647
648   if (sym1->nRegs == 0 || sym2->nRegs == 0)
649     return FALSE;
650
651   for (i = 0; i < sym1->nRegs; i++)
652     {
653       int j;
654       if (!sym1->regs[i])
655         continue;
656
657       for (j = 0; j < sym2->nRegs; j++)
658         {
659           if (!sym2->regs[j])
660             continue;
661
662           if (sym2->regs[j] == sym1->regs[i])
663             return TRUE;
664         }
665     }
666
667   return FALSE;
668 }
669
670 /*-----------------------------------------------------------------*/
671 /* operandsEqu - equivalent                                        */
672 /*-----------------------------------------------------------------*/
673 static bool
674 operandsEqu (operand * op1, operand * op2)
675 {
676   symbol *sym1, *sym2;
677
678   /* if they're not symbols */
679   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
680     return FALSE;
681
682   sym1 = OP_SYMBOL (op1);
683   sym2 = OP_SYMBOL (op2);
684
685   /* if both are itemps & one is spilt
686      and the other is not then false */
687   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
688       sym1->isspilt != sym2->isspilt)
689     return FALSE;
690
691   /* if they are the same */
692   if (sym1 == sym2)
693     return TRUE;
694
695   /* if they have the same rname */
696   if (sym1->rname[0] && sym2->rname[0]
697       && strcmp (sym1->rname, sym2->rname) == 0)
698     return TRUE;
699
700   /* if left is a tmp & right is not */
701   if (IS_ITEMP (op1) &&
702       !IS_ITEMP (op2) &&
703       sym1->isspilt &&
704       (sym1->usl.spillLoc == sym2))
705     return TRUE;
706
707   if (IS_ITEMP (op2) &&
708       !IS_ITEMP (op1) &&
709       sym2->isspilt &&
710       sym1->level > 0 &&
711       (sym2->usl.spillLoc == sym1))
712     return TRUE;
713
714   return FALSE;
715 }
716
717 /*-----------------------------------------------------------------*/
718 /* sameRegs - two asmops have the same registers                   */
719 /*-----------------------------------------------------------------*/
720 static bool
721 sameRegs (asmop * aop1, asmop * aop2)
722 {
723   int i;
724
725   if (aop1 == aop2)
726     return TRUE;
727
728   if (aop1->type != AOP_REG ||
729       aop2->type != AOP_REG)
730     return FALSE;
731
732   if (aop1->size != aop2->size)
733     return FALSE;
734
735   for (i = 0; i < aop1->size; i++)
736     if (aop1->aopu.aop_reg[i] !=
737         aop2->aopu.aop_reg[i])
738       return FALSE;
739
740   return TRUE;
741 }
742
743 /*-----------------------------------------------------------------*/
744 /* aopOp - allocates an asmop for an operand  :                    */
745 /*-----------------------------------------------------------------*/
746 static void
747 aopOp (operand * op, iCode * ic, bool result)
748 {
749   asmop *aop;
750   symbol *sym;
751   int i;
752
753   if (!op)
754     return;
755
756   /* if this a literal */
757   if (IS_OP_LITERAL (op))
758     {
759       op->aop = aop = newAsmop (AOP_LIT);
760       aop->aopu.aop_lit = op->operand.valOperand;
761       aop->size = getSize (operandType (op));
762       return;
763     }
764
765   /* if already has a asmop then continue */
766   if (op->aop )
767     return;
768
769   /* if the underlying symbol has a aop */
770   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
771     {
772       op->aop = OP_SYMBOL (op)->aop;
773       return;
774     }
775
776   /* if this is a true symbol */
777   if (IS_TRUE_SYMOP (op))
778     {
779       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
780       return;
781     }
782
783   /* this is a temporary : this has
784      only four choices :
785      a) register
786      b) spillocation
787      c) rematerialize
788      d) conditional
789      e) can be a return use only */
790
791   sym = OP_SYMBOL (op);
792
793   /* if the type is a conditional */
794   if (sym->regType == REG_CND)
795     {
796       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
797       aop->size = 0;
798       return;
799     }
800
801   /* if it is spilt then two situations
802      a) is rematerialize
803      b) has a spill location */
804   if (sym->isspilt || sym->nRegs == 0)
805     {
806
807       /* rematerialize it NOW */
808       if (sym->remat)
809         {
810           sym->aop = op->aop = aop =
811             aopForRemat (sym);
812           aop->size = getSize (sym->type);
813           return;
814         }
815
816       if (sym->accuse)
817         {
818           int i;
819           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
820           aop->size = getSize (sym->type);
821           for (i = 0; i < 2; i++)
822             aop->aopu.aop_str[i] = accUse[i];
823           return;
824         }
825
826       if (sym->ruonly)
827         {
828           unsigned i;
829
830           aop = op->aop = sym->aop = newAsmop (AOP_STR);
831           aop->size = getSize (sym->type);
832           for (i = 0; i < fReturnSizeMCS51; i++)
833             aop->aopu.aop_str[i] = fReturn[i];
834           return;
835         }
836
837       if (sym->usl.spillLoc)
838         {
839           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
840             {
841               /* force a new aop if sizes differ */
842               sym->usl.spillLoc->aop = NULL;
843             }
844           sym->aop = op->aop = aop =
845                      aopForSym (ic, sym->usl.spillLoc, result);
846           aop->size = getSize (sym->type);
847           return;
848         }
849
850       /* else must be a dummy iTemp */
851       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
852       aop->size = getSize (sym->type);
853       return;
854     }
855
856   /* must be in a register */
857   sym->aop = op->aop = aop = newAsmop (AOP_REG);
858   aop->size = sym->nRegs;
859   for (i = 0; i < sym->nRegs; i++)
860     aop->aopu.aop_reg[i] = sym->regs[i];
861 }
862
863 /*-----------------------------------------------------------------*/
864 /* freeAsmop - free up the asmop given to an operand               */
865 /*----------------------------------------------------------------*/
866 static void
867 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
868 {
869   asmop *aop;
870
871   if (!op)
872     aop = aaop;
873   else
874     aop = op->aop;
875
876   if (!aop)
877     return;
878
879   if (aop->freed)
880     goto dealloc;
881
882   aop->freed = 1;
883
884   /* depending on the asmop type only three cases need work AOP_RO
885      , AOP_R1 && AOP_STK */
886   switch (aop->type)
887     {
888     case AOP_R0:
889       if (_G.r0InB)
890         {
891           emitcode ("mov", "r0,b");
892           _G.r0InB--;
893         }
894       else if (_G.r0Pushed)
895         {
896           if (pop)
897             {
898               emitcode ("pop", "ar0");
899               _G.r0Pushed--;
900             }
901         }
902       bitVectUnSetBit (ic->rUsed, R0_IDX);
903       break;
904
905     case AOP_R1:
906       if (_G.r1InB)
907         {
908           emitcode ("mov", "r1,b");
909           _G.r1InB--;
910         }
911       if (_G.r1Pushed)
912         {
913           if (pop)
914             {
915               emitcode ("pop", "ar1");
916               _G.r1Pushed--;
917             }
918         }
919       bitVectUnSetBit (ic->rUsed, R1_IDX);
920       break;
921
922     case AOP_STK:
923       {
924         int sz = aop->size;
925         int stk = aop->aopu.aop_stk + aop->size - 1;
926         bitVectUnSetBit (ic->rUsed, R0_IDX);
927         bitVectUnSetBit (ic->rUsed, R1_IDX);
928
929         getFreePtr (ic, &aop, FALSE);
930
931         if (stk)
932           {
933             emitcode ("mov", "a,_bp");
934             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
935             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
936           }
937         else
938           {
939             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
940           }
941
942         while (sz--)
943           {
944             emitcode ("pop", "acc");
945             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
946             if (!sz)
947               break;
948             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
949           }
950         op->aop = aop;
951         freeAsmop (op, NULL, ic, TRUE);
952         if (_G.r1Pushed)
953           {
954             emitcode ("pop", "ar1");
955             _G.r1Pushed--;
956           }
957
958         if (_G.r0Pushed)
959           {
960             emitcode ("pop", "ar0");
961             _G.r0Pushed--;
962           }
963       }
964     }
965
966 dealloc:
967   /* all other cases just dealloc */
968   if (op)
969     {
970       op->aop = NULL;
971       if (IS_SYMOP (op))
972         {
973           OP_SYMBOL (op)->aop = NULL;
974           /* if the symbol has a spill */
975           if (SPIL_LOC (op))
976             SPIL_LOC (op)->aop = NULL;
977         }
978     }
979 }
980
981 /*------------------------------------------------------------------*/
982 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
983 /*                      pop r0 or r1 off stack if pushed            */
984 /*------------------------------------------------------------------*/
985 static void
986 freeForBranchAsmop (operand * op)
987 {
988   asmop *aop;
989
990   if (!op)
991     return;
992
993   aop = op->aop;
994
995   if (!aop)
996     return;
997
998   if (aop->freed)
999     return;
1000
1001   switch (aop->type)
1002     {
1003     case AOP_R0:
1004       if (_G.r0InB)
1005         {
1006           emitcode ("mov", "r0,b");
1007         }
1008       else if (_G.r0Pushed)
1009         {
1010           emitcode ("pop", "ar0");
1011         }
1012       break;
1013
1014     case AOP_R1:
1015       if (_G.r1InB)
1016         {
1017           emitcode ("mov", "r1,b");
1018         }
1019       else if (_G.r1Pushed)
1020         {
1021           emitcode ("pop", "ar1");
1022         }
1023       break;
1024
1025     case AOP_STK:
1026       {
1027         int sz = aop->size;
1028         int stk = aop->aopu.aop_stk + aop->size - 1;
1029
1030         emitcode ("mov", "b,r0");
1031         if (stk)
1032           {
1033             emitcode ("mov", "a,_bp");
1034             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1035             emitcode ("mov", "r0,a");
1036           }
1037         else
1038           {
1039             emitcode ("mov", "r0,_bp");
1040           }
1041
1042         while (sz--)
1043           {
1044             emitcode ("pop", "acc");
1045             emitcode ("mov", "@r0,a");
1046             if (!sz)
1047               break;
1048             emitcode ("dec", "r0");
1049           }
1050         emitcode ("mov", "r0,b");
1051       }
1052     }
1053
1054 }
1055
1056 /*-----------------------------------------------------------------*/
1057 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1058 /*                 clobber the accumulator                         */
1059 /*-----------------------------------------------------------------*/
1060 static bool
1061 aopGetUsesAcc (asmop *aop, int offset)
1062 {
1063   if (offset > (aop->size - 1))
1064     return FALSE;
1065
1066   switch (aop->type)
1067     {
1068
1069     case AOP_R0:
1070     case AOP_R1:
1071       if (aop->paged)
1072         return TRUE;
1073       return FALSE;
1074     case AOP_DPTR:
1075       return TRUE;
1076     case AOP_IMMD:
1077       return FALSE;
1078     case AOP_DIR:
1079       return FALSE;
1080     case AOP_REG:
1081       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1082       return FALSE;
1083     case AOP_CRY:
1084       return TRUE;
1085     case AOP_ACC:
1086       return TRUE;
1087     case AOP_LIT:
1088       return FALSE;
1089     case AOP_STR:
1090       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1091         return TRUE;
1092       return FALSE;
1093     case AOP_DUMMY:
1094       return FALSE;
1095     default:
1096       /* Error case --- will have been caught already */
1097       wassert(0);
1098       return FALSE;
1099     }
1100 }
1101
1102 /*-----------------------------------------------------------------*/
1103 /* aopGet - for fetching value of the aop                          */
1104 /*-----------------------------------------------------------------*/
1105 static char *
1106 aopGet (asmop * aop, int offset, bool bit16, bool dname)
1107 {
1108   char *s = buffer;
1109   char *rs;
1110
1111   /* offset is greater than
1112      size then zero */
1113   if (offset > (aop->size - 1) &&
1114       aop->type != AOP_LIT)
1115     return zero;
1116
1117   /* depending on type */
1118   switch (aop->type)
1119     {
1120     case AOP_DUMMY:
1121       return zero;
1122
1123     case AOP_R0:
1124     case AOP_R1:
1125       /* if we need to increment it */
1126       while (offset > aop->coff)
1127         {
1128           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1129           aop->coff++;
1130         }
1131
1132       while (offset < aop->coff)
1133         {
1134           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1135           aop->coff--;
1136         }
1137
1138       aop->coff = offset;
1139       if (aop->paged)
1140         {
1141           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1142           return (dname ? "acc" : "a");
1143         }
1144       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1145       rs = Safe_calloc (1, strlen (s) + 1);
1146       strcpy (rs, s);
1147       return rs;
1148
1149     case AOP_DPTR:
1150       if (aop->code && aop->coff==0 && offset>=1) {
1151         emitcode ("mov", "a,#0x%02x", offset);
1152         emitcode ("movc", "a,@a+dptr");
1153         return (dname ? "acc" : "a");
1154       }
1155
1156       while (offset > aop->coff)
1157         {
1158           emitcode ("inc", "dptr");
1159           aop->coff++;
1160         }
1161
1162       while (offset < aop->coff)
1163         {
1164           emitcode ("lcall", "__decdptr");
1165           aop->coff--;
1166         }
1167
1168       aop->coff = offset;
1169       if (aop->code)
1170         {
1171           emitcode ("clr", "a");
1172           emitcode ("movc", "a,@a+dptr");
1173         }
1174       else
1175         {
1176           emitcode ("movx", "a,@dptr");
1177         }
1178       return (dname ? "acc" : "a");
1179
1180
1181     case AOP_IMMD:
1182       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1183               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1184       } else if (bit16)
1185         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1186       else if (offset)
1187         sprintf (s, "#(%s >> %d)",
1188                  aop->aopu.aop_immd.aop_immd1,
1189                  offset * 8);
1190       else
1191         sprintf (s, "#%s",
1192                  aop->aopu.aop_immd.aop_immd1);
1193       rs = Safe_calloc (1, strlen (s) + 1);
1194       strcpy (rs, s);
1195       return rs;
1196
1197     case AOP_DIR:
1198       if (offset)
1199         sprintf (s, "(%s + %d)",
1200                  aop->aopu.aop_dir,
1201                  offset);
1202       else
1203         sprintf (s, "%s", aop->aopu.aop_dir);
1204       rs = Safe_calloc (1, strlen (s) + 1);
1205       strcpy (rs, s);
1206       return rs;
1207
1208     case AOP_REG:
1209       if (dname)
1210         return aop->aopu.aop_reg[offset]->dname;
1211       else
1212         return aop->aopu.aop_reg[offset]->name;
1213
1214     case AOP_CRY:
1215       emitcode ("clr", "a");
1216       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1217       emitcode ("rlc", "a");
1218       return (dname ? "acc" : "a");
1219
1220     case AOP_ACC:
1221       if (!offset && dname)
1222         return "acc";
1223       return aop->aopu.aop_str[offset];
1224
1225     case AOP_LIT:
1226       return aopLiteral (aop->aopu.aop_lit, offset);
1227
1228     case AOP_STR:
1229       aop->coff = offset;
1230       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1231           dname)
1232         return "acc";
1233
1234       return aop->aopu.aop_str[offset];
1235
1236     }
1237
1238   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1239           "aopget got unsupported aop->type");
1240   exit (1);
1241 }
1242 /*-----------------------------------------------------------------*/
1243 /* aopPut - puts a string for a aop                                */
1244 /*-----------------------------------------------------------------*/
1245 static void
1246 aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
1247 {
1248   char *d = buffer;
1249
1250   if (aop->size && offset > (aop->size - 1))
1251     {
1252       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1253               "aopPut got offset > aop->size");
1254       exit (1);
1255     }
1256
1257   /* will assign value to value */
1258   /* depending on where it is ofcourse */
1259   switch (aop->type)
1260     {
1261     case AOP_DUMMY:
1262       MOVA (s);         /* read s in case it was volatile */
1263       break;
1264
1265     case AOP_DIR:
1266       if (offset)
1267         sprintf (d, "(%s + %d)",
1268                  aop->aopu.aop_dir, offset);
1269       else
1270         sprintf (d, "%s", aop->aopu.aop_dir);
1271
1272       if (strcmp (d, s) ||
1273           bvolatile)
1274           emitcode ("mov", "%s,%s", d, s);
1275
1276       break;
1277
1278     case AOP_REG:
1279       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1280           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1281         {
1282           if (*s == '@' ||
1283               strcmp (s, "r0") == 0 ||
1284               strcmp (s, "r1") == 0 ||
1285               strcmp (s, "r2") == 0 ||
1286               strcmp (s, "r3") == 0 ||
1287               strcmp (s, "r4") == 0 ||
1288               strcmp (s, "r5") == 0 ||
1289               strcmp (s, "r6") == 0 ||
1290               strcmp (s, "r7") == 0)
1291             emitcode ("mov", "%s,%s",
1292                       aop->aopu.aop_reg[offset]->dname, s);
1293           else
1294             emitcode ("mov", "%s,%s",
1295                       aop->aopu.aop_reg[offset]->name, s);
1296         }
1297       break;
1298
1299     case AOP_DPTR:
1300       if (aop->code)
1301         {
1302           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1303                   "aopPut writing to code space");
1304           exit (1);
1305         }
1306
1307       while (offset > aop->coff)
1308         {
1309           aop->coff++;
1310           emitcode ("inc", "dptr");
1311         }
1312
1313       while (offset < aop->coff)
1314         {
1315           aop->coff--;
1316           emitcode ("lcall", "__decdptr");
1317         }
1318
1319       aop->coff = offset;
1320
1321       /* if not in accumulater */
1322       MOVA (s);
1323
1324       emitcode ("movx", "@dptr,a");
1325       break;
1326
1327     case AOP_R0:
1328     case AOP_R1:
1329       while (offset > aop->coff)
1330         {
1331           aop->coff++;
1332           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1333         }
1334       while (offset < aop->coff)
1335         {
1336           aop->coff--;
1337           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1338         }
1339       aop->coff = offset;
1340
1341       if (aop->paged)
1342         {
1343           MOVA (s);
1344           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1345
1346         }
1347       else if (*s == '@')
1348         {
1349           MOVA (s);
1350           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1351         }
1352       else if (strcmp (s, "r0") == 0 ||
1353                strcmp (s, "r1") == 0 ||
1354                strcmp (s, "r2") == 0 ||
1355                strcmp (s, "r3") == 0 ||
1356                strcmp (s, "r4") == 0 ||
1357                strcmp (s, "r5") == 0 ||
1358                strcmp (s, "r6") == 0 ||
1359                strcmp (s, "r7") == 0)
1360         {
1361           char buffer[10];
1362           sprintf (buffer, "a%s", s);
1363           emitcode ("mov", "@%s,%s",
1364                     aop->aopu.aop_ptr->name, buffer);
1365         }
1366       else
1367         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1368
1369       break;
1370
1371     case AOP_STK:
1372       if (strcmp (s, "a") == 0)
1373         emitcode ("push", "acc");
1374       else
1375         if (*s=='@') {
1376           MOVA(s);
1377           emitcode ("push", "acc");
1378         } else {
1379           emitcode ("push", s);
1380         }
1381
1382       break;
1383
1384     case AOP_CRY:
1385       /* if bit variable */
1386       if (!aop->aopu.aop_dir)
1387         {
1388           emitcode ("clr", "a");
1389           emitcode ("rlc", "a");
1390         }
1391       else
1392         {
1393           if (s == zero)
1394             emitcode ("clr", "%s", aop->aopu.aop_dir);
1395           else if (s == one)
1396             emitcode ("setb", "%s", aop->aopu.aop_dir);
1397           else if (!strcmp (s, "c"))
1398             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1399           else
1400             {
1401               if (strcmp (s, "a"))
1402                 {
1403                   MOVA (s);
1404                 }
1405               {
1406                 /* set C, if a >= 1 */
1407                 emitcode ("add", "a,#0xff");
1408                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1409               }
1410             }
1411         }
1412       break;
1413
1414     case AOP_STR:
1415       aop->coff = offset;
1416       if (strcmp (aop->aopu.aop_str[offset], s) ||
1417           bvolatile)
1418         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1419       break;
1420
1421     case AOP_ACC:
1422       aop->coff = offset;
1423       if (!offset && (strcmp (s, "acc") == 0) &&
1424           !bvolatile)
1425         break;
1426
1427       if (strcmp (aop->aopu.aop_str[offset], s) &&
1428           !bvolatile)
1429         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1430       break;
1431
1432     default:
1433       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1434               "aopPut got unsupported aop->type");
1435       exit (1);
1436     }
1437
1438 }
1439
1440
1441 #if 0
1442 /*-----------------------------------------------------------------*/
1443 /* pointToEnd :- points to the last byte of the operand            */
1444 /*-----------------------------------------------------------------*/
1445 static void
1446 pointToEnd (asmop * aop)
1447 {
1448   int count;
1449   if (!aop)
1450     return;
1451
1452   aop->coff = count = (aop->size - 1);
1453   switch (aop->type)
1454     {
1455     case AOP_R0:
1456     case AOP_R1:
1457       while (count--)
1458         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1459       break;
1460     case AOP_DPTR:
1461       while (count--)
1462         emitcode ("inc", "dptr");
1463       break;
1464     }
1465
1466 }
1467 #endif
1468
1469 /*-----------------------------------------------------------------*/
1470 /* reAdjustPreg - points a register back to where it should        */
1471 /*-----------------------------------------------------------------*/
1472 static void
1473 reAdjustPreg (asmop * aop)
1474 {
1475   if ((aop->coff==0) || aop->size <= 1)
1476     return;
1477
1478   switch (aop->type)
1479     {
1480     case AOP_R0:
1481     case AOP_R1:
1482       while (aop->coff--)
1483         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1484       break;
1485     case AOP_DPTR:
1486       while (aop->coff--)
1487         {
1488           emitcode ("lcall", "__decdptr");
1489         }
1490       break;
1491     }
1492   aop->coff = 0;
1493 }
1494
1495 #define AOP(op) op->aop
1496 #define AOP_TYPE(op) AOP(op)->type
1497 #define AOP_SIZE(op) AOP(op)->size
1498 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1499                        AOP_TYPE(x) == AOP_R0))
1500
1501 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1502                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
1503
1504 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1505                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
1506                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
1507
1508
1509 /*-----------------------------------------------------------------*/
1510 /* opIsGptr: returns non-zero if the passed operand is       */
1511 /* a generic pointer type.             */
1512 /*-----------------------------------------------------------------*/
1513 static int
1514 opIsGptr (operand * op)
1515 {
1516   sym_link *type = operandType (op);
1517
1518   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1519     {
1520       return 1;
1521     }
1522   return 0;
1523 }
1524
1525 /*-----------------------------------------------------------------*/
1526 /* getDataSize - get the operand data size                         */
1527 /*-----------------------------------------------------------------*/
1528 static int
1529 getDataSize (operand * op)
1530 {
1531   int size;
1532   size = AOP_SIZE (op);
1533   if (size == GPTRSIZE)
1534     {
1535       sym_link *type = operandType (op);
1536       if (IS_GENPTR (type))
1537         {
1538           /* generic pointer; arithmetic operations
1539            * should ignore the high byte (pointer type).
1540            */
1541           size--;
1542         }
1543     }
1544   return size;
1545 }
1546
1547 /*-----------------------------------------------------------------*/
1548 /* outAcc - output Acc                                             */
1549 /*-----------------------------------------------------------------*/
1550 static void
1551 outAcc (operand * result)
1552 {
1553   int size, offset;
1554   size = getDataSize (result);
1555   if (size)
1556     {
1557       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
1558       size--;
1559       offset = 1;
1560       /* unsigned or positive */
1561       while (size--)
1562         {
1563           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
1564         }
1565     }
1566 }
1567
1568 /*-----------------------------------------------------------------*/
1569 /* outBitC - output a bit C                                        */
1570 /*-----------------------------------------------------------------*/
1571 static void
1572 outBitC (operand * result)
1573 {
1574   /* if the result is bit */
1575   if (AOP_TYPE (result) == AOP_CRY)
1576     aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
1577   else
1578     {
1579       emitcode ("clr", "a");
1580       emitcode ("rlc", "a");
1581       outAcc (result);
1582     }
1583 }
1584
1585 /*-----------------------------------------------------------------*/
1586 /* toBoolean - emit code for orl a,operator(sizeop)                */
1587 /*-----------------------------------------------------------------*/
1588 static void
1589 toBoolean (operand * oper)
1590 {
1591   int size = AOP_SIZE (oper) - 1;
1592   int offset = 1;
1593   bool AccUsed = FALSE;
1594   bool pushedB;
1595
1596   while (!AccUsed && size--)
1597     {
1598       AccUsed |= aopGetUsesAcc(AOP (oper), offset++);
1599     }
1600
1601   size = AOP_SIZE (oper) - 1;
1602   offset = 1;
1603   MOVA (aopGet (AOP (oper), 0, FALSE, FALSE));
1604   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1605     {
1606       pushedB = pushB ();
1607       emitcode("mov", "b,a");
1608       while (size--)
1609         {
1610           MOVA (aopGet (AOP (oper), offset++, FALSE, FALSE));
1611           emitcode ("orl", "b,a");
1612         }
1613       popB (pushedB);
1614     }
1615   else
1616     {
1617       while (size--)
1618         {
1619           emitcode ("orl", "a,%s", aopGet (AOP (oper), offset++, FALSE, FALSE));
1620         }
1621     }
1622 }
1623
1624
1625 /*-----------------------------------------------------------------*/
1626 /* genNot - generate code for ! operation                          */
1627 /*-----------------------------------------------------------------*/
1628 static void
1629 genNot (iCode * ic)
1630 {
1631   symbol *tlbl;
1632
1633   D(emitcode (";     genNot",""));
1634
1635   /* assign asmOps to operand & result */
1636   aopOp (IC_LEFT (ic), ic, FALSE);
1637   aopOp (IC_RESULT (ic), ic, TRUE);
1638
1639   /* if in bit space then a special case */
1640   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1641     {
1642       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1643       emitcode ("cpl", "c");
1644       outBitC (IC_RESULT (ic));
1645       goto release;
1646     }
1647
1648   toBoolean (IC_LEFT (ic));
1649
1650   tlbl = newiTempLabel (NULL);
1651   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1652   emitcode ("", "%05d$:", tlbl->key + 100);
1653   outBitC (IC_RESULT (ic));
1654
1655 release:
1656   /* release the aops */
1657   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1658   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1659 }
1660
1661
1662 /*-----------------------------------------------------------------*/
1663 /* genCpl - generate code for complement                           */
1664 /*-----------------------------------------------------------------*/
1665 static void
1666 genCpl (iCode * ic)
1667 {
1668   int offset = 0;
1669   int size;
1670   symbol *tlbl;
1671   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1672
1673   D(emitcode (";", "genCpl"));
1674
1675   /* assign asmOps to operand & result */
1676   aopOp (IC_LEFT (ic), ic, FALSE);
1677   aopOp (IC_RESULT (ic), ic, TRUE);
1678
1679   /* special case if in bit space */
1680   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1681     {
1682       char *l;
1683
1684       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1685           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1686         {
1687           /* promotion rules are responsible for this strange result:
1688              bit -> int -> ~int -> bit
1689              uchar -> int -> ~int -> bit
1690           */
1691           werror(W_COMPLEMENT);
1692           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1693           goto release;
1694         }
1695
1696       tlbl=newiTempLabel(NULL);
1697       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, FALSE);
1698       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC ||
1699           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1700           IS_AOP_PREG (IC_LEFT (ic)))
1701         {
1702           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1703         }
1704       else
1705         {
1706           MOVA (l);
1707           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1708         }
1709       emitcode ("", "%05d$:", tlbl->key + 100);
1710       outBitC (IC_RESULT(ic));
1711       goto release;
1712     }
1713
1714   size = AOP_SIZE (IC_RESULT (ic));
1715   while (size--)
1716     {
1717       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1718       MOVA (l);
1719       emitcode ("cpl", "a");
1720       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1721     }
1722
1723
1724 release:
1725   /* release the aops */
1726   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1727   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1728 }
1729
1730 /*-----------------------------------------------------------------*/
1731 /* genUminusFloat - unary minus for floating points                */
1732 /*-----------------------------------------------------------------*/
1733 static void
1734 genUminusFloat (operand * op, operand * result)
1735 {
1736   int size, offset = 0;
1737   char *l;
1738
1739   D(emitcode (";     genUminusFloat",""));
1740
1741   /* for this we just copy and then flip the bit */
1742
1743   size = AOP_SIZE (op) - 1;
1744
1745   while (size--)
1746     {
1747       aopPut (AOP (result),
1748               aopGet (AOP (op), offset, FALSE, FALSE),
1749               offset,
1750               isOperandVolatile (result, FALSE));
1751       offset++;
1752     }
1753
1754   l = aopGet (AOP (op), offset, FALSE, FALSE);
1755
1756   MOVA (l);
1757
1758   emitcode ("cpl", "acc.7");
1759   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
1760 }
1761
1762 /*-----------------------------------------------------------------*/
1763 /* genUminus - unary minus code generation                         */
1764 /*-----------------------------------------------------------------*/
1765 static void
1766 genUminus (iCode * ic)
1767 {
1768   int offset, size;
1769   sym_link *optype, *rtype;
1770
1771
1772   D(emitcode (";     genUminus",""));
1773
1774   /* assign asmops */
1775   aopOp (IC_LEFT (ic), ic, FALSE);
1776   aopOp (IC_RESULT (ic), ic, TRUE);
1777
1778   /* if both in bit space then special
1779      case */
1780   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1781       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1782     {
1783
1784       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1785       emitcode ("cpl", "c");
1786       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1787       goto release;
1788     }
1789
1790   optype = operandType (IC_LEFT (ic));
1791   rtype = operandType (IC_RESULT (ic));
1792
1793   /* if float then do float stuff */
1794   if (IS_FLOAT (optype))
1795     {
1796       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1797       goto release;
1798     }
1799
1800   /* otherwise subtract from zero */
1801   size = AOP_SIZE (IC_LEFT (ic));
1802   offset = 0;
1803   //CLRC ;
1804   while (size--)
1805     {
1806       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1807       if (!strcmp (l, "a"))
1808         {
1809           if (offset == 0)
1810             SETC;
1811           emitcode ("cpl", "a");
1812           emitcode ("addc", "a,#0");
1813         }
1814       else
1815         {
1816           if (offset == 0)
1817             CLRC;
1818           emitcode ("clr", "a");
1819           emitcode ("subb", "a,%s", l);
1820         }
1821       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1822     }
1823
1824   /* if any remaining bytes in the result */
1825   /* we just need to propagate the sign   */
1826   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1827     {
1828       emitcode ("rlc", "a");
1829       emitcode ("subb", "a,acc");
1830       while (size--)
1831         aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1832     }
1833
1834 release:
1835   /* release the aops */
1836   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1837   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1838 }
1839
1840 /*-----------------------------------------------------------------*/
1841 /* saveRegisters - will look for a call and save the registers     */
1842 /*-----------------------------------------------------------------*/
1843 static void
1844 saveRegisters (iCode * lic)
1845 {
1846   int i;
1847   iCode *ic;
1848   bitVect *rsave;
1849
1850   /* look for call */
1851   for (ic = lic; ic; ic = ic->next)
1852     if (ic->op == CALL || ic->op == PCALL)
1853       break;
1854
1855   if (!ic)
1856     {
1857       fprintf (stderr, "found parameter push with no function call\n");
1858       return;
1859     }
1860
1861   /* if the registers have been saved already or don't need to be then
1862      do nothing */
1863   if (ic->regsSaved)
1864     return;
1865   if (IS_SYMOP(IC_LEFT(ic)) &&
1866       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1867        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1868     return;
1869
1870   /* save the registers in use at this time but skip the
1871      ones for the result */
1872   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1873                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1874
1875   ic->regsSaved = 1;
1876   if (options.useXstack)
1877     {
1878       int count = bitVectnBitsOn (rsave);
1879
1880       if (count == 1)
1881         {
1882           i = bitVectFirstBit (rsave);
1883           emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1884           emitcode ("mov", "r0,%s", spname);
1885           emitcode ("inc", "%s", spname);// allocate before use
1886           emitcode ("movx", "@r0,a");
1887           if (bitVectBitValue (rsave, R0_IDX))
1888             emitcode ("mov", "r0,a");
1889         }
1890       else if (count != 0)
1891         {
1892           if (bitVectBitValue (rsave, R0_IDX))
1893             {
1894               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1895             }
1896           emitcode ("mov", "r0,%s", spname);
1897           MOVA ("r0");
1898           emitcode ("add", "a,#%d", count);
1899           emitcode ("mov", "%s,a", spname);
1900           for (i = 0; i < mcs51_nRegs; i++)
1901             {
1902               if (bitVectBitValue (rsave, i))
1903                 {
1904                   if (i == R0_IDX)
1905                     {
1906                       emitcode ("pop", "acc");
1907                       emitcode ("push", "acc");
1908                     }
1909                   else
1910                     {
1911                       emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1912                     }
1913                   emitcode ("movx", "@r0,a");
1914                   if (--count)
1915                     {
1916                       emitcode ("inc", "r0");
1917                     }
1918                 }
1919             }
1920           if (bitVectBitValue (rsave, R0_IDX))
1921             {
1922               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1923             }
1924         }
1925     }
1926   else
1927     for (i = 0; i < mcs51_nRegs; i++)
1928       {
1929         if (bitVectBitValue (rsave, i))
1930           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1931       }
1932 }
1933
1934 /*-----------------------------------------------------------------*/
1935 /* unsaveRegisters - pop the pushed registers                      */
1936 /*-----------------------------------------------------------------*/
1937 static void
1938 unsaveRegisters (iCode * ic)
1939 {
1940   int i;
1941   bitVect *rsave;
1942
1943   /* restore the registers in use at this time but skip the
1944      ones for the result */
1945   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1946                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1947
1948   if (options.useXstack)
1949     {
1950       int count = bitVectnBitsOn (rsave);
1951
1952       if (count == 1)
1953         {
1954           emitcode ("mov", "r0,%s", spname);
1955           emitcode ("dec", "r0");
1956           emitcode ("movx", "a,@r0");
1957           i = bitVectFirstBit (rsave);
1958           emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1959           emitcode ("dec", "%s", spname);
1960         }
1961       else
1962         {
1963           emitcode ("mov", "r0,%s", spname);
1964           for (i = mcs51_nRegs; i >= 0; i--)
1965             {
1966               if (bitVectBitValue (rsave, i))
1967                 {
1968                   emitcode ("dec", "r0");
1969                   emitcode ("movx", "a,@r0");
1970                   if (i != R0_IDX)
1971                     emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1972                 }
1973             }
1974           emitcode ("mov", "%s,r0", spname);
1975           if (bitVectBitValue (rsave, R0_IDX))
1976             {
1977               emitcode ("mov", "r0,a");
1978             }
1979         }
1980     }
1981   else
1982     for (i = mcs51_nRegs; i >= 0; i--)
1983       {
1984         if (bitVectBitValue (rsave, i))
1985           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
1986       }
1987 }
1988
1989
1990 /*-----------------------------------------------------------------*/
1991 /* pushSide -                */
1992 /*-----------------------------------------------------------------*/
1993 static void
1994 pushSide (operand * oper, int size)
1995 {
1996   int offset = 0;
1997   while (size--)
1998     {
1999       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE);
2000       if (AOP_TYPE (oper) != AOP_REG &&
2001           AOP_TYPE (oper) != AOP_DIR &&
2002           strcmp (l, "a"))
2003         {
2004           MOVA (l);
2005           emitcode ("push", "acc");
2006         }
2007       else
2008           emitcode ("push", "%s", l);
2009         }
2010     }
2011
2012 /*-----------------------------------------------------------------*/
2013 /* assignResultValue -               */
2014 /*-----------------------------------------------------------------*/
2015 static void
2016 assignResultValue (operand * oper)
2017 {
2018   int offset = 0;
2019   int size = AOP_SIZE (oper);
2020   while (size--)
2021     {
2022       aopPut (AOP (oper), fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2023       offset++;
2024     }
2025 }
2026
2027
2028 /*-----------------------------------------------------------------*/
2029 /* genXpush - pushes onto the external stack                       */
2030 /*-----------------------------------------------------------------*/
2031 static void
2032 genXpush (iCode * ic)
2033 {
2034   asmop *aop = newAsmop (0);
2035   regs *r;
2036   int size, offset = 0;
2037
2038   D(emitcode (";     genXpush",""));
2039
2040   aopOp (IC_LEFT (ic), ic, FALSE);
2041   r = getFreePtr (ic, &aop, FALSE);
2042
2043   size = AOP_SIZE (IC_LEFT (ic));
2044
2045   if (size == 1)
2046     {
2047       MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
2048       emitcode ("mov", "%s,%s", r->name, spname);
2049       emitcode ("inc", "%s", spname); // allocate space first
2050       emitcode ("movx", "@%s,a", r->name);
2051     }
2052   else
2053     {
2054       // allocate space first
2055       emitcode ("mov", "%s,%s", r->name, spname);
2056       MOVA (r->name);
2057       emitcode ("add", "a,#%d", size);
2058       emitcode ("mov", "%s,a", spname);
2059
2060       while (size--)
2061         {
2062           MOVA (aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, FALSE));
2063           emitcode ("movx", "@%s,a", r->name);
2064           emitcode ("inc", "%s", r->name);
2065         }
2066     }
2067
2068   freeAsmop (NULL, aop, ic, TRUE);
2069   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2070 }
2071
2072 /*-----------------------------------------------------------------*/
2073 /* genIpush - genrate code for pushing this gets a little complex  */
2074 /*-----------------------------------------------------------------*/
2075 static void
2076 genIpush (iCode * ic)
2077 {
2078   int size, offset = 0;
2079   char *l;
2080
2081   D(emitcode (";     genIpush",""));
2082
2083   /* if this is not a parm push : ie. it is spill push
2084      and spill push is always done on the local stack */
2085   if (!ic->parmPush)
2086     {
2087
2088       /* and the item is spilt then do nothing */
2089       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2090         return;
2091
2092       aopOp (IC_LEFT (ic), ic, FALSE);
2093       size = AOP_SIZE (IC_LEFT (ic));
2094       /* push it on the stack */
2095       while (size--)
2096         {
2097           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2098           if (*l == '#')
2099             {
2100               MOVA (l);
2101               l = "acc";
2102             }
2103           emitcode ("push", "%s", l);
2104         }
2105       return;
2106     }
2107
2108   /* this is a paramter push: in this case we call
2109      the routine to find the call and save those
2110      registers that need to be saved */
2111   saveRegisters (ic);
2112
2113   /* if use external stack then call the external
2114      stack pushing routine */
2115   if (options.useXstack)
2116     {
2117       genXpush (ic);
2118       return;
2119     }
2120
2121   /* then do the push */
2122   aopOp (IC_LEFT (ic), ic, FALSE);
2123
2124   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2125   size = AOP_SIZE (IC_LEFT (ic));
2126
2127   while (size--)
2128     {
2129       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2130       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2131           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2132           strcmp (l, "a"))
2133         {
2134           MOVA (l);
2135           emitcode ("push", "acc");
2136         }
2137       else
2138           emitcode ("push", "%s", l);
2139     }
2140
2141   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2142 }
2143
2144 /*-----------------------------------------------------------------*/
2145 /* genIpop - recover the registers: can happen only for spilling   */
2146 /*-----------------------------------------------------------------*/
2147 static void
2148 genIpop (iCode * ic)
2149 {
2150   int size, offset;
2151
2152   D(emitcode (";     genIpop",""));
2153
2154   /* if the temp was not pushed then */
2155   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2156     return;
2157
2158   aopOp (IC_LEFT (ic), ic, FALSE);
2159   size = AOP_SIZE (IC_LEFT (ic));
2160   offset = (size - 1);
2161   while (size--)
2162     emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2163                                    FALSE, TRUE));
2164
2165   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2166 }
2167
2168 /*-----------------------------------------------------------------*/
2169 /* saveRBank - saves an entire register bank on the stack          */
2170 /*-----------------------------------------------------------------*/
2171 static void
2172 saveRBank (int bank, iCode * ic, bool pushPsw)
2173 {
2174   int i;
2175   int count = mcs51_nRegs + (pushPsw ? 1 : 0);
2176   asmop *aop = NULL;
2177   regs *r = NULL;
2178
2179   if (options.useXstack)
2180     {
2181       if (!ic)
2182       {
2183           /* Assume r0 is available for use. */
2184           r = mcs51_regWithIdx (R0_IDX);;
2185       }
2186       else
2187       {
2188           aop = newAsmop (0);
2189           r = getFreePtr (ic, &aop, FALSE);
2190       }
2191       // allocate space first
2192       emitcode ("mov", "%s,%s", r->name, spname);
2193       MOVA (r->name);
2194       emitcode ("add", "a,#%d", count);
2195       emitcode ("mov", "%s,a", spname);
2196     }
2197
2198   for (i = 0; i < mcs51_nRegs; i++)
2199     {
2200       if (options.useXstack)
2201         {
2202           emitcode ("mov", "a,(%s+%d)",
2203                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2204           emitcode ("movx", "@%s,a", r->name);
2205           if (--count)
2206             emitcode ("inc", "%s", r->name);
2207         }
2208       else
2209         emitcode ("push", "(%s+%d)",
2210                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2211     }
2212
2213   if (pushPsw)
2214     {
2215       if (options.useXstack)
2216         {
2217           emitcode ("mov", "a,psw");
2218           emitcode ("movx", "@%s,a", r->name);
2219
2220         }
2221       else
2222         {
2223           emitcode ("push", "psw");
2224         }
2225
2226       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2227     }
2228
2229   if (aop)
2230     {
2231       freeAsmop (NULL, aop, ic, TRUE);
2232     }
2233
2234   if (ic)
2235   {
2236     ic->bankSaved = 1;
2237   }
2238 }
2239
2240 /*-----------------------------------------------------------------*/
2241 /* unsaveRBank - restores the register bank from stack             */
2242 /*-----------------------------------------------------------------*/
2243 static void
2244 unsaveRBank (int bank, iCode * ic, bool popPsw)
2245 {
2246   int i;
2247   asmop *aop = NULL;
2248   regs *r = NULL;
2249
2250   if (options.useXstack)
2251     {
2252       if (!ic)
2253         {
2254           /* Assume r0 is available for use. */
2255           r = mcs51_regWithIdx (R0_IDX);;
2256         }
2257       else
2258         {
2259           aop = newAsmop (0);
2260           r = getFreePtr (ic, &aop, FALSE);
2261         }
2262       emitcode ("mov", "%s,%s", r->name, spname);
2263     }
2264
2265   if (popPsw)
2266     {
2267       if (options.useXstack)
2268         {
2269           emitcode ("dec", "%s", r->name);
2270           emitcode ("movx", "a,@%s", r->name);
2271           emitcode ("mov", "psw,a");
2272         }
2273       else
2274         {
2275           emitcode ("pop", "psw");
2276         }
2277     }
2278
2279   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2280     {
2281       if (options.useXstack)
2282         {
2283           emitcode ("dec", "%s", r->name);
2284           emitcode ("movx", "a,@%s", r->name);
2285           emitcode ("mov", "(%s+%d),a",
2286                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2287         }
2288       else
2289         {
2290           emitcode ("pop", "(%s+%d)",
2291                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2292         }
2293     }
2294
2295   if (options.useXstack)
2296     {
2297       emitcode ("mov", "%s,%s", spname, r->name);
2298     }
2299
2300   if (aop)
2301     {
2302       freeAsmop (NULL, aop, ic, TRUE);
2303     }
2304 }
2305
2306 /*-----------------------------------------------------------------*/
2307 /* genSend - gen code for SEND                                     */
2308 /*-----------------------------------------------------------------*/
2309 static void genSend(set *sendSet)
2310 {
2311     iCode *sic;
2312     int rb1_count = 0 ;
2313
2314     for (sic = setFirstItem (sendSet); sic;
2315          sic = setNextItem (sendSet)) {
2316           int size, offset = 0;
2317           aopOp (IC_LEFT (sic), sic, FALSE);
2318           size = AOP_SIZE (IC_LEFT (sic));
2319
2320           if (sic->argreg == 1) {
2321               while (size--) {
2322                   char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2323                                     FALSE, FALSE);
2324                   if (strcmp (l, fReturn[offset]))
2325                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2326                   offset++;
2327               }
2328               rb1_count = 0;
2329           } else {
2330               while (size--) {
2331                   emitcode ("mov","b1_%d,%s",rb1_count++,
2332                             aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE));
2333               }
2334           }
2335           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2336     }
2337 }
2338
2339 /*-----------------------------------------------------------------*/
2340 /* genCall - generates a call statement                            */
2341 /*-----------------------------------------------------------------*/
2342 static void
2343 genCall (iCode * ic)
2344 {
2345   sym_link *dtype;
2346 //  bool restoreBank = FALSE;
2347   bool swapBanks = FALSE;
2348
2349   D(emitcode(";     genCall",""));
2350
2351   dtype = operandType (IC_LEFT (ic));
2352   /* if send set is not empty then assign */
2353   if (_G.sendSet)
2354     {
2355         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2356             genSend(reverseSet(_G.sendSet));
2357         } else {
2358             genSend(_G.sendSet);
2359         }
2360
2361       _G.sendSet = NULL;
2362     }
2363
2364   /* if we are calling a not _naked function that is not using
2365      the same register bank then we need to save the
2366      destination registers on the stack */
2367   dtype = operandType (IC_LEFT (ic));
2368   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2369       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2370        !IFFUNC_ISISR (dtype))
2371   {
2372       swapBanks = TRUE;
2373   }
2374
2375   /* if caller saves & we have not saved then */
2376   if (!ic->regsSaved)
2377       saveRegisters (ic);
2378
2379   if (swapBanks)
2380   {
2381         emitcode ("mov", "psw,#0x%02x",
2382            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2383   }
2384
2385   /* make the call */
2386   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2387                             OP_SYMBOL (IC_LEFT (ic))->rname :
2388                             OP_SYMBOL (IC_LEFT (ic))->name));
2389
2390   if (swapBanks)
2391   {
2392        emitcode ("mov", "psw,#0x%02x",
2393           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2394   }
2395
2396   /* if we need assign a result value */
2397   if ((IS_ITEMP (IC_RESULT (ic)) &&
2398        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2399         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2400         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2401       IS_TRUE_SYMOP (IC_RESULT (ic)))
2402     {
2403
2404       _G.accInUse++;
2405       aopOp (IC_RESULT (ic), ic, FALSE);
2406       _G.accInUse--;
2407
2408       assignResultValue (IC_RESULT (ic));
2409
2410       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2411     }
2412
2413   /* adjust the stack for parameters if
2414      required */
2415   if (ic->parmBytes)
2416     {
2417       int i;
2418       if (ic->parmBytes > 3)
2419         {
2420           emitcode ("mov", "a,%s", spname);
2421           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2422           emitcode ("mov", "%s,a", spname);
2423         }
2424       else
2425         for (i = 0; i < ic->parmBytes; i++)
2426           emitcode ("dec", "%s", spname);
2427     }
2428
2429   /* if we hade saved some registers then unsave them */
2430   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2431     unsaveRegisters (ic);
2432
2433 //  /* if register bank was saved then pop them */
2434 //  if (restoreBank)
2435 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2436 }
2437
2438 /*-----------------------------------------------------------------*/
2439 /* -10l - generates a call by pointer statement                */
2440 /*-----------------------------------------------------------------*/
2441 static void
2442 genPcall (iCode * ic)
2443 {
2444   sym_link *dtype;
2445   symbol *rlbl = newiTempLabel (NULL);
2446 //  bool restoreBank=FALSE;
2447   bool swapBanks = FALSE;
2448
2449   D(emitcode(";     genPCall",""));
2450
2451   /* if caller saves & we have not saved then */
2452   if (!ic->regsSaved)
2453     saveRegisters (ic);
2454
2455   /* if we are calling a not _naked function that is not using
2456      the same register bank then we need to save the
2457      destination registers on the stack */
2458   dtype = operandType (IC_LEFT (ic))->next;
2459   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2460       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2461       !IFFUNC_ISISR (dtype))
2462   {
2463 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2464 //    restoreBank=TRUE;
2465       swapBanks = TRUE;
2466       // need caution message to user here
2467   }
2468
2469   /* push the return address on to the stack */
2470   emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2471   emitcode ("push", "acc");
2472   emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2473   emitcode ("push", "acc");
2474
2475   /* now push the calling address */
2476   aopOp (IC_LEFT (ic), ic, FALSE);
2477
2478   pushSide (IC_LEFT (ic), FPTRSIZE);
2479
2480   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2481
2482   /* if send set is not empty the assign */
2483   if (_G.sendSet)
2484     {
2485         genSend(reverseSet(_G.sendSet));
2486         _G.sendSet = NULL;
2487     }
2488
2489   if (swapBanks)
2490   {
2491         emitcode ("mov", "psw,#0x%02x",
2492            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2493   }
2494
2495   /* make the call */
2496   emitcode ("ret", "");
2497   emitcode ("", "%05d$:", (rlbl->key + 100));
2498
2499
2500   if (swapBanks)
2501   {
2502        emitcode ("mov", "psw,#0x%02x",
2503           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2504   }
2505
2506   /* if we need assign a result value */
2507   if ((IS_ITEMP (IC_RESULT (ic)) &&
2508        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2509         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2510       IS_TRUE_SYMOP (IC_RESULT (ic)))
2511     {
2512
2513       _G.accInUse++;
2514       aopOp (IC_RESULT (ic), ic, FALSE);
2515       _G.accInUse--;
2516
2517       assignResultValue (IC_RESULT (ic));
2518
2519       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2520     }
2521
2522   /* adjust the stack for parameters if
2523      required */
2524   if (ic->parmBytes)
2525     {
2526       int i;
2527       if (ic->parmBytes > 3)
2528         {
2529           emitcode ("mov", "a,%s", spname);
2530           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2531           emitcode ("mov", "%s,a", spname);
2532         }
2533       else
2534         for (i = 0; i < ic->parmBytes; i++)
2535           emitcode ("dec", "%s", spname);
2536
2537     }
2538
2539 //  /* if register bank was saved then unsave them */
2540 //  if (restoreBank)
2541 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2542
2543   /* if we hade saved some registers then
2544      unsave them */
2545   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2546     unsaveRegisters (ic);
2547 }
2548
2549 /*-----------------------------------------------------------------*/
2550 /* resultRemat - result  is rematerializable                       */
2551 /*-----------------------------------------------------------------*/
2552 static int
2553 resultRemat (iCode * ic)
2554 {
2555   if (SKIP_IC (ic) || ic->op == IFX)
2556     return 0;
2557
2558   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2559     {
2560       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2561       if (sym->remat && !POINTER_SET (ic))
2562         return 1;
2563     }
2564
2565   return 0;
2566 }
2567
2568 #if defined(__BORLANDC__) || defined(_MSC_VER)
2569 #define STRCASECMP stricmp
2570 #else
2571 #define STRCASECMP strcasecmp
2572 #endif
2573
2574 /*-----------------------------------------------------------------*/
2575 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2576 /*-----------------------------------------------------------------*/
2577 static int
2578 regsCmp(void *p1, void *p2)
2579 {
2580   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2581 }
2582
2583 static bool
2584 inExcludeList (char *s)
2585 {
2586   const char *p = setFirstItem(options.excludeRegsSet);
2587
2588   if (p == NULL || STRCASECMP(p, "none") == 0)
2589     return FALSE;
2590
2591
2592   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2593 }
2594
2595 /*-----------------------------------------------------------------*/
2596 /* genFunction - generated code for function entry                 */
2597 /*-----------------------------------------------------------------*/
2598 static void
2599 genFunction (iCode * ic)
2600 {
2601   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
2602   sym_link *ftype;
2603   bool     switchedPSW = FALSE;
2604   int      calleesaves_saved_register = -1;
2605   int      stackAdjust = sym->stack;
2606   int      accIsFree = sym->recvSize < 4;
2607   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2608   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
2609
2610   _G.nRegsSaved = 0;
2611   /* create the function header */
2612   emitcode (";", "-----------------------------------------");
2613   emitcode (";", " function %s", sym->name);
2614   emitcode (";", "-----------------------------------------");
2615
2616   emitcode ("", "%s:", sym->rname);
2617   ftype = operandType (IC_LEFT (ic));
2618   _G.currentFunc = sym;
2619
2620   if (IFFUNC_ISNAKED(ftype))
2621   {
2622       emitcode(";", "naked function: no prologue.");
2623       return;
2624   }
2625
2626   /* here we need to generate the equates for the
2627      register bank if required */
2628   if (FUNC_REGBANK (ftype) != rbank)
2629     {
2630       int i;
2631
2632       rbank = FUNC_REGBANK (ftype);
2633       for (i = 0; i < mcs51_nRegs; i++)
2634         {
2635           if (strcmp (regs8051[i].base, "0") == 0)
2636             emitcode ("", "%s = 0x%02x",
2637                       regs8051[i].dname,
2638                       8 * rbank + regs8051[i].offset);
2639           else
2640             emitcode ("", "%s = %s + 0x%02x",
2641                       regs8051[i].dname,
2642                       regs8051[i].base,
2643                       8 * rbank + regs8051[i].offset);
2644         }
2645     }
2646
2647   /* if this is an interrupt service routine then
2648      save acc, b, dpl, dph  */
2649   if (IFFUNC_ISISR (sym->type))
2650     {
2651
2652       if (!inExcludeList ("acc"))
2653         emitcode ("push", "acc");
2654       if (!inExcludeList ("b"))
2655         emitcode ("push", "b");
2656       if (!inExcludeList ("dpl"))
2657         emitcode ("push", "dpl");
2658       if (!inExcludeList ("dph"))
2659         emitcode ("push", "dph");
2660       /* if this isr has no bank i.e. is going to
2661          run with bank 0 , then we need to save more
2662          registers :-) */
2663       if (!FUNC_REGBANK (sym->type))
2664         {
2665
2666           /* if this function does not call any other
2667              function then we can be economical and
2668              save only those registers that are used */
2669           if (!IFFUNC_HASFCALL(sym->type))
2670             {
2671               int i;
2672
2673               /* if any registers used */
2674               if (sym->regsUsed)
2675                 {
2676                   /* save the registers used */
2677                   for (i = 0; i < sym->regsUsed->size; i++)
2678                     {
2679                       if (bitVectBitValue (sym->regsUsed, i))
2680                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2681                     }
2682                 }
2683             }
2684           else
2685             {
2686
2687               /* this function has a function call. We cannot
2688                  determines register usage so we will have to push the
2689                  entire bank */
2690                 saveRBank (0, ic, FALSE);
2691                 if (options.parms_in_bank1) {
2692                     int i;
2693                     for (i=0; i < 8 ; i++ ) {
2694                         emitcode ("push","%s",rb1regs[i]);
2695                     }
2696                 }
2697             }
2698         }
2699         else
2700         {
2701             /* This ISR uses a non-zero bank.
2702              *
2703              * We assume that the bank is available for our
2704              * exclusive use.
2705              *
2706              * However, if this ISR calls a function which uses some
2707              * other bank, we must save that bank entirely.
2708              */
2709             unsigned long banksToSave = 0;
2710
2711             if (IFFUNC_HASFCALL(sym->type))
2712             {
2713
2714 #define MAX_REGISTER_BANKS 4
2715
2716                 iCode *i;
2717                 int ix;
2718
2719                 for (i = ic; i; i = i->next)
2720                 {
2721                     if (i->op == ENDFUNCTION)
2722                     {
2723                         /* we got to the end OK. */
2724                         break;
2725                     }
2726
2727                     if (i->op == CALL)
2728                     {
2729                         sym_link *dtype;
2730
2731                         dtype = operandType (IC_LEFT(i));
2732                         if (dtype
2733                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2734                         {
2735                              /* Mark this bank for saving. */
2736                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2737                              {
2738                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2739                              }
2740                              else
2741                              {
2742                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2743                              }
2744
2745                              /* And note that we don't need to do it in
2746                               * genCall.
2747                               */
2748                              i->bankSaved = 1;
2749                         }
2750                     }
2751                     if (i->op == PCALL)
2752                     {
2753                         /* This is a mess; we have no idea what
2754                          * register bank the called function might
2755                          * use.
2756                          *
2757                          * The only thing I can think of to do is
2758                          * throw a warning and hope.
2759                          */
2760                         werror(W_FUNCPTR_IN_USING_ISR);
2761                     }
2762                 }
2763
2764                 if (banksToSave && options.useXstack)
2765                 {
2766                     /* Since we aren't passing it an ic,
2767                      * saveRBank will assume r0 is available to abuse.
2768                      *
2769                      * So switch to our (trashable) bank now, so
2770                      * the caller's R0 isn't trashed.
2771                      */
2772                     emitcode ("push", "psw");
2773                     emitcode ("mov", "psw,#0x%02x",
2774                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2775                     switchedPSW = TRUE;
2776                 }
2777
2778                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2779                 {
2780                      if (banksToSave & (1 << ix))
2781                      {
2782                          saveRBank(ix, NULL, FALSE);
2783                      }
2784                 }
2785             }
2786             // TODO: this needs a closer look
2787             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2788         }
2789
2790       /* Set the register bank to the desired value if nothing else */
2791       /* has done so yet. */
2792       if (!switchedPSW)
2793         {
2794           emitcode ("push", "psw");
2795           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2796         }
2797     }
2798   else
2799     {
2800       /* This is a non-ISR function. The caller has already switched register */
2801       /* banks, if necessary, so just handle the callee-saves option. */
2802
2803       /* if callee-save to be used for this function
2804          then save the registers being used in this function */
2805       if (IFFUNC_CALLEESAVES(sym->type))
2806         {
2807           int i;
2808
2809           /* if any registers used */
2810           if (sym->regsUsed)
2811             {
2812               /* save the registers used */
2813               for (i = 0; i < sym->regsUsed->size; i++)
2814                 {
2815                   if (bitVectBitValue (sym->regsUsed, i))
2816                     {
2817                       /* remember one saved register for later usage */
2818                       if (calleesaves_saved_register < 0)
2819                         calleesaves_saved_register = i;
2820                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2821                       _G.nRegsSaved++;
2822                     }
2823                 }
2824             }
2825         }
2826     }
2827
2828
2829   if (fReentrant)
2830     {
2831       if (options.useXstack)
2832         {
2833           emitcode ("mov", "r0,%s", spname);
2834           emitcode ("inc", "%s", spname);
2835           emitcode ("xch", "a,_bp");
2836           emitcode ("movx", "@r0,a");
2837           emitcode ("inc", "r0");
2838           emitcode ("mov", "a,r0");
2839           emitcode ("xch", "a,_bp");
2840         }
2841       else
2842         {
2843           /* set up the stack */
2844           emitcode ("push", "_bp");     /* save the callers stack  */
2845           emitcode ("mov", "_bp,%s", spname);
2846         }
2847     }
2848
2849   /* For some cases it is worthwhile to perform a RECEIVE iCode */
2850   /* before setting up the stack frame completely. */
2851   if (ric && ric->argreg == 1 && IC_RESULT (ric))
2852     {
2853       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
2854
2855       if (rsym->isitmp)
2856         {
2857           if (rsym && rsym->regType == REG_CND)
2858             rsym = NULL;
2859           if (rsym && (rsym->accuse || rsym->ruonly))
2860             rsym = NULL;
2861           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
2862             rsym = rsym->usl.spillLoc;
2863         }
2864
2865       /* If the RECEIVE operand immediately spills to the first entry on the */
2866       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
2867       /* rather than the usual @r0/r1 machinations. */
2868       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
2869         {
2870           int ofs;
2871
2872           _G.current_iCode = ric;
2873           D(emitcode (";     genReceive",""));
2874           for (ofs=0; ofs < sym->recvSize; ofs++)
2875             {
2876               if (!strcmp (fReturn[ofs], "a"))
2877                 emitcode ("push", "acc");
2878               else
2879                 emitcode ("push", fReturn[ofs]);
2880             }
2881           stackAdjust -= sym->recvSize;
2882           if (stackAdjust<0)
2883             {
2884               assert (stackAdjust>=0);
2885               stackAdjust = 0;
2886             }
2887           _G.current_iCode = ic;
2888           ric->generated = 1;
2889           accIsFree = 1;
2890         }
2891       /* If the RECEIVE operand is 4 registers, we can do the moves now */
2892       /* to free up the accumulator. */
2893       else if (rsym && rsym->nRegs && sym->recvSize == 4)
2894         {
2895           int ofs;
2896
2897           _G.current_iCode = ric;
2898           D(emitcode (";     genReceive",""));
2899           for (ofs=0; ofs < sym->recvSize; ofs++)
2900             {
2901               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
2902             }
2903           _G.current_iCode = ic;
2904           ric->generated = 1;
2905           accIsFree = 1;
2906         }
2907     }
2908
2909   /* adjust the stack for the function */
2910   if (stackAdjust)
2911     {
2912       int i = stackAdjust;
2913       if (i > 256)
2914         werror (W_STACK_OVERFLOW, sym->name);
2915
2916       if (i > 3 && accIsFree)
2917         {
2918           emitcode ("mov", "a,sp");
2919           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2920           emitcode ("mov", "sp,a");
2921         }
2922       else if (i > 5)
2923         {
2924           /* The accumulator is not free, so we will need another register */
2925           /* to clobber. No need to worry about a possible conflict with */
2926           /* the above early RECEIVE optimizations since they would have */
2927           /* freed the accumulator if they were generated. */
2928
2929           if (IFFUNC_CALLEESAVES(sym->type))
2930             {
2931               /* if it's a callee-saves function we need a saved register */
2932               if (calleesaves_saved_register >= 0)
2933                 {
2934                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2935                   emitcode ("mov", "a,sp");
2936                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2937                   emitcode ("mov", "sp,a");
2938                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2939                 }
2940               else
2941                 /* do it the hard way */
2942                 while (i--)
2943                   emitcode ("inc", "sp");
2944             }
2945           else
2946             {
2947               /* not callee-saves, we can clobber r0 */
2948               emitcode ("mov", "r0,a");
2949               emitcode ("mov", "a,sp");
2950               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2951               emitcode ("mov", "sp,a");
2952               emitcode ("mov", "a,r0");
2953             }
2954         }
2955       else
2956         while (i--)
2957           emitcode ("inc", "sp");
2958     }
2959
2960   if (sym->xstack)
2961     {
2962       char i = ((char) sym->xstack & 0xff);
2963
2964       if (i > 3 && accIsFree)
2965         {
2966           emitcode ("mov", "a,_spx");
2967           emitcode ("add", "a,#0x%02x", i);
2968           emitcode ("mov", "_spx,a");
2969         }
2970       else if (i > 5)
2971         {
2972           emitcode ("push", "acc");
2973           emitcode ("mov", "a,_spx");
2974           emitcode ("add", "a,#0x%02x", i);
2975           emitcode ("mov", "_spx,a");
2976           emitcode ("pop", "acc");
2977         }
2978       else
2979         {
2980           while (i--)
2981             emitcode ("inc", "_spx");
2982         }
2983     }
2984
2985   /* if critical function then turn interrupts off */
2986   if (IFFUNC_ISCRITICAL (ftype))
2987     {
2988       symbol *tlbl = newiTempLabel (NULL);
2989       emitcode ("setb", "c");
2990       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
2991       emitcode ("clr", "c");
2992       emitcode ("", "%05d$:", (tlbl->key + 100));
2993       emitcode ("push", "psw"); /* save old ea via c in psw */
2994     }
2995 }
2996
2997 /*-----------------------------------------------------------------*/
2998 /* genEndFunction - generates epilogue for functions               */
2999 /*-----------------------------------------------------------------*/
3000 static void
3001 genEndFunction (iCode * ic)
3002 {
3003   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3004   lineNode *lnp = lineCurr;
3005   bitVect  *regsUsed;
3006   bitVect  *regsUsedPrologue;
3007   bitVect  *regsUnneeded;
3008   int      accIsFree = sym->recvSize < 4;
3009   int      idx;
3010
3011   _G.currentFunc = NULL;
3012   if (IFFUNC_ISNAKED(sym->type))
3013   {
3014       emitcode(";", "naked function: no epilogue.");
3015       if (options.debug && currFunc)
3016         debugFile->writeEndFunction (currFunc, ic, 0);
3017       return;
3018   }
3019
3020   if (IFFUNC_ISCRITICAL (sym->type))
3021     {
3022       emitcode ("pop", "psw"); /* restore ea via c in psw */
3023       emitcode ("mov", "ea,c");
3024     }
3025
3026   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) && !options.useXstack)
3027     {
3028       emitcode ("mov", "%s,_bp", spname);
3029     }
3030
3031   /* if use external stack but some variables were
3032      added to the local stack then decrement the
3033      local stack */
3034   if (options.useXstack && sym->stack)
3035     {
3036       char count = sym->stack;
3037
3038       if ((count>3) && accIsFree)
3039         {
3040           emitcode ("mov", "a,sp");
3041           emitcode ("add", "a,#0x%02x", ((char) -count) & 0xff);
3042           emitcode ("mov", "sp,a");
3043         }
3044       else
3045         {
3046           while (count--)
3047             emitcode ("dec", "sp");
3048         }
3049     }
3050
3051   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3052     {
3053       if (options.useXstack)
3054         {
3055           emitcode ("xch", "a,_bp");
3056           emitcode ("mov", "r0,a");
3057           emitcode ("dec", "r0");
3058           emitcode ("movx", "a,@r0");
3059           emitcode ("xch", "a,_bp");
3060           emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3061         }
3062       else
3063         {
3064           emitcode ("pop", "_bp");
3065         }
3066     }
3067
3068   /* restore the register bank  */
3069   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3070   {
3071     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3072      || !options.useXstack)
3073     {
3074         /* Special case of ISR using non-zero bank with useXstack
3075          * is handled below.
3076          */
3077         emitcode ("pop", "psw");
3078     }
3079   }
3080
3081   if (IFFUNC_ISISR (sym->type))
3082     {
3083
3084       /* now we need to restore the registers */
3085       /* if this isr has no bank i.e. is going to
3086          run with bank 0 , then we need to save more
3087          registers :-) */
3088       if (!FUNC_REGBANK (sym->type))
3089         {
3090           /* if this function does not call any other
3091              function then we can be economical and
3092              save only those registers that are used */
3093           if (!IFFUNC_HASFCALL(sym->type))
3094             {
3095               int i;
3096
3097               /* if any registers used */
3098               if (sym->regsUsed)
3099                 {
3100                   /* save the registers used */
3101                   for (i = sym->regsUsed->size; i >= 0; i--)
3102                     {
3103                       if (bitVectBitValue (sym->regsUsed, i))
3104                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3105                     }
3106                 }
3107             }
3108           else
3109             {
3110               if (options.parms_in_bank1) {
3111                   int i;
3112                   for (i = 7 ; i >= 0 ; i-- ) {
3113                       emitcode ("pop","%s",rb1regs[i]);
3114                   }
3115               }
3116               /* this function has  a function call cannot
3117                  determines register usage so we will have to pop the
3118                  entire bank */
3119               unsaveRBank (0, ic, FALSE);
3120             }
3121         }
3122         else
3123         {
3124             /* This ISR uses a non-zero bank.
3125              *
3126              * Restore any register banks saved by genFunction
3127              * in reverse order.
3128              */
3129             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3130             int ix;
3131
3132             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3133             {
3134                 if (savedBanks & (1 << ix))
3135                 {
3136                     unsaveRBank(ix, NULL, FALSE);
3137                 }
3138             }
3139
3140             if (options.useXstack)
3141             {
3142                 /* Restore bank AFTER calling unsaveRBank,
3143                  * since it can trash r0.
3144                  */
3145                 emitcode ("pop", "psw");
3146             }
3147         }
3148
3149       if (!inExcludeList ("dph"))
3150         emitcode ("pop", "dph");
3151       if (!inExcludeList ("dpl"))
3152         emitcode ("pop", "dpl");
3153       if (!inExcludeList ("b"))
3154         emitcode ("pop", "b");
3155       if (!inExcludeList ("acc"))
3156         emitcode ("pop", "acc");
3157
3158       /* if debug then send end of function */
3159       if (options.debug && currFunc)
3160         {
3161           debugFile->writeEndFunction (currFunc, ic, 1);
3162         }
3163
3164       emitcode ("reti", "");
3165     }
3166   else
3167     {
3168       if (IFFUNC_CALLEESAVES(sym->type))
3169         {
3170           int i;
3171
3172           /* if any registers used */
3173           if (sym->regsUsed)
3174             {
3175               /* save the registers used */
3176               for (i = sym->regsUsed->size; i >= 0; i--)
3177                 {
3178                   if (bitVectBitValue (sym->regsUsed, i) ||
3179                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3180                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3181                 }
3182             }
3183           else if (mcs51_ptrRegReq)
3184             {
3185               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3186               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3187             }
3188
3189         }
3190
3191       /* if debug then send end of function */
3192       if (options.debug && currFunc)
3193         {
3194           debugFile->writeEndFunction (currFunc, ic, 1);
3195         }
3196
3197       emitcode ("ret", "");
3198     }
3199
3200   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3201     return;
3202
3203   /* If this was an interrupt handler using bank 0 that called another */
3204   /* function, then all registers must be saved; nothing to optimized. */
3205   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3206       && !FUNC_REGBANK(sym->type))
3207     return;
3208
3209   /* There are no push/pops to optimize if not callee-saves or ISR */
3210   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3211     return;
3212
3213   /* If there were stack parameters, we cannot optimize without also    */
3214   /* fixing all of the stack offsets; this is too dificult to consider. */
3215   if (FUNC_HASSTACKPARM(sym->type))
3216     return;
3217
3218   /* Compute the registers actually used */
3219   regsUsed = newBitVect (mcs51_nRegs);
3220   regsUsedPrologue = newBitVect (mcs51_nRegs);
3221   while (lnp)
3222     {
3223       if (lnp->ic && lnp->ic->op == FUNCTION)
3224         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3225       else
3226         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3227
3228       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3229           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3230         break;
3231       if (!lnp->prev)
3232         break;
3233       lnp = lnp->prev;
3234     }
3235
3236   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3237       && !bitVectBitValue (regsUsed, CND_IDX))
3238     {
3239       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3240       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3241           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3242         bitVectUnSetBit (regsUsed, CND_IDX);
3243     }
3244   else
3245     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3246
3247   /* If this was an interrupt handler that called another function */
3248   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3249   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3250     {
3251       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3252       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3253       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3254       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3255       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3256     }
3257
3258   /* Remove the unneeded push/pops */
3259   regsUnneeded = newBitVect (mcs51_nRegs);
3260   while (lnp)
3261     {
3262       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3263         {
3264           if (!strncmp(lnp->line, "push", 4))
3265             {
3266               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3267               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3268                 {
3269                   connectLine (lnp->prev, lnp->next);
3270                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3271                 }
3272             }
3273           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3274             {
3275               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3276               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3277                 {
3278                   connectLine (lnp->prev, lnp->next);
3279                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3280                 }
3281             }
3282         }
3283       lnp = lnp->next;
3284     }
3285
3286   for (idx = 0; idx < regsUnneeded->size; idx++)
3287     if (bitVectBitValue (regsUnneeded, idx))
3288       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3289
3290   freeBitVect (regsUnneeded);
3291   freeBitVect (regsUsed);
3292   freeBitVect (regsUsedPrologue);
3293 }
3294
3295 /*-----------------------------------------------------------------*/
3296 /* genRet - generate code for return statement                     */
3297 /*-----------------------------------------------------------------*/
3298 static void
3299 genRet (iCode * ic)
3300 {
3301   int size, offset = 0, pushed = 0;
3302
3303   D(emitcode (";     genRet",""));
3304
3305   /* if we have no return value then
3306      just generate the "ret" */
3307   if (!IC_LEFT (ic))
3308     goto jumpret;
3309
3310   /* we have something to return then
3311      move the return value into place */
3312   aopOp (IC_LEFT (ic), ic, FALSE);
3313   size = AOP_SIZE (IC_LEFT (ic));
3314
3315   while (size--)
3316     {
3317       char *l;
3318       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3319         {
3320           /* #NOCHANGE */
3321           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3322                       FALSE, TRUE);
3323           emitcode ("push", "%s", l);
3324           pushed++;
3325         }
3326       else
3327         {
3328           l = aopGet (AOP (IC_LEFT (ic)), offset,
3329                       FALSE, FALSE);
3330           if (strcmp (fReturn[offset], l))
3331             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3332         }
3333     }
3334
3335   if (pushed)
3336     {
3337       while (pushed)
3338         {
3339           pushed--;
3340           if (strcmp (fReturn[pushed], "a"))
3341             emitcode ("pop", fReturn[pushed]);
3342           else
3343             emitcode ("pop", "acc");
3344         }
3345     }
3346   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3347
3348 jumpret:
3349   /* generate a jump to the return label
3350      if the next is not the return statement */
3351   if (!(ic->next && ic->next->op == LABEL &&
3352         IC_LABEL (ic->next) == returnLabel))
3353
3354     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3355
3356 }
3357
3358 /*-----------------------------------------------------------------*/
3359 /* genLabel - generates a label                                    */
3360 /*-----------------------------------------------------------------*/
3361 static void
3362 genLabel (iCode * ic)
3363 {
3364   /* special case never generate */
3365   if (IC_LABEL (ic) == entryLabel)
3366     return;
3367
3368   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3369 }
3370
3371 /*-----------------------------------------------------------------*/
3372 /* genGoto - generates a ljmp                                      */
3373 /*-----------------------------------------------------------------*/
3374 static void
3375 genGoto (iCode * ic)
3376 {
3377   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3378 }
3379
3380 /*-----------------------------------------------------------------*/
3381 /* findLabelBackwards: walks back through the iCode chain looking  */
3382 /* for the given label. Returns number of iCode instructions     */
3383 /* between that label and given ic.          */
3384 /* Returns zero if label not found.          */
3385 /*-----------------------------------------------------------------*/
3386 static int
3387 findLabelBackwards (iCode * ic, int key)
3388 {
3389   int count = 0;
3390
3391   while (ic->prev)
3392     {
3393       ic = ic->prev;
3394       count++;
3395
3396       /* If we have any pushes or pops, we cannot predict the distance.
3397          I don't like this at all, this should be dealt with in the
3398          back-end */
3399       if (ic->op == IPUSH || ic->op == IPOP) {
3400         return 0;
3401       }
3402
3403       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3404         {
3405           return count;
3406         }
3407     }
3408
3409   return 0;
3410 }
3411
3412 /*-----------------------------------------------------------------*/
3413 /* genPlusIncr :- does addition with increment if possible         */
3414 /*-----------------------------------------------------------------*/
3415 static bool
3416 genPlusIncr (iCode * ic)
3417 {
3418   unsigned int icount;
3419   unsigned int size = getDataSize (IC_RESULT (ic));
3420
3421   /* will try to generate an increment */
3422   /* if the right side is not a literal
3423      we cannot */
3424   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3425     return FALSE;
3426
3427   /* if the literal value of the right hand side
3428      is greater than 4 then it is not worth it */
3429   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3430     return FALSE;
3431
3432   D(emitcode (";     genPlusIncr",""));
3433
3434   /* if increment >=16 bits in register or direct space */
3435   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3436       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3437       (size > 1) &&
3438       (icount == 1))
3439     {
3440       symbol *tlbl;
3441       int emitTlbl;
3442       int labelRange;
3443
3444       /* If the next instruction is a goto and the goto target
3445        * is < 10 instructions previous to this, we can generate
3446        * jumps straight to that target.
3447        */
3448       if (ic->next && ic->next->op == GOTO
3449           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3450           && labelRange <= 10)
3451         {
3452           emitcode (";", "tail increment optimized");
3453           tlbl = IC_LABEL (ic->next);
3454           emitTlbl = 0;
3455         }
3456       else
3457         {
3458           tlbl = newiTempLabel (NULL);
3459           emitTlbl = 1;
3460         }
3461       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3462       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3463           IS_AOP_PREG (IC_RESULT (ic)))
3464         emitcode ("cjne", "%s,#0x00,%05d$",
3465                   aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3466                   tlbl->key + 100);
3467       else
3468         {
3469           emitcode ("clr", "a");
3470           emitcode ("cjne", "a,%s,%05d$",
3471                     aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3472                     tlbl->key + 100);
3473         }
3474
3475       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3476       if (size > 2)
3477         {
3478           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3479               IS_AOP_PREG (IC_RESULT (ic)))
3480             emitcode ("cjne", "%s,#0x00,%05d$",
3481                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3482                       tlbl->key + 100);
3483           else
3484             emitcode ("cjne", "a,%s,%05d$",
3485                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3486                       tlbl->key + 100);
3487
3488           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3489         }
3490       if (size > 3)
3491         {
3492           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3493               IS_AOP_PREG (IC_RESULT (ic)))
3494             emitcode ("cjne", "%s,#0x00,%05d$",
3495                       aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3496                       tlbl->key + 100);
3497           else
3498             {
3499               emitcode ("cjne", "a,%s,%05d$",
3500                         aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3501                         tlbl->key + 100);
3502             }
3503           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3504         }
3505
3506       if (emitTlbl)
3507         {
3508           emitcode ("", "%05d$:", tlbl->key + 100);
3509         }
3510       return TRUE;
3511     }
3512
3513   /* if the sizes are greater than 1 then we cannot */
3514   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3515       AOP_SIZE (IC_LEFT (ic)) > 1)
3516     return FALSE;
3517
3518   /* we can if the aops of the left & result match or
3519      if they are in registers and the registers are the
3520      same */
3521   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3522     {
3523
3524       if (icount > 3)
3525         {
3526           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3527           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3528           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3529         }
3530       else
3531         {
3532
3533           while (icount--)
3534             emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3535         }
3536
3537       return TRUE;
3538     }
3539
3540   return FALSE;
3541 }
3542
3543 /*-----------------------------------------------------------------*/
3544 /* outBitAcc - output a bit in acc                                 */
3545 /*-----------------------------------------------------------------*/
3546 static void
3547 outBitAcc (operand * result)
3548 {
3549   symbol *tlbl = newiTempLabel (NULL);
3550   /* if the result is a bit */
3551   if (AOP_TYPE (result) == AOP_CRY)
3552     {
3553       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
3554     }
3555   else
3556     {
3557       emitcode ("jz", "%05d$", tlbl->key + 100);
3558       emitcode ("mov", "a,%s", one);
3559       emitcode ("", "%05d$:", tlbl->key + 100);
3560       outAcc (result);
3561     }
3562 }
3563
3564 /*-----------------------------------------------------------------*/
3565 /* genPlusBits - generates code for addition of two bits           */
3566 /*-----------------------------------------------------------------*/
3567 static void
3568 genPlusBits (iCode * ic)
3569 {
3570   D(emitcode (";     genPlusBits",""));
3571
3572   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3573     {
3574       symbol *lbl = newiTempLabel (NULL);
3575       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3576       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3577       emitcode ("cpl", "c");
3578       emitcode ("", "%05d$:", (lbl->key + 100));
3579       outBitC (IC_RESULT (ic));
3580     }
3581   else
3582     {
3583       emitcode ("clr", "a");
3584       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3585       emitcode ("rlc", "a");
3586       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3587       emitcode ("addc", "a,#0x00");
3588       outAcc (IC_RESULT (ic));
3589     }
3590 }
3591
3592 #if 0
3593 /* This is the original version of this code.
3594
3595  * This is being kept around for reference,
3596  * because I am not entirely sure I got it right...
3597  */
3598 static void
3599 adjustArithmeticResult (iCode * ic)
3600 {
3601   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3602       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3603       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3604     aopPut (AOP (IC_RESULT (ic)),
3605             aopGet (AOP (IC_LEFT (ic)), 2, FALSE, FALSE),
3606             2,
3607             isOperandVolatile (IC_RESULT (ic), FALSE));
3608
3609   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3610       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3611       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3612     aopPut (AOP (IC_RESULT (ic)),
3613             aopGet (AOP (IC_RIGHT (ic)), 2, FALSE, FALSE),
3614             2,
3615             isOperandVolatile (IC_RESULT (ic), FALSE));
3616
3617   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3618       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3619       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3620       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3621       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3622     {
3623       char buffer[5];
3624       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3625       aopPut (AOP (IC_RESULT (ic)), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3626     }
3627 }
3628 #else
3629 /* This is the pure and virtuous version of this code.
3630  * I'm pretty certain it's right, but not enough to toss the old
3631  * code just yet...
3632  */
3633 static void
3634 adjustArithmeticResult (iCode * ic)
3635 {
3636   if (opIsGptr (IC_RESULT (ic)) &&
3637       opIsGptr (IC_LEFT (ic)) &&
3638       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3639     {
3640       aopPut (AOP (IC_RESULT (ic)),
3641               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3642               GPTRSIZE - 1,
3643               isOperandVolatile (IC_RESULT (ic), FALSE));
3644     }
3645
3646   if (opIsGptr (IC_RESULT (ic)) &&
3647       opIsGptr (IC_RIGHT (ic)) &&
3648       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3649     {
3650       aopPut (AOP (IC_RESULT (ic)),
3651               aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3652               GPTRSIZE - 1,
3653               isOperandVolatile (IC_RESULT (ic), FALSE));
3654     }
3655
3656   if (opIsGptr (IC_RESULT (ic)) &&
3657       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3658       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3659       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3660       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3661     {
3662       char buffer[5];
3663       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3664       aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3665     }
3666 }
3667 #endif
3668
3669 /*-----------------------------------------------------------------*/
3670 /* genPlus - generates code for addition                           */
3671 /*-----------------------------------------------------------------*/
3672 static void
3673 genPlus (iCode * ic)
3674 {
3675   int size, offset = 0;
3676   int skip_bytes = 0;
3677   char *add = "add";
3678   asmop *leftOp, *rightOp;
3679   operand * op;
3680
3681   /* special cases :- */
3682
3683   D(emitcode (";     genPlus",""));
3684
3685   aopOp (IC_LEFT (ic), ic, FALSE);
3686   aopOp (IC_RIGHT (ic), ic, FALSE);
3687   aopOp (IC_RESULT (ic), ic, TRUE);
3688
3689   /* if literal, literal on the right or
3690      if left requires ACC or right is already
3691      in ACC */
3692   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3693       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3694       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3695     {
3696       operand *t = IC_RIGHT (ic);
3697       IC_RIGHT (ic) = IC_LEFT (ic);
3698       IC_LEFT (ic) = t;
3699     }
3700
3701   /* if both left & right are in bit
3702      space */
3703   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3704       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3705     {
3706       genPlusBits (ic);
3707       goto release;
3708     }
3709
3710   /* if left in bit space & right literal */
3711   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3712       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3713     {
3714       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3715       /* if result in bit space */
3716       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3717         {
3718           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3719             emitcode ("cpl", "c");
3720           outBitC (IC_RESULT (ic));
3721         }
3722       else
3723         {
3724           size = getDataSize (IC_RESULT (ic));
3725           while (size--)
3726             {
3727               MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE));
3728               emitcode ("addc", "a,#00");
3729               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3730             }
3731         }
3732       goto release;
3733     }
3734
3735   /* if I can do an increment instead
3736      of add then GOOD for ME */
3737   if (genPlusIncr (ic) == TRUE)
3738     goto release;
3739
3740   size = getDataSize (IC_RESULT (ic));
3741   leftOp = AOP(IC_LEFT(ic));
3742   rightOp = AOP(IC_RIGHT(ic));
3743   op=IC_LEFT(ic);
3744
3745   /* if this is an add for an array access
3746      at a 256 byte boundary */
3747   if ( 2 == size
3748        && AOP_TYPE (op) == AOP_IMMD
3749        && IS_SYMOP (op)
3750        && IS_SPEC (OP_SYM_ETYPE (op))
3751        && SPEC_ABSA (OP_SYM_ETYPE (op))
3752        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3753      )
3754     {
3755       D(emitcode (";     genPlus aligned array",""));
3756       aopPut (AOP (IC_RESULT (ic)),
3757               aopGet (rightOp, 0, FALSE, FALSE),
3758               0,
3759               isOperandVolatile (IC_RESULT (ic), FALSE));
3760
3761       if( 1 == getDataSize (IC_RIGHT (ic)) )
3762         {
3763           aopPut (AOP (IC_RESULT (ic)),
3764                   aopGet (leftOp, 1, FALSE, FALSE),
3765                   1,
3766                   isOperandVolatile (IC_RESULT (ic), FALSE));
3767         }
3768       else
3769         {
3770           MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
3771           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3772           aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3773         }
3774       goto release;
3775     }
3776
3777   /* if the lower bytes of a literal are zero skip the addition */
3778   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3779     {
3780        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3781               (skip_bytes+1 < size))
3782          {
3783            skip_bytes++;
3784          }
3785        if (skip_bytes)
3786          D(emitcode (";     genPlus shortcut",""));
3787     }
3788
3789   while (size--)
3790     {
3791       if( offset >= skip_bytes )
3792         {
3793           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3794             {
3795               bool pushedB;
3796               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3797               pushedB = pushB ();
3798               emitcode("xch", "a,b");
3799               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3800               emitcode (add, "a,b");
3801               popB (pushedB);
3802             }
3803           else if (aopGetUsesAcc (leftOp, offset))
3804             {
3805               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3806               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3807             }
3808           else
3809             {
3810               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3811               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3812             }
3813           aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3814           add = "addc";  /* further adds must propagate carry */
3815         }
3816       else
3817         {
3818           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3819               isOperandVolatile (IC_RESULT (ic), FALSE))
3820             {
3821               /* just move */
3822               aopPut (AOP (IC_RESULT (ic)),
3823                       aopGet (leftOp, offset, FALSE, FALSE),
3824                       offset,
3825                       isOperandVolatile (IC_RESULT (ic), FALSE));
3826             }
3827         }
3828       offset++;
3829     }
3830
3831   adjustArithmeticResult (ic);
3832
3833 release:
3834   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3835   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3836   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3837 }
3838
3839 /*-----------------------------------------------------------------*/
3840 /* genMinusDec :- does subtraction with deccrement if possible     */
3841 /*-----------------------------------------------------------------*/
3842 static bool
3843 genMinusDec (iCode * ic)
3844 {
3845   unsigned int icount;
3846   unsigned int size = getDataSize (IC_RESULT (ic));
3847
3848   /* will try to generate an increment */
3849   /* if the right side is not a literal
3850      we cannot */
3851   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3852     return FALSE;
3853
3854   /* if the literal value of the right hand side
3855      is greater than 4 then it is not worth it */
3856   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3857     return FALSE;
3858
3859   D(emitcode (";     genMinusDec",""));
3860
3861   /* if decrement >=16 bits in register or direct space */
3862   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3863       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3864       (size > 1) &&
3865       (icount == 1))
3866     {
3867       symbol *tlbl;
3868       int emitTlbl;
3869       int labelRange;
3870
3871       /* If the next instruction is a goto and the goto target
3872        * is <= 10 instructions previous to this, we can generate
3873        * jumps straight to that target.
3874        */
3875       if (ic->next && ic->next->op == GOTO
3876           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3877           && labelRange <= 10)
3878         {
3879           emitcode (";", "tail decrement optimized");
3880           tlbl = IC_LABEL (ic->next);
3881           emitTlbl = 0;
3882         }
3883       else
3884         {
3885           tlbl = newiTempLabel (NULL);
3886           emitTlbl = 1;
3887         }
3888
3889       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3890       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3891           IS_AOP_PREG (IC_RESULT (ic)))
3892         emitcode ("cjne", "%s,#0xff,%05d$"
3893                   ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3894                   ,tlbl->key + 100);
3895       else
3896         {
3897           emitcode ("mov", "a,#0xff");
3898           emitcode ("cjne", "a,%s,%05d$"
3899                     ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3900                     ,tlbl->key + 100);
3901         }
3902       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3903       if (size > 2)
3904         {
3905           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3906               IS_AOP_PREG (IC_RESULT (ic)))
3907             emitcode ("cjne", "%s,#0xff,%05d$"
3908                       ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3909                       ,tlbl->key + 100);
3910           else
3911             {
3912               emitcode ("cjne", "a,%s,%05d$"
3913                         ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3914                         ,tlbl->key + 100);
3915             }
3916           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3917         }
3918       if (size > 3)
3919         {
3920           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3921               IS_AOP_PREG (IC_RESULT (ic)))
3922             emitcode ("cjne", "%s,#0xff,%05d$"
3923                       ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3924                       ,tlbl->key + 100);
3925           else
3926             {
3927               emitcode ("cjne", "a,%s,%05d$"
3928                         ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3929                         ,tlbl->key + 100);
3930             }
3931           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3932         }
3933       if (emitTlbl)
3934         {
3935           emitcode ("", "%05d$:", tlbl->key + 100);
3936         }
3937       return TRUE;
3938     }
3939
3940   /* if the sizes are greater than 1 then we cannot */
3941   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3942       AOP_SIZE (IC_LEFT (ic)) > 1)
3943     return FALSE;
3944
3945   /* we can if the aops of the left & result match or
3946      if they are in registers and the registers are the
3947      same */
3948   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3949     {
3950
3951       while (icount--)
3952         emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
3953
3954       return TRUE;
3955     }
3956
3957   return FALSE;
3958 }
3959
3960 /*-----------------------------------------------------------------*/
3961 /* addSign - complete with sign                                    */
3962 /*-----------------------------------------------------------------*/
3963 static void
3964 addSign (operand * result, int offset, int sign)
3965 {
3966   int size = (getDataSize (result) - offset);
3967   if (size > 0)
3968     {
3969       if (sign)
3970         {
3971           emitcode ("rlc", "a");
3972           emitcode ("subb", "a,acc");
3973           while (size--)
3974             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
3975         }
3976       else
3977         while (size--)
3978           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
3979     }
3980 }
3981
3982 /*-----------------------------------------------------------------*/
3983 /* genMinusBits - generates code for subtraction  of two bits      */
3984 /*-----------------------------------------------------------------*/
3985 static void
3986 genMinusBits (iCode * ic)
3987 {
3988   symbol *lbl = newiTempLabel (NULL);
3989
3990   D(emitcode (";     genMinusBits",""));
3991
3992   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3993     {
3994       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3995       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3996       emitcode ("cpl", "c");
3997       emitcode ("", "%05d$:", (lbl->key + 100));
3998       outBitC (IC_RESULT (ic));
3999     }
4000   else
4001     {
4002       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4003       emitcode ("subb", "a,acc");
4004       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4005       emitcode ("inc", "a");
4006       emitcode ("", "%05d$:", (lbl->key + 100));
4007       aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4008       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4009     }
4010 }
4011
4012 /*-----------------------------------------------------------------*/
4013 /* genMinus - generates code for subtraction                       */
4014 /*-----------------------------------------------------------------*/
4015 static void
4016 genMinus (iCode * ic)
4017 {
4018   int size, offset = 0;
4019
4020   D(emitcode (";     genMinus",""));
4021
4022   aopOp (IC_LEFT (ic), ic, FALSE);
4023   aopOp (IC_RIGHT (ic), ic, FALSE);
4024   aopOp (IC_RESULT (ic), ic, TRUE);
4025
4026   /* special cases :- */
4027   /* if both left & right are in bit space */
4028   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4029       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4030     {
4031       genMinusBits (ic);
4032       goto release;
4033     }
4034
4035   /* if I can do an decrement instead
4036      of subtract then GOOD for ME */
4037   if (genMinusDec (ic) == TRUE)
4038     goto release;
4039
4040   size = getDataSize (IC_RESULT (ic));
4041
4042   /* if literal, add a,#-lit, else normal subb */
4043   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4044     {
4045       unsigned long lit = 0L;
4046
4047       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4048       lit = -(long) lit;
4049
4050       while (size--)
4051         {
4052           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE));
4053           /* first add without previous c */
4054           if (!offset) {
4055             if (!size && lit== (unsigned long) -1) {
4056               emitcode ("dec", "a");
4057             } else {
4058               emitcode ("add", "a,#0x%02x",
4059                         (unsigned int) (lit & 0x0FFL));
4060             }
4061           } else {
4062             emitcode ("addc", "a,#0x%02x",
4063                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4064           }
4065           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4066         }
4067     }
4068   else
4069     {
4070       asmop *leftOp, *rightOp;
4071
4072       leftOp = AOP(IC_LEFT(ic));
4073       rightOp = AOP(IC_RIGHT(ic));
4074
4075       while (size--)
4076         {
4077           if (aopGetUsesAcc(rightOp, offset)) {
4078             if (aopGetUsesAcc(leftOp, offset)) {
4079               bool pushedB;
4080
4081               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4082               pushedB = pushB ();
4083               emitcode ("mov", "b,a");
4084               if (offset == 0)
4085                 CLRC;
4086               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4087               emitcode ("subb", "a,b");
4088               popB (pushedB);
4089             } else {
4090               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4091               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4092               if (offset == 0) {
4093                 emitcode( "setb", "c");
4094               }
4095               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4096               emitcode("cpl", "a");
4097             }
4098           } else {
4099             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4100             if (offset == 0)
4101               CLRC;
4102             emitcode ("subb", "a,%s",
4103                       aopGet(rightOp, offset, FALSE, TRUE));
4104           }
4105
4106           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4107         }
4108     }
4109
4110
4111   adjustArithmeticResult (ic);
4112
4113 release:
4114   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4115   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4116   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4117 }
4118
4119
4120 /*-----------------------------------------------------------------*/
4121 /* genMultbits :- multiplication of bits                           */
4122 /*-----------------------------------------------------------------*/
4123 static void
4124 genMultbits (operand * left,
4125              operand * right,
4126              operand * result)
4127 {
4128   D(emitcode (";     genMultbits",""));
4129
4130   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4131   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4132   outBitC (result);
4133 }
4134
4135 /*-----------------------------------------------------------------*/
4136 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4137 /*-----------------------------------------------------------------*/
4138 static void
4139 genMultOneByte (operand * left,
4140                 operand * right,
4141                 operand * result)
4142 {
4143   symbol *lbl;
4144   int size = AOP_SIZE (result);
4145   bool runtimeSign, compiletimeSign;
4146   bool lUnsigned, rUnsigned, pushedB;
4147
4148   D(emitcode (";     genMultOneByte",""));
4149
4150   if (size < 1 || size > 2)
4151     {
4152       /* this should never happen */
4153       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4154                AOP_SIZE(result), __FILE__, lineno);
4155       exit (1);
4156     }
4157
4158   /* (if two literals: the value is computed before) */
4159   /* if one literal, literal on the right */
4160   if (AOP_TYPE (left) == AOP_LIT)
4161     {
4162       operand *t = right;
4163       right = left;
4164       left = t;
4165       /* emitcode (";", "swapped left and right"); */
4166     }
4167   /* if no literal, unsigned on the right: shorter code */
4168   if (   AOP_TYPE (right) != AOP_LIT
4169       && SPEC_USIGN (getSpec (operandType (left))))
4170     {
4171       operand *t = right;
4172       right = left;
4173       left = t;
4174     }
4175
4176   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4177   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4178
4179   pushedB = pushB ();
4180
4181   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4182                    no need to take care about the signedness! */
4183       || (lUnsigned && rUnsigned))
4184     {
4185       /* just an unsigned 8 * 8 = 8 multiply
4186          or 8u * 8u = 16u */
4187       /* emitcode (";","unsigned"); */
4188       /* TODO: check for accumulator clash between left & right aops? */
4189
4190       if (AOP_TYPE (right) == AOP_LIT)
4191         {
4192           /* moving to accumulator first helps peepholes */
4193           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4194           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4195         }
4196       else
4197         {
4198           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4199           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4200         }
4201
4202       emitcode ("mul", "ab");
4203       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4204       if (size == 2)
4205         aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4206
4207       popB (pushedB);
4208       return;
4209     }
4210
4211   /* we have to do a signed multiply */
4212   /* emitcode (";", "signed"); */
4213
4214   /* now sign adjust for both left & right */
4215
4216   /* let's see what's needed: */
4217   /* apply negative sign during runtime */
4218   runtimeSign = FALSE;
4219   /* negative sign from literals */
4220   compiletimeSign = FALSE;
4221
4222   if (!lUnsigned)
4223     {
4224       if (AOP_TYPE(left) == AOP_LIT)
4225         {
4226           /* signed literal */
4227           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4228           if (val < 0)
4229             compiletimeSign = TRUE;
4230         }
4231       else
4232         /* signed but not literal */
4233         runtimeSign = TRUE;
4234     }
4235
4236   if (!rUnsigned)
4237     {
4238       if (AOP_TYPE(right) == AOP_LIT)
4239         {
4240           /* signed literal */
4241           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4242           if (val < 0)
4243             compiletimeSign ^= TRUE;
4244         }
4245       else
4246         /* signed but not literal */
4247         runtimeSign = TRUE;
4248     }
4249
4250   /* initialize F0, which stores the runtime sign */
4251   if (runtimeSign)
4252     {
4253       if (compiletimeSign)
4254         emitcode ("setb", "F0"); /* set sign flag */
4255       else
4256         emitcode ("clr", "F0"); /* reset sign flag */
4257     }
4258
4259   /* save the signs of the operands */
4260   if (AOP_TYPE(right) == AOP_LIT)
4261     {
4262       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4263
4264       if (!rUnsigned && val < 0)
4265         emitcode ("mov", "b,#0x%02x", -val);
4266       else
4267         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4268     }
4269   else /* ! literal */
4270     {
4271       if (rUnsigned)  /* emitcode (";", "signed"); */
4272
4273         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4274       else
4275         {
4276           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4277           lbl = newiTempLabel (NULL);
4278           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4279           emitcode ("cpl", "F0"); /* complement sign flag */
4280           emitcode ("cpl", "a");  /* 2's complement */
4281           emitcode ("inc", "a");
4282           emitcode ("", "%05d$:", (lbl->key + 100));
4283           emitcode ("mov", "b,a");
4284         }
4285     }
4286
4287   if (AOP_TYPE(left) == AOP_LIT)
4288     {
4289       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4290
4291       if (!lUnsigned && val < 0)
4292         emitcode ("mov", "a,#0x%02x", -val);
4293       else
4294         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4295     }
4296   else /* ! literal */
4297     {
4298       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4299
4300       if (!lUnsigned)
4301         {
4302           lbl = newiTempLabel (NULL);
4303           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4304           emitcode ("cpl", "F0"); /* complement sign flag */
4305           emitcode ("cpl", "a"); /* 2's complement */
4306           emitcode ("inc", "a");
4307           emitcode ("", "%05d$:", (lbl->key + 100));
4308         }
4309     }
4310
4311   /* now the multiplication */
4312   emitcode ("mul", "ab");
4313   if (runtimeSign || compiletimeSign)
4314     {
4315       lbl = newiTempLabel (NULL);
4316       if (runtimeSign)
4317         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4318       emitcode ("cpl", "a"); /* lsb 2's complement */
4319       if (size != 2)
4320         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4321       else
4322         {
4323           emitcode ("add", "a,#1"); /* this sets carry flag */
4324           emitcode ("xch", "a,b");
4325           emitcode ("cpl", "a"); /* msb 2's complement */
4326           emitcode ("addc", "a,#0");
4327           emitcode ("xch", "a,b");
4328         }
4329       emitcode ("", "%05d$:", (lbl->key + 100));
4330     }
4331   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4332   if (size == 2)
4333     aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4334
4335   popB (pushedB);
4336 }
4337
4338 /*-----------------------------------------------------------------*/
4339 /* genMult - generates code for multiplication                     */
4340 /*-----------------------------------------------------------------*/
4341 static void
4342 genMult (iCode * ic)
4343 {
4344   operand *left = IC_LEFT (ic);
4345   operand *right = IC_RIGHT (ic);
4346   operand *result = IC_RESULT (ic);
4347
4348   D(emitcode (";     genMult",""));
4349
4350   /* assign the amsops */
4351   aopOp (left, ic, FALSE);
4352   aopOp (right, ic, FALSE);
4353   aopOp (result, ic, TRUE);
4354
4355   /* special cases first */
4356   /* both are bits */
4357   if (AOP_TYPE (left) == AOP_CRY &&
4358       AOP_TYPE (right) == AOP_CRY)
4359     {
4360       genMultbits (left, right, result);
4361       goto release;
4362     }
4363
4364   /* if both are of size == 1 */
4365 #if 0 // one of them can be a sloc shared with the result
4366     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4367 #else
4368   if (getSize(operandType(left)) == 1 &&
4369       getSize(operandType(right)) == 1)
4370 #endif
4371     {
4372       genMultOneByte (left, right, result);
4373       goto release;
4374     }
4375
4376   /* should have been converted to function call */
4377     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4378              getSize(OP_SYMBOL(right)->type));
4379   assert (0);
4380
4381 release:
4382   freeAsmop (result, NULL, ic, TRUE);
4383   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4384   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4385 }
4386
4387 /*-----------------------------------------------------------------*/
4388 /* genDivbits :- division of bits                                  */
4389 /*-----------------------------------------------------------------*/
4390 static void
4391 genDivbits (operand * left,
4392             operand * right,
4393             operand * result)
4394 {
4395   char *l;
4396   bool pushedB;
4397
4398   D(emitcode (";     genDivbits",""));
4399
4400   pushedB = pushB ();
4401
4402   /* the result must be bit */
4403   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4404   l = aopGet (AOP (left), 0, FALSE, FALSE);
4405
4406   MOVA (l);
4407
4408   emitcode ("div", "ab");
4409   emitcode ("rrc", "a");
4410
4411   popB (pushedB);
4412
4413   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4414 }
4415
4416 /*-----------------------------------------------------------------*/
4417 /* genDivOneByte : 8 bit division                                  */
4418 /*-----------------------------------------------------------------*/
4419 static void
4420 genDivOneByte (operand * left,
4421                operand * right,
4422                operand * result)
4423 {
4424   bool lUnsigned, rUnsigned, pushedB;
4425   bool runtimeSign, compiletimeSign;
4426   symbol *lbl;
4427   int size, offset;
4428
4429   D(emitcode (";     genDivOneByte",""));
4430
4431   /* Why is it necessary that genDivOneByte() can return an int result?
4432      Have a look at:
4433
4434         volatile unsigned char uc;
4435         volatile signed char sc1, sc2;
4436         volatile int i;
4437
4438         uc  = 255;
4439         sc1 = -1;
4440         i = uc / sc1;
4441
4442      Or:
4443
4444         sc1 = -128;
4445         sc2 = -1;
4446         i = sc1 / sc2;
4447
4448      In all cases a one byte result would overflow, the following cast to int
4449      would return the wrong result.
4450
4451      Two possible solution:
4452         a) cast operands to int, if ((unsigned) / (signed)) or
4453            ((signed) / (signed))
4454         b) return an 16 bit signed int; this is what we're doing here!
4455   */
4456
4457   size = AOP_SIZE (result) - 1;
4458   offset = 1;
4459   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4460   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4461
4462   pushedB = pushB ();
4463
4464   /* signed or unsigned */
4465   if (lUnsigned && rUnsigned)
4466     {
4467       /* unsigned is easy */
4468       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4469       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4470       emitcode ("div", "ab");
4471       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4472       while (size--)
4473         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4474
4475       popB (pushedB);
4476       return;
4477     }
4478
4479   /* signed is a little bit more difficult */
4480
4481   /* now sign adjust for both left & right */
4482
4483   /* let's see what's needed: */
4484   /* apply negative sign during runtime */
4485   runtimeSign = FALSE;
4486   /* negative sign from literals */
4487   compiletimeSign = FALSE;
4488
4489   if (!lUnsigned)
4490     {
4491       if (AOP_TYPE(left) == AOP_LIT)
4492         {
4493           /* signed literal */
4494           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4495           if (val < 0)
4496             compiletimeSign = TRUE;
4497         }
4498       else
4499         /* signed but not literal */
4500         runtimeSign = TRUE;
4501     }
4502
4503   if (!rUnsigned)
4504     {
4505       if (AOP_TYPE(right) == AOP_LIT)
4506         {
4507           /* signed literal */
4508           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4509           if (val < 0)
4510             compiletimeSign ^= TRUE;
4511         }
4512       else
4513         /* signed but not literal */
4514         runtimeSign = TRUE;
4515     }
4516
4517   /* initialize F0, which stores the runtime sign */
4518   if (runtimeSign)
4519     {
4520       if (compiletimeSign)
4521         emitcode ("setb", "F0"); /* set sign flag */
4522       else
4523         emitcode ("clr", "F0"); /* reset sign flag */
4524     }
4525
4526   /* save the signs of the operands */
4527   if (AOP_TYPE(right) == AOP_LIT)
4528     {
4529       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4530
4531       if (!rUnsigned && val < 0)
4532         emitcode ("mov", "b,#0x%02x", -val);
4533       else
4534         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4535     }
4536   else /* ! literal */
4537     {
4538       if (rUnsigned)
4539         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4540       else
4541         {
4542           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4543           lbl = newiTempLabel (NULL);
4544           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4545           emitcode ("cpl", "F0"); /* complement sign flag */
4546           emitcode ("cpl", "a");  /* 2's complement */
4547           emitcode ("inc", "a");
4548           emitcode ("", "%05d$:", (lbl->key + 100));
4549           emitcode ("mov", "b,a");
4550         }
4551     }
4552
4553   if (AOP_TYPE(left) == AOP_LIT)
4554     {
4555       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4556
4557       if (!lUnsigned && val < 0)
4558         emitcode ("mov", "a,#0x%02x", -val);
4559       else
4560         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4561     }
4562   else /* ! literal */
4563     {
4564       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4565
4566       if (!lUnsigned)
4567         {
4568           lbl = newiTempLabel (NULL);
4569           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4570           emitcode ("cpl", "F0"); /* complement sign flag */
4571           emitcode ("cpl", "a");  /* 2's complement */
4572           emitcode ("inc", "a");
4573           emitcode ("", "%05d$:", (lbl->key + 100));
4574         }
4575     }
4576
4577   /* now the division */
4578   emitcode ("div", "ab");
4579
4580   if (runtimeSign || compiletimeSign)
4581     {
4582       lbl = newiTempLabel (NULL);
4583       if (runtimeSign)
4584         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4585       emitcode ("cpl", "a"); /* lsb 2's complement */
4586       emitcode ("inc", "a");
4587       emitcode ("", "%05d$:", (lbl->key + 100));
4588
4589       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4590       if (size > 0)
4591         {
4592           /* msb is 0x00 or 0xff depending on the sign */
4593           if (runtimeSign)
4594             {
4595               emitcode ("mov", "c,F0");
4596               emitcode ("subb", "a,acc");
4597               while (size--)
4598                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4599             }
4600           else /* compiletimeSign */
4601             while (size--)
4602               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4603         }
4604     }
4605   else
4606     {
4607       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4608       while (size--)
4609         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4610     }
4611
4612   popB (pushedB);
4613 }
4614
4615 /*-----------------------------------------------------------------*/
4616 /* genDiv - generates code for division                            */
4617 /*-----------------------------------------------------------------*/
4618 static void
4619 genDiv (iCode * ic)
4620 {
4621   operand *left = IC_LEFT (ic);
4622   operand *right = IC_RIGHT (ic);
4623   operand *result = IC_RESULT (ic);
4624
4625   D(emitcode (";     genDiv",""));
4626
4627   /* assign the amsops */
4628   aopOp (left, ic, FALSE);
4629   aopOp (right, ic, FALSE);
4630   aopOp (result, ic, TRUE);
4631
4632   /* special cases first */
4633   /* both are bits */
4634   if (AOP_TYPE (left) == AOP_CRY &&
4635       AOP_TYPE (right) == AOP_CRY)
4636     {
4637       genDivbits (left, right, result);
4638       goto release;
4639     }
4640
4641   /* if both are of size == 1 */
4642   if (AOP_SIZE (left) == 1 &&
4643       AOP_SIZE (right) == 1)
4644     {
4645       genDivOneByte (left, right, result);
4646       goto release;
4647     }
4648
4649   /* should have been converted to function call */
4650   assert (0);
4651 release:
4652   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4653   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4654   freeAsmop (result, NULL, ic, TRUE);
4655 }
4656
4657 /*-----------------------------------------------------------------*/
4658 /* genModbits :- modulus of bits                                   */
4659 /*-----------------------------------------------------------------*/
4660 static void
4661 genModbits (operand * left,
4662             operand * right,
4663             operand * result)
4664 {
4665   char *l;
4666   bool pushedB;
4667
4668   D(emitcode (";     genModbits",""));
4669
4670   pushedB = pushB ();
4671
4672   /* the result must be bit */
4673   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4674   l = aopGet (AOP (left), 0, FALSE, FALSE);
4675
4676   MOVA (l);
4677
4678   emitcode ("div", "ab");
4679   emitcode ("mov", "a,b");
4680   emitcode ("rrc", "a");
4681
4682   popB (pushedB);
4683
4684   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4685 }
4686
4687 /*-----------------------------------------------------------------*/
4688 /* genModOneByte : 8 bit modulus                                   */
4689 /*-----------------------------------------------------------------*/
4690 static void
4691 genModOneByte (operand * left,
4692                operand * right,
4693                operand * result)
4694 {
4695   bool lUnsigned, rUnsigned, pushedB;
4696   bool runtimeSign, compiletimeSign;
4697   symbol *lbl;
4698   int size, offset;
4699
4700   D(emitcode (";     genModOneByte",""));
4701
4702   size = AOP_SIZE (result) - 1;
4703   offset = 1;
4704   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4705   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4706
4707   /* if right is a literal, check it for 2^n */
4708   if (AOP_TYPE(right) == AOP_LIT)
4709     {
4710       unsigned char val = abs(operandLitValue(right));
4711       symbol *lbl2 = NULL;
4712
4713       switch (val)
4714         {
4715           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
4716           case 2:
4717           case 4:
4718           case 8:
4719           case 16:
4720           case 32:
4721           case 64:
4722           case 128:
4723             if (lUnsigned)
4724               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
4725                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
4726               /* because iCode should have been changed to genAnd  */
4727               /* see file "SDCCopt.c", function "convertToFcall()" */
4728
4729             MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4730             emitcode ("mov", "c,acc.7");
4731             emitcode ("anl", "a,#0x%02x", val - 1);
4732             lbl = newiTempLabel (NULL);
4733             emitcode ("jz", "%05d$", (lbl->key + 100));
4734             emitcode ("jnc", "%05d$", (lbl->key + 100));
4735             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
4736             if (size)
4737               {
4738                 int size2 = size;
4739                 int offs2 = offset;
4740
4741                 aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4742                 while (size2--)
4743                   aopPut (AOP (result), "#0xff", offs2++, isOperandVolatile (result, FALSE));
4744                 lbl2 = newiTempLabel (NULL);
4745                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
4746               }
4747             emitcode ("", "%05d$:", (lbl->key + 100));
4748             aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4749             while (size--)
4750               aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4751             if (lbl2)
4752               {
4753                 emitcode ("", "%05d$:", (lbl2->key + 100));
4754               }
4755             return;
4756
4757           default:
4758             break;
4759         }
4760     }
4761
4762   pushedB = pushB ();
4763
4764   /* signed or unsigned */
4765   if (lUnsigned && rUnsigned)
4766     {
4767       /* unsigned is easy */
4768       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4769       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4770       emitcode ("div", "ab");
4771       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4772       while (size--)
4773         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4774
4775       popB (pushedB);
4776       return;
4777     }
4778
4779   /* signed is a little bit more difficult */
4780
4781   /* now sign adjust for both left & right */
4782
4783   /* modulus: sign of the right operand has no influence on the result! */
4784   if (AOP_TYPE(right) == AOP_LIT)
4785     {
4786       signed char val = (char) operandLitValue(right);
4787
4788       if (!rUnsigned && val < 0)
4789         emitcode ("mov", "b,#0x%02x", -val);
4790       else
4791         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4792     }
4793   else /* not literal */
4794     {
4795       if (rUnsigned)
4796         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4797       else
4798         {
4799           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4800           lbl = newiTempLabel (NULL);
4801           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4802           emitcode ("cpl", "a"); /* 2's complement */
4803           emitcode ("inc", "a");
4804           emitcode ("", "%05d$:", (lbl->key + 100));
4805           emitcode ("mov", "b,a");
4806         }
4807     }
4808
4809   /* let's see what's needed: */
4810   /* apply negative sign during runtime */
4811   runtimeSign = FALSE;
4812   /* negative sign from literals */
4813   compiletimeSign = FALSE;
4814
4815   /* sign adjust left side */
4816   if (AOP_TYPE(left) == AOP_LIT)
4817     {
4818       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4819
4820       if (!lUnsigned && val < 0)
4821         {
4822           compiletimeSign = TRUE; /* set sign flag */
4823           emitcode ("mov", "a,#0x%02x", -val);
4824         }
4825       else
4826         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4827     }
4828   else /* ! literal */
4829     {
4830       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4831
4832       if (!lUnsigned)
4833         {
4834           runtimeSign = TRUE;
4835           emitcode ("clr", "F0"); /* clear sign flag */
4836
4837           lbl = newiTempLabel (NULL);
4838           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4839           emitcode ("setb", "F0"); /* set sign flag */
4840           emitcode ("cpl", "a");   /* 2's complement */
4841           emitcode ("inc", "a");
4842           emitcode ("", "%05d$:", (lbl->key + 100));
4843         }
4844     }
4845
4846   /* now the modulus */
4847   emitcode ("div", "ab");
4848
4849   if (runtimeSign || compiletimeSign)
4850     {
4851       emitcode ("mov", "a,b");
4852       lbl = newiTempLabel (NULL);
4853       if (runtimeSign)
4854         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4855       emitcode ("cpl", "a"); /* 2's complement */
4856       emitcode ("inc", "a");
4857       emitcode ("", "%05d$:", (lbl->key + 100));
4858
4859       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4860       if (size > 0)
4861         {
4862           /* msb is 0x00 or 0xff depending on the sign */
4863           if (runtimeSign)
4864             {
4865               emitcode ("mov", "c,F0");
4866               emitcode ("subb", "a,acc");
4867               while (size--)
4868                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4869             }
4870           else /* compiletimeSign */
4871             while (size--)
4872               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4873         }
4874     }
4875   else
4876     {
4877       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4878       while (size--)
4879         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4880     }
4881
4882   popB (pushedB);
4883 }
4884
4885 /*-----------------------------------------------------------------*/
4886 /* genMod - generates code for division                            */
4887 /*-----------------------------------------------------------------*/
4888 static void
4889 genMod (iCode * ic)
4890 {
4891   operand *left = IC_LEFT (ic);
4892   operand *right = IC_RIGHT (ic);
4893   operand *result = IC_RESULT (ic);
4894
4895   D(emitcode (";     genMod",""));
4896
4897   /* assign the asmops */
4898   aopOp (left, ic, FALSE);
4899   aopOp (right, ic, FALSE);
4900   aopOp (result, ic, TRUE);
4901
4902   /* special cases first */
4903   /* both are bits */
4904   if (AOP_TYPE (left) == AOP_CRY &&
4905       AOP_TYPE (right) == AOP_CRY)
4906     {
4907       genModbits (left, right, result);
4908       goto release;
4909     }
4910
4911   /* if both are of size == 1 */
4912   if (AOP_SIZE (left) == 1 &&
4913       AOP_SIZE (right) == 1)
4914     {
4915       genModOneByte (left, right, result);
4916       goto release;
4917     }
4918
4919   /* should have been converted to function call */
4920   assert (0);
4921
4922 release:
4923   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4924   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4925   freeAsmop (result, NULL, ic, TRUE);
4926 }
4927
4928 /*-----------------------------------------------------------------*/
4929 /* genIfxJump :- will create a jump depending on the ifx           */
4930 /*-----------------------------------------------------------------*/
4931 static void
4932 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
4933 {
4934   symbol *jlbl;
4935   symbol *tlbl = newiTempLabel (NULL);
4936   char *inst;
4937
4938   D(emitcode (";     genIfxJump",""));
4939
4940   /* if true label then we jump if condition
4941      supplied is true */
4942   if (IC_TRUE (ic))
4943     {
4944       jlbl = IC_TRUE (ic);
4945       inst = ((strcmp (jval, "a") == 0 ? "jz" :
4946                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
4947     }
4948   else
4949     {
4950       /* false label is present */
4951       jlbl = IC_FALSE (ic);
4952       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
4953                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
4954     }
4955   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
4956     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
4957   else
4958     emitcode (inst, "%05d$", tlbl->key + 100);
4959   freeForBranchAsmop (result);
4960   freeForBranchAsmop (right);
4961   freeForBranchAsmop (left);
4962   emitcode ("ljmp", "%05d$", jlbl->key + 100);
4963   emitcode ("", "%05d$:", tlbl->key + 100);
4964
4965   /* mark the icode as generated */
4966   ic->generated = 1;
4967 }
4968
4969 /*-----------------------------------------------------------------*/
4970 /* genCmp :- greater or less than comparison                       */
4971 /*-----------------------------------------------------------------*/
4972 static void
4973 genCmp (operand * left, operand * right,
4974         operand * result, iCode * ifx, int sign, iCode *ic)
4975 {
4976   int size, offset = 0;
4977   unsigned long lit = 0L;
4978   bool rightInB;
4979
4980   D(emitcode (";     genCmp",""));
4981
4982   /* if left & right are bit variables */
4983   if (AOP_TYPE (left) == AOP_CRY &&
4984       AOP_TYPE (right) == AOP_CRY)
4985     {
4986       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
4987       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
4988     }
4989   else
4990     {
4991       /* subtract right from left if at the
4992          end the carry flag is set then we know that
4993          left is greater than right */
4994       size = max (AOP_SIZE (left), AOP_SIZE (right));
4995
4996       /* if unsigned char cmp with lit, do cjne left,#right,zz */
4997       if ((size == 1) && !sign &&
4998           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4999         {
5000           symbol *lbl = newiTempLabel (NULL);
5001           emitcode ("cjne", "%s,%s,%05d$",
5002                     aopGet (AOP (left), offset, FALSE, FALSE),
5003                     aopGet (AOP (right), offset, FALSE, FALSE),
5004                     lbl->key + 100);
5005           emitcode ("", "%05d$:", lbl->key + 100);
5006         }
5007       else
5008         {
5009           if (AOP_TYPE (right) == AOP_LIT)
5010             {
5011               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5012               /* optimize if(x < 0) or if(x >= 0) */
5013               if (lit == 0L)
5014                 {
5015                   if (!sign)
5016                     {
5017                       CLRC;
5018                     }
5019                   else
5020                     {
5021                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
5022                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5023                         {
5024                           genIfxJump (ifx, "acc.7", left, right, result);
5025                           freeAsmop (right, NULL, ic, TRUE);
5026                           freeAsmop (left, NULL, ic, TRUE);
5027
5028                           return;
5029                         }
5030                       else
5031                         emitcode ("rlc", "a");
5032                     }
5033                   goto release;
5034                 }
5035             }
5036           CLRC;
5037           while (size--)
5038             {
5039               bool pushedB = FALSE;
5040               rightInB = aopGetUsesAcc(AOP (right), offset);
5041               if (rightInB)
5042                 {
5043                   pushedB = pushB ();
5044                   emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5045                 }
5046               MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5047               if (sign && size == 0)
5048                 {
5049                   emitcode ("xrl", "a,#0x80");
5050                   if (AOP_TYPE (right) == AOP_LIT)
5051                     {
5052                       unsigned long lit = (unsigned long)
5053                       floatFromVal (AOP (right)->aopu.aop_lit);
5054                       emitcode ("subb", "a,#0x%02x",
5055                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5056                     }
5057                   else
5058                     {
5059                       if (!rightInB)
5060                         {
5061                           pushedB = pushB ();
5062                           rightInB++;
5063                           emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5064                         }
5065                       emitcode ("xrl", "b,#0x80");
5066                       emitcode ("subb", "a,b");
5067                     }
5068                 }
5069               else
5070                 {
5071                   if (rightInB)
5072                     emitcode ("subb", "a,b");
5073                   else
5074                     emitcode ("subb", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5075                 }
5076               if (rightInB)
5077                 popB (pushedB);
5078               offset++;
5079             }
5080         }
5081     }
5082
5083 release:
5084   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5085   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5086   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5087     {
5088       outBitC (result);
5089     }
5090   else
5091     {
5092       /* if the result is used in the next
5093          ifx conditional branch then generate
5094          code a little differently */
5095       if (ifx)
5096         genIfxJump (ifx, "c", NULL, NULL, result);
5097       else
5098         outBitC (result);
5099       /* leave the result in acc */
5100     }
5101 }
5102
5103 /*-----------------------------------------------------------------*/
5104 /* genCmpGt :- greater than comparison                             */
5105 /*-----------------------------------------------------------------*/
5106 static void
5107 genCmpGt (iCode * ic, iCode * ifx)
5108 {
5109   operand *left, *right, *result;
5110   sym_link *letype, *retype;
5111   int sign;
5112
5113   D(emitcode (";     genCmpGt",""));
5114
5115   left = IC_LEFT (ic);
5116   right = IC_RIGHT (ic);
5117   result = IC_RESULT (ic);
5118
5119   letype = getSpec (operandType (left));
5120   retype = getSpec (operandType (right));
5121   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5122            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5123   /* assign the amsops */
5124   aopOp (left, ic, FALSE);
5125   aopOp (right, ic, FALSE);
5126   aopOp (result, ic, TRUE);
5127
5128   genCmp (right, left, result, ifx, sign, ic);
5129
5130   freeAsmop (result, NULL, ic, TRUE);
5131 }
5132
5133 /*-----------------------------------------------------------------*/
5134 /* genCmpLt - less than comparisons                                */
5135 /*-----------------------------------------------------------------*/
5136 static void
5137 genCmpLt (iCode * ic, iCode * ifx)
5138 {
5139   operand *left, *right, *result;
5140   sym_link *letype, *retype;
5141   int sign;
5142
5143   D(emitcode (";     genCmpLt",""));
5144
5145   left = IC_LEFT (ic);
5146   right = IC_RIGHT (ic);
5147   result = IC_RESULT (ic);
5148
5149   letype = getSpec (operandType (left));
5150   retype = getSpec (operandType (right));
5151   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5152            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5153   /* assign the amsops */
5154   aopOp (left, ic, FALSE);
5155   aopOp (right, ic, FALSE);
5156   aopOp (result, ic, TRUE);
5157
5158   genCmp (left, right, result, ifx, sign,ic);
5159
5160   freeAsmop (result, NULL, ic, TRUE);
5161 }
5162
5163 /*-----------------------------------------------------------------*/
5164 /* gencjneshort - compare and jump if not equal                    */
5165 /*-----------------------------------------------------------------*/
5166 static void
5167 gencjneshort (operand * left, operand * right, symbol * lbl)
5168 {
5169   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5170   int offset = 0;
5171   unsigned long lit = 0L;
5172
5173   /* if the left side is a literal or
5174      if the right is in a pointer register and left
5175      is not */
5176   if ((AOP_TYPE (left) == AOP_LIT) ||
5177       (AOP_TYPE (left) == AOP_IMMD) ||
5178       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5179     {
5180       operand *t = right;
5181       right = left;
5182       left = t;
5183     }
5184
5185   if (AOP_TYPE (right) == AOP_LIT)
5186     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5187
5188   /* if the right side is a literal then anything goes */
5189   if (AOP_TYPE (right) == AOP_LIT &&
5190       AOP_TYPE (left) != AOP_DIR  &&
5191       AOP_TYPE (left) != AOP_IMMD)
5192     {
5193       while (size--)
5194         {
5195           emitcode ("cjne", "%s,%s,%05d$",
5196                     aopGet (AOP (left), offset, FALSE, FALSE),
5197                     aopGet (AOP (right), offset, FALSE, FALSE),
5198                     lbl->key + 100);
5199           offset++;
5200         }
5201     }
5202
5203   /* if the right side is in a register or in direct space or
5204      if the left is a pointer register & right is not */
5205   else if (AOP_TYPE (right) == AOP_REG ||
5206            AOP_TYPE (right) == AOP_DIR ||
5207            AOP_TYPE (right) == AOP_LIT ||
5208            AOP_TYPE (right) == AOP_IMMD ||
5209            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5210            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5211     {
5212       while (size--)
5213         {
5214           MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5215           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5216               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5217             emitcode ("jnz", "%05d$", lbl->key + 100);
5218           else
5219             emitcode ("cjne", "a,%s,%05d$",
5220                       aopGet (AOP (right), offset, FALSE, TRUE),
5221                       lbl->key + 100);
5222           offset++;
5223         }
5224     }
5225   else
5226     {
5227       /* right is a pointer reg need both a & b */
5228       while (size--)
5229         {
5230           char *l;
5231           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5232           wassertl(!_G.BInUse, "B was in use");
5233           l = aopGet (AOP (left), offset, FALSE, FALSE);
5234           if (strcmp (l, "b"))
5235             emitcode ("mov", "b,%s", l);
5236           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5237           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5238           offset++;
5239         }
5240     }
5241 }
5242
5243 /*-----------------------------------------------------------------*/
5244 /* gencjne - compare and jump if not equal                         */
5245 /*-----------------------------------------------------------------*/
5246 static void
5247 gencjne (operand * left, operand * right, symbol * lbl)
5248 {
5249   symbol *tlbl = newiTempLabel (NULL);
5250
5251   gencjneshort (left, right, lbl);
5252
5253   emitcode ("mov", "a,%s", one);
5254   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5255   emitcode ("", "%05d$:", lbl->key + 100);
5256   emitcode ("clr", "a");
5257   emitcode ("", "%05d$:", tlbl->key + 100);
5258 }
5259
5260 /*-----------------------------------------------------------------*/
5261 /* genCmpEq - generates code for equal to                          */
5262 /*-----------------------------------------------------------------*/
5263 static void
5264 genCmpEq (iCode * ic, iCode * ifx)
5265 {
5266   operand *left, *right, *result;
5267
5268   D(emitcode (";     genCmpEq",""));
5269
5270   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5271   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5272   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5273
5274   /* if literal, literal on the right or
5275      if the right is in a pointer register and left
5276      is not */
5277   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5278       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5279     {
5280       operand *t = IC_RIGHT (ic);
5281       IC_RIGHT (ic) = IC_LEFT (ic);
5282       IC_LEFT (ic) = t;
5283     }
5284
5285   if (ifx && !AOP_SIZE (result))
5286     {
5287       symbol *tlbl;
5288       /* if they are both bit variables */
5289       if (AOP_TYPE (left) == AOP_CRY &&
5290           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5291         {
5292           if (AOP_TYPE (right) == AOP_LIT)
5293             {
5294               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5295               if (lit == 0L)
5296                 {
5297                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5298                   emitcode ("cpl", "c");
5299                 }
5300               else if (lit == 1L)
5301                 {
5302                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5303                 }
5304               else
5305                 {
5306                   emitcode ("clr", "c");
5307                 }
5308               /* AOP_TYPE(right) == AOP_CRY */
5309             }
5310           else
5311             {
5312               symbol *lbl = newiTempLabel (NULL);
5313               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5314               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5315               emitcode ("cpl", "c");
5316               emitcode ("", "%05d$:", (lbl->key + 100));
5317             }
5318           /* if true label then we jump if condition
5319              supplied is true */
5320           tlbl = newiTempLabel (NULL);
5321           if (IC_TRUE (ifx))
5322             {
5323               emitcode ("jnc", "%05d$", tlbl->key + 100);
5324               freeForBranchAsmop (result);
5325               freeForBranchAsmop (right);
5326               freeForBranchAsmop (left);
5327               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5328             }
5329           else
5330             {
5331               emitcode ("jc", "%05d$", tlbl->key + 100);
5332               freeForBranchAsmop (result);
5333               freeForBranchAsmop (right);
5334               freeForBranchAsmop (left);
5335               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5336             }
5337           emitcode ("", "%05d$:", tlbl->key + 100);
5338         }
5339       else
5340         {
5341           tlbl = newiTempLabel (NULL);
5342           gencjneshort (left, right, tlbl);
5343           if (IC_TRUE (ifx))
5344             {
5345               freeForBranchAsmop (result);
5346               freeForBranchAsmop (right);
5347               freeForBranchAsmop (left);
5348               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5349               emitcode ("", "%05d$:", tlbl->key + 100);
5350             }
5351           else
5352             {
5353               symbol *lbl = newiTempLabel (NULL);
5354               emitcode ("sjmp", "%05d$", lbl->key + 100);
5355               emitcode ("", "%05d$:", tlbl->key + 100);
5356               freeForBranchAsmop (result);
5357               freeForBranchAsmop (right);
5358               freeForBranchAsmop (left);
5359               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5360               emitcode ("", "%05d$:", lbl->key + 100);
5361             }
5362         }
5363       /* mark the icode as generated */
5364       ifx->generated = 1;
5365       goto release;
5366     }
5367
5368   /* if they are both bit variables */
5369   if (AOP_TYPE (left) == AOP_CRY &&
5370       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5371     {
5372       if (AOP_TYPE (right) == AOP_LIT)
5373         {
5374           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5375           if (lit == 0L)
5376             {
5377               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5378               emitcode ("cpl", "c");
5379             }
5380           else if (lit == 1L)
5381             {
5382               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5383             }
5384           else
5385             {
5386               emitcode ("clr", "c");
5387             }
5388           /* AOP_TYPE(right) == AOP_CRY */
5389         }
5390       else
5391         {
5392           symbol *lbl = newiTempLabel (NULL);
5393           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5394           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5395           emitcode ("cpl", "c");
5396           emitcode ("", "%05d$:", (lbl->key + 100));
5397         }
5398       /* c = 1 if egal */
5399       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5400         {
5401           outBitC (result);
5402           goto release;
5403         }
5404       if (ifx)
5405         {
5406           genIfxJump (ifx, "c", left, right, result);
5407           goto release;
5408         }
5409       /* if the result is used in an arithmetic operation
5410          then put the result in place */
5411       outBitC (result);
5412     }
5413   else
5414     {
5415       gencjne (left, right, newiTempLabel (NULL));
5416       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5417         {
5418           aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
5419           goto release;
5420         }
5421       if (ifx)
5422         {
5423           genIfxJump (ifx, "a", left, right, result);
5424           goto release;
5425         }
5426       /* if the result is used in an arithmetic operation
5427          then put the result in place */
5428       if (AOP_TYPE (result) != AOP_CRY)
5429         outAcc (result);
5430       /* leave the result in acc */
5431     }
5432
5433 release:
5434   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5435   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5436   freeAsmop (result, NULL, ic, TRUE);
5437 }
5438
5439 /*-----------------------------------------------------------------*/
5440 /* ifxForOp - returns the icode containing the ifx for operand     */
5441 /*-----------------------------------------------------------------*/
5442 static iCode *
5443 ifxForOp (operand * op, iCode * ic)
5444 {
5445   /* if true symbol then needs to be assigned */
5446   if (IS_TRUE_SYMOP (op))
5447     return NULL;
5448
5449   /* if this has register type condition and
5450      the next instruction is ifx with the same operand
5451      and live to of the operand is upto the ifx only then */
5452   if (ic->next &&
5453       ic->next->op == IFX &&
5454       IC_COND (ic->next)->key == op->key &&
5455       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5456     return ic->next;
5457
5458   return NULL;
5459 }
5460
5461 /*-----------------------------------------------------------------*/
5462 /* hasInc - operand is incremented before any other use            */
5463 /*-----------------------------------------------------------------*/
5464 static iCode *
5465 hasInc (operand *op, iCode *ic,int osize)
5466 {
5467   sym_link *type = operandType(op);
5468   sym_link *retype = getSpec (type);
5469   iCode *lic = ic->next;
5470   int isize ;
5471
5472   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5473   if (!IS_SYMOP(op)) return NULL;
5474
5475   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5476   if (IS_AGGREGATE(type->next)) return NULL;
5477   if (osize != (isize = getSize(type->next))) return NULL;
5478
5479   while (lic) {
5480     /* if operand of the form op = op + <sizeof *op> */
5481     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5482         isOperandEqual(IC_RESULT(lic),op) &&
5483         isOperandLiteral(IC_RIGHT(lic)) &&
5484         operandLitValue(IC_RIGHT(lic)) == isize) {
5485       return lic;
5486     }
5487     /* if the operand used or deffed */
5488     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5489       return NULL;
5490     }
5491     /* if GOTO or IFX */
5492     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5493     lic = lic->next;
5494   }
5495   return NULL;
5496 }
5497
5498 /*-----------------------------------------------------------------*/
5499 /* genAndOp - for && operation                                     */
5500 /*-----------------------------------------------------------------*/
5501 static void
5502 genAndOp (iCode * ic)
5503 {
5504   operand *left, *right, *result;
5505   symbol *tlbl;
5506
5507   D(emitcode (";     genAndOp",""));
5508
5509   /* note here that && operations that are in an
5510      if statement are taken away by backPatchLabels
5511      only those used in arthmetic operations remain */
5512   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5513   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5514   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5515
5516   /* if both are bit variables */
5517   if (AOP_TYPE (left) == AOP_CRY &&
5518       AOP_TYPE (right) == AOP_CRY)
5519     {
5520       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5521       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5522       outBitC (result);
5523     }
5524   else
5525     {
5526       tlbl = newiTempLabel (NULL);
5527       toBoolean (left);
5528       emitcode ("jz", "%05d$", tlbl->key + 100);
5529       toBoolean (right);
5530       emitcode ("", "%05d$:", tlbl->key + 100);
5531       outBitAcc (result);
5532     }
5533
5534   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5535   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5536   freeAsmop (result, NULL, ic, TRUE);
5537 }
5538
5539
5540 /*-----------------------------------------------------------------*/
5541 /* genOrOp - for || operation                                      */
5542 /*-----------------------------------------------------------------*/
5543 static void
5544 genOrOp (iCode * ic)
5545 {
5546   operand *left, *right, *result;
5547   symbol *tlbl;
5548
5549   D(emitcode (";     genOrOp",""));
5550
5551   /* note here that || operations that are in an
5552      if statement are taken away by backPatchLabels
5553      only those used in arthmetic operations remain */
5554   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5555   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5556   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5557
5558   /* if both are bit variables */
5559   if (AOP_TYPE (left) == AOP_CRY &&
5560       AOP_TYPE (right) == AOP_CRY)
5561     {
5562       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5563       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5564       outBitC (result);
5565     }
5566   else
5567     {
5568       tlbl = newiTempLabel (NULL);
5569       toBoolean (left);
5570       emitcode ("jnz", "%05d$", tlbl->key + 100);
5571       toBoolean (right);
5572       emitcode ("", "%05d$:", tlbl->key + 100);
5573       outBitAcc (result);
5574     }
5575
5576   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5577   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5578   freeAsmop (result, NULL, ic, TRUE);
5579 }
5580
5581 /*-----------------------------------------------------------------*/
5582 /* isLiteralBit - test if lit == 2^n                               */
5583 /*-----------------------------------------------------------------*/
5584 static int
5585 isLiteralBit (unsigned long lit)
5586 {
5587   unsigned long pw[32] =
5588   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5589    0x100L, 0x200L, 0x400L, 0x800L,
5590    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5591    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5592    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5593    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5594    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5595   int idx;
5596
5597   for (idx = 0; idx < 32; idx++)
5598     if (lit == pw[idx])
5599       return idx + 1;
5600   return 0;
5601 }
5602
5603 /*-----------------------------------------------------------------*/
5604 /* continueIfTrue -                                                */
5605 /*-----------------------------------------------------------------*/
5606 static void
5607 continueIfTrue (iCode * ic)
5608 {
5609   if (IC_TRUE (ic))
5610     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5611   ic->generated = 1;
5612 }
5613
5614 /*-----------------------------------------------------------------*/
5615 /* jmpIfTrue -                                                     */
5616 /*-----------------------------------------------------------------*/
5617 static void
5618 jumpIfTrue (iCode * ic)
5619 {
5620   if (!IC_TRUE (ic))
5621     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5622   ic->generated = 1;
5623 }
5624
5625 /*-----------------------------------------------------------------*/
5626 /* jmpTrueOrFalse -                                                */
5627 /*-----------------------------------------------------------------*/
5628 static void
5629 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5630 {
5631   // ugly but optimized by peephole
5632   if (IC_TRUE (ic))
5633     {
5634       symbol *nlbl = newiTempLabel (NULL);
5635       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5636       emitcode ("", "%05d$:", tlbl->key + 100);
5637       freeForBranchAsmop (result);
5638       freeForBranchAsmop (right);
5639       freeForBranchAsmop (left);
5640       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5641       emitcode ("", "%05d$:", nlbl->key + 100);
5642     }
5643   else
5644     {
5645       freeForBranchAsmop (result);
5646       freeForBranchAsmop (right);
5647       freeForBranchAsmop (left);
5648       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5649       emitcode ("", "%05d$:", tlbl->key + 100);
5650     }
5651   ic->generated = 1;
5652 }
5653
5654 /*-----------------------------------------------------------------*/
5655 /* genAnd  - code for and                                          */
5656 /*-----------------------------------------------------------------*/
5657 static void
5658 genAnd (iCode * ic, iCode * ifx)
5659 {
5660   operand *left, *right, *result;
5661   int size, offset = 0;
5662   unsigned long lit = 0L;
5663   int bytelit = 0;
5664   char buffer[10];
5665
5666   D(emitcode (";     genAnd",""));
5667
5668   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5669   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5670   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5671
5672 #ifdef DEBUG_TYPE
5673   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5674             AOP_TYPE (result),
5675             AOP_TYPE (left), AOP_TYPE (right));
5676   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5677             AOP_SIZE (result),
5678             AOP_SIZE (left), AOP_SIZE (right));
5679 #endif
5680
5681   /* if left is a literal & right is not then exchange them */
5682   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5683       AOP_NEEDSACC (left))
5684     {
5685       operand *tmp = right;
5686       right = left;
5687       left = tmp;
5688     }
5689
5690   /* if result = right then exchange left and right */
5691   if (sameRegs (AOP (result), AOP (right)))
5692     {
5693       operand *tmp = right;
5694       right = left;
5695       left = tmp;
5696     }
5697
5698   /* if right is bit then exchange them */
5699   if (AOP_TYPE (right) == AOP_CRY &&
5700       AOP_TYPE (left) != AOP_CRY)
5701     {
5702       operand *tmp = right;
5703       right = left;
5704       left = tmp;
5705     }
5706   if (AOP_TYPE (right) == AOP_LIT)
5707     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5708
5709   size = AOP_SIZE (result);
5710
5711   // if(bit & yy)
5712   // result = bit & yy;
5713   if (AOP_TYPE (left) == AOP_CRY)
5714     {
5715       // c = bit & literal;
5716       if (AOP_TYPE (right) == AOP_LIT)
5717         {
5718           if (lit & 1)
5719             {
5720               if (size && sameRegs (AOP (result), AOP (left)))
5721                 // no change
5722                 goto release;
5723               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5724             }
5725           else
5726             {
5727               // bit(result) = 0;
5728               if (size && (AOP_TYPE (result) == AOP_CRY))
5729                 {
5730                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5731                   goto release;
5732                 }
5733               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5734                 {
5735                   jumpIfTrue (ifx);
5736                   goto release;
5737                 }
5738               emitcode ("clr", "c");
5739             }
5740         }
5741       else
5742         {
5743           if (AOP_TYPE (right) == AOP_CRY)
5744             {
5745               // c = bit & bit;
5746               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5747               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5748             }
5749           else
5750             {
5751               // c = bit & val;
5752               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
5753               // c = lsb
5754               emitcode ("rrc", "a");
5755               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5756             }
5757         }
5758       // bit = c
5759       // val = c
5760       if (size)
5761         outBitC (result);
5762       // if(bit & ...)
5763       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5764         genIfxJump (ifx, "c", left, right, result);
5765       goto release;
5766     }
5767
5768   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5769   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5770   if ((AOP_TYPE (right) == AOP_LIT) &&
5771       (AOP_TYPE (result) == AOP_CRY) &&
5772       (AOP_TYPE (left) != AOP_CRY))
5773     {
5774       int posbit = isLiteralBit (lit);
5775       /* left &  2^n */
5776       if (posbit)
5777         {
5778           posbit--;
5779           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE));
5780           // bit = left & 2^n
5781           if (size)
5782             emitcode ("mov", "c,acc.%d", posbit & 0x07);
5783           // if(left &  2^n)
5784           else
5785             {
5786               if (ifx)
5787                 {
5788                   SNPRINTF (buffer, sizeof(buffer),
5789                             "acc.%d", posbit & 0x07);
5790                   genIfxJump (ifx, buffer, left, right, result);
5791                 }
5792               else
5793                 {// what is this case? just found it in ds390/gen.c
5794                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
5795                 }
5796               goto release;
5797             }
5798         }
5799       else
5800         {
5801           symbol *tlbl = newiTempLabel (NULL);
5802           int sizel = AOP_SIZE (left);
5803           if (size)
5804             emitcode ("setb", "c");
5805           while (sizel--)
5806             {
5807               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5808                 {
5809                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5810                   // byte ==  2^n ?
5811                   if ((posbit = isLiteralBit (bytelit)) != 0)
5812                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5813                   else
5814                     {
5815                       if (bytelit != 0x0FFL)
5816                         emitcode ("anl", "a,%s",
5817                                   aopGet (AOP (right), offset, FALSE, TRUE));
5818                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5819                     }
5820                 }
5821               offset++;
5822             }
5823           // bit = left & literal
5824           if (size)
5825             {
5826               emitcode ("clr", "c");
5827               emitcode ("", "%05d$:", tlbl->key + 100);
5828             }
5829           // if(left & literal)
5830           else
5831             {
5832               if (ifx)
5833                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5834               else
5835                 emitcode ("", "%05d$:", tlbl->key + 100);
5836               goto release;
5837             }
5838         }
5839       outBitC (result);
5840       goto release;
5841     }
5842
5843   /* if left is same as result */
5844   if (sameRegs (AOP (result), AOP (left)))
5845     {
5846       for (; size--; offset++)
5847         {
5848           if (AOP_TYPE (right) == AOP_LIT)
5849             {
5850               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5851               if (bytelit == 0x0FF)
5852                 {
5853                   /* dummy read of volatile operand */
5854                   if (isOperandVolatile (left, FALSE))
5855                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5856                   else
5857                     continue;
5858                 }
5859               else if (bytelit == 0)
5860                 {
5861                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5862                 }
5863               else if (IS_AOP_PREG (result))
5864                 {
5865                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5866                   emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5867                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5868                 }
5869               else
5870                 emitcode ("anl", "%s,%s",
5871                           aopGet (AOP (left), offset, FALSE, TRUE),
5872                           aopGet (AOP (right), offset, FALSE, FALSE));
5873             }
5874           else
5875             {
5876               if (AOP_TYPE (left) == AOP_ACC)
5877                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5878               else
5879                 {
5880                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5881                   if (IS_AOP_PREG (result))
5882                     {
5883                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5884                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5885                     }
5886                   else
5887                     emitcode ("anl", "%s,a",
5888                               aopGet (AOP (left), offset, FALSE, TRUE));
5889                 }
5890             }
5891         }
5892     }
5893   else
5894     {
5895       // left & result in different registers
5896       if (AOP_TYPE (result) == AOP_CRY)
5897         {
5898           // result = bit
5899           // if(size), result in bit
5900           // if(!size && ifx), conditional oper: if(left & right)
5901           symbol *tlbl = newiTempLabel (NULL);
5902           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5903           if (size)
5904             emitcode ("setb", "c");
5905           while (sizer--)
5906             {
5907               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5908                 emitcode ("anl", "a,%s",
5909                           aopGet (AOP (right), offset, FALSE, FALSE));
5910               } else {
5911                 if (AOP_TYPE(left)==AOP_ACC) {
5912                   bool pushedB = pushB ();
5913                   emitcode("mov", "b,a");
5914                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5915                   emitcode("anl", "a,b");
5916                   popB (pushedB);
5917                 }else {
5918                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5919                   emitcode ("anl", "a,%s",
5920                             aopGet (AOP (left), offset, FALSE, FALSE));
5921                 }
5922               }
5923               emitcode ("jnz", "%05d$", tlbl->key + 100);
5924               offset++;
5925             }
5926           if (size)
5927             {
5928               CLRC;
5929               emitcode ("", "%05d$:", tlbl->key + 100);
5930               outBitC (result);
5931             }
5932           else if (ifx)
5933             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5934           else
5935             emitcode ("", "%05d$:", tlbl->key + 100);
5936         }
5937       else
5938         {
5939           for (; (size--); offset++)
5940             {
5941               // normal case
5942               // result = left & right
5943               if (AOP_TYPE (right) == AOP_LIT)
5944                 {
5945                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5946                   if (bytelit == 0x0FF)
5947                     {
5948                       aopPut (AOP (result),
5949                               aopGet (AOP (left), offset, FALSE, FALSE),
5950                               offset,
5951                               isOperandVolatile (result, FALSE));
5952                       continue;
5953                     }
5954                   else if (bytelit == 0)
5955                     {
5956                       /* dummy read of volatile operand */
5957                       if (isOperandVolatile (left, FALSE))
5958                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5959                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5960                       continue;
5961                     }
5962                 }
5963               // faster than result <- left, anl result,right
5964               // and better if result is SFR
5965               if (AOP_TYPE (left) == AOP_ACC)
5966                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5967               else
5968                 {
5969                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5970                   emitcode ("anl", "a,%s",
5971                             aopGet (AOP (left), offset, FALSE, FALSE));
5972                 }
5973               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5974             }
5975         }
5976     }
5977
5978 release:
5979   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5980   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5981   freeAsmop (result, NULL, ic, TRUE);
5982 }
5983
5984 /*-----------------------------------------------------------------*/
5985 /* genOr  - code for or                                            */
5986 /*-----------------------------------------------------------------*/
5987 static void
5988 genOr (iCode * ic, iCode * ifx)
5989 {
5990   operand *left, *right, *result;
5991   int size, offset = 0;
5992   unsigned long lit = 0L;
5993   int bytelit = 0;
5994
5995   D(emitcode (";     genOr",""));
5996
5997   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5998   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5999   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6000
6001 #ifdef DEBUG_TYPE
6002   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6003             AOP_TYPE (result),
6004             AOP_TYPE (left), AOP_TYPE (right));
6005   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6006             AOP_SIZE (result),
6007             AOP_SIZE (left), AOP_SIZE (right));
6008 #endif
6009
6010   /* if left is a literal & right is not then exchange them */
6011   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6012       AOP_NEEDSACC (left))
6013     {
6014       operand *tmp = right;
6015       right = left;
6016       left = tmp;
6017     }
6018
6019   /* if result = right then exchange them */
6020   if (sameRegs (AOP (result), AOP (right)))
6021     {
6022       operand *tmp = right;
6023       right = left;
6024       left = tmp;
6025     }
6026
6027   /* if right is bit then exchange them */
6028   if (AOP_TYPE (right) == AOP_CRY &&
6029       AOP_TYPE (left) != AOP_CRY)
6030     {
6031       operand *tmp = right;
6032       right = left;
6033       left = tmp;
6034     }
6035   if (AOP_TYPE (right) == AOP_LIT)
6036     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6037
6038   size = AOP_SIZE (result);
6039
6040   // if(bit | yy)
6041   // xx = bit | yy;
6042   if (AOP_TYPE (left) == AOP_CRY)
6043     {
6044       if (AOP_TYPE (right) == AOP_LIT)
6045         {
6046           // c = bit | literal;
6047           if (lit)
6048             {
6049               // lit != 0 => result = 1
6050               if (AOP_TYPE (result) == AOP_CRY)
6051                 {
6052                   if (size)
6053                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6054                   else if (ifx)
6055                     continueIfTrue (ifx);
6056                   goto release;
6057                 }
6058               emitcode ("setb", "c");
6059             }
6060           else
6061             {
6062               // lit == 0 => result = left
6063               if (size && sameRegs (AOP (result), AOP (left)))
6064                 goto release;
6065               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6066             }
6067         }
6068       else
6069         {
6070           if (AOP_TYPE (right) == AOP_CRY)
6071             {
6072               // c = bit | bit;
6073               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6074               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6075             }
6076           else
6077             {
6078               // c = bit | val;
6079               symbol *tlbl = newiTempLabel (NULL);
6080               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6081                 emitcode ("setb", "c");
6082               emitcode ("jb", "%s,%05d$",
6083                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6084               toBoolean (right);
6085               emitcode ("jnz", "%05d$", tlbl->key + 100);
6086               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6087                 {
6088                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6089                   goto release;
6090                 }
6091               else
6092                 {
6093                   CLRC;
6094                   emitcode ("", "%05d$:", tlbl->key + 100);
6095                 }
6096             }
6097         }
6098       // bit = c
6099       // val = c
6100       if (size)
6101         outBitC (result);
6102       // if(bit | ...)
6103       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6104         genIfxJump (ifx, "c", left, right, result);
6105       goto release;
6106     }
6107
6108   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6109   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6110   if ((AOP_TYPE (right) == AOP_LIT) &&
6111       (AOP_TYPE (result) == AOP_CRY) &&
6112       (AOP_TYPE (left) != AOP_CRY))
6113     {
6114       if (lit)
6115         {
6116           // result = 1
6117           if (size)
6118             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6119           else
6120             continueIfTrue (ifx);
6121           goto release;
6122         }
6123       else
6124         {
6125           // lit = 0, result = boolean(left)
6126           if (size)
6127             emitcode ("setb", "c");
6128           toBoolean (right);
6129           if (size)
6130             {
6131               symbol *tlbl = newiTempLabel (NULL);
6132               emitcode ("jnz", "%05d$", tlbl->key + 100);
6133               CLRC;
6134               emitcode ("", "%05d$:", tlbl->key + 100);
6135             }
6136           else
6137             {
6138               genIfxJump (ifx, "a", left, right, result);
6139               goto release;
6140             }
6141         }
6142       outBitC (result);
6143       goto release;
6144     }
6145
6146   /* if left is same as result */
6147   if (sameRegs (AOP (result), AOP (left)))
6148     {
6149       for (; size--; offset++)
6150         {
6151           if (AOP_TYPE (right) == AOP_LIT)
6152             {
6153               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6154               if (bytelit == 0)
6155                 {
6156                   /* dummy read of volatile operand */
6157                   if (isOperandVolatile (left, FALSE))
6158                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6159                   else
6160                     continue;
6161                 }
6162               else if (bytelit == 0x0FF)
6163                 {
6164                   aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6165                 }
6166               else if (IS_AOP_PREG (left))
6167                 {
6168                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6169                   emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6170                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6171                 }
6172               else
6173                 {
6174                   emitcode ("orl", "%s,%s",
6175                             aopGet (AOP (left), offset, FALSE, TRUE),
6176                             aopGet (AOP (right), offset, FALSE, FALSE));
6177                 }
6178             }
6179           else
6180             {
6181               if (AOP_TYPE (left) == AOP_ACC)
6182                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6183               else
6184                 {
6185                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6186                   if (IS_AOP_PREG (left))
6187                     {
6188                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6189                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6190                     }
6191                   else
6192                     {
6193                       emitcode ("orl", "%s,a",
6194                                 aopGet (AOP (left), offset, FALSE, TRUE));
6195                     }
6196                 }
6197             }
6198         }
6199     }
6200   else
6201     {
6202       // left & result in different registers
6203       if (AOP_TYPE (result) == AOP_CRY)
6204         {
6205           // result = bit
6206           // if(size), result in bit
6207           // if(!size && ifx), conditional oper: if(left | right)
6208           symbol *tlbl = newiTempLabel (NULL);
6209           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6210           if (size)
6211             emitcode ("setb", "c");
6212           while (sizer--)
6213             {
6214               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6215                 emitcode ("orl", "a,%s",
6216                           aopGet (AOP (right), offset, FALSE, FALSE));
6217               } else {
6218                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6219                 emitcode ("orl", "a,%s",
6220                           aopGet (AOP (left), offset, FALSE, FALSE));
6221               }
6222               emitcode ("jnz", "%05d$", tlbl->key + 100);
6223               offset++;
6224             }
6225           if (size)
6226             {
6227               CLRC;
6228               emitcode ("", "%05d$:", tlbl->key + 100);
6229               outBitC (result);
6230             }
6231           else if (ifx)
6232             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6233           else
6234             emitcode ("", "%05d$:", tlbl->key + 100);
6235         }
6236       else
6237         {
6238           for (; (size--); offset++)
6239             {
6240               // normal case
6241               // result = left | right
6242               if (AOP_TYPE (right) == AOP_LIT)
6243                 {
6244                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6245                   if (bytelit == 0)
6246                     {
6247                       aopPut (AOP (result),
6248                               aopGet (AOP (left), offset, FALSE, FALSE),
6249                               offset,
6250                               isOperandVolatile (result, FALSE));
6251                       continue;
6252                     }
6253                   else if (bytelit == 0x0FF)
6254                     {
6255                       /* dummy read of volatile operand */
6256                       if (isOperandVolatile (left, FALSE))
6257                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6258                       aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6259                       continue;
6260                     }
6261                 }
6262               // faster than result <- left, anl result,right
6263               // and better if result is SFR
6264               if (AOP_TYPE (left) == AOP_ACC)
6265                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6266               else
6267                 {
6268                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6269                   emitcode ("orl", "a,%s",
6270                             aopGet (AOP (left), offset, FALSE, FALSE));
6271                 }
6272               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6273             }
6274         }
6275     }
6276
6277 release:
6278   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6279   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6280   freeAsmop (result, NULL, ic, TRUE);
6281 }
6282
6283 /*-----------------------------------------------------------------*/
6284 /* genXor - code for xclusive or                                   */
6285 /*-----------------------------------------------------------------*/
6286 static void
6287 genXor (iCode * ic, iCode * ifx)
6288 {
6289   operand *left, *right, *result;
6290   int size, offset = 0;
6291   unsigned long lit = 0L;
6292   int bytelit = 0;
6293
6294   D(emitcode (";     genXor",""));
6295
6296   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6297   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6298   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6299
6300 #ifdef DEBUG_TYPE
6301   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6302             AOP_TYPE (result),
6303             AOP_TYPE (left), AOP_TYPE (right));
6304   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6305             AOP_SIZE (result),
6306             AOP_SIZE (left), AOP_SIZE (right));
6307 #endif
6308
6309   /* if left is a literal & right is not ||
6310      if left needs acc & right does not */
6311   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6312       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6313     {
6314       operand *tmp = right;
6315       right = left;
6316       left = tmp;
6317     }
6318
6319   /* if result = right then exchange them */
6320   if (sameRegs (AOP (result), AOP (right)))
6321     {
6322       operand *tmp = right;
6323       right = left;
6324       left = tmp;
6325     }
6326
6327   /* if right is bit then exchange them */
6328   if (AOP_TYPE (right) == AOP_CRY &&
6329       AOP_TYPE (left) != AOP_CRY)
6330     {
6331       operand *tmp = right;
6332       right = left;
6333       left = tmp;
6334     }
6335   if (AOP_TYPE (right) == AOP_LIT)
6336     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6337
6338   size = AOP_SIZE (result);
6339
6340   // if(bit ^ yy)
6341   // xx = bit ^ yy;
6342   if (AOP_TYPE (left) == AOP_CRY)
6343     {
6344       if (AOP_TYPE (right) == AOP_LIT)
6345         {
6346           // c = bit & literal;
6347           if (lit >> 1)
6348             {
6349               // lit>>1  != 0 => result = 1
6350               if (AOP_TYPE (result) == AOP_CRY)
6351                 {
6352                   if (size)
6353                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6354                   else if (ifx)
6355                     continueIfTrue (ifx);
6356                   goto release;
6357                 }
6358               emitcode ("setb", "c");
6359             }
6360           else
6361             {
6362               // lit == (0 or 1)
6363               if (lit == 0)
6364                 {
6365                   // lit == 0, result = left
6366                   if (size && sameRegs (AOP (result), AOP (left)))
6367                     goto release;
6368                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6369                 }
6370               else
6371                 {
6372                   // lit == 1, result = not(left)
6373                   if (size && sameRegs (AOP (result), AOP (left)))
6374                     {
6375                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6376                       goto release;
6377                     }
6378                   else
6379                     {
6380                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6381                       emitcode ("cpl", "c");
6382                     }
6383                 }
6384             }
6385
6386         }
6387       else
6388         {
6389           // right != literal
6390           symbol *tlbl = newiTempLabel (NULL);
6391           if (AOP_TYPE (right) == AOP_CRY)
6392             {
6393               // c = bit ^ bit;
6394               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6395             }
6396           else
6397             {
6398               int sizer = AOP_SIZE (right);
6399               // c = bit ^ val
6400               // if val>>1 != 0, result = 1
6401               emitcode ("setb", "c");
6402               while (sizer)
6403                 {
6404                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
6405                   if (sizer == 1)
6406                     // test the msb of the lsb
6407                     emitcode ("anl", "a,#0xfe");
6408                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6409                   sizer--;
6410                 }
6411               // val = (0,1)
6412               emitcode ("rrc", "a");
6413             }
6414           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6415           emitcode ("cpl", "c");
6416           emitcode ("", "%05d$:", (tlbl->key + 100));
6417         }
6418       // bit = c
6419       // val = c
6420       if (size)
6421         outBitC (result);
6422       // if(bit | ...)
6423       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6424         genIfxJump (ifx, "c", left, right, result);
6425       goto release;
6426     }
6427
6428   /* if left is same as result */
6429   if (sameRegs (AOP (result), AOP (left)))
6430     {
6431       for (; size--; offset++)
6432         {
6433           if (AOP_TYPE (right) == AOP_LIT)
6434             {
6435               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6436               if (bytelit == 0)
6437                 {
6438                   /* dummy read of volatile operand */
6439                   if (isOperandVolatile (left, FALSE))
6440                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6441                   else
6442                     continue;
6443                 }
6444               else if (IS_AOP_PREG (left))
6445                 {
6446                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6447                   emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6448                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6449                 }
6450               else
6451                 {
6452                   emitcode ("xrl", "%s,%s",
6453                             aopGet (AOP (left), offset, FALSE, TRUE),
6454                             aopGet (AOP (right), offset, FALSE, FALSE));
6455                 }
6456             }
6457           else
6458             {
6459               if (AOP_TYPE (left) == AOP_ACC)
6460                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6461               else
6462                 {
6463                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6464                   if (IS_AOP_PREG (left))
6465                     {
6466                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6467                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6468                     }
6469                   else
6470                     emitcode ("xrl", "%s,a",
6471                               aopGet (AOP (left), offset, FALSE, TRUE));
6472                 }
6473             }
6474         }
6475     }
6476   else
6477     {
6478       // left & result in different registers
6479       if (AOP_TYPE (result) == AOP_CRY)
6480         {
6481           // result = bit
6482           // if(size), result in bit
6483           // if(!size && ifx), conditional oper: if(left ^ right)
6484           symbol *tlbl = newiTempLabel (NULL);
6485           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6486           if (size)
6487             emitcode ("setb", "c");
6488           while (sizer--)
6489             {
6490               if ((AOP_TYPE (right) == AOP_LIT) &&
6491                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6492                 {
6493                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6494                 }
6495               else
6496                 {
6497                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6498                     emitcode ("xrl", "a,%s",
6499                               aopGet (AOP (right), offset, FALSE, FALSE));
6500                   } else {
6501                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6502                     emitcode ("xrl", "a,%s",
6503                               aopGet (AOP (left), offset, FALSE, FALSE));
6504                   }
6505                 }
6506               emitcode ("jnz", "%05d$", tlbl->key + 100);
6507               offset++;
6508             }
6509           if (size)
6510             {
6511               CLRC;
6512               emitcode ("", "%05d$:", tlbl->key + 100);
6513               outBitC (result);
6514             }
6515           else if (ifx)
6516             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6517         }
6518       else
6519         {
6520           for (; (size--); offset++)
6521             {
6522               // normal case
6523               // result = left & right
6524               if (AOP_TYPE (right) == AOP_LIT)
6525                 {
6526                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6527                   if (bytelit == 0)
6528                     {
6529                       aopPut (AOP (result),
6530                               aopGet (AOP (left), offset, FALSE, FALSE),
6531                               offset,
6532                               isOperandVolatile (result, FALSE));
6533                       continue;
6534                     }
6535                 }
6536               // faster than result <- left, anl result,right
6537               // and better if result is SFR
6538               if (AOP_TYPE (left) == AOP_ACC)
6539                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6540               else
6541                 {
6542                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6543                   emitcode ("xrl", "a,%s",
6544                             aopGet (AOP (left), offset, FALSE, TRUE));
6545                 }
6546               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6547             }
6548         }
6549     }
6550
6551 release:
6552   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6553   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6554   freeAsmop (result, NULL, ic, TRUE);
6555 }
6556
6557 /*-----------------------------------------------------------------*/
6558 /* genInline - write the inline code out                           */
6559 /*-----------------------------------------------------------------*/
6560 static void
6561 genInline (iCode * ic)
6562 {
6563   char *buffer, *bp, *bp1;
6564
6565   D(emitcode (";     genInline",""));
6566
6567   _G.inLine += (!options.asmpeep);
6568
6569   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6570   strcpy (buffer, IC_INLINE (ic));
6571
6572   /* emit each line as a code */
6573   while (*bp)
6574     {
6575       if (*bp == '\n')
6576         {
6577           *bp++ = '\0';
6578           emitcode (bp1, "");
6579           bp1 = bp;
6580         }
6581       else
6582         {
6583           /* Add \n for labels, not dirs such as c:\mydir */
6584           if ( (*bp == ':') && (isspace(bp[1])) )
6585             {
6586               bp++;
6587               *bp = '\0';
6588               bp++;
6589               emitcode (bp1, "");
6590               bp1 = bp;
6591             }
6592           else
6593             bp++;
6594         }
6595     }
6596   if (bp1 != bp)
6597     emitcode (bp1, "");
6598   /*     emitcode("",buffer); */
6599   _G.inLine -= (!options.asmpeep);
6600 }
6601
6602 /*-----------------------------------------------------------------*/
6603 /* genRRC - rotate right with carry                                */
6604 /*-----------------------------------------------------------------*/
6605 static void
6606 genRRC (iCode * ic)
6607 {
6608   operand *left, *result;
6609   int size, offset = 0;
6610   char *l;
6611
6612   D(emitcode (";     genRRC",""));
6613
6614   /* rotate right with carry */
6615   left = IC_LEFT (ic);
6616   result = IC_RESULT (ic);
6617   aopOp (left, ic, FALSE);
6618   aopOp (result, ic, FALSE);
6619
6620   /* move it to the result */
6621   size = AOP_SIZE (result);
6622   offset = size - 1;
6623   if (size == 1) { /* special case for 1 byte */
6624       l = aopGet (AOP (left), offset, FALSE, FALSE);
6625       MOVA (l);
6626       emitcode ("rr", "a");
6627       goto release;
6628   }
6629   /* no need to clear carry, bit7 will be written later */
6630   while (size--)
6631     {
6632       l = aopGet (AOP (left), offset, FALSE, FALSE);
6633       MOVA (l);
6634       emitcode ("rrc", "a");
6635       if (AOP_SIZE (result) > 1)
6636         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6637     }
6638   /* now we need to put the carry into the
6639      highest order byte of the result */
6640   if (AOP_SIZE (result) > 1)
6641     {
6642       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6643       MOVA (l);
6644     }
6645   emitcode ("mov", "acc.7,c");
6646  release:
6647   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6648   freeAsmop (left, NULL, ic, TRUE);
6649   freeAsmop (result, NULL, ic, TRUE);
6650 }
6651
6652 /*-----------------------------------------------------------------*/
6653 /* genRLC - generate code for rotate left with carry               */
6654 /*-----------------------------------------------------------------*/
6655 static void
6656 genRLC (iCode * ic)
6657 {
6658   operand *left, *result;
6659   int size, offset = 0;
6660   char *l;
6661
6662   D(emitcode (";     genRLC",""));
6663
6664   /* rotate right with carry */
6665   left = IC_LEFT (ic);
6666   result = IC_RESULT (ic);
6667   aopOp (left, ic, FALSE);
6668   aopOp (result, ic, FALSE);
6669
6670   /* move it to the result */
6671   size = AOP_SIZE (result);
6672   offset = 0;
6673   if (size--)
6674     {
6675       l = aopGet (AOP (left), offset, FALSE, FALSE);
6676       MOVA (l);
6677       if (size == 0) { /* special case for 1 byte */
6678               emitcode("rl","a");
6679               goto release;
6680       }
6681       emitcode("rlc","a"); /* bit0 will be written later */
6682       if (AOP_SIZE (result) > 1)
6683         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6684       while (size--)
6685         {
6686           l = aopGet (AOP (left), offset, FALSE, FALSE);
6687           MOVA (l);
6688           emitcode ("rlc", "a");
6689           if (AOP_SIZE (result) > 1)
6690             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6691         }
6692     }
6693   /* now we need to put the carry into the
6694      highest order byte of the result */
6695   if (AOP_SIZE (result) > 1)
6696     {
6697       l = aopGet (AOP (result), 0, FALSE, FALSE);
6698       MOVA (l);
6699     }
6700   emitcode ("mov", "acc.0,c");
6701  release:
6702   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6703   freeAsmop (left, NULL, ic, TRUE);
6704   freeAsmop (result, NULL, ic, TRUE);
6705 }
6706
6707 /*-----------------------------------------------------------------*/
6708 /* genGetHbit - generates code get highest order bit               */
6709 /*-----------------------------------------------------------------*/
6710 static void
6711 genGetHbit (iCode * ic)
6712 {
6713   operand *left, *result;
6714
6715   D(emitcode (";     genGetHbit",""));
6716
6717   left = IC_LEFT (ic);
6718   result = IC_RESULT (ic);
6719   aopOp (left, ic, FALSE);
6720   aopOp (result, ic, FALSE);
6721
6722   /* get the highest order byte into a */
6723   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6724   if (AOP_TYPE (result) == AOP_CRY)
6725     {
6726       emitcode ("rlc", "a");
6727       outBitC (result);
6728     }
6729   else
6730     {
6731       emitcode ("rl", "a");
6732       emitcode ("anl", "a,#0x01");
6733       outAcc (result);
6734     }
6735
6736
6737   freeAsmop (left, NULL, ic, TRUE);
6738   freeAsmop (result, NULL, ic, TRUE);
6739 }
6740
6741 /*-----------------------------------------------------------------*/
6742 /* genSwap - generates code to swap nibbles or bytes               */
6743 /*-----------------------------------------------------------------*/
6744 static void
6745 genSwap (iCode * ic)
6746 {
6747   operand *left, *result;
6748
6749   D(emitcode (";     genSwap",""));
6750
6751   left = IC_LEFT (ic);
6752   result = IC_RESULT (ic);
6753   aopOp (left, ic, FALSE);
6754   aopOp (result, ic, FALSE);
6755
6756   switch (AOP_SIZE (left))
6757     {
6758     case 1: /* swap nibbles in byte */
6759       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6760       emitcode ("swap", "a");
6761       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6762       break;
6763     case 2: /* swap bytes in word */
6764       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6765         {
6766           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6767           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6768                   0, isOperandVolatile (result, FALSE));
6769           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6770         }
6771       else if (operandsEqu (left, result))
6772         {
6773           char * reg = "a";
6774           bool pushedB = FALSE, leftInB = FALSE;
6775
6776           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6777           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6778             {
6779               pushedB = pushB ();
6780               emitcode ("mov", "b,a");
6781               reg = "b";
6782               leftInB = TRUE;
6783             }
6784           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6785                   0, isOperandVolatile (result, FALSE));
6786           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6787
6788           if (leftInB)
6789             popB (pushedB);
6790         }
6791       else
6792         {
6793           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6794                   0, isOperandVolatile (result, FALSE));
6795           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6796                   1, isOperandVolatile (result, FALSE));
6797         }
6798       break;
6799     default:
6800       wassertl(FALSE, "unsupported SWAP operand size");
6801     }
6802
6803   freeAsmop (left, NULL, ic, TRUE);
6804   freeAsmop (result, NULL, ic, TRUE);
6805 }
6806
6807
6808 /*-----------------------------------------------------------------*/
6809 /* AccRol - rotate left accumulator by known count                 */
6810 /*-----------------------------------------------------------------*/
6811 static void
6812 AccRol (int shCount)
6813 {
6814   shCount &= 0x0007;            // shCount : 0..7
6815
6816   switch (shCount)
6817     {
6818     case 0:
6819       break;
6820     case 1:
6821       emitcode ("rl", "a");
6822       break;
6823     case 2:
6824       emitcode ("rl", "a");
6825       emitcode ("rl", "a");
6826       break;
6827     case 3:
6828       emitcode ("swap", "a");
6829       emitcode ("rr", "a");
6830       break;
6831     case 4:
6832       emitcode ("swap", "a");
6833       break;
6834     case 5:
6835       emitcode ("swap", "a");
6836       emitcode ("rl", "a");
6837       break;
6838     case 6:
6839       emitcode ("rr", "a");
6840       emitcode ("rr", "a");
6841       break;
6842     case 7:
6843       emitcode ("rr", "a");
6844       break;
6845     }
6846 }
6847
6848 /*-----------------------------------------------------------------*/
6849 /* AccLsh - left shift accumulator by known count                  */
6850 /*-----------------------------------------------------------------*/
6851 static void
6852 AccLsh (int shCount)
6853 {
6854   if (shCount != 0)
6855     {
6856       if (shCount == 1)
6857         emitcode ("add", "a,acc");
6858       else if (shCount == 2)
6859         {
6860           emitcode ("add", "a,acc");
6861           emitcode ("add", "a,acc");
6862         }
6863       else
6864         {
6865           /* rotate left accumulator */
6866           AccRol (shCount);
6867           /* and kill the lower order bits */
6868           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6869         }
6870     }
6871 }
6872
6873 /*-----------------------------------------------------------------*/
6874 /* AccRsh - right shift accumulator by known count                 */
6875 /*-----------------------------------------------------------------*/
6876 static void
6877 AccRsh (int shCount)
6878 {
6879   if (shCount != 0)
6880     {
6881       if (shCount == 1)
6882         {
6883           CLRC;
6884           emitcode ("rrc", "a");
6885         }
6886       else
6887         {
6888           /* rotate right accumulator */
6889           AccRol (8 - shCount);
6890           /* and kill the higher order bits */
6891           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6892         }
6893     }
6894 }
6895
6896 /*-----------------------------------------------------------------*/
6897 /* AccSRsh - signed right shift accumulator by known count                 */
6898 /*-----------------------------------------------------------------*/
6899 static void
6900 AccSRsh (int shCount)
6901 {
6902   symbol *tlbl;
6903   if (shCount != 0)
6904     {
6905       if (shCount == 1)
6906         {
6907           emitcode ("mov", "c,acc.7");
6908           emitcode ("rrc", "a");
6909         }
6910       else if (shCount == 2)
6911         {
6912           emitcode ("mov", "c,acc.7");
6913           emitcode ("rrc", "a");
6914           emitcode ("mov", "c,acc.7");
6915           emitcode ("rrc", "a");
6916         }
6917       else
6918         {
6919           tlbl = newiTempLabel (NULL);
6920           /* rotate right accumulator */
6921           AccRol (8 - shCount);
6922           /* and kill the higher order bits */
6923           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6924           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6925           emitcode ("orl", "a,#0x%02x",
6926                     (unsigned char) ~SRMask[shCount]);
6927           emitcode ("", "%05d$:", tlbl->key + 100);
6928         }
6929     }
6930 }
6931
6932 /*-----------------------------------------------------------------*/
6933 /* shiftR1Left2Result - shift right one byte from left to result   */
6934 /*-----------------------------------------------------------------*/
6935 static void
6936 shiftR1Left2Result (operand * left, int offl,
6937                     operand * result, int offr,
6938                     int shCount, int sign)
6939 {
6940   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6941   /* shift right accumulator */
6942   if (sign)
6943     AccSRsh (shCount);
6944   else
6945     AccRsh (shCount);
6946   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6947 }
6948
6949 /*-----------------------------------------------------------------*/
6950 /* shiftL1Left2Result - shift left one byte from left to result    */
6951 /*-----------------------------------------------------------------*/
6952 static void
6953 shiftL1Left2Result (operand * left, int offl,
6954                     operand * result, int offr, int shCount)
6955 {
6956   char *l;
6957   l = aopGet (AOP (left), offl, FALSE, FALSE);
6958   MOVA (l);
6959   /* shift left accumulator */
6960   AccLsh (shCount);
6961   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6962 }
6963
6964 /*-----------------------------------------------------------------*/
6965 /* movLeft2Result - move byte from left to result                  */
6966 /*-----------------------------------------------------------------*/
6967 static void
6968 movLeft2Result (operand * left, int offl,
6969                 operand * result, int offr, int sign)
6970 {
6971   char *l;
6972   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
6973     {
6974       l = aopGet (AOP (left), offl, FALSE, FALSE);
6975
6976       if (*l == '@' && (IS_AOP_PREG (result)))
6977         {
6978           emitcode ("mov", "a,%s", l);
6979           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6980         }
6981       else
6982         {
6983           if (!sign)
6984             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
6985           else
6986             {
6987               /* MSB sign in acc.7 ! */
6988               if (getDataSize (left) == offl + 1)
6989                 {
6990                   emitcode ("mov", "a,%s", l);
6991                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6992                 }
6993             }
6994         }
6995     }
6996 }
6997
6998 /*-----------------------------------------------------------------*/
6999 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7000 /*-----------------------------------------------------------------*/
7001 static void
7002 AccAXRrl1 (char *x)
7003 {
7004   emitcode ("rrc", "a");
7005   emitcode ("xch", "a,%s", x);
7006   emitcode ("rrc", "a");
7007   emitcode ("xch", "a,%s", x);
7008 }
7009
7010 /*-----------------------------------------------------------------*/
7011 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7012 /*-----------------------------------------------------------------*/
7013 static void
7014 AccAXLrl1 (char *x)
7015 {
7016   emitcode ("xch", "a,%s", x);
7017   emitcode ("rlc", "a");
7018   emitcode ("xch", "a,%s", x);
7019   emitcode ("rlc", "a");
7020 }
7021
7022 /*-----------------------------------------------------------------*/
7023 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7024 /*-----------------------------------------------------------------*/
7025 static void
7026 AccAXLsh1 (char *x)
7027 {
7028   emitcode ("xch", "a,%s", x);
7029   emitcode ("add", "a,acc");
7030   emitcode ("xch", "a,%s", x);
7031   emitcode ("rlc", "a");
7032 }
7033
7034 /*-----------------------------------------------------------------*/
7035 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7036 /*-----------------------------------------------------------------*/
7037 static void
7038 AccAXLsh (char *x, int shCount)
7039 {
7040   switch (shCount)
7041     {
7042     case 0:
7043       break;
7044     case 1:
7045       AccAXLsh1 (x);
7046       break;
7047     case 2:
7048       AccAXLsh1 (x);
7049       AccAXLsh1 (x);
7050       break;
7051     case 3:
7052     case 4:
7053     case 5:                     // AAAAABBB:CCCCCDDD
7054
7055       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7056
7057       emitcode ("anl", "a,#0x%02x",
7058                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7059
7060       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7061
7062       AccRol (shCount);         // DDDCCCCC:BBB00000
7063
7064       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7065
7066       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7067
7068       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7069
7070       emitcode ("anl", "a,#0x%02x",
7071                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7072
7073       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7074
7075       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7076
7077       break;
7078     case 6:                     // AAAAAABB:CCCCCCDD
7079       emitcode ("anl", "a,#0x%02x",
7080                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7081       emitcode ("mov", "c,acc.0");      // c = B
7082       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7083 #if 0 // REMOVE ME
7084       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7085       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7086 #else
7087       emitcode("rrc","a");
7088       emitcode("xch","a,%s", x);
7089       emitcode("rrc","a");
7090       emitcode("mov","c,acc.0"); //<< get correct bit
7091       emitcode("xch","a,%s", x);
7092
7093       emitcode("rrc","a");
7094       emitcode("xch","a,%s", x);
7095       emitcode("rrc","a");
7096       emitcode("xch","a,%s", x);
7097 #endif
7098       break;
7099     case 7:                     // a:x <<= 7
7100
7101       emitcode ("anl", "a,#0x%02x",
7102                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7103
7104       emitcode ("mov", "c,acc.0");      // c = B
7105
7106       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7107
7108       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7109
7110       break;
7111     default:
7112       break;
7113     }
7114 }
7115
7116 /*-----------------------------------------------------------------*/
7117 /* AccAXRsh - right shift a:x known count (0..7)                   */
7118 /*-----------------------------------------------------------------*/
7119 static void
7120 AccAXRsh (char *x, int shCount)
7121 {
7122   switch (shCount)
7123     {
7124     case 0:
7125       break;
7126     case 1:
7127       CLRC;
7128       AccAXRrl1 (x);            // 0->a:x
7129
7130       break;
7131     case 2:
7132       CLRC;
7133       AccAXRrl1 (x);            // 0->a:x
7134
7135       CLRC;
7136       AccAXRrl1 (x);            // 0->a:x
7137
7138       break;
7139     case 3:
7140     case 4:
7141     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7142
7143       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7144
7145       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7146
7147       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7148
7149       emitcode ("anl", "a,#0x%02x",
7150                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7151
7152       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7153
7154       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7155
7156       emitcode ("anl", "a,#0x%02x",
7157                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7158
7159       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7160
7161       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7162
7163       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7164
7165       break;
7166     case 6:                     // AABBBBBB:CCDDDDDD
7167
7168       emitcode ("mov", "c,acc.7");
7169       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7170
7171       emitcode ("mov", "c,acc.7");
7172       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7173
7174       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7175
7176       emitcode ("anl", "a,#0x%02x",
7177                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7178
7179       break;
7180     case 7:                     // ABBBBBBB:CDDDDDDD
7181
7182       emitcode ("mov", "c,acc.7");      // c = A
7183
7184       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7185
7186       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7187
7188       emitcode ("anl", "a,#0x%02x",
7189                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7190
7191       break;
7192     default:
7193       break;
7194     }
7195 }
7196
7197 /*-----------------------------------------------------------------*/
7198 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7199 /*-----------------------------------------------------------------*/
7200 static void
7201 AccAXRshS (char *x, int shCount)
7202 {
7203   symbol *tlbl;
7204   switch (shCount)
7205     {
7206     case 0:
7207       break;
7208     case 1:
7209       emitcode ("mov", "c,acc.7");
7210       AccAXRrl1 (x);            // s->a:x
7211
7212       break;
7213     case 2:
7214       emitcode ("mov", "c,acc.7");
7215       AccAXRrl1 (x);            // s->a:x
7216
7217       emitcode ("mov", "c,acc.7");
7218       AccAXRrl1 (x);            // s->a:x
7219
7220       break;
7221     case 3:
7222     case 4:
7223     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7224
7225       tlbl = newiTempLabel (NULL);
7226       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7227
7228       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7229
7230       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7231
7232       emitcode ("anl", "a,#0x%02x",
7233                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7234
7235       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7236
7237       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7238
7239       emitcode ("anl", "a,#0x%02x",
7240                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7241
7242       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7243
7244       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7245
7246       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7247
7248       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7249       emitcode ("orl", "a,#0x%02x",
7250                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7251
7252       emitcode ("", "%05d$:", tlbl->key + 100);
7253       break;                    // SSSSAAAA:BBBCCCCC
7254
7255     case 6:                     // AABBBBBB:CCDDDDDD
7256
7257       tlbl = newiTempLabel (NULL);
7258       emitcode ("mov", "c,acc.7");
7259       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7260
7261       emitcode ("mov", "c,acc.7");
7262       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7263
7264       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7265
7266       emitcode ("anl", "a,#0x%02x",
7267                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7268
7269       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7270       emitcode ("orl", "a,#0x%02x",
7271                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7272
7273       emitcode ("", "%05d$:", tlbl->key + 100);
7274       break;
7275     case 7:                     // ABBBBBBB:CDDDDDDD
7276
7277       tlbl = newiTempLabel (NULL);
7278       emitcode ("mov", "c,acc.7");      // c = A
7279
7280       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7281
7282       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7283
7284       emitcode ("anl", "a,#0x%02x",
7285                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7286
7287       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7288       emitcode ("orl", "a,#0x%02x",
7289                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7290
7291       emitcode ("", "%05d$:", tlbl->key + 100);
7292       break;
7293     default:
7294       break;
7295     }
7296 }
7297
7298 /*-----------------------------------------------------------------*/
7299 /* shiftL2Left2Result - shift left two bytes from left to result   */
7300 /*-----------------------------------------------------------------*/
7301 static void
7302 shiftL2Left2Result (operand * left, int offl,
7303                     operand * result, int offr, int shCount)
7304 {
7305   if (sameRegs (AOP (result), AOP (left)) &&
7306       ((offl + MSB16) == offr))
7307     {
7308       /* don't crash result[offr] */
7309       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7310       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7311     }
7312   else
7313     {
7314       movLeft2Result (left, offl, result, offr, 0);
7315       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7316     }
7317   /* ax << shCount (x = lsb(result)) */
7318   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7319   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7320 }
7321
7322
7323 /*-----------------------------------------------------------------*/
7324 /* shiftR2Left2Result - shift right two bytes from left to result  */
7325 /*-----------------------------------------------------------------*/
7326 static void
7327 shiftR2Left2Result (operand * left, int offl,
7328                     operand * result, int offr,
7329                     int shCount, int sign)
7330 {
7331   if (sameRegs (AOP (result), AOP (left)) &&
7332       ((offl + MSB16) == offr))
7333     {
7334       /* don't crash result[offr] */
7335       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7336       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7337     }
7338   else
7339     {
7340       movLeft2Result (left, offl, result, offr, 0);
7341       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7342     }
7343   /* a:x >> shCount (x = lsb(result)) */
7344   if (sign)
7345     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7346   else
7347     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7348   if (getDataSize (result) > 1)
7349     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7350 }
7351
7352 /*-----------------------------------------------------------------*/
7353 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7354 /*-----------------------------------------------------------------*/
7355 static void
7356 shiftLLeftOrResult (operand * left, int offl,
7357                     operand * result, int offr, int shCount)
7358 {
7359   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7360   /* shift left accumulator */
7361   AccLsh (shCount);
7362   /* or with result */
7363   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7364   /* back to result */
7365   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7366 }
7367
7368 /*-----------------------------------------------------------------*/
7369 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7370 /*-----------------------------------------------------------------*/
7371 static void
7372 shiftRLeftOrResult (operand * left, int offl,
7373                     operand * result, int offr, int shCount)
7374 {
7375   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7376   /* shift right accumulator */
7377   AccRsh (shCount);
7378   /* or with result */
7379   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7380   /* back to result */
7381   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7382 }
7383
7384 /*-----------------------------------------------------------------*/
7385 /* genlshOne - left shift a one byte quantity by known count       */
7386 /*-----------------------------------------------------------------*/
7387 static void
7388 genlshOne (operand * result, operand * left, int shCount)
7389 {
7390   D(emitcode (";     genlshOne",""));
7391
7392   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7393 }
7394
7395 /*-----------------------------------------------------------------*/
7396 /* genlshTwo - left shift two bytes by known amount != 0           */
7397 /*-----------------------------------------------------------------*/
7398 static void
7399 genlshTwo (operand * result, operand * left, int shCount)
7400 {
7401   int size;
7402
7403   D(emitcode (";     genlshTwo",""));
7404
7405   size = getDataSize (result);
7406
7407   /* if shCount >= 8 */
7408   if (shCount >= 8)
7409     {
7410       shCount -= 8;
7411
7412       if (size > 1)
7413         {
7414           if (shCount)
7415             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7416           else
7417             movLeft2Result (left, LSB, result, MSB16, 0);
7418         }
7419       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7420     }
7421
7422   /*  1 <= shCount <= 7 */
7423   else
7424     {
7425       if (size == 1)
7426         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7427       else
7428         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7429     }
7430 }
7431
7432 /*-----------------------------------------------------------------*/
7433 /* shiftLLong - shift left one long from left to result            */
7434 /* offl = LSB or MSB16                                             */
7435 /*-----------------------------------------------------------------*/
7436 static void
7437 shiftLLong (operand * left, operand * result, int offr)
7438 {
7439   char *l;
7440   int size = AOP_SIZE (result);
7441
7442   if (size >= LSB + offr)
7443     {
7444       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7445       MOVA (l);
7446       emitcode ("add", "a,acc");
7447       if (sameRegs (AOP (left), AOP (result)) &&
7448           size >= MSB16 + offr && offr != LSB)
7449         emitcode ("xch", "a,%s",
7450                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7451       else
7452         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7453     }
7454
7455   if (size >= MSB16 + offr)
7456     {
7457       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7458         {
7459           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7460           MOVA (l);
7461         }
7462       emitcode ("rlc", "a");
7463       if (sameRegs (AOP (left), AOP (result)) &&
7464           size >= MSB24 + offr && offr != LSB)
7465         emitcode ("xch", "a,%s",
7466                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7467       else
7468         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7469     }
7470
7471   if (size >= MSB24 + offr)
7472     {
7473       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7474         {
7475           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7476           MOVA (l);
7477         }
7478       emitcode ("rlc", "a");
7479       if (sameRegs (AOP (left), AOP (result)) &&
7480           size >= MSB32 + offr && offr != LSB)
7481         emitcode ("xch", "a,%s",
7482                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7483       else
7484         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7485     }
7486
7487   if (size > MSB32 + offr)
7488     {
7489       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7490         {
7491           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7492           MOVA (l);
7493         }
7494       emitcode ("rlc", "a");
7495       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7496     }
7497   if (offr != LSB)
7498     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7499 }
7500
7501 /*-----------------------------------------------------------------*/
7502 /* genlshFour - shift four byte by a known amount != 0             */
7503 /*-----------------------------------------------------------------*/
7504 static void
7505 genlshFour (operand * result, operand * left, int shCount)
7506 {
7507   int size;
7508
7509   D(emitcode (";     genlshFour",""));
7510
7511   size = AOP_SIZE (result);
7512
7513   /* if shifting more that 3 bytes */
7514   if (shCount >= 24)
7515     {
7516       shCount -= 24;
7517       if (shCount)
7518         /* lowest order of left goes to the highest
7519            order of the destination */
7520         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7521       else
7522         movLeft2Result (left, LSB, result, MSB32, 0);
7523       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7524       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7525       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7526       return;
7527     }
7528
7529   /* more than two bytes */
7530   else if (shCount >= 16)
7531     {
7532       /* lower order two bytes goes to higher order two bytes */
7533       shCount -= 16;
7534       /* if some more remaining */
7535       if (shCount)
7536         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7537       else
7538         {
7539           movLeft2Result (left, MSB16, result, MSB32, 0);
7540           movLeft2Result (left, LSB, result, MSB24, 0);
7541         }
7542       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7543       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7544       return;
7545     }
7546
7547   /* if more than 1 byte */
7548   else if (shCount >= 8)
7549     {
7550       /* lower order three bytes goes to higher order  three bytes */
7551       shCount -= 8;
7552       if (size == 2)
7553         {
7554           if (shCount)
7555             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7556           else
7557             movLeft2Result (left, LSB, result, MSB16, 0);
7558         }
7559       else
7560         {                       /* size = 4 */
7561           if (shCount == 0)
7562             {
7563               movLeft2Result (left, MSB24, result, MSB32, 0);
7564               movLeft2Result (left, MSB16, result, MSB24, 0);
7565               movLeft2Result (left, LSB, result, MSB16, 0);
7566               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7567             }
7568           else if (shCount == 1)
7569             shiftLLong (left, result, MSB16);
7570           else
7571             {
7572               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7573               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7574               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7575               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7576             }
7577         }
7578     }
7579
7580   /* 1 <= shCount <= 7 */
7581   else if (shCount <= 2)
7582     {
7583       shiftLLong (left, result, LSB);
7584       if (shCount == 2)
7585         shiftLLong (result, result, LSB);
7586     }
7587   /* 3 <= shCount <= 7, optimize */
7588   else
7589     {
7590       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7591       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7592       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7593     }
7594 }
7595
7596 /*-----------------------------------------------------------------*/
7597 /* genLeftShiftLiteral - left shifting by known count              */
7598 /*-----------------------------------------------------------------*/
7599 static void
7600 genLeftShiftLiteral (operand * left,
7601                      operand * right,
7602                      operand * result,
7603                      iCode * ic)
7604 {
7605   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7606   int size;
7607
7608   D(emitcode (";     genLeftShiftLiteral",""));
7609
7610   freeAsmop (right, NULL, ic, TRUE);
7611
7612   aopOp (left, ic, FALSE);
7613   aopOp (result, ic, FALSE);
7614
7615   size = getSize (operandType (result));
7616
7617 #if VIEW_SIZE
7618   emitcode ("; shift left ", "result %d, left %d", size,
7619             AOP_SIZE (left));
7620 #endif
7621
7622   /* I suppose that the left size >= result size */
7623   if (shCount == 0)
7624     {
7625       while (size--)
7626         {
7627           movLeft2Result (left, size, result, size, 0);
7628         }
7629     }
7630
7631   else if (shCount >= (size * 8))
7632     while (size--)
7633       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7634   else
7635     {
7636       switch (size)
7637         {
7638         case 1:
7639           genlshOne (result, left, shCount);
7640           break;
7641
7642         case 2:
7643           genlshTwo (result, left, shCount);
7644           break;
7645
7646         case 4:
7647           genlshFour (result, left, shCount);
7648           break;
7649         default:
7650           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7651                   "*** ack! mystery literal shift!\n");
7652           break;
7653         }
7654     }
7655   freeAsmop (left, NULL, ic, TRUE);
7656   freeAsmop (result, NULL, ic, TRUE);
7657 }
7658
7659 /*-----------------------------------------------------------------*/
7660 /* genLeftShift - generates code for left shifting                 */
7661 /*-----------------------------------------------------------------*/
7662 static void
7663 genLeftShift (iCode * ic)
7664 {
7665   operand *left, *right, *result;
7666   int size, offset;
7667   char *l;
7668   symbol *tlbl, *tlbl1;
7669   bool pushedB;
7670
7671   D(emitcode (";     genLeftShift",""));
7672
7673   right = IC_RIGHT (ic);
7674   left = IC_LEFT (ic);
7675   result = IC_RESULT (ic);
7676
7677   aopOp (right, ic, FALSE);
7678
7679   /* if the shift count is known then do it
7680      as efficiently as possible */
7681   if (AOP_TYPE (right) == AOP_LIT)
7682     {
7683       genLeftShiftLiteral (left, right, result, ic);
7684       return;
7685     }
7686
7687   /* shift count is unknown then we have to form
7688      a loop get the loop count in B : Note: we take
7689      only the lower order byte since shifting
7690      more that 32 bits make no sense anyway, ( the
7691      largest size of an object can be only 32 bits ) */
7692
7693   pushedB = pushB ();
7694   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7695   emitcode ("inc", "b");
7696   freeAsmop (right, NULL, ic, TRUE);
7697   aopOp (left, ic, FALSE);
7698   aopOp (result, ic, FALSE);
7699
7700   /* now move the left to the result if they are not the same */
7701   if (!sameRegs (AOP (left), AOP (result)) &&
7702       AOP_SIZE (result) > 1)
7703     {
7704
7705       size = AOP_SIZE (result);
7706       offset = 0;
7707       while (size--)
7708         {
7709           l = aopGet (AOP (left), offset, FALSE, TRUE);
7710           if (*l == '@' && (IS_AOP_PREG (result)))
7711             {
7712
7713               emitcode ("mov", "a,%s", l);
7714               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7715             }
7716           else
7717             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7718           offset++;
7719         }
7720     }
7721
7722   tlbl = newiTempLabel (NULL);
7723   size = AOP_SIZE (result);
7724   offset = 0;
7725   tlbl1 = newiTempLabel (NULL);
7726
7727   /* if it is only one byte then */
7728   if (size == 1)
7729     {
7730       symbol *tlbl1 = newiTempLabel (NULL);
7731
7732       l = aopGet (AOP (left), 0, FALSE, FALSE);
7733       MOVA (l);
7734       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7735       emitcode ("", "%05d$:", tlbl->key + 100);
7736       emitcode ("add", "a,acc");
7737       emitcode ("", "%05d$:", tlbl1->key + 100);
7738       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7739       popB (pushedB);
7740       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7741       goto release;
7742     }
7743
7744   reAdjustPreg (AOP (result));
7745
7746   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7747   emitcode ("", "%05d$:", tlbl->key + 100);
7748   l = aopGet (AOP (result), offset, FALSE, FALSE);
7749   MOVA (l);
7750   emitcode ("add", "a,acc");
7751   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7752   while (--size)
7753     {
7754       l = aopGet (AOP (result), offset, FALSE, FALSE);
7755       MOVA (l);
7756       emitcode ("rlc", "a");
7757       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7758     }
7759   reAdjustPreg (AOP (result));
7760
7761   emitcode ("", "%05d$:", tlbl1->key + 100);
7762   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7763   popB (pushedB);
7764 release:
7765   freeAsmop (left, NULL, ic, TRUE);
7766   freeAsmop (result, NULL, ic, TRUE);
7767 }
7768
7769 /*-----------------------------------------------------------------*/
7770 /* genrshOne - right shift a one byte quantity by known count      */
7771 /*-----------------------------------------------------------------*/
7772 static void
7773 genrshOne (operand * result, operand * left,
7774            int shCount, int sign)
7775 {
7776   D(emitcode (";     genrshOne",""));
7777
7778   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7779 }
7780
7781 /*-----------------------------------------------------------------*/
7782 /* genrshTwo - right shift two bytes by known amount != 0          */
7783 /*-----------------------------------------------------------------*/
7784 static void
7785 genrshTwo (operand * result, operand * left,
7786            int shCount, int sign)
7787 {
7788   D(emitcode (";     genrshTwo",""));
7789
7790   /* if shCount >= 8 */
7791   if (shCount >= 8)
7792     {
7793       shCount -= 8;
7794       if (shCount)
7795         shiftR1Left2Result (left, MSB16, result, LSB,
7796                             shCount, sign);
7797       else
7798         movLeft2Result (left, MSB16, result, LSB, sign);
7799       addSign (result, MSB16, sign);
7800     }
7801
7802   /*  1 <= shCount <= 7 */
7803   else
7804     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7805 }
7806
7807 /*-----------------------------------------------------------------*/
7808 /* shiftRLong - shift right one long from left to result           */
7809 /* offl = LSB or MSB16                                             */
7810 /*-----------------------------------------------------------------*/
7811 static void
7812 shiftRLong (operand * left, int offl,
7813             operand * result, int sign)
7814 {
7815   int isSameRegs=sameRegs(AOP(left),AOP(result));
7816
7817   if (isSameRegs && offl>1) {
7818     // we are in big trouble, but this shouldn't happen
7819     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7820   }
7821
7822   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7823
7824   if (offl==MSB16) {
7825     // shift is > 8
7826     if (sign) {
7827       emitcode ("rlc", "a");
7828       emitcode ("subb", "a,acc");
7829       if (isSameRegs)
7830         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7831       else {
7832         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7833         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7834       }
7835     } else {
7836       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7837     }
7838   }
7839
7840   if (!sign) {
7841     emitcode ("clr", "c");
7842   } else {
7843     emitcode ("mov", "c,acc.7");
7844   }
7845
7846   emitcode ("rrc", "a");
7847
7848   if (isSameRegs && offl==MSB16) {
7849     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7850   } else {
7851     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7852     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7853   }
7854
7855   emitcode ("rrc", "a");
7856   if (isSameRegs && offl==1) {
7857     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7858   } else {
7859     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7860     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7861   }
7862   emitcode ("rrc", "a");
7863   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7864
7865   if (offl == LSB)
7866     {
7867       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7868       emitcode ("rrc", "a");
7869       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7870     }
7871 }
7872
7873 /*-----------------------------------------------------------------*/
7874 /* genrshFour - shift four byte by a known amount != 0             */
7875 /*-----------------------------------------------------------------*/
7876 static void
7877 genrshFour (operand * result, operand * left,
7878             int shCount, int sign)
7879 {
7880   D(emitcode (";     genrshFour",""));
7881
7882   /* if shifting more that 3 bytes */
7883   if (shCount >= 24)
7884     {
7885       shCount -= 24;
7886       if (shCount)
7887         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7888       else
7889         movLeft2Result (left, MSB32, result, LSB, sign);
7890       addSign (result, MSB16, sign);
7891     }
7892   else if (shCount >= 16)
7893     {
7894       shCount -= 16;
7895       if (shCount)
7896         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7897       else
7898         {
7899           movLeft2Result (left, MSB24, result, LSB, 0);
7900           movLeft2Result (left, MSB32, result, MSB16, sign);
7901         }
7902       addSign (result, MSB24, sign);
7903     }
7904   else if (shCount >= 8)
7905     {
7906       shCount -= 8;
7907       if (shCount == 1)
7908         shiftRLong (left, MSB16, result, sign);
7909       else if (shCount == 0)
7910         {
7911           movLeft2Result (left, MSB16, result, LSB, 0);
7912           movLeft2Result (left, MSB24, result, MSB16, 0);
7913           movLeft2Result (left, MSB32, result, MSB24, sign);
7914           addSign (result, MSB32, sign);
7915         }
7916       else
7917         {
7918           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
7919           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
7920           /* the last shift is signed */
7921           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
7922           addSign (result, MSB32, sign);
7923         }
7924     }
7925   else
7926     {                           /* 1 <= shCount <= 7 */
7927       if (shCount <= 2)
7928         {
7929           shiftRLong (left, LSB, result, sign);
7930           if (shCount == 2)
7931             shiftRLong (result, LSB, result, sign);
7932         }
7933       else
7934         {
7935           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
7936           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
7937           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
7938         }
7939     }
7940 }
7941
7942 /*-----------------------------------------------------------------*/
7943 /* genRightShiftLiteral - right shifting by known count            */
7944 /*-----------------------------------------------------------------*/
7945 static void
7946 genRightShiftLiteral (operand * left,
7947                       operand * right,
7948                       operand * result,
7949                       iCode * ic,
7950                       int sign)
7951 {
7952   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7953   int size;
7954
7955   D(emitcode (";     genRightShiftLiteral",""));
7956
7957   freeAsmop (right, NULL, ic, TRUE);
7958
7959   aopOp (left, ic, FALSE);
7960   aopOp (result, ic, FALSE);
7961
7962 #if VIEW_SIZE
7963   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
7964             AOP_SIZE (left));
7965 #endif
7966
7967   size = getDataSize (left);
7968   /* test the LEFT size !!! */
7969
7970   /* I suppose that the left size >= result size */
7971   if (shCount == 0)
7972     {
7973       size = getDataSize (result);
7974       while (size--)
7975         movLeft2Result (left, size, result, size, 0);
7976     }
7977
7978   else if (shCount >= (size * 8))
7979     {
7980       if (sign) {
7981         /* get sign in acc.7 */
7982         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
7983       }
7984       addSign (result, LSB, sign);
7985     }
7986   else
7987     {
7988       switch (size)
7989         {
7990         case 1:
7991           genrshOne (result, left, shCount, sign);
7992           break;
7993
7994         case 2:
7995           genrshTwo (result, left, shCount, sign);
7996           break;
7997
7998         case 4:
7999           genrshFour (result, left, shCount, sign);
8000           break;
8001         default:
8002           break;
8003         }
8004     }
8005   freeAsmop (left, NULL, ic, TRUE);
8006   freeAsmop (result, NULL, ic, TRUE);
8007 }
8008
8009 /*-----------------------------------------------------------------*/
8010 /* genSignedRightShift - right shift of signed number              */
8011 /*-----------------------------------------------------------------*/
8012 static void
8013 genSignedRightShift (iCode * ic)
8014 {
8015   operand *right, *left, *result;
8016   int size, offset;
8017   char *l;
8018   symbol *tlbl, *tlbl1;
8019   bool pushedB;
8020
8021   D(emitcode (";     genSignedRightShift",""));
8022
8023   /* we do it the hard way put the shift count in b
8024      and loop thru preserving the sign */
8025
8026   right = IC_RIGHT (ic);
8027   left = IC_LEFT (ic);
8028   result = IC_RESULT (ic);
8029
8030   aopOp (right, ic, FALSE);
8031
8032
8033   if (AOP_TYPE (right) == AOP_LIT)
8034     {
8035       genRightShiftLiteral (left, right, result, ic, 1);
8036       return;
8037     }
8038   /* shift count is unknown then we have to form
8039      a loop get the loop count in B : Note: we take
8040      only the lower order byte since shifting
8041      more that 32 bits make no sense anyway, ( the
8042      largest size of an object can be only 32 bits ) */
8043
8044   pushedB = pushB ();
8045   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
8046   emitcode ("inc", "b");
8047   freeAsmop (right, NULL, ic, TRUE);
8048   aopOp (left, ic, FALSE);
8049   aopOp (result, ic, FALSE);
8050
8051   /* now move the left to the result if they are not the
8052      same */
8053   if (!sameRegs (AOP (left), AOP (result)) &&
8054       AOP_SIZE (result) > 1)
8055     {
8056
8057       size = AOP_SIZE (result);
8058       offset = 0;
8059       while (size--)
8060         {
8061           l = aopGet (AOP (left), offset, FALSE, TRUE);
8062           if (*l == '@' && IS_AOP_PREG (result))
8063             {
8064
8065               emitcode ("mov", "a,%s", l);
8066               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8067             }
8068           else
8069             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
8070           offset++;
8071         }
8072     }
8073
8074   /* mov the highest order bit to OVR */
8075   tlbl = newiTempLabel (NULL);
8076   tlbl1 = newiTempLabel (NULL);
8077
8078   size = AOP_SIZE (result);
8079   offset = size - 1;
8080   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
8081   emitcode ("rlc", "a");
8082   emitcode ("mov", "ov,c");
8083   /* if it is only one byte then */
8084   if (size == 1)
8085     {
8086       l = aopGet (AOP (left), 0, FALSE, FALSE);
8087       MOVA (l);
8088       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8089       emitcode ("", "%05d$:", tlbl->key + 100);
8090       emitcode ("mov", "c,ov");
8091       emitcode ("rrc", "a");
8092       emitcode ("", "%05d$:", tlbl1->key + 100);
8093       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8094       popB (pushedB);
8095       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
8096       goto release;
8097     }
8098
8099   reAdjustPreg (AOP (result));
8100   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8101   emitcode ("", "%05d$:", tlbl->key + 100);
8102   emitcode ("mov", "c,ov");
8103   while (size--)
8104     {
8105       l = aopGet (AOP (result), offset, FALSE, FALSE);
8106       MOVA (l);
8107       emitcode ("rrc", "a");
8108       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
8109     }
8110   reAdjustPreg (AOP (result));
8111   emitcode ("", "%05d$:", tlbl1->key + 100);
8112   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8113   popB (pushedB);
8114
8115 release:
8116   freeAsmop (left, NULL, ic, TRUE);
8117   freeAsmop (result, NULL, ic, TRUE);
8118 }
8119
8120 /*-----------------------------------------------------------------*/
8121 /* genRightShift - generate code for right shifting                */
8122 /*-----------------------------------------------------------------*/
8123 static void
8124 genRightShift (iCode * ic)
8125 {
8126   operand *right, *left, *result;
8127   sym_link *letype;
8128   int size, offset;
8129   char *l;
8130   symbol *tlbl, *tlbl1;
8131   bool pushedB;
8132
8133   D(emitcode (";     genRightShift",""));
8134
8135   /* if signed then we do it the hard way preserve the
8136      sign bit moving it inwards */
8137   letype = getSpec (operandType (IC_LEFT (ic)));
8138
8139   if (!SPEC_USIGN (letype))
8140     {
8141       genSignedRightShift (ic);
8142       return;
8143     }
8144
8145   /* signed & unsigned types are treated the same : i.e. the
8146      signed is NOT propagated inwards : quoting from the
8147      ANSI - standard : "for E1 >> E2, is equivalent to division
8148      by 2**E2 if unsigned or if it has a non-negative value,
8149      otherwise the result is implementation defined ", MY definition
8150      is that the sign does not get propagated */
8151
8152   right = IC_RIGHT (ic);
8153   left = IC_LEFT (ic);
8154   result = IC_RESULT (ic);
8155
8156   aopOp (right, ic, FALSE);
8157
8158   /* if the shift count is known then do it
8159      as efficiently as possible */
8160   if (AOP_TYPE (right) == AOP_LIT)
8161     {
8162       genRightShiftLiteral (left, right, result, ic, 0);
8163       return;
8164     }
8165
8166   /* shift count is unknown then we have to form
8167      a loop get the loop count in B : Note: we take
8168      only the lower order byte since shifting
8169      more that 32 bits make no sense anyway, ( the
8170      largest size of an object can be only 32 bits ) */
8171
8172   pushedB = pushB ();
8173   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
8174   emitcode ("inc", "b");
8175   freeAsmop (right, NULL, ic, TRUE);
8176   aopOp (left, ic, FALSE);
8177   aopOp (result, ic, FALSE);
8178
8179   /* now move the left to the result if they are not the
8180      same */
8181   if (!sameRegs (AOP (left), AOP (result)) &&
8182       AOP_SIZE (result) > 1)
8183     {
8184
8185       size = AOP_SIZE (result);
8186       offset = 0;
8187       while (size--)
8188         {
8189           l = aopGet (AOP (left), offset, FALSE, TRUE);
8190           if (*l == '@' && IS_AOP_PREG (result))
8191             {
8192
8193               emitcode ("mov", "a,%s", l);
8194               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8195             }
8196           else
8197             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
8198           offset++;
8199         }
8200     }
8201
8202   tlbl = newiTempLabel (NULL);
8203   tlbl1 = newiTempLabel (NULL);
8204   size = AOP_SIZE (result);
8205   offset = size - 1;
8206
8207   /* if it is only one byte then */
8208   if (size == 1)
8209     {
8210       l = aopGet (AOP (left), 0, FALSE, FALSE);
8211       MOVA (l);
8212       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8213       emitcode ("", "%05d$:", tlbl->key + 100);
8214       CLRC;
8215       emitcode ("rrc", "a");
8216       emitcode ("", "%05d$:", tlbl1->key + 100);
8217       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8218       popB (pushedB);
8219       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
8220       goto release;
8221     }
8222
8223   reAdjustPreg (AOP (result));
8224   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8225   emitcode ("", "%05d$:", tlbl->key + 100);
8226   CLRC;
8227   while (size--)
8228     {
8229       l = aopGet (AOP (result), offset, FALSE, FALSE);
8230       MOVA (l);
8231       emitcode ("rrc", "a");
8232       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
8233     }
8234   reAdjustPreg (AOP (result));
8235
8236   emitcode ("", "%05d$:", tlbl1->key + 100);
8237   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8238   popB (pushedB);
8239
8240 release:
8241   freeAsmop (left, NULL, ic, TRUE);
8242   freeAsmop (result, NULL, ic, TRUE);
8243 }
8244
8245 /*-----------------------------------------------------------------*/
8246 /* emitPtrByteGet - emits code to get a byte into A through a      */
8247 /*                  pointer register (R0, R1, or DPTR). The        */
8248 /*                  original value of A can be preserved in B.     */
8249 /*-----------------------------------------------------------------*/
8250 static void
8251 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8252 {
8253   switch (p_type)
8254     {
8255     case IPOINTER:
8256     case POINTER:
8257       if (preserveAinB)
8258         emitcode ("mov", "b,a");
8259       emitcode ("mov", "a,@%s", rname);
8260       break;
8261
8262     case PPOINTER:
8263       if (preserveAinB)
8264         emitcode ("mov", "b,a");
8265       emitcode ("movx", "a,@%s", rname);
8266       break;
8267
8268     case FPOINTER:
8269       if (preserveAinB)
8270         emitcode ("mov", "b,a");
8271       emitcode ("movx", "a,@dptr");
8272       break;
8273
8274     case CPOINTER:
8275       if (preserveAinB)
8276         emitcode ("mov", "b,a");
8277       emitcode ("clr", "a");
8278       emitcode ("movc", "a,@a+dptr");
8279       break;
8280
8281     case GPOINTER:
8282       if (preserveAinB)
8283         {
8284           emitcode ("push", "b");
8285           emitcode ("push", "acc");
8286         }
8287       emitcode ("lcall", "__gptrget");
8288       if (preserveAinB)
8289         emitcode ("pop", "b");
8290       break;
8291     }
8292 }
8293
8294 /*-----------------------------------------------------------------*/
8295 /* emitPtrByteSet - emits code to set a byte from src through a    */
8296 /*                  pointer register (R0, R1, or DPTR).            */
8297 /*-----------------------------------------------------------------*/
8298 static void
8299 emitPtrByteSet (char *rname, int p_type, char *src)
8300 {
8301   switch (p_type)
8302     {
8303     case IPOINTER:
8304     case POINTER:
8305       if (*src=='@')
8306         {
8307           MOVA (src);
8308           emitcode ("mov", "@%s,a", rname);
8309         }
8310       else
8311         emitcode ("mov", "@%s,%s", rname, src);
8312       break;
8313
8314     case PPOINTER:
8315       MOVA (src);
8316       emitcode ("movx", "@%s,a", rname);
8317       break;
8318
8319     case FPOINTER:
8320       MOVA (src);
8321       emitcode ("movx", "@dptr,a");
8322       break;
8323
8324     case GPOINTER:
8325       MOVA (src);
8326       emitcode ("lcall", "__gptrput");
8327       break;
8328     }
8329 }
8330
8331 /*-----------------------------------------------------------------*/
8332 /* genUnpackBits - generates code for unpacking bits               */
8333 /*-----------------------------------------------------------------*/
8334 static void
8335 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8336 {
8337   int offset = 0;       /* result byte offset */
8338   int rsize;            /* result size */
8339   int rlen = 0;         /* remaining bitfield length */
8340   sym_link *etype;      /* bitfield type information */
8341   int blen;             /* bitfield length */
8342   int bstr;             /* bitfield starting bit within byte */
8343   char buffer[10];
8344
8345   D(emitcode (";     genUnpackBits",""));
8346
8347   etype = getSpec (operandType (result));
8348   rsize = getSize (operandType (result));
8349   blen = SPEC_BLEN (etype);
8350   bstr = SPEC_BSTR (etype);
8351
8352   if (ifx && blen <= 8)
8353     {
8354       emitPtrByteGet (rname, ptype, FALSE);
8355       if (blen == 1)
8356         {
8357           SNPRINTF (buffer, sizeof(buffer),
8358                     "acc.%d", bstr);
8359           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8360         }
8361       else
8362         {
8363           if (blen < 8)
8364             emitcode ("anl", "a,#0x%02x",
8365                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8366           genIfxJump (ifx, "a", NULL, NULL, NULL);
8367         }
8368       return;
8369     }
8370   wassert (!ifx);
8371
8372   /* If the bitfield length is less than a byte */
8373   if (blen < 8)
8374     {
8375       emitPtrByteGet (rname, ptype, FALSE);
8376       AccRsh (bstr);
8377       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8378       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8379       goto finish;
8380     }
8381
8382   /* Bit field did not fit in a byte. Copy all
8383      but the partial byte at the end.  */
8384   for (rlen=blen;rlen>=8;rlen-=8)
8385     {
8386       emitPtrByteGet (rname, ptype, FALSE);
8387       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8388       if (rlen>8)
8389         emitcode ("inc", "%s", rname);
8390     }
8391
8392   /* Handle the partial byte at the end */
8393   if (rlen)
8394     {
8395       emitPtrByteGet (rname, ptype, FALSE);
8396       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8397       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8398     }
8399
8400 finish:
8401   if (offset < rsize)
8402     {
8403       rsize -= offset;
8404       while (rsize--)
8405         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
8406     }
8407 }
8408
8409
8410 /*-----------------------------------------------------------------*/
8411 /* genDataPointerGet - generates code when ptr offset is known     */
8412 /*-----------------------------------------------------------------*/
8413 static void
8414 genDataPointerGet (operand * left,
8415                    operand * result,
8416                    iCode * ic)
8417 {
8418   char *l;
8419   char buffer[256];
8420   int size, offset = 0;
8421
8422   D(emitcode (";     genDataPointerGet",""));
8423
8424   aopOp (result, ic, TRUE);
8425
8426   /* get the string representation of the name */
8427   l = aopGet (AOP (left), 0, FALSE, TRUE);
8428   size = AOP_SIZE (result);
8429   while (size--)
8430     {
8431       if (offset)
8432         sprintf (buffer, "(%s + %d)", l + 1, offset);
8433       else
8434         sprintf (buffer, "%s", l + 1);
8435       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
8436     }
8437
8438   freeAsmop (left, NULL, ic, TRUE);
8439   freeAsmop (result, NULL, ic, TRUE);
8440 }
8441
8442 /*-----------------------------------------------------------------*/
8443 /* genNearPointerGet - emitcode for near pointer fetch             */
8444 /*-----------------------------------------------------------------*/
8445 static void
8446 genNearPointerGet (operand * left,
8447                    operand * result,
8448                    iCode * ic,
8449                    iCode * pi,
8450                    iCode * ifx)
8451 {
8452   asmop *aop = NULL;
8453   regs *preg = NULL;
8454   char *rname;
8455   sym_link *rtype, *retype;
8456   sym_link *ltype = operandType (left);
8457   char buffer[80];
8458
8459   D(emitcode (";     genNearPointerGet",""));
8460
8461   rtype = operandType (result);
8462   retype = getSpec (rtype);
8463
8464   aopOp (left, ic, FALSE);
8465
8466   /* if left is rematerialisable and
8467      result is not bitfield variable type and
8468      the left is pointer to data space i.e
8469      lower 128 bytes of space */
8470   if (AOP_TYPE (left) == AOP_IMMD &&
8471       !IS_BITFIELD (retype) &&
8472       DCL_TYPE (ltype) == POINTER)
8473     {
8474       genDataPointerGet (left, result, ic);
8475       return;
8476     }
8477
8478  /* if the value is already in a pointer register
8479      then don't need anything more */
8480   if (!AOP_INPREG (AOP (left)))
8481     {
8482       if (IS_AOP_PREG (left))
8483         {
8484           // Aha, it is a pointer, just in disguise.
8485           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8486           if (*rname != '@')
8487             {
8488               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8489                       __FILE__, __LINE__);
8490             }
8491           else
8492             {
8493               // Expected case.
8494               emitcode ("mov", "a%s,%s", rname + 1, rname);
8495               rname++;  // skip the '@'.
8496             }
8497         }
8498       else
8499         {
8500           /* otherwise get a free pointer register */
8501           aop = newAsmop (0);
8502           preg = getFreePtr (ic, &aop, FALSE);
8503           emitcode ("mov", "%s,%s",
8504                     preg->name,
8505                     aopGet (AOP (left), 0, FALSE, TRUE));
8506           rname = preg->name;
8507         }
8508     }
8509   else
8510     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8511
8512   //aopOp (result, ic, FALSE);
8513   aopOp (result, ic, result?TRUE:FALSE);
8514
8515   /* if bitfield then unpack the bits */
8516   if (IS_BITFIELD (retype))
8517     genUnpackBits (result, rname, POINTER, ifx);
8518   else
8519     {
8520       /* we have can just get the values */
8521       int size = AOP_SIZE (result);
8522       int offset = 0;
8523
8524       while (size--)
8525         {
8526           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8527             {
8528
8529               emitcode ("mov", "a,@%s", rname);
8530               if (!ifx)
8531               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8532             }
8533           else
8534             {
8535               sprintf (buffer, "@%s", rname);
8536               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8537             }
8538           offset++;
8539           if (size || pi)
8540             emitcode ("inc", "%s", rname);
8541         }
8542     }
8543
8544   /* now some housekeeping stuff */
8545   if (aop)       /* we had to allocate for this iCode */
8546     {
8547       if (pi) { /* post increment present */
8548         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8549       }
8550       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8551     }
8552   else
8553     {
8554       /* we did not allocate which means left
8555          already in a pointer register, then
8556          if size > 0 && this could be used again
8557          we have to point it back to where it
8558          belongs */
8559       if ((AOP_SIZE (result) > 1 &&
8560            !OP_SYMBOL (left)->remat &&
8561            (OP_SYMBOL (left)->liveTo > ic->seq ||
8562             ic->depth)) &&
8563           !pi)
8564         {
8565           int size = AOP_SIZE (result) - 1;
8566           while (size--)
8567             emitcode ("dec", "%s", rname);
8568         }
8569     }
8570
8571   if (ifx && !ifx->generated)
8572     {
8573       genIfxJump (ifx, "a", left, NULL, result);
8574     }
8575
8576   /* done */
8577   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8578   freeAsmop (left, NULL, ic, TRUE);
8579   if (pi) pi->generated = 1;
8580 }
8581
8582 /*-----------------------------------------------------------------*/
8583 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8584 /*-----------------------------------------------------------------*/
8585 static void
8586 genPagedPointerGet (operand * left,
8587                     operand * result,
8588                     iCode * ic,
8589                     iCode *pi,
8590                     iCode *ifx)
8591 {
8592   asmop *aop = NULL;
8593   regs *preg = NULL;
8594   char *rname;
8595   sym_link *rtype, *retype;
8596
8597   D(emitcode (";     genPagedPointerGet",""));
8598
8599   rtype = operandType (result);
8600   retype = getSpec (rtype);
8601
8602   aopOp (left, ic, FALSE);
8603
8604   /* if the value is already in a pointer register
8605      then don't need anything more */
8606   if (!AOP_INPREG (AOP (left)))
8607     {
8608       /* otherwise get a free pointer register */
8609       aop = newAsmop (0);
8610       preg = getFreePtr (ic, &aop, FALSE);
8611       emitcode ("mov", "%s,%s",
8612                 preg->name,
8613                 aopGet (AOP (left), 0, FALSE, TRUE));
8614       rname = preg->name;
8615     }
8616   else
8617     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8618
8619   aopOp (result, ic, FALSE);
8620
8621   /* if bitfield then unpack the bits */
8622   if (IS_BITFIELD (retype))
8623     genUnpackBits (result, rname, PPOINTER, ifx);
8624   else
8625     {
8626       /* we have can just get the values */
8627       int size = AOP_SIZE (result);
8628       int offset = 0;
8629
8630       while (size--)
8631         {
8632
8633           emitcode ("movx", "a,@%s", rname);
8634           if (!ifx)
8635           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8636
8637           offset++;
8638
8639           if (size || pi)
8640             emitcode ("inc", "%s", rname);
8641         }
8642     }
8643
8644   /* now some housekeeping stuff */
8645   if (aop) /* we had to allocate for this iCode */
8646     {
8647       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8648       freeAsmop (NULL, aop, ic, TRUE);
8649     }
8650   else
8651     {
8652       /* we did not allocate which means left
8653          already in a pointer register, then
8654          if size > 0 && this could be used again
8655          we have to point it back to where it
8656          belongs */
8657       if ((AOP_SIZE (result) > 1 &&
8658            !OP_SYMBOL (left)->remat &&
8659            (OP_SYMBOL (left)->liveTo > ic->seq ||
8660             ic->depth)) &&
8661           !pi)
8662         {
8663           int size = AOP_SIZE (result) - 1;
8664           while (size--)
8665             emitcode ("dec", "%s", rname);
8666         }
8667     }
8668
8669   if (ifx && !ifx->generated)
8670     {
8671       genIfxJump (ifx, "a", left, NULL, result);
8672     }
8673
8674   /* done */
8675   freeAsmop (left, NULL, ic, TRUE);
8676   freeAsmop (result, NULL, ic, TRUE);
8677   if (pi) pi->generated = 1;
8678
8679 }
8680
8681 /*--------------------------------------------------------------------*/
8682 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8683 /*--------------------------------------------------------------------*/
8684 static void
8685 loadDptrFromOperand (operand *op, bool loadBToo)
8686 {
8687   if (AOP_TYPE (op) != AOP_STR)
8688     {
8689       /* if this is rematerializable */
8690       if (AOP_TYPE (op) == AOP_IMMD)
8691         {
8692           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8693           if (loadBToo)
8694             {
8695               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8696                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8697               else
8698                 {
8699                   wassertl(FALSE, "need pointerCode");
8700                   emitcode ("", "; mov b,???");
8701                   /* genPointerGet and genPointerSet originally did different
8702                   ** things for this case. Both seem wrong.
8703                   ** from genPointerGet:
8704                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8705                   ** from genPointerSet:
8706                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8707                   */
8708                 }
8709             }
8710         }
8711       else if (AOP_TYPE (op) == AOP_DPTR)
8712         {
8713           if (loadBToo)
8714             {
8715               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8716               emitcode ("push", "acc");
8717               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8718               emitcode ("push", "acc");
8719               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8720               emitcode ("pop", "dph");
8721               emitcode ("pop", "dpl");
8722             }
8723           else
8724             {
8725               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8726               emitcode ("push", "acc");
8727               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8728               emitcode ("pop", "dpl");
8729             }
8730         }
8731       else
8732         {                       /* we need to get it byte by byte */
8733           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8734           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8735           if (loadBToo)
8736             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8737         }
8738     }
8739 }
8740
8741 /*-----------------------------------------------------------------*/
8742 /* genFarPointerGet - gget value from far space                    */
8743 /*-----------------------------------------------------------------*/
8744 static void
8745 genFarPointerGet (operand * left,
8746                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
8747 {
8748   int size, offset;
8749   sym_link *retype = getSpec (operandType (result));
8750
8751   D(emitcode (";     genFarPointerGet",""));
8752
8753   aopOp (left, ic, FALSE);
8754   loadDptrFromOperand (left, FALSE);
8755
8756   /* so dptr now contains the address */
8757   aopOp (result, ic, FALSE);
8758
8759   /* if bit then unpack */
8760   if (IS_BITFIELD (retype))
8761     genUnpackBits (result, "dptr", FPOINTER, ifx);
8762   else
8763     {
8764       size = AOP_SIZE (result);
8765       offset = 0;
8766
8767       while (size--)
8768         {
8769           emitcode ("movx", "a,@dptr");
8770           if (!ifx)
8771             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8772           if (size || pi)
8773             emitcode ("inc", "dptr");
8774         }
8775     }
8776
8777   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8778     {
8779     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8780     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8781     pi->generated = 1;
8782   }
8783
8784   if (ifx && !ifx->generated)
8785     {
8786       genIfxJump (ifx, "a", left, NULL, result);
8787     }
8788
8789   freeAsmop (left, NULL, ic, TRUE);
8790   freeAsmop (result, NULL, ic, TRUE);
8791 }
8792
8793 /*-----------------------------------------------------------------*/
8794 /* genCodePointerGet - gget value from code space                  */
8795 /*-----------------------------------------------------------------*/
8796 static void
8797 genCodePointerGet (operand * left,
8798                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
8799 {
8800   int size, offset;
8801   sym_link *retype = getSpec (operandType (result));
8802
8803   D(emitcode (";     genCodePointerGet",""));
8804
8805   aopOp (left, ic, FALSE);
8806   loadDptrFromOperand (left, FALSE);
8807
8808   /* so dptr now contains the address */
8809   aopOp (result, ic, FALSE);
8810
8811   /* if bit then unpack */
8812   if (IS_BITFIELD (retype))
8813     genUnpackBits (result, "dptr", CPOINTER, ifx);
8814   else
8815     {
8816       size = AOP_SIZE (result);
8817       offset = 0;
8818
8819       while (size--)
8820         {
8821           if (pi)
8822             {
8823               emitcode ("clr", "a");
8824               emitcode ("movc", "a,@a+dptr");
8825               if (!ifx)
8826               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8827               emitcode ("inc", "dptr");
8828             }
8829           else
8830             {
8831               emitcode ("mov", "a,#0x%02x", offset);
8832               emitcode ("movc", "a,@a+dptr");
8833               if (!ifx)
8834               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8835             }
8836         }
8837     }
8838
8839   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8840     {
8841     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8842     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8843     pi->generated = 1;
8844   }
8845
8846   if (ifx && !ifx->generated)
8847     {
8848       genIfxJump (ifx, "a", left, NULL, result);
8849     }
8850
8851   freeAsmop (left, NULL, ic, TRUE);
8852   freeAsmop (result, NULL, ic, TRUE);
8853 }
8854
8855 /*-----------------------------------------------------------------*/
8856 /* genGenPointerGet - gget value from generic pointer space        */
8857 /*-----------------------------------------------------------------*/
8858 static void
8859 genGenPointerGet (operand * left,
8860                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
8861 {
8862   int size, offset;
8863   sym_link *retype = getSpec (operandType (result));
8864
8865   D(emitcode (";     genGenPointerGet",""));
8866
8867   aopOp (left, ic, FALSE);
8868   loadDptrFromOperand (left, TRUE);
8869
8870   /* so dptr know contains the address */
8871   aopOp (result, ic, FALSE);
8872
8873   /* if bit then unpack */
8874   if (IS_BITFIELD (retype))
8875     genUnpackBits (result, "dptr", GPOINTER, ifx);
8876   else
8877     {
8878       size = AOP_SIZE (result);
8879       offset = 0;
8880
8881       while (size--)
8882         {
8883           emitcode ("lcall", "__gptrget");
8884           if (!ifx)
8885           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8886           if (size || pi)
8887             emitcode ("inc", "dptr");
8888         }
8889     }
8890
8891   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8892     {
8893     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8894     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8895     pi->generated = 1;
8896   }
8897
8898   if (ifx && !ifx->generated)
8899     {
8900       genIfxJump (ifx, "a", left, NULL, result);
8901     }
8902
8903
8904   freeAsmop (left, NULL, ic, TRUE);
8905   freeAsmop (result, NULL, ic, TRUE);
8906 }
8907
8908 /*-----------------------------------------------------------------*/
8909 /* genPointerGet - generate code for pointer get                   */
8910 /*-----------------------------------------------------------------*/
8911 static void
8912 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
8913 {
8914   operand *left, *result;
8915   sym_link *type, *etype;
8916   int p_type;
8917
8918   D(emitcode (";     genPointerGet",""));
8919
8920   left = IC_LEFT (ic);
8921   result = IC_RESULT (ic);
8922
8923   if (getSize (operandType (result))>1)
8924     ifx = NULL;
8925
8926   /* depending on the type of pointer we need to
8927      move it to the correct pointer register */
8928   type = operandType (left);
8929   etype = getSpec (type);
8930   /* if left is of type of pointer then it is simple */
8931   if (IS_PTR (type) && !IS_FUNC (type->next))
8932     p_type = DCL_TYPE (type);
8933   else
8934     {
8935       /* we have to go by the storage class */
8936       p_type = PTR_TYPE (SPEC_OCLS (etype));
8937     }
8938
8939   /* special case when cast remat */
8940   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
8941       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
8942           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
8943           type = operandType (left);
8944           p_type = DCL_TYPE (type);
8945   }
8946   /* now that we have the pointer type we assign
8947      the pointer values */
8948   switch (p_type)
8949     {
8950
8951     case POINTER:
8952     case IPOINTER:
8953       genNearPointerGet (left, result, ic, pi, ifx);
8954       break;
8955
8956     case PPOINTER:
8957       genPagedPointerGet (left, result, ic, pi, ifx);
8958       break;
8959
8960     case FPOINTER:
8961       genFarPointerGet (left, result, ic, pi, ifx);
8962       break;
8963
8964     case CPOINTER:
8965       genCodePointerGet (left, result, ic, pi, ifx);
8966       break;
8967
8968     case GPOINTER:
8969       genGenPointerGet (left, result, ic, pi, ifx);
8970       break;
8971     }
8972
8973 }
8974
8975
8976
8977 /*-----------------------------------------------------------------*/
8978 /* genPackBits - generates code for packed bit storage             */
8979 /*-----------------------------------------------------------------*/
8980 static void
8981 genPackBits (sym_link * etype,
8982              operand * right,
8983              char *rname, int p_type)
8984 {
8985   int offset = 0;       /* source byte offset */
8986   int rlen = 0;         /* remaining bitfield length */
8987   int blen;             /* bitfield length */
8988   int bstr;             /* bitfield starting bit within byte */
8989   int litval;           /* source literal value (if AOP_LIT) */
8990   unsigned char mask;   /* bitmask within current byte */
8991
8992   D(emitcode (";     genPackBits",""));
8993
8994   blen = SPEC_BLEN (etype);
8995   bstr = SPEC_BSTR (etype);
8996
8997   /* If the bitfield length is less than a byte */
8998   if (blen < 8)
8999     {
9000       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9001               (unsigned char) (0xFF >> (8 - bstr)));
9002
9003       if (AOP_TYPE (right) == AOP_LIT)
9004         {
9005           /* Case with a bitfield length <8 and literal source
9006           */
9007           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9008           litval <<= bstr;
9009           litval &= (~mask) & 0xff;
9010           emitPtrByteGet (rname, p_type, FALSE);
9011           if ((mask|litval)!=0xff)
9012             emitcode ("anl","a,#0x%02x", mask);
9013           if (litval)
9014             emitcode ("orl","a,#0x%02x", litval);
9015         }
9016       else
9017         {
9018           if ((blen==1) && (p_type!=GPOINTER))
9019             {
9020               /* Case with a bitfield length == 1 and no generic pointer
9021               */
9022               if (AOP_TYPE (right) == AOP_CRY)
9023                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9024               else
9025                 {
9026                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
9027                   emitcode ("rrc","a");
9028                 }
9029               emitPtrByteGet (rname, p_type, FALSE);
9030               emitcode ("mov","acc.%d,c",bstr);
9031             }
9032           else
9033             {
9034               bool pushedB;
9035               /* Case with a bitfield length < 8 and arbitrary source
9036               */
9037               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
9038               /* shift and mask source value */
9039               AccLsh (bstr);
9040               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9041
9042               pushedB = pushB ();
9043               /* transfer A to B and get next byte */
9044               emitPtrByteGet (rname, p_type, TRUE);
9045
9046               emitcode ("anl", "a,#0x%02x", mask);
9047               emitcode ("orl", "a,b");
9048               if (p_type == GPOINTER)
9049                 emitcode ("pop", "b");
9050
9051               popB (pushedB);
9052            }
9053         }
9054
9055       emitPtrByteSet (rname, p_type, "a");
9056       return;
9057     }
9058
9059   /* Bit length is greater than 7 bits. In this case, copy  */
9060   /* all except the partial byte at the end                 */
9061   for (rlen=blen;rlen>=8;rlen-=8)
9062     {
9063       emitPtrByteSet (rname, p_type,
9064                       aopGet (AOP (right), offset++, FALSE, TRUE) );
9065       if (rlen>8)
9066         emitcode ("inc", "%s", rname);
9067     }
9068
9069   /* If there was a partial byte at the end */
9070   if (rlen)
9071     {
9072       mask = (((unsigned char) -1 << rlen) & 0xff);
9073
9074       if (AOP_TYPE (right) == AOP_LIT)
9075         {
9076           /* Case with partial byte and literal source
9077           */
9078           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9079           litval >>= (blen-rlen);
9080           litval &= (~mask) & 0xff;
9081           emitPtrByteGet (rname, p_type, FALSE);
9082           if ((mask|litval)!=0xff)
9083             emitcode ("anl","a,#0x%02x", mask);
9084           if (litval)
9085             emitcode ("orl","a,#0x%02x", litval);
9086         }
9087       else
9088         {
9089           bool pushedB;
9090           /* Case with partial byte and arbitrary source
9091           */
9092           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
9093           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9094
9095           pushedB = pushB ();
9096           /* transfer A to B and get next byte */
9097           emitPtrByteGet (rname, p_type, TRUE);
9098
9099           emitcode ("anl", "a,#0x%02x", mask);
9100           emitcode ("orl", "a,b");
9101           if (p_type == GPOINTER)
9102             emitcode ("pop", "b");
9103
9104           popB (pushedB);
9105         }
9106       emitPtrByteSet (rname, p_type, "a");
9107     }
9108
9109 }
9110
9111
9112 /*-----------------------------------------------------------------*/
9113 /* genDataPointerSet - remat pointer to data space                 */
9114 /*-----------------------------------------------------------------*/
9115 static void
9116 genDataPointerSet (operand * right,
9117                    operand * result,
9118                    iCode * ic)
9119 {
9120   int size, offset = 0;
9121   char *l, buffer[256];
9122
9123   D(emitcode (";     genDataPointerSet",""));
9124
9125   aopOp (right, ic, FALSE);
9126
9127   l = aopGet (AOP (result), 0, FALSE, TRUE);
9128   size = AOP_SIZE (right);
9129   while (size--)
9130     {
9131       if (offset)
9132         sprintf (buffer, "(%s + %d)", l + 1, offset);
9133       else
9134         sprintf (buffer, "%s", l + 1);
9135       emitcode ("mov", "%s,%s", buffer,
9136                 aopGet (AOP (right), offset++, FALSE, FALSE));
9137     }
9138
9139   freeAsmop (right, NULL, ic, TRUE);
9140   freeAsmop (result, NULL, ic, TRUE);
9141 }
9142
9143 /*-----------------------------------------------------------------*/
9144 /* genNearPointerSet - emitcode for near pointer put                */
9145 /*-----------------------------------------------------------------*/
9146 static void
9147 genNearPointerSet (operand * right,
9148                    operand * result,
9149                    iCode * ic,
9150                    iCode * pi)
9151 {
9152   asmop *aop = NULL;
9153   regs *preg = NULL;
9154   char *rname, *l;
9155   sym_link *retype, *letype;
9156   sym_link *ptype = operandType (result);
9157
9158   D(emitcode (";     genNearPointerSet",""));
9159
9160   retype = getSpec (operandType (right));
9161   letype = getSpec (ptype);
9162   aopOp (result, ic, FALSE);
9163
9164   /* if the result is rematerializable &
9165      in data space & not a bit variable */
9166   if (AOP_TYPE (result) == AOP_IMMD &&
9167       DCL_TYPE (ptype) == POINTER &&
9168       !IS_BITVAR (retype) &&
9169       !IS_BITVAR (letype))
9170     {
9171       genDataPointerSet (right, result, ic);
9172       return;
9173     }
9174
9175   /* if the value is already in a pointer register
9176      then don't need anything more */
9177   if (!AOP_INPREG (AOP (result)))
9178     {
9179         if (
9180             //AOP_TYPE (result) == AOP_STK
9181             IS_AOP_PREG(result)
9182             )
9183         {
9184             // Aha, it is a pointer, just in disguise.
9185             rname = aopGet (AOP (result), 0, FALSE, FALSE);
9186             if (*rname != '@')
9187             {
9188                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9189                         __FILE__, __LINE__);
9190             }
9191             else
9192             {
9193                 // Expected case.
9194                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9195                 rname++;  // skip the '@'.
9196             }
9197         }
9198         else
9199         {
9200             /* otherwise get a free pointer register */
9201             aop = newAsmop (0);
9202             preg = getFreePtr (ic, &aop, FALSE);
9203             emitcode ("mov", "%s,%s",
9204                       preg->name,
9205                       aopGet (AOP (result), 0, FALSE, TRUE));
9206             rname = preg->name;
9207         }
9208     }
9209     else
9210     {
9211         rname = aopGet (AOP (result), 0, FALSE, FALSE);
9212     }
9213
9214   aopOp (right, ic, FALSE);
9215
9216   /* if bitfield then unpack the bits */
9217   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9218     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9219   else
9220     {
9221       /* we have can just get the values */
9222       int size = AOP_SIZE (right);
9223       int offset = 0;
9224
9225       while (size--)
9226         {
9227           l = aopGet (AOP (right), offset, FALSE, TRUE);
9228           if (*l == '@')
9229             {
9230               MOVA (l);
9231               emitcode ("mov", "@%s,a", rname);
9232             }
9233           else
9234             emitcode ("mov", "@%s,%s", rname, l);
9235           if (size || pi)
9236             emitcode ("inc", "%s", rname);
9237           offset++;
9238         }
9239     }
9240
9241   /* now some housekeeping stuff */
9242   if (aop) /* we had to allocate for this iCode */
9243     {
9244       if (pi)
9245         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9246       freeAsmop (NULL, aop, ic, TRUE);
9247     }
9248   else
9249     {
9250       /* we did not allocate which means left
9251          already in a pointer register, then
9252          if size > 0 && this could be used again
9253          we have to point it back to where it
9254          belongs */
9255       if ((AOP_SIZE (right) > 1 &&
9256            !OP_SYMBOL (result)->remat &&
9257            (OP_SYMBOL (result)->liveTo > ic->seq ||
9258             ic->depth)) &&
9259           !pi)
9260         {
9261           int size = AOP_SIZE (right) - 1;
9262           while (size--)
9263             emitcode ("dec", "%s", rname);
9264         }
9265     }
9266
9267   /* done */
9268   if (pi) pi->generated = 1;
9269   freeAsmop (result, NULL, ic, TRUE);
9270   freeAsmop (right, NULL, ic, TRUE);
9271 }
9272
9273 /*-----------------------------------------------------------------*/
9274 /* genPagedPointerSet - emitcode for Paged pointer put             */
9275 /*-----------------------------------------------------------------*/
9276 static void
9277 genPagedPointerSet (operand * right,
9278                     operand * result,
9279                     iCode * ic,
9280                     iCode * pi)
9281 {
9282   asmop *aop = NULL;
9283   regs *preg = NULL;
9284   char *rname, *l;
9285   sym_link *retype, *letype;
9286
9287   D(emitcode (";     genPagedPointerSet",""));
9288
9289   retype = getSpec (operandType (right));
9290   letype = getSpec (operandType (result));
9291
9292   aopOp (result, ic, FALSE);
9293
9294   /* if the value is already in a pointer register
9295      then don't need anything more */
9296   if (!AOP_INPREG (AOP (result)))
9297     {
9298       /* otherwise get a free pointer register */
9299       aop = newAsmop (0);
9300       preg = getFreePtr (ic, &aop, FALSE);
9301       emitcode ("mov", "%s,%s",
9302                 preg->name,
9303                 aopGet (AOP (result), 0, FALSE, TRUE));
9304       rname = preg->name;
9305     }
9306   else
9307     rname = aopGet (AOP (result), 0, FALSE, FALSE);
9308
9309   aopOp (right, ic, FALSE);
9310
9311   /* if bitfield then unpack the bits */
9312   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9313     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9314   else
9315     {
9316       /* we have can just get the values */
9317       int size = AOP_SIZE (right);
9318       int offset = 0;
9319
9320       while (size--)
9321         {
9322           l = aopGet (AOP (right), offset, FALSE, TRUE);
9323
9324           MOVA (l);
9325           emitcode ("movx", "@%s,a", rname);
9326
9327           if (size || pi)
9328             emitcode ("inc", "%s", rname);
9329
9330           offset++;
9331         }
9332     }
9333
9334   /* now some housekeeping stuff */
9335   if (aop) /* we had to allocate for this iCode */
9336     {
9337       if (pi)
9338         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9339       freeAsmop (NULL, aop, ic, TRUE);
9340     }
9341   else
9342     {
9343       /* we did not allocate which means left
9344          already in a pointer register, then
9345          if size > 0 && this could be used again
9346          we have to point it back to where it
9347          belongs */
9348       if (AOP_SIZE (right) > 1 &&
9349           !OP_SYMBOL (result)->remat &&
9350           (OP_SYMBOL (result)->liveTo > ic->seq ||
9351            ic->depth))
9352         {
9353           int size = AOP_SIZE (right) - 1;
9354           while (size--)
9355             emitcode ("dec", "%s", rname);
9356         }
9357     }
9358
9359   /* done */
9360   if (pi) pi->generated = 1;
9361   freeAsmop (result, NULL, ic, TRUE);
9362   freeAsmop (right, NULL, ic, TRUE);
9363
9364
9365 }
9366
9367 /*-----------------------------------------------------------------*/
9368 /* genFarPointerSet - set value from far space                     */
9369 /*-----------------------------------------------------------------*/
9370 static void
9371 genFarPointerSet (operand * right,
9372                   operand * result, iCode * ic, iCode * pi)
9373 {
9374   int size, offset;
9375   sym_link *retype = getSpec (operandType (right));
9376   sym_link *letype = getSpec (operandType (result));
9377
9378   D(emitcode (";     genFarPointerSet",""));
9379
9380   aopOp (result, ic, FALSE);
9381   loadDptrFromOperand (result, FALSE);
9382
9383   /* so dptr know contains the address */
9384   aopOp (right, ic, FALSE);
9385
9386   /* if bit then unpack */
9387   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9388     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9389   else
9390     {
9391       size = AOP_SIZE (right);
9392       offset = 0;
9393
9394       while (size--)
9395         {
9396           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9397           MOVA (l);
9398           emitcode ("movx", "@dptr,a");
9399           if (size || pi)
9400             emitcode ("inc", "dptr");
9401         }
9402     }
9403   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9404     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9405     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9406     pi->generated=1;
9407   }
9408   freeAsmop (result, NULL, ic, TRUE);
9409   freeAsmop (right, NULL, ic, TRUE);
9410 }
9411
9412 /*-----------------------------------------------------------------*/
9413 /* genGenPointerSet - set value from generic pointer space         */
9414 /*-----------------------------------------------------------------*/
9415 static void
9416 genGenPointerSet (operand * right,
9417                   operand * result, iCode * ic, iCode * pi)
9418 {
9419   int size, offset;
9420   sym_link *retype = getSpec (operandType (right));
9421   sym_link *letype = getSpec (operandType (result));
9422
9423   D(emitcode (";     genGenPointerSet",""));
9424
9425   aopOp (result, ic, FALSE);
9426   loadDptrFromOperand (result, TRUE);
9427
9428   /* so dptr know contains the address */
9429   aopOp (right, ic, FALSE);
9430
9431   /* if bit then unpack */
9432   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9433     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9434   else
9435     {
9436       size = AOP_SIZE (right);
9437       offset = 0;
9438
9439       while (size--)
9440         {
9441           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9442           MOVA (l);
9443           emitcode ("lcall", "__gptrput");
9444           if (size || pi)
9445             emitcode ("inc", "dptr");
9446         }
9447     }
9448
9449   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9450     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9451     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9452     pi->generated=1;
9453   }
9454   freeAsmop (result, NULL, ic, TRUE);
9455   freeAsmop (right, NULL, ic, TRUE);
9456 }
9457
9458 /*-----------------------------------------------------------------*/
9459 /* genPointerSet - stores the value into a pointer location        */
9460 /*-----------------------------------------------------------------*/
9461 static void
9462 genPointerSet (iCode * ic, iCode *pi)
9463 {
9464   operand *right, *result;
9465   sym_link *type, *etype;
9466   int p_type;
9467
9468   D(emitcode (";     genPointerSet",""));
9469
9470   right = IC_RIGHT (ic);
9471   result = IC_RESULT (ic);
9472
9473   /* depending on the type of pointer we need to
9474      move it to the correct pointer register */
9475   type = operandType (result);
9476   etype = getSpec (type);
9477   /* if left is of type of pointer then it is simple */
9478   if (IS_PTR (type) && !IS_FUNC (type->next))
9479     {
9480       p_type = DCL_TYPE (type);
9481     }
9482   else
9483     {
9484       /* we have to go by the storage class */
9485       p_type = PTR_TYPE (SPEC_OCLS (etype));
9486     }
9487
9488   /* special case when cast remat */
9489   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9490       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9491           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9492           type = operandType (result);
9493           p_type = DCL_TYPE (type);
9494   }
9495   /* now that we have the pointer type we assign
9496      the pointer values */
9497   switch (p_type)
9498     {
9499
9500     case POINTER:
9501     case IPOINTER:
9502       genNearPointerSet (right, result, ic, pi);
9503       break;
9504
9505     case PPOINTER:
9506       genPagedPointerSet (right, result, ic, pi);
9507       break;
9508
9509     case FPOINTER:
9510       genFarPointerSet (right, result, ic, pi);
9511       break;
9512
9513     case GPOINTER:
9514       genGenPointerSet (right, result, ic, pi);
9515       break;
9516
9517     default:
9518       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9519               "genPointerSet: illegal pointer type");
9520     }
9521
9522 }
9523
9524 /*-----------------------------------------------------------------*/
9525 /* genIfx - generate code for Ifx statement                        */
9526 /*-----------------------------------------------------------------*/
9527 static void
9528 genIfx (iCode * ic, iCode * popIc)
9529 {
9530   operand *cond = IC_COND (ic);
9531   int isbit = 0;
9532
9533   D(emitcode (";     genIfx",""));
9534
9535   aopOp (cond, ic, FALSE);
9536
9537   /* get the value into acc */
9538   if (AOP_TYPE (cond) != AOP_CRY)
9539     toBoolean (cond);
9540   else
9541     isbit = 1;
9542   /* the result is now in the accumulator */
9543   freeAsmop (cond, NULL, ic, TRUE);
9544
9545   /* if there was something to be popped then do it */
9546   if (popIc)
9547     genIpop (popIc);
9548
9549   /* if the condition is a bit variable */
9550   if (isbit && IS_ITEMP (cond) &&
9551       SPIL_LOC (cond))
9552     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9553   else if (isbit && !IS_ITEMP (cond))
9554     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9555   else
9556     genIfxJump (ic, "a", NULL, NULL, NULL);
9557
9558   ic->generated = 1;
9559 }
9560
9561 /*-----------------------------------------------------------------*/
9562 /* genAddrOf - generates code for address of                       */
9563 /*-----------------------------------------------------------------*/
9564 static void
9565 genAddrOf (iCode * ic)
9566 {
9567   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9568   int size, offset;
9569
9570   D(emitcode (";     genAddrOf",""));
9571
9572   aopOp (IC_RESULT (ic), ic, FALSE);
9573
9574   /* if the operand is on the stack then we
9575      need to get the stack offset of this
9576      variable */
9577   if (sym->onStack)
9578     {
9579       /* if it has an offset then we need to compute
9580          it */
9581       if (sym->stack)
9582         {
9583           emitcode ("mov", "a,_bp");
9584           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9585                                          ((char) (sym->stack - _G.nRegsSaved)) :
9586                                          ((char) sym->stack)) & 0xff);
9587           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9588         }
9589       else
9590         {
9591           /* we can just move _bp */
9592           aopPut (AOP (IC_RESULT (ic)), "_bp", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9593         }
9594       /* fill the result with zero */
9595       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9596
9597       offset = 1;
9598       while (size--)
9599         {
9600           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9601         }
9602
9603       goto release;
9604     }
9605
9606   /* object not on stack then we need the name */
9607   size = AOP_SIZE (IC_RESULT (ic));
9608   offset = 0;
9609
9610   while (size--)
9611     {
9612       char s[SDCC_NAME_MAX];
9613       if (offset)
9614         sprintf (s, "#(%s >> %d)",
9615                  sym->rname,
9616                  offset * 8);
9617       else
9618         sprintf (s, "#%s", sym->rname);
9619       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9620     }
9621
9622 release:
9623   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9624
9625 }
9626
9627 /*-----------------------------------------------------------------*/
9628 /* genFarFarAssign - assignment when both are in far space         */
9629 /*-----------------------------------------------------------------*/
9630 static void
9631 genFarFarAssign (operand * result, operand * right, iCode * ic)
9632 {
9633   int size = AOP_SIZE (right);
9634   int offset = 0;
9635   char *l;
9636
9637   D(emitcode (";     genFarFarAssign",""));
9638
9639   /* first push the right side on to the stack */
9640   while (size--)
9641     {
9642       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9643       MOVA (l);
9644       emitcode ("push", "acc");
9645     }
9646
9647   freeAsmop (right, NULL, ic, FALSE);
9648   /* now assign DPTR to result */
9649   aopOp (result, ic, FALSE);
9650   size = AOP_SIZE (result);
9651   while (size--)
9652     {
9653       emitcode ("pop", "acc");
9654       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9655     }
9656   freeAsmop (result, NULL, ic, FALSE);
9657
9658 }
9659
9660 /*-----------------------------------------------------------------*/
9661 /* genAssign - generate code for assignment                        */
9662 /*-----------------------------------------------------------------*/
9663 static void
9664 genAssign (iCode * ic)
9665 {
9666   operand *result, *right;
9667   int size, offset;
9668   unsigned long lit = 0L;
9669
9670   D(emitcode(";     genAssign",""));
9671
9672   result = IC_RESULT (ic);
9673   right = IC_RIGHT (ic);
9674
9675   /* if they are the same */
9676   if (operandsEqu (result, right) &&
9677       !isOperandVolatile (result, FALSE) &&
9678       !isOperandVolatile (right, FALSE))
9679     return;
9680
9681   aopOp (right, ic, FALSE);
9682
9683   /* special case both in far space */
9684   if (AOP_TYPE (right) == AOP_DPTR &&
9685       IS_TRUE_SYMOP (result) &&
9686       isOperandInFarSpace (result))
9687     {
9688
9689       genFarFarAssign (result, right, ic);
9690       return;
9691     }
9692
9693   aopOp (result, ic, TRUE);
9694
9695   /* if they are the same registers */
9696   if (sameRegs (AOP (right), AOP (result)) &&
9697       !isOperandVolatile (result, FALSE) &&
9698       !isOperandVolatile (right, FALSE))
9699     goto release;
9700
9701   /* if the result is a bit */
9702   if (AOP_TYPE (result) == AOP_CRY)
9703     {
9704
9705       /* if the right size is a literal then
9706          we know what the value is */
9707       if (AOP_TYPE (right) == AOP_LIT)
9708         {
9709           if (((int) operandLitValue (right)))
9710             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9711           else
9712             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9713           goto release;
9714         }
9715
9716       /* the right is also a bit variable */
9717       if (AOP_TYPE (right) == AOP_CRY)
9718         {
9719           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9720           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9721           goto release;
9722         }
9723
9724       /* we need to or */
9725       toBoolean (right);
9726       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9727       goto release;
9728     }
9729
9730   /* bit variables done */
9731   /* general case */
9732   size = AOP_SIZE (result);
9733   offset = 0;
9734   if (AOP_TYPE (right) == AOP_LIT)
9735     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9736   if ((size > 1) &&
9737       (AOP_TYPE (result) != AOP_REG) &&
9738       (AOP_TYPE (right) == AOP_LIT) &&
9739       !IS_FLOAT (operandType (right)) &&
9740       (lit < 256L))
9741     {
9742       while ((size) && (lit))
9743         {
9744           aopPut (AOP (result),
9745                   aopGet (AOP (right), offset, FALSE, FALSE),
9746                   offset,
9747                   isOperandVolatile (result, FALSE));
9748           lit >>= 8;
9749           offset++;
9750           size--;
9751         }
9752       emitcode ("clr", "a");
9753       while (size--)
9754         {
9755           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
9756           offset++;
9757         }
9758     }
9759   else
9760     {
9761       while (size--)
9762         {
9763           aopPut (AOP (result),
9764                   aopGet (AOP (right), offset, FALSE, FALSE),
9765                   offset,
9766                   isOperandVolatile (result, FALSE));
9767           offset++;
9768         }
9769     }
9770
9771 release:
9772   freeAsmop (right, NULL, ic, TRUE);
9773   freeAsmop (result, NULL, ic, TRUE);
9774 }
9775
9776 /*-----------------------------------------------------------------*/
9777 /* genJumpTab - genrates code for jump table                       */
9778 /*-----------------------------------------------------------------*/
9779 static void
9780 genJumpTab (iCode * ic)
9781 {
9782   symbol *jtab,*jtablo,*jtabhi;
9783   char *l;
9784   unsigned int count;
9785
9786   D(emitcode (";     genJumpTab",""));
9787
9788   count = elementsInSet( IC_JTLABELS (ic) );
9789
9790   if( count <= 16 )
9791     {
9792       /* this algorithm needs 9 cycles and 7 + 3*n bytes
9793          if the switch argument is in a register.
9794          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
9795       /* (MB) What if peephole converts ljmp to sjmp or ret ???
9796          How will multiply by three be updated ???*/
9797       aopOp (IC_JTCOND (ic), ic, FALSE);
9798       /* get the condition into accumulator */
9799       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9800       MOVA (l);
9801       /* multiply by three */
9802       emitcode ("add", "a,acc");
9803       emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9804       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9805
9806       jtab = newiTempLabel (NULL);
9807       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9808       emitcode ("jmp", "@a+dptr");
9809       emitcode ("", "%05d$:", jtab->key + 100);
9810       /* now generate the jump labels */
9811       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9812            jtab = setNextItem (IC_JTLABELS (ic)))
9813         emitcode ("ljmp", "%05d$", jtab->key + 100);
9814     }
9815   else
9816     {
9817       /* this algorithm needs 14 cycles and 13 + 2*n bytes
9818          if the switch argument is in a register.
9819          For n>6 this algorithm may be more compact */
9820       jtablo = newiTempLabel (NULL);
9821       jtabhi = newiTempLabel (NULL);
9822
9823       /* get the condition into accumulator.
9824          Using b as temporary storage, if register push/pop is needed */
9825       aopOp (IC_JTCOND (ic), ic, FALSE);
9826       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9827       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
9828           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
9829         {
9830           // (MB) what if B is in use???
9831           wassertl(!_G.BInUse, "B was in use");
9832           emitcode ("mov", "b,%s", l);
9833           l = "b";
9834         }
9835       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9836       MOVA (l);
9837       if( count <= 112 )
9838         {
9839           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
9840           emitcode ("movc", "a,@a+pc");
9841           emitcode ("push", "acc");
9842
9843           MOVA (l);
9844           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
9845           emitcode ("movc", "a,@a+pc");
9846           emitcode ("push", "acc");
9847         }
9848       else
9849         {
9850           /* this scales up to n<=255, but needs two more bytes
9851              and changes dptr */
9852           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
9853           emitcode ("movc", "a,@a+dptr");
9854           emitcode ("push", "acc");
9855
9856           MOVA (l);
9857           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
9858           emitcode ("movc", "a,@a+dptr");
9859           emitcode ("push", "acc");
9860         }
9861
9862       emitcode ("ret", "");
9863
9864       /* now generate jump table, LSB */
9865       emitcode ("", "%05d$:", jtablo->key + 100);
9866       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9867            jtab = setNextItem (IC_JTLABELS (ic)))
9868         emitcode (".db", "%05d$", jtab->key + 100);
9869
9870       /* now generate jump table, MSB */
9871       emitcode ("", "%05d$:", jtabhi->key + 100);
9872       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9873            jtab = setNextItem (IC_JTLABELS (ic)))
9874          emitcode (".db", "%05d$>>8", jtab->key + 100);
9875     }
9876 }
9877
9878 /*-----------------------------------------------------------------*/
9879 /* genCast - gen code for casting                                  */
9880 /*-----------------------------------------------------------------*/
9881 static void
9882 genCast (iCode * ic)
9883 {
9884   operand *result = IC_RESULT (ic);
9885   sym_link *ctype = operandType (IC_LEFT (ic));
9886   sym_link *rtype = operandType (IC_RIGHT (ic));
9887   operand *right = IC_RIGHT (ic);
9888   int size, offset;
9889
9890   D(emitcode(";     genCast",""));
9891
9892   /* if they are equivalent then do nothing */
9893   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9894     return;
9895
9896   aopOp (right, ic, FALSE);
9897   aopOp (result, ic, FALSE);
9898
9899   /* if the result is a bit (and not a bitfield) */
9900   // if (AOP_TYPE (result) == AOP_CRY)
9901   if (IS_BITVAR (OP_SYMBOL (result)->type)
9902       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
9903     {
9904       /* if the right size is a literal then
9905          we know what the value is */
9906       if (AOP_TYPE (right) == AOP_LIT)
9907         {
9908           if (((int) operandLitValue (right)))
9909             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9910           else
9911             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9912
9913           goto release;
9914         }
9915
9916       /* the right is also a bit variable */
9917       if (AOP_TYPE (right) == AOP_CRY)
9918         {
9919           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9920           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9921           goto release;
9922         }
9923
9924       /* we need to or */
9925       toBoolean (right);
9926       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9927       goto release;
9928     }
9929
9930
9931   /* if they are the same size : or less */
9932   if (AOP_SIZE (result) <= AOP_SIZE (right))
9933     {
9934
9935       /* if they are in the same place */
9936       if (sameRegs (AOP (right), AOP (result)))
9937         goto release;
9938
9939       /* if they in different places then copy */
9940       size = AOP_SIZE (result);
9941       offset = 0;
9942       while (size--)
9943         {
9944           aopPut (AOP (result),
9945                   aopGet (AOP (right), offset, FALSE, FALSE),
9946                   offset,
9947                   isOperandVolatile (result, FALSE));
9948           offset++;
9949         }
9950       goto release;
9951     }
9952
9953
9954   /* if the result is of type pointer */
9955   if (IS_PTR (ctype))
9956     {
9957
9958       int p_type;
9959       sym_link *type = operandType (right);
9960       sym_link *etype = getSpec (type);
9961
9962       /* pointer to generic pointer */
9963       if (IS_GENPTR (ctype))
9964         {
9965           if (IS_PTR (type))
9966             p_type = DCL_TYPE (type);
9967           else
9968             {
9969               if (SPEC_SCLS(etype)==S_REGISTER) {
9970                 // let's assume it is a generic pointer
9971                 p_type=GPOINTER;
9972               } else {
9973                 /* we have to go by the storage class */
9974                 p_type = PTR_TYPE (SPEC_OCLS (etype));
9975               }
9976             }
9977
9978           /* the first two bytes are known */
9979           size = GPTRSIZE - 1;
9980           offset = 0;
9981           while (size--)
9982             {
9983               aopPut (AOP (result),
9984                       aopGet (AOP (right), offset, FALSE, FALSE),
9985                       offset,
9986                       isOperandVolatile (result, FALSE));
9987               offset++;
9988             }
9989           /* the last byte depending on type */
9990             {
9991                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
9992                 char gpValStr[10];
9993
9994                 if (gpVal == -1)
9995                 {
9996                     // pointerTypeToGPByte will have bitched.
9997                     exit(1);
9998                 }
9999
10000                 sprintf(gpValStr, "#0x%d", gpVal);
10001                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10002             }
10003           goto release;
10004         }
10005
10006       /* just copy the pointers */
10007       size = AOP_SIZE (result);
10008       offset = 0;
10009       while (size--)
10010         {
10011           aopPut (AOP (result),
10012                   aopGet (AOP (right), offset, FALSE, FALSE),
10013                   offset,
10014                   isOperandVolatile (result, FALSE));
10015           offset++;
10016         }
10017       goto release;
10018     }
10019
10020   /* so we now know that the size of destination is greater
10021      than the size of the source */
10022   /* we move to result for the size of source */
10023   size = AOP_SIZE (right);
10024   offset = 0;
10025   while (size--)
10026     {
10027       aopPut (AOP (result),
10028               aopGet (AOP (right), offset, FALSE, FALSE),
10029               offset,
10030               isOperandVolatile (result, FALSE));
10031       offset++;
10032     }
10033
10034   /* now depending on the sign of the source && destination */
10035   size = AOP_SIZE (result) - AOP_SIZE (right);
10036   /* if unsigned or not an integral type */
10037   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10038     {
10039       while (size--)
10040         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
10041     }
10042   else
10043     {
10044       /* we need to extend the sign :{ */
10045       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
10046                         FALSE, FALSE);
10047       MOVA (l);
10048       emitcode ("rlc", "a");
10049       emitcode ("subb", "a,acc");
10050       while (size--)
10051         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
10052     }
10053
10054   /* we are done hurray !!!! */
10055
10056 release:
10057   freeAsmop (right, NULL, ic, TRUE);
10058   freeAsmop (result, NULL, ic, TRUE);
10059
10060 }
10061
10062 /*-----------------------------------------------------------------*/
10063 /* genDjnz - generate decrement & jump if not zero instrucion      */
10064 /*-----------------------------------------------------------------*/
10065 static int
10066 genDjnz (iCode * ic, iCode * ifx)
10067 {
10068   symbol *lbl, *lbl1;
10069   if (!ifx)
10070     return 0;
10071
10072   D(emitcode (";     genDjnz",""));
10073
10074   /* if the if condition has a false label
10075      then we cannot save */
10076   if (IC_FALSE (ifx))
10077     return 0;
10078
10079   /* if the minus is not of the form
10080      a = a - 1 */
10081   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10082       !IS_OP_LITERAL (IC_RIGHT (ic)))
10083     return 0;
10084
10085   if (operandLitValue (IC_RIGHT (ic)) != 1)
10086     return 0;
10087
10088   /* if the size of this greater than one then no
10089      saving */
10090   if (getSize (operandType (IC_RESULT (ic))) > 1)
10091     return 0;
10092
10093   /* otherwise we can save BIG */
10094   lbl = newiTempLabel (NULL);
10095   lbl1 = newiTempLabel (NULL);
10096
10097   aopOp (IC_RESULT (ic), ic, FALSE);
10098
10099   if (AOP_NEEDSACC(IC_RESULT(ic)))
10100   {
10101       /* If the result is accessed indirectly via
10102        * the accumulator, we must explicitly write
10103        * it back after the decrement.
10104        */
10105       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
10106
10107       if (strcmp(rByte, "a"))
10108       {
10109            /* Something is hopelessly wrong */
10110            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10111                    __FILE__, __LINE__);
10112            /* We can just give up; the generated code will be inefficient,
10113             * but what the hey.
10114             */
10115            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10116            return 0;
10117       }
10118       emitcode ("dec", "%s", rByte);
10119       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10120       emitcode ("jnz", "%05d$", lbl->key + 100);
10121   }
10122   else if (IS_AOP_PREG (IC_RESULT (ic)))
10123     {
10124       emitcode ("dec", "%s",
10125                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
10126       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
10127       emitcode ("jnz", "%05d$", lbl->key + 100);
10128     }
10129   else
10130     {
10131       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
10132                 lbl->key + 100);
10133     }
10134   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10135   emitcode ("", "%05d$:", lbl->key + 100);
10136   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10137   emitcode ("", "%05d$:", lbl1->key + 100);
10138
10139   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10140   ifx->generated = 1;
10141   return 1;
10142 }
10143
10144 /*-----------------------------------------------------------------*/
10145 /* genReceive - generate code for a receive iCode                  */
10146 /*-----------------------------------------------------------------*/
10147 static void
10148 genReceive (iCode * ic)
10149 {
10150     int size = getSize (operandType (IC_RESULT (ic)));
10151     int offset = 0;
10152   D(emitcode (";     genReceive",""));
10153
10154   if (ic->argreg == 1) { /* first parameter */
10155       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10156           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10157            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
10158
10159           regs *tempRegs[4];
10160           int receivingA = 0;
10161           int roffset = 0;
10162
10163           for (offset = 0; offset<size; offset++)
10164             if (!strcmp (fReturn[offset], "a"))
10165               receivingA = 1;
10166
10167           if (!receivingA)
10168             {
10169               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10170                 {
10171                   for (offset = size-1; offset>0; offset--)
10172                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10173                   emitcode("mov","a,%s", fReturn[0]);
10174                   _G.accInUse++;
10175                   aopOp (IC_RESULT (ic), ic, FALSE);
10176                   _G.accInUse--;
10177                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
10178                           isOperandVolatile (IC_RESULT (ic), FALSE));
10179                   for (offset = 1; offset<size; offset++)
10180                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
10181                             isOperandVolatile (IC_RESULT (ic), FALSE));
10182                   goto release;
10183                 }
10184             }
10185           else
10186             {
10187               if (getTempRegs(tempRegs, size, ic))
10188                 {
10189                   for (offset = 0; offset<size; offset++)
10190                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10191                   aopOp (IC_RESULT (ic), ic, FALSE);
10192                   for (offset = 0; offset<size; offset++)
10193                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
10194                             isOperandVolatile (IC_RESULT (ic), FALSE));
10195                   goto release;
10196                 }
10197             }
10198
10199           offset = fReturnSizeMCS51 - size;
10200           while (size--) {
10201               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10202                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10203               offset++;
10204           }
10205           aopOp (IC_RESULT (ic), ic, FALSE);
10206           size = AOP_SIZE (IC_RESULT (ic));
10207           offset = 0;
10208           while (size--) {
10209               emitcode ("pop", "acc");
10210               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10211           }
10212
10213       } else {
10214           _G.accInUse++;
10215           aopOp (IC_RESULT (ic), ic, FALSE);
10216           _G.accInUse--;
10217           assignResultValue (IC_RESULT (ic));
10218       }
10219   } else { /* second receive onwards */
10220       int rb1off ;
10221       aopOp (IC_RESULT (ic), ic, FALSE);
10222       rb1off = ic->argreg;
10223       while (size--) {
10224           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10225       }
10226   }
10227
10228 release:
10229   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10230 }
10231
10232 /*-----------------------------------------------------------------*/
10233 /* genDummyRead - generate code for dummy read of volatiles        */
10234 /*-----------------------------------------------------------------*/
10235 static void
10236 genDummyRead (iCode * ic)
10237 {
10238   operand *op;
10239   int size, offset;
10240
10241   D(emitcode(";     genDummyRead",""));
10242
10243   op = IC_RIGHT (ic);
10244   if (op && IS_SYMOP (op))
10245     {
10246       aopOp (op, ic, FALSE);
10247
10248       /* if the result is a bit */
10249       if (AOP_TYPE (op) == AOP_CRY)
10250         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10251       else
10252         {
10253           /* bit variables done */
10254           /* general case */
10255           size = AOP_SIZE (op);
10256           offset = 0;
10257           while (size--)
10258           {
10259             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10260             offset++;
10261           }
10262         }
10263
10264       freeAsmop (op, NULL, ic, TRUE);
10265     }
10266
10267   op = IC_LEFT (ic);
10268   if (op && IS_SYMOP (op))
10269     {
10270       aopOp (op, ic, FALSE);
10271
10272       /* if the result is a bit */
10273       if (AOP_TYPE (op) == AOP_CRY)
10274         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10275       else
10276         {
10277           /* bit variables done */
10278           /* general case */
10279           size = AOP_SIZE (op);
10280           offset = 0;
10281           while (size--)
10282           {
10283             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10284             offset++;
10285           }
10286         }
10287
10288       freeAsmop (op, NULL, ic, TRUE);
10289     }
10290 }
10291
10292 /*-----------------------------------------------------------------*/
10293 /* genCritical - generate code for start of a critical sequence    */
10294 /*-----------------------------------------------------------------*/
10295 static void
10296 genCritical (iCode *ic)
10297 {
10298   symbol *tlbl = newiTempLabel (NULL);
10299
10300   D(emitcode(";     genCritical",""));
10301
10302   if (IC_RESULT (ic))
10303     {
10304       aopOp (IC_RESULT (ic), ic, TRUE);
10305       aopPut (AOP (IC_RESULT (ic)), one, 0, 0);
10306       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10307       aopPut (AOP (IC_RESULT (ic)), zero, 0, 0);
10308       emitcode ("", "%05d$:", (tlbl->key + 100));
10309       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10310     }
10311   else
10312     {
10313       emitcode ("setb", "c");
10314       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10315       emitcode ("clr", "c");
10316       emitcode ("", "%05d$:", (tlbl->key + 100));
10317       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10318     }
10319 }
10320
10321 /*-----------------------------------------------------------------*/
10322 /* genEndCritical - generate code for end of a critical sequence   */
10323 /*-----------------------------------------------------------------*/
10324 static void
10325 genEndCritical (iCode *ic)
10326 {
10327   D(emitcode(";     genEndCritical",""));
10328
10329   if (IC_RIGHT (ic))
10330     {
10331       aopOp (IC_RIGHT (ic), ic, FALSE);
10332       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10333         {
10334           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10335           emitcode ("mov", "ea,c");
10336         }
10337       else
10338         {
10339           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10340             MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
10341           emitcode ("rrc", "a");
10342           emitcode ("mov", "ea,c");
10343         }
10344       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10345     }
10346   else
10347     {
10348       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10349       emitcode ("mov", "ea,c");
10350     }
10351 }
10352
10353 /*-----------------------------------------------------------------*/
10354 /* gen51Code - generate code for 8051 based controllers            */
10355 /*-----------------------------------------------------------------*/
10356 void
10357 gen51Code (iCode * lic)
10358 {
10359   iCode *ic;
10360   int cln = 0;
10361   /* int cseq = 0; */
10362
10363   _G.currentFunc = NULL;
10364   lineHead = lineCurr = NULL;
10365
10366   /* print the allocation information */
10367   if (allocInfo && currFunc)
10368     printAllocInfo (currFunc, codeOutFile);
10369   /* if debug information required */
10370   if (options.debug && currFunc)
10371     {
10372       debugFile->writeFunction (currFunc, lic);
10373     }
10374   /* stack pointer name */
10375   if (options.useXstack)
10376     spname = "_spx";
10377   else
10378     spname = "sp";
10379
10380
10381   for (ic = lic; ic; ic = ic->next)
10382     {
10383       _G.current_iCode = ic;
10384
10385       if (ic->lineno && cln != ic->lineno)
10386         {
10387           if (options.debug)
10388             {
10389               debugFile->writeCLine (ic);
10390             }
10391           if (!options.noCcodeInAsm) {
10392             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10393                       printCLine(ic->filename, ic->lineno));
10394           }
10395           cln = ic->lineno;
10396         }
10397       #if 0
10398       if (ic->seqPoint && ic->seqPoint != cseq)
10399         {
10400           emitcode ("", "; sequence point %d", ic->seqPoint);
10401           cseq = ic->seqPoint;
10402         }
10403       #endif
10404       if (options.iCodeInAsm) {
10405         char regsInUse[80];
10406         int i;
10407
10408         for (i=0; i<8; i++) {
10409           sprintf (&regsInUse[i],
10410                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10411         }
10412         regsInUse[i]=0;
10413         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10414       }
10415       /* if the result is marked as
10416          spilt and rematerializable or code for
10417          this has already been generated then
10418          do nothing */
10419       if (resultRemat (ic) || ic->generated)
10420         continue;
10421
10422       /* depending on the operation */
10423       switch (ic->op)
10424         {
10425         case '!':
10426           genNot (ic);
10427           break;
10428
10429         case '~':
10430           genCpl (ic);
10431           break;
10432
10433         case UNARYMINUS:
10434           genUminus (ic);
10435           break;
10436
10437         case IPUSH:
10438           genIpush (ic);
10439           break;
10440
10441         case IPOP:
10442           /* IPOP happens only when trying to restore a
10443              spilt live range, if there is an ifx statement
10444              following this pop then the if statement might
10445              be using some of the registers being popped which
10446              would destory the contents of the register so
10447              we need to check for this condition and handle it */
10448           if (ic->next &&
10449               ic->next->op == IFX &&
10450               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10451             genIfx (ic->next, ic);
10452           else
10453             genIpop (ic);
10454           break;
10455
10456         case CALL:
10457           genCall (ic);
10458           break;
10459
10460         case PCALL:
10461           genPcall (ic);
10462           break;
10463
10464         case FUNCTION:
10465           genFunction (ic);
10466           break;
10467
10468         case ENDFUNCTION:
10469           genEndFunction (ic);
10470           break;
10471
10472         case RETURN:
10473           genRet (ic);
10474           break;
10475
10476         case LABEL:
10477           genLabel (ic);
10478           break;
10479
10480         case GOTO:
10481           genGoto (ic);
10482           break;
10483
10484         case '+':
10485           genPlus (ic);
10486           break;
10487
10488         case '-':
10489           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10490             genMinus (ic);
10491           break;
10492
10493         case '*':
10494           genMult (ic);
10495           break;
10496
10497         case '/':
10498           genDiv (ic);
10499           break;
10500
10501         case '%':
10502           genMod (ic);
10503           break;
10504
10505         case '>':
10506           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10507           break;
10508
10509         case '<':
10510           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10511           break;
10512
10513         case LE_OP:
10514         case GE_OP:
10515         case NE_OP:
10516
10517           /* note these two are xlated by algebraic equivalence
10518              during parsing SDCC.y */
10519           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10520                   "got '>=' or '<=' shouldn't have come here");
10521           break;
10522
10523         case EQ_OP:
10524           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10525           break;
10526
10527         case AND_OP:
10528           genAndOp (ic);
10529           break;
10530
10531         case OR_OP:
10532           genOrOp (ic);
10533           break;
10534
10535         case '^':
10536           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10537           break;
10538
10539         case '|':
10540           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10541           break;
10542
10543         case BITWISEAND:
10544           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10545           break;
10546
10547         case INLINEASM:
10548           genInline (ic);
10549           break;
10550
10551         case RRC:
10552           genRRC (ic);
10553           break;
10554
10555         case RLC:
10556           genRLC (ic);
10557           break;
10558
10559         case GETHBIT:
10560           genGetHbit (ic);
10561           break;
10562
10563         case LEFT_OP:
10564           genLeftShift (ic);
10565           break;
10566
10567         case RIGHT_OP:
10568           genRightShift (ic);
10569           break;
10570
10571         case GET_VALUE_AT_ADDRESS:
10572           genPointerGet (ic,
10573                          hasInc (IC_LEFT (ic), ic,
10574                                  getSize (operandType (IC_RESULT (ic)))),
10575                          ifxForOp (IC_RESULT (ic), ic) );
10576           break;
10577
10578         case '=':
10579           if (POINTER_SET (ic))
10580             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10581           else
10582             genAssign (ic);
10583           break;
10584
10585         case IFX:
10586           genIfx (ic, NULL);
10587           break;
10588
10589         case ADDRESS_OF:
10590           genAddrOf (ic);
10591           break;
10592
10593         case JUMPTABLE:
10594           genJumpTab (ic);
10595           break;
10596
10597         case CAST:
10598           genCast (ic);
10599           break;
10600
10601         case RECEIVE:
10602           genReceive (ic);
10603           break;
10604
10605         case SEND:
10606           addSet (&_G.sendSet, ic);
10607           break;
10608
10609         case DUMMY_READ_VOLATILE:
10610           genDummyRead (ic);
10611           break;
10612
10613         case CRITICAL:
10614           genCritical (ic);
10615           break;
10616
10617         case ENDCRITICAL:
10618           genEndCritical (ic);
10619           break;
10620
10621         case SWAP:
10622           genSwap (ic);
10623           break;
10624
10625         default:
10626           ic = ic;
10627         }
10628     }
10629
10630   _G.current_iCode = NULL;
10631
10632   /* now we are ready to call the
10633      peep hole optimizer */
10634   if (!options.nopeep)
10635     peepHole (&lineHead);
10636
10637   /* now do the actual printing */
10638   printLine (lineHead, codeOutFile);
10639   return;
10640 }