(genAnd): accessing LSB/MSB by rotating acc
[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             {
5783               switch (posbit & 0x07)
5784                 {
5785                   case 0: emitcode ("rrc", "a");
5786                           break;
5787                   case 7: emitcode ("rlc", "a");
5788                           break;
5789                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
5790                           break;
5791                 }            
5792             }
5793           // if(left &  2^n)
5794           else
5795             {
5796               if (ifx)
5797                 {
5798                   SNPRINTF (buffer, sizeof(buffer),
5799                             "acc.%d", posbit & 0x07);
5800                   genIfxJump (ifx, buffer, left, right, result);
5801                 }
5802               else
5803                 {// what is this case? just found it in ds390/gen.c
5804                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
5805                 }
5806               goto release;
5807             }
5808         }
5809       else
5810         {
5811           symbol *tlbl = newiTempLabel (NULL);
5812           int sizel = AOP_SIZE (left);
5813           if (size)
5814             emitcode ("setb", "c");
5815           while (sizel--)
5816             {
5817               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5818                 {
5819                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5820                   // byte ==  2^n ?
5821                   if ((posbit = isLiteralBit (bytelit)) != 0)
5822                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5823                   else
5824                     {
5825                       if (bytelit != 0x0FFL)
5826                         emitcode ("anl", "a,%s",
5827                                   aopGet (AOP (right), offset, FALSE, TRUE));
5828                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5829                     }
5830                 }
5831               offset++;
5832             }
5833           // bit = left & literal
5834           if (size)
5835             {
5836               emitcode ("clr", "c");
5837               emitcode ("", "%05d$:", tlbl->key + 100);
5838             }
5839           // if(left & literal)
5840           else
5841             {
5842               if (ifx)
5843                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5844               else
5845                 emitcode ("", "%05d$:", tlbl->key + 100);
5846               goto release;
5847             }
5848         }
5849       outBitC (result);
5850       goto release;
5851     }
5852
5853   /* if left is same as result */
5854   if (sameRegs (AOP (result), AOP (left)))
5855     {
5856       for (; size--; offset++)
5857         {
5858           if (AOP_TYPE (right) == AOP_LIT)
5859             {
5860               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5861               if (bytelit == 0x0FF)
5862                 {
5863                   /* dummy read of volatile operand */
5864                   if (isOperandVolatile (left, FALSE))
5865                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5866                   else
5867                     continue;
5868                 }
5869               else if (bytelit == 0)
5870                 {
5871                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5872                 }
5873               else if (IS_AOP_PREG (result))
5874                 {
5875                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5876                   emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5877                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5878                 }
5879               else
5880                 emitcode ("anl", "%s,%s",
5881                           aopGet (AOP (left), offset, FALSE, TRUE),
5882                           aopGet (AOP (right), offset, FALSE, FALSE));
5883             }
5884           else
5885             {
5886               if (AOP_TYPE (left) == AOP_ACC)
5887                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5888               else
5889                 {
5890                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5891                   if (IS_AOP_PREG (result))
5892                     {
5893                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5894                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5895                     }
5896                   else
5897                     emitcode ("anl", "%s,a",
5898                               aopGet (AOP (left), offset, FALSE, TRUE));
5899                 }
5900             }
5901         }
5902     }
5903   else
5904     {
5905       // left & result in different registers
5906       if (AOP_TYPE (result) == AOP_CRY)
5907         {
5908           // result = bit
5909           // if(size), result in bit
5910           // if(!size && ifx), conditional oper: if(left & right)
5911           symbol *tlbl = newiTempLabel (NULL);
5912           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5913           if (size)
5914             emitcode ("setb", "c");
5915           while (sizer--)
5916             {
5917               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5918                 emitcode ("anl", "a,%s",
5919                           aopGet (AOP (right), offset, FALSE, FALSE));
5920               } else {
5921                 if (AOP_TYPE(left)==AOP_ACC) {
5922                   bool pushedB = pushB ();
5923                   emitcode("mov", "b,a");
5924                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5925                   emitcode("anl", "a,b");
5926                   popB (pushedB);
5927                 }else {
5928                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5929                   emitcode ("anl", "a,%s",
5930                             aopGet (AOP (left), offset, FALSE, FALSE));
5931                 }
5932               }
5933               emitcode ("jnz", "%05d$", tlbl->key + 100);
5934               offset++;
5935             }
5936           if (size)
5937             {
5938               CLRC;
5939               emitcode ("", "%05d$:", tlbl->key + 100);
5940               outBitC (result);
5941             }
5942           else if (ifx)
5943             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5944           else
5945             emitcode ("", "%05d$:", tlbl->key + 100);
5946         }
5947       else
5948         {
5949           for (; (size--); offset++)
5950             {
5951               // normal case
5952               // result = left & right
5953               if (AOP_TYPE (right) == AOP_LIT)
5954                 {
5955                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5956                   if (bytelit == 0x0FF)
5957                     {
5958                       aopPut (AOP (result),
5959                               aopGet (AOP (left), offset, FALSE, FALSE),
5960                               offset,
5961                               isOperandVolatile (result, FALSE));
5962                       continue;
5963                     }
5964                   else if (bytelit == 0)
5965                     {
5966                       /* dummy read of volatile operand */
5967                       if (isOperandVolatile (left, FALSE))
5968                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5969                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5970                       continue;
5971                     }
5972                 }
5973               // faster than result <- left, anl result,right
5974               // and better if result is SFR
5975               if (AOP_TYPE (left) == AOP_ACC)
5976                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5977               else
5978                 {
5979                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5980                   emitcode ("anl", "a,%s",
5981                             aopGet (AOP (left), offset, FALSE, FALSE));
5982                 }
5983               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5984             }
5985         }
5986     }
5987
5988 release:
5989   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5990   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5991   freeAsmop (result, NULL, ic, TRUE);
5992 }
5993
5994 /*-----------------------------------------------------------------*/
5995 /* genOr  - code for or                                            */
5996 /*-----------------------------------------------------------------*/
5997 static void
5998 genOr (iCode * ic, iCode * ifx)
5999 {
6000   operand *left, *right, *result;
6001   int size, offset = 0;
6002   unsigned long lit = 0L;
6003   int bytelit = 0;
6004
6005   D(emitcode (";     genOr",""));
6006
6007   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6008   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6009   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6010
6011 #ifdef DEBUG_TYPE
6012   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6013             AOP_TYPE (result),
6014             AOP_TYPE (left), AOP_TYPE (right));
6015   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6016             AOP_SIZE (result),
6017             AOP_SIZE (left), AOP_SIZE (right));
6018 #endif
6019
6020   /* if left is a literal & right is not then exchange them */
6021   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6022       AOP_NEEDSACC (left))
6023     {
6024       operand *tmp = right;
6025       right = left;
6026       left = tmp;
6027     }
6028
6029   /* if result = right then exchange them */
6030   if (sameRegs (AOP (result), AOP (right)))
6031     {
6032       operand *tmp = right;
6033       right = left;
6034       left = tmp;
6035     }
6036
6037   /* if right is bit then exchange them */
6038   if (AOP_TYPE (right) == AOP_CRY &&
6039       AOP_TYPE (left) != AOP_CRY)
6040     {
6041       operand *tmp = right;
6042       right = left;
6043       left = tmp;
6044     }
6045   if (AOP_TYPE (right) == AOP_LIT)
6046     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6047
6048   size = AOP_SIZE (result);
6049
6050   // if(bit | yy)
6051   // xx = bit | yy;
6052   if (AOP_TYPE (left) == AOP_CRY)
6053     {
6054       if (AOP_TYPE (right) == AOP_LIT)
6055         {
6056           // c = bit | literal;
6057           if (lit)
6058             {
6059               // lit != 0 => result = 1
6060               if (AOP_TYPE (result) == AOP_CRY)
6061                 {
6062                   if (size)
6063                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6064                   else if (ifx)
6065                     continueIfTrue (ifx);
6066                   goto release;
6067                 }
6068               emitcode ("setb", "c");
6069             }
6070           else
6071             {
6072               // lit == 0 => result = left
6073               if (size && sameRegs (AOP (result), AOP (left)))
6074                 goto release;
6075               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6076             }
6077         }
6078       else
6079         {
6080           if (AOP_TYPE (right) == AOP_CRY)
6081             {
6082               // c = bit | bit;
6083               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6084               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6085             }
6086           else
6087             {
6088               // c = bit | val;
6089               symbol *tlbl = newiTempLabel (NULL);
6090               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6091                 emitcode ("setb", "c");
6092               emitcode ("jb", "%s,%05d$",
6093                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6094               toBoolean (right);
6095               emitcode ("jnz", "%05d$", tlbl->key + 100);
6096               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6097                 {
6098                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6099                   goto release;
6100                 }
6101               else
6102                 {
6103                   CLRC;
6104                   emitcode ("", "%05d$:", tlbl->key + 100);
6105                 }
6106             }
6107         }
6108       // bit = c
6109       // val = c
6110       if (size)
6111         outBitC (result);
6112       // if(bit | ...)
6113       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6114         genIfxJump (ifx, "c", left, right, result);
6115       goto release;
6116     }
6117
6118   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6119   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6120   if ((AOP_TYPE (right) == AOP_LIT) &&
6121       (AOP_TYPE (result) == AOP_CRY) &&
6122       (AOP_TYPE (left) != AOP_CRY))
6123     {
6124       if (lit)
6125         {
6126           // result = 1
6127           if (size)
6128             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6129           else
6130             continueIfTrue (ifx);
6131           goto release;
6132         }
6133       else
6134         {
6135           // lit = 0, result = boolean(left)
6136           if (size)
6137             emitcode ("setb", "c");
6138           toBoolean (right);
6139           if (size)
6140             {
6141               symbol *tlbl = newiTempLabel (NULL);
6142               emitcode ("jnz", "%05d$", tlbl->key + 100);
6143               CLRC;
6144               emitcode ("", "%05d$:", tlbl->key + 100);
6145             }
6146           else
6147             {
6148               genIfxJump (ifx, "a", left, right, result);
6149               goto release;
6150             }
6151         }
6152       outBitC (result);
6153       goto release;
6154     }
6155
6156   /* if left is same as result */
6157   if (sameRegs (AOP (result), AOP (left)))
6158     {
6159       for (; size--; offset++)
6160         {
6161           if (AOP_TYPE (right) == AOP_LIT)
6162             {
6163               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6164               if (bytelit == 0)
6165                 {
6166                   /* dummy read of volatile operand */
6167                   if (isOperandVolatile (left, FALSE))
6168                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6169                   else
6170                     continue;
6171                 }
6172               else if (bytelit == 0x0FF)
6173                 {
6174                   aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6175                 }
6176               else if (IS_AOP_PREG (left))
6177                 {
6178                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6179                   emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6180                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6181                 }
6182               else
6183                 {
6184                   emitcode ("orl", "%s,%s",
6185                             aopGet (AOP (left), offset, FALSE, TRUE),
6186                             aopGet (AOP (right), offset, FALSE, FALSE));
6187                 }
6188             }
6189           else
6190             {
6191               if (AOP_TYPE (left) == AOP_ACC)
6192                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6193               else
6194                 {
6195                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6196                   if (IS_AOP_PREG (left))
6197                     {
6198                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6199                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6200                     }
6201                   else
6202                     {
6203                       emitcode ("orl", "%s,a",
6204                                 aopGet (AOP (left), offset, FALSE, TRUE));
6205                     }
6206                 }
6207             }
6208         }
6209     }
6210   else
6211     {
6212       // left & result in different registers
6213       if (AOP_TYPE (result) == AOP_CRY)
6214         {
6215           // result = bit
6216           // if(size), result in bit
6217           // if(!size && ifx), conditional oper: if(left | right)
6218           symbol *tlbl = newiTempLabel (NULL);
6219           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6220           if (size)
6221             emitcode ("setb", "c");
6222           while (sizer--)
6223             {
6224               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6225                 emitcode ("orl", "a,%s",
6226                           aopGet (AOP (right), offset, FALSE, FALSE));
6227               } else {
6228                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6229                 emitcode ("orl", "a,%s",
6230                           aopGet (AOP (left), offset, FALSE, FALSE));
6231               }
6232               emitcode ("jnz", "%05d$", tlbl->key + 100);
6233               offset++;
6234             }
6235           if (size)
6236             {
6237               CLRC;
6238               emitcode ("", "%05d$:", tlbl->key + 100);
6239               outBitC (result);
6240             }
6241           else if (ifx)
6242             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6243           else
6244             emitcode ("", "%05d$:", tlbl->key + 100);
6245         }
6246       else
6247         {
6248           for (; (size--); offset++)
6249             {
6250               // normal case
6251               // result = left | right
6252               if (AOP_TYPE (right) == AOP_LIT)
6253                 {
6254                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6255                   if (bytelit == 0)
6256                     {
6257                       aopPut (AOP (result),
6258                               aopGet (AOP (left), offset, FALSE, FALSE),
6259                               offset,
6260                               isOperandVolatile (result, FALSE));
6261                       continue;
6262                     }
6263                   else if (bytelit == 0x0FF)
6264                     {
6265                       /* dummy read of volatile operand */
6266                       if (isOperandVolatile (left, FALSE))
6267                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6268                       aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6269                       continue;
6270                     }
6271                 }
6272               // faster than result <- left, anl result,right
6273               // and better if result is SFR
6274               if (AOP_TYPE (left) == AOP_ACC)
6275                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6276               else
6277                 {
6278                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6279                   emitcode ("orl", "a,%s",
6280                             aopGet (AOP (left), offset, FALSE, FALSE));
6281                 }
6282               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6283             }
6284         }
6285     }
6286
6287 release:
6288   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6289   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6290   freeAsmop (result, NULL, ic, TRUE);
6291 }
6292
6293 /*-----------------------------------------------------------------*/
6294 /* genXor - code for xclusive or                                   */
6295 /*-----------------------------------------------------------------*/
6296 static void
6297 genXor (iCode * ic, iCode * ifx)
6298 {
6299   operand *left, *right, *result;
6300   int size, offset = 0;
6301   unsigned long lit = 0L;
6302   int bytelit = 0;
6303
6304   D(emitcode (";     genXor",""));
6305
6306   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6307   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6308   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6309
6310 #ifdef DEBUG_TYPE
6311   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6312             AOP_TYPE (result),
6313             AOP_TYPE (left), AOP_TYPE (right));
6314   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6315             AOP_SIZE (result),
6316             AOP_SIZE (left), AOP_SIZE (right));
6317 #endif
6318
6319   /* if left is a literal & right is not ||
6320      if left needs acc & right does not */
6321   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6322       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6323     {
6324       operand *tmp = right;
6325       right = left;
6326       left = tmp;
6327     }
6328
6329   /* if result = right then exchange them */
6330   if (sameRegs (AOP (result), AOP (right)))
6331     {
6332       operand *tmp = right;
6333       right = left;
6334       left = tmp;
6335     }
6336
6337   /* if right is bit then exchange them */
6338   if (AOP_TYPE (right) == AOP_CRY &&
6339       AOP_TYPE (left) != AOP_CRY)
6340     {
6341       operand *tmp = right;
6342       right = left;
6343       left = tmp;
6344     }
6345   if (AOP_TYPE (right) == AOP_LIT)
6346     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6347
6348   size = AOP_SIZE (result);
6349
6350   // if(bit ^ yy)
6351   // xx = bit ^ yy;
6352   if (AOP_TYPE (left) == AOP_CRY)
6353     {
6354       if (AOP_TYPE (right) == AOP_LIT)
6355         {
6356           // c = bit & literal;
6357           if (lit >> 1)
6358             {
6359               // lit>>1  != 0 => result = 1
6360               if (AOP_TYPE (result) == AOP_CRY)
6361                 {
6362                   if (size)
6363                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6364                   else if (ifx)
6365                     continueIfTrue (ifx);
6366                   goto release;
6367                 }
6368               emitcode ("setb", "c");
6369             }
6370           else
6371             {
6372               // lit == (0 or 1)
6373               if (lit == 0)
6374                 {
6375                   // lit == 0, result = left
6376                   if (size && sameRegs (AOP (result), AOP (left)))
6377                     goto release;
6378                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6379                 }
6380               else
6381                 {
6382                   // lit == 1, result = not(left)
6383                   if (size && sameRegs (AOP (result), AOP (left)))
6384                     {
6385                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6386                       goto release;
6387                     }
6388                   else
6389                     {
6390                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6391                       emitcode ("cpl", "c");
6392                     }
6393                 }
6394             }
6395
6396         }
6397       else
6398         {
6399           // right != literal
6400           symbol *tlbl = newiTempLabel (NULL);
6401           if (AOP_TYPE (right) == AOP_CRY)
6402             {
6403               // c = bit ^ bit;
6404               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6405             }
6406           else
6407             {
6408               int sizer = AOP_SIZE (right);
6409               // c = bit ^ val
6410               // if val>>1 != 0, result = 1
6411               emitcode ("setb", "c");
6412               while (sizer)
6413                 {
6414                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
6415                   if (sizer == 1)
6416                     // test the msb of the lsb
6417                     emitcode ("anl", "a,#0xfe");
6418                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6419                   sizer--;
6420                 }
6421               // val = (0,1)
6422               emitcode ("rrc", "a");
6423             }
6424           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6425           emitcode ("cpl", "c");
6426           emitcode ("", "%05d$:", (tlbl->key + 100));
6427         }
6428       // bit = c
6429       // val = c
6430       if (size)
6431         outBitC (result);
6432       // if(bit | ...)
6433       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6434         genIfxJump (ifx, "c", left, right, result);
6435       goto release;
6436     }
6437
6438   /* if left is same as result */
6439   if (sameRegs (AOP (result), AOP (left)))
6440     {
6441       for (; size--; offset++)
6442         {
6443           if (AOP_TYPE (right) == AOP_LIT)
6444             {
6445               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6446               if (bytelit == 0)
6447                 {
6448                   /* dummy read of volatile operand */
6449                   if (isOperandVolatile (left, FALSE))
6450                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6451                   else
6452                     continue;
6453                 }
6454               else if (IS_AOP_PREG (left))
6455                 {
6456                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6457                   emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6458                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6459                 }
6460               else
6461                 {
6462                   emitcode ("xrl", "%s,%s",
6463                             aopGet (AOP (left), offset, FALSE, TRUE),
6464                             aopGet (AOP (right), offset, FALSE, FALSE));
6465                 }
6466             }
6467           else
6468             {
6469               if (AOP_TYPE (left) == AOP_ACC)
6470                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6471               else
6472                 {
6473                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6474                   if (IS_AOP_PREG (left))
6475                     {
6476                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6477                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6478                     }
6479                   else
6480                     emitcode ("xrl", "%s,a",
6481                               aopGet (AOP (left), offset, FALSE, TRUE));
6482                 }
6483             }
6484         }
6485     }
6486   else
6487     {
6488       // left & result in different registers
6489       if (AOP_TYPE (result) == AOP_CRY)
6490         {
6491           // result = bit
6492           // if(size), result in bit
6493           // if(!size && ifx), conditional oper: if(left ^ right)
6494           symbol *tlbl = newiTempLabel (NULL);
6495           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6496           if (size)
6497             emitcode ("setb", "c");
6498           while (sizer--)
6499             {
6500               if ((AOP_TYPE (right) == AOP_LIT) &&
6501                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6502                 {
6503                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6504                 }
6505               else
6506                 {
6507                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6508                     emitcode ("xrl", "a,%s",
6509                               aopGet (AOP (right), offset, FALSE, FALSE));
6510                   } else {
6511                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6512                     emitcode ("xrl", "a,%s",
6513                               aopGet (AOP (left), offset, FALSE, FALSE));
6514                   }
6515                 }
6516               emitcode ("jnz", "%05d$", tlbl->key + 100);
6517               offset++;
6518             }
6519           if (size)
6520             {
6521               CLRC;
6522               emitcode ("", "%05d$:", tlbl->key + 100);
6523               outBitC (result);
6524             }
6525           else if (ifx)
6526             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6527         }
6528       else
6529         {
6530           for (; (size--); offset++)
6531             {
6532               // normal case
6533               // result = left & right
6534               if (AOP_TYPE (right) == AOP_LIT)
6535                 {
6536                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6537                   if (bytelit == 0)
6538                     {
6539                       aopPut (AOP (result),
6540                               aopGet (AOP (left), offset, FALSE, FALSE),
6541                               offset,
6542                               isOperandVolatile (result, FALSE));
6543                       continue;
6544                     }
6545                 }
6546               // faster than result <- left, anl result,right
6547               // and better if result is SFR
6548               if (AOP_TYPE (left) == AOP_ACC)
6549                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6550               else
6551                 {
6552                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6553                   emitcode ("xrl", "a,%s",
6554                             aopGet (AOP (left), offset, FALSE, TRUE));
6555                 }
6556               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6557             }
6558         }
6559     }
6560
6561 release:
6562   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6563   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6564   freeAsmop (result, NULL, ic, TRUE);
6565 }
6566
6567 /*-----------------------------------------------------------------*/
6568 /* genInline - write the inline code out                           */
6569 /*-----------------------------------------------------------------*/
6570 static void
6571 genInline (iCode * ic)
6572 {
6573   char *buffer, *bp, *bp1;
6574
6575   D(emitcode (";     genInline",""));
6576
6577   _G.inLine += (!options.asmpeep);
6578
6579   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6580   strcpy (buffer, IC_INLINE (ic));
6581
6582   /* emit each line as a code */
6583   while (*bp)
6584     {
6585       if (*bp == '\n')
6586         {
6587           *bp++ = '\0';
6588           emitcode (bp1, "");
6589           bp1 = bp;
6590         }
6591       else
6592         {
6593           /* Add \n for labels, not dirs such as c:\mydir */
6594           if ( (*bp == ':') && (isspace(bp[1])) )
6595             {
6596               bp++;
6597               *bp = '\0';
6598               bp++;
6599               emitcode (bp1, "");
6600               bp1 = bp;
6601             }
6602           else
6603             bp++;
6604         }
6605     }
6606   if (bp1 != bp)
6607     emitcode (bp1, "");
6608   /*     emitcode("",buffer); */
6609   _G.inLine -= (!options.asmpeep);
6610 }
6611
6612 /*-----------------------------------------------------------------*/
6613 /* genRRC - rotate right with carry                                */
6614 /*-----------------------------------------------------------------*/
6615 static void
6616 genRRC (iCode * ic)
6617 {
6618   operand *left, *result;
6619   int size, offset = 0;
6620   char *l;
6621
6622   D(emitcode (";     genRRC",""));
6623
6624   /* rotate right with carry */
6625   left = IC_LEFT (ic);
6626   result = IC_RESULT (ic);
6627   aopOp (left, ic, FALSE);
6628   aopOp (result, ic, FALSE);
6629
6630   /* move it to the result */
6631   size = AOP_SIZE (result);
6632   offset = size - 1;
6633   if (size == 1) { /* special case for 1 byte */
6634       l = aopGet (AOP (left), offset, FALSE, FALSE);
6635       MOVA (l);
6636       emitcode ("rr", "a");
6637       goto release;
6638   }
6639   /* no need to clear carry, bit7 will be written later */
6640   while (size--)
6641     {
6642       l = aopGet (AOP (left), offset, FALSE, FALSE);
6643       MOVA (l);
6644       emitcode ("rrc", "a");
6645       if (AOP_SIZE (result) > 1)
6646         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6647     }
6648   /* now we need to put the carry into the
6649      highest order byte of the result */
6650   if (AOP_SIZE (result) > 1)
6651     {
6652       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6653       MOVA (l);
6654     }
6655   emitcode ("mov", "acc.7,c");
6656  release:
6657   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6658   freeAsmop (left, NULL, ic, TRUE);
6659   freeAsmop (result, NULL, ic, TRUE);
6660 }
6661
6662 /*-----------------------------------------------------------------*/
6663 /* genRLC - generate code for rotate left with carry               */
6664 /*-----------------------------------------------------------------*/
6665 static void
6666 genRLC (iCode * ic)
6667 {
6668   operand *left, *result;
6669   int size, offset = 0;
6670   char *l;
6671
6672   D(emitcode (";     genRLC",""));
6673
6674   /* rotate right with carry */
6675   left = IC_LEFT (ic);
6676   result = IC_RESULT (ic);
6677   aopOp (left, ic, FALSE);
6678   aopOp (result, ic, FALSE);
6679
6680   /* move it to the result */
6681   size = AOP_SIZE (result);
6682   offset = 0;
6683   if (size--)
6684     {
6685       l = aopGet (AOP (left), offset, FALSE, FALSE);
6686       MOVA (l);
6687       if (size == 0) { /* special case for 1 byte */
6688               emitcode("rl","a");
6689               goto release;
6690       }
6691       emitcode("rlc","a"); /* bit0 will be written later */
6692       if (AOP_SIZE (result) > 1)
6693         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6694       while (size--)
6695         {
6696           l = aopGet (AOP (left), offset, FALSE, FALSE);
6697           MOVA (l);
6698           emitcode ("rlc", "a");
6699           if (AOP_SIZE (result) > 1)
6700             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6701         }
6702     }
6703   /* now we need to put the carry into the
6704      highest order byte of the result */
6705   if (AOP_SIZE (result) > 1)
6706     {
6707       l = aopGet (AOP (result), 0, FALSE, FALSE);
6708       MOVA (l);
6709     }
6710   emitcode ("mov", "acc.0,c");
6711  release:
6712   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6713   freeAsmop (left, NULL, ic, TRUE);
6714   freeAsmop (result, NULL, ic, TRUE);
6715 }
6716
6717 /*-----------------------------------------------------------------*/
6718 /* genGetHbit - generates code get highest order bit               */
6719 /*-----------------------------------------------------------------*/
6720 static void
6721 genGetHbit (iCode * ic)
6722 {
6723   operand *left, *result;
6724
6725   D(emitcode (";     genGetHbit",""));
6726
6727   left = IC_LEFT (ic);
6728   result = IC_RESULT (ic);
6729   aopOp (left, ic, FALSE);
6730   aopOp (result, ic, FALSE);
6731
6732   /* get the highest order byte into a */
6733   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6734   if (AOP_TYPE (result) == AOP_CRY)
6735     {
6736       emitcode ("rlc", "a");
6737       outBitC (result);
6738     }
6739   else
6740     {
6741       emitcode ("rl", "a");
6742       emitcode ("anl", "a,#0x01");
6743       outAcc (result);
6744     }
6745
6746
6747   freeAsmop (left, NULL, ic, TRUE);
6748   freeAsmop (result, NULL, ic, TRUE);
6749 }
6750
6751 /*-----------------------------------------------------------------*/
6752 /* genSwap - generates code to swap nibbles or bytes               */
6753 /*-----------------------------------------------------------------*/
6754 static void
6755 genSwap (iCode * ic)
6756 {
6757   operand *left, *result;
6758
6759   D(emitcode (";     genSwap",""));
6760
6761   left = IC_LEFT (ic);
6762   result = IC_RESULT (ic);
6763   aopOp (left, ic, FALSE);
6764   aopOp (result, ic, FALSE);
6765
6766   switch (AOP_SIZE (left))
6767     {
6768     case 1: /* swap nibbles in byte */
6769       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6770       emitcode ("swap", "a");
6771       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6772       break;
6773     case 2: /* swap bytes in word */
6774       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6775         {
6776           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6777           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6778                   0, isOperandVolatile (result, FALSE));
6779           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6780         }
6781       else if (operandsEqu (left, result))
6782         {
6783           char * reg = "a";
6784           bool pushedB = FALSE, leftInB = FALSE;
6785
6786           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6787           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6788             {
6789               pushedB = pushB ();
6790               emitcode ("mov", "b,a");
6791               reg = "b";
6792               leftInB = TRUE;
6793             }
6794           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6795                   0, isOperandVolatile (result, FALSE));
6796           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6797
6798           if (leftInB)
6799             popB (pushedB);
6800         }
6801       else
6802         {
6803           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6804                   0, isOperandVolatile (result, FALSE));
6805           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6806                   1, isOperandVolatile (result, FALSE));
6807         }
6808       break;
6809     default:
6810       wassertl(FALSE, "unsupported SWAP operand size");
6811     }
6812
6813   freeAsmop (left, NULL, ic, TRUE);
6814   freeAsmop (result, NULL, ic, TRUE);
6815 }
6816
6817
6818 /*-----------------------------------------------------------------*/
6819 /* AccRol - rotate left accumulator by known count                 */
6820 /*-----------------------------------------------------------------*/
6821 static void
6822 AccRol (int shCount)
6823 {
6824   shCount &= 0x0007;            // shCount : 0..7
6825
6826   switch (shCount)
6827     {
6828     case 0:
6829       break;
6830     case 1:
6831       emitcode ("rl", "a");
6832       break;
6833     case 2:
6834       emitcode ("rl", "a");
6835       emitcode ("rl", "a");
6836       break;
6837     case 3:
6838       emitcode ("swap", "a");
6839       emitcode ("rr", "a");
6840       break;
6841     case 4:
6842       emitcode ("swap", "a");
6843       break;
6844     case 5:
6845       emitcode ("swap", "a");
6846       emitcode ("rl", "a");
6847       break;
6848     case 6:
6849       emitcode ("rr", "a");
6850       emitcode ("rr", "a");
6851       break;
6852     case 7:
6853       emitcode ("rr", "a");
6854       break;
6855     }
6856 }
6857
6858 /*-----------------------------------------------------------------*/
6859 /* AccLsh - left shift accumulator by known count                  */
6860 /*-----------------------------------------------------------------*/
6861 static void
6862 AccLsh (int shCount)
6863 {
6864   if (shCount != 0)
6865     {
6866       if (shCount == 1)
6867         emitcode ("add", "a,acc");
6868       else if (shCount == 2)
6869         {
6870           emitcode ("add", "a,acc");
6871           emitcode ("add", "a,acc");
6872         }
6873       else
6874         {
6875           /* rotate left accumulator */
6876           AccRol (shCount);
6877           /* and kill the lower order bits */
6878           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6879         }
6880     }
6881 }
6882
6883 /*-----------------------------------------------------------------*/
6884 /* AccRsh - right shift accumulator by known count                 */
6885 /*-----------------------------------------------------------------*/
6886 static void
6887 AccRsh (int shCount)
6888 {
6889   if (shCount != 0)
6890     {
6891       if (shCount == 1)
6892         {
6893           CLRC;
6894           emitcode ("rrc", "a");
6895         }
6896       else
6897         {
6898           /* rotate right accumulator */
6899           AccRol (8 - shCount);
6900           /* and kill the higher order bits */
6901           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6902         }
6903     }
6904 }
6905
6906 /*-----------------------------------------------------------------*/
6907 /* AccSRsh - signed right shift accumulator by known count                 */
6908 /*-----------------------------------------------------------------*/
6909 static void
6910 AccSRsh (int shCount)
6911 {
6912   symbol *tlbl;
6913   if (shCount != 0)
6914     {
6915       if (shCount == 1)
6916         {
6917           emitcode ("mov", "c,acc.7");
6918           emitcode ("rrc", "a");
6919         }
6920       else if (shCount == 2)
6921         {
6922           emitcode ("mov", "c,acc.7");
6923           emitcode ("rrc", "a");
6924           emitcode ("mov", "c,acc.7");
6925           emitcode ("rrc", "a");
6926         }
6927       else
6928         {
6929           tlbl = newiTempLabel (NULL);
6930           /* rotate right accumulator */
6931           AccRol (8 - shCount);
6932           /* and kill the higher order bits */
6933           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6934           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6935           emitcode ("orl", "a,#0x%02x",
6936                     (unsigned char) ~SRMask[shCount]);
6937           emitcode ("", "%05d$:", tlbl->key + 100);
6938         }
6939     }
6940 }
6941
6942 /*-----------------------------------------------------------------*/
6943 /* shiftR1Left2Result - shift right one byte from left to result   */
6944 /*-----------------------------------------------------------------*/
6945 static void
6946 shiftR1Left2Result (operand * left, int offl,
6947                     operand * result, int offr,
6948                     int shCount, int sign)
6949 {
6950   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6951   /* shift right accumulator */
6952   if (sign)
6953     AccSRsh (shCount);
6954   else
6955     AccRsh (shCount);
6956   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6957 }
6958
6959 /*-----------------------------------------------------------------*/
6960 /* shiftL1Left2Result - shift left one byte from left to result    */
6961 /*-----------------------------------------------------------------*/
6962 static void
6963 shiftL1Left2Result (operand * left, int offl,
6964                     operand * result, int offr, int shCount)
6965 {
6966   char *l;
6967   l = aopGet (AOP (left), offl, FALSE, FALSE);
6968   MOVA (l);
6969   /* shift left accumulator */
6970   AccLsh (shCount);
6971   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6972 }
6973
6974 /*-----------------------------------------------------------------*/
6975 /* movLeft2Result - move byte from left to result                  */
6976 /*-----------------------------------------------------------------*/
6977 static void
6978 movLeft2Result (operand * left, int offl,
6979                 operand * result, int offr, int sign)
6980 {
6981   char *l;
6982   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
6983     {
6984       l = aopGet (AOP (left), offl, FALSE, FALSE);
6985
6986       if (*l == '@' && (IS_AOP_PREG (result)))
6987         {
6988           emitcode ("mov", "a,%s", l);
6989           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6990         }
6991       else
6992         {
6993           if (!sign)
6994             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
6995           else
6996             {
6997               /* MSB sign in acc.7 ! */
6998               if (getDataSize (left) == offl + 1)
6999                 {
7000                   emitcode ("mov", "a,%s", l);
7001                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7002                 }
7003             }
7004         }
7005     }
7006 }
7007
7008 /*-----------------------------------------------------------------*/
7009 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7010 /*-----------------------------------------------------------------*/
7011 static void
7012 AccAXRrl1 (char *x)
7013 {
7014   emitcode ("rrc", "a");
7015   emitcode ("xch", "a,%s", x);
7016   emitcode ("rrc", "a");
7017   emitcode ("xch", "a,%s", x);
7018 }
7019
7020 /*-----------------------------------------------------------------*/
7021 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7022 /*-----------------------------------------------------------------*/
7023 static void
7024 AccAXLrl1 (char *x)
7025 {
7026   emitcode ("xch", "a,%s", x);
7027   emitcode ("rlc", "a");
7028   emitcode ("xch", "a,%s", x);
7029   emitcode ("rlc", "a");
7030 }
7031
7032 /*-----------------------------------------------------------------*/
7033 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7034 /*-----------------------------------------------------------------*/
7035 static void
7036 AccAXLsh1 (char *x)
7037 {
7038   emitcode ("xch", "a,%s", x);
7039   emitcode ("add", "a,acc");
7040   emitcode ("xch", "a,%s", x);
7041   emitcode ("rlc", "a");
7042 }
7043
7044 /*-----------------------------------------------------------------*/
7045 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7046 /*-----------------------------------------------------------------*/
7047 static void
7048 AccAXLsh (char *x, int shCount)
7049 {
7050   switch (shCount)
7051     {
7052     case 0:
7053       break;
7054     case 1:
7055       AccAXLsh1 (x);
7056       break;
7057     case 2:
7058       AccAXLsh1 (x);
7059       AccAXLsh1 (x);
7060       break;
7061     case 3:
7062     case 4:
7063     case 5:                     // AAAAABBB:CCCCCDDD
7064
7065       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7066
7067       emitcode ("anl", "a,#0x%02x",
7068                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7069
7070       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7071
7072       AccRol (shCount);         // DDDCCCCC:BBB00000
7073
7074       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7075
7076       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7077
7078       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7079
7080       emitcode ("anl", "a,#0x%02x",
7081                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7082
7083       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7084
7085       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7086
7087       break;
7088     case 6:                     // AAAAAABB:CCCCCCDD
7089       emitcode ("anl", "a,#0x%02x",
7090                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7091       emitcode ("mov", "c,acc.0");      // c = B
7092       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7093 #if 0 // REMOVE ME
7094       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7095       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7096 #else
7097       emitcode("rrc","a");
7098       emitcode("xch","a,%s", x);
7099       emitcode("rrc","a");
7100       emitcode("mov","c,acc.0"); //<< get correct bit
7101       emitcode("xch","a,%s", x);
7102
7103       emitcode("rrc","a");
7104       emitcode("xch","a,%s", x);
7105       emitcode("rrc","a");
7106       emitcode("xch","a,%s", x);
7107 #endif
7108       break;
7109     case 7:                     // a:x <<= 7
7110
7111       emitcode ("anl", "a,#0x%02x",
7112                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7113
7114       emitcode ("mov", "c,acc.0");      // c = B
7115
7116       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7117
7118       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7119
7120       break;
7121     default:
7122       break;
7123     }
7124 }
7125
7126 /*-----------------------------------------------------------------*/
7127 /* AccAXRsh - right shift a:x known count (0..7)                   */
7128 /*-----------------------------------------------------------------*/
7129 static void
7130 AccAXRsh (char *x, int shCount)
7131 {
7132   switch (shCount)
7133     {
7134     case 0:
7135       break;
7136     case 1:
7137       CLRC;
7138       AccAXRrl1 (x);            // 0->a:x
7139
7140       break;
7141     case 2:
7142       CLRC;
7143       AccAXRrl1 (x);            // 0->a:x
7144
7145       CLRC;
7146       AccAXRrl1 (x);            // 0->a:x
7147
7148       break;
7149     case 3:
7150     case 4:
7151     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7152
7153       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7154
7155       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7156
7157       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7158
7159       emitcode ("anl", "a,#0x%02x",
7160                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7161
7162       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7163
7164       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7165
7166       emitcode ("anl", "a,#0x%02x",
7167                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7168
7169       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7170
7171       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7172
7173       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7174
7175       break;
7176     case 6:                     // AABBBBBB:CCDDDDDD
7177
7178       emitcode ("mov", "c,acc.7");
7179       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7180
7181       emitcode ("mov", "c,acc.7");
7182       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7183
7184       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7185
7186       emitcode ("anl", "a,#0x%02x",
7187                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7188
7189       break;
7190     case 7:                     // ABBBBBBB:CDDDDDDD
7191
7192       emitcode ("mov", "c,acc.7");      // c = A
7193
7194       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7195
7196       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7197
7198       emitcode ("anl", "a,#0x%02x",
7199                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7200
7201       break;
7202     default:
7203       break;
7204     }
7205 }
7206
7207 /*-----------------------------------------------------------------*/
7208 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7209 /*-----------------------------------------------------------------*/
7210 static void
7211 AccAXRshS (char *x, int shCount)
7212 {
7213   symbol *tlbl;
7214   switch (shCount)
7215     {
7216     case 0:
7217       break;
7218     case 1:
7219       emitcode ("mov", "c,acc.7");
7220       AccAXRrl1 (x);            // s->a:x
7221
7222       break;
7223     case 2:
7224       emitcode ("mov", "c,acc.7");
7225       AccAXRrl1 (x);            // s->a:x
7226
7227       emitcode ("mov", "c,acc.7");
7228       AccAXRrl1 (x);            // s->a:x
7229
7230       break;
7231     case 3:
7232     case 4:
7233     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7234
7235       tlbl = newiTempLabel (NULL);
7236       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7237
7238       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7239
7240       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7241
7242       emitcode ("anl", "a,#0x%02x",
7243                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7244
7245       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7246
7247       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7248
7249       emitcode ("anl", "a,#0x%02x",
7250                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7251
7252       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7253
7254       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7255
7256       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7257
7258       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7259       emitcode ("orl", "a,#0x%02x",
7260                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7261
7262       emitcode ("", "%05d$:", tlbl->key + 100);
7263       break;                    // SSSSAAAA:BBBCCCCC
7264
7265     case 6:                     // AABBBBBB:CCDDDDDD
7266
7267       tlbl = newiTempLabel (NULL);
7268       emitcode ("mov", "c,acc.7");
7269       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7270
7271       emitcode ("mov", "c,acc.7");
7272       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7273
7274       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7275
7276       emitcode ("anl", "a,#0x%02x",
7277                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7278
7279       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7280       emitcode ("orl", "a,#0x%02x",
7281                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7282
7283       emitcode ("", "%05d$:", tlbl->key + 100);
7284       break;
7285     case 7:                     // ABBBBBBB:CDDDDDDD
7286
7287       tlbl = newiTempLabel (NULL);
7288       emitcode ("mov", "c,acc.7");      // c = A
7289
7290       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7291
7292       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7293
7294       emitcode ("anl", "a,#0x%02x",
7295                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7296
7297       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7298       emitcode ("orl", "a,#0x%02x",
7299                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7300
7301       emitcode ("", "%05d$:", tlbl->key + 100);
7302       break;
7303     default:
7304       break;
7305     }
7306 }
7307
7308 /*-----------------------------------------------------------------*/
7309 /* shiftL2Left2Result - shift left two bytes from left to result   */
7310 /*-----------------------------------------------------------------*/
7311 static void
7312 shiftL2Left2Result (operand * left, int offl,
7313                     operand * result, int offr, int shCount)
7314 {
7315   if (sameRegs (AOP (result), AOP (left)) &&
7316       ((offl + MSB16) == offr))
7317     {
7318       /* don't crash result[offr] */
7319       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7320       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7321     }
7322   else
7323     {
7324       movLeft2Result (left, offl, result, offr, 0);
7325       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7326     }
7327   /* ax << shCount (x = lsb(result)) */
7328   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7329   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7330 }
7331
7332
7333 /*-----------------------------------------------------------------*/
7334 /* shiftR2Left2Result - shift right two bytes from left to result  */
7335 /*-----------------------------------------------------------------*/
7336 static void
7337 shiftR2Left2Result (operand * left, int offl,
7338                     operand * result, int offr,
7339                     int shCount, int sign)
7340 {
7341   if (sameRegs (AOP (result), AOP (left)) &&
7342       ((offl + MSB16) == offr))
7343     {
7344       /* don't crash result[offr] */
7345       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7346       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7347     }
7348   else
7349     {
7350       movLeft2Result (left, offl, result, offr, 0);
7351       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7352     }
7353   /* a:x >> shCount (x = lsb(result)) */
7354   if (sign)
7355     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7356   else
7357     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7358   if (getDataSize (result) > 1)
7359     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7360 }
7361
7362 /*-----------------------------------------------------------------*/
7363 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7364 /*-----------------------------------------------------------------*/
7365 static void
7366 shiftLLeftOrResult (operand * left, int offl,
7367                     operand * result, int offr, int shCount)
7368 {
7369   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7370   /* shift left accumulator */
7371   AccLsh (shCount);
7372   /* or with result */
7373   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7374   /* back to result */
7375   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7376 }
7377
7378 /*-----------------------------------------------------------------*/
7379 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7380 /*-----------------------------------------------------------------*/
7381 static void
7382 shiftRLeftOrResult (operand * left, int offl,
7383                     operand * result, int offr, int shCount)
7384 {
7385   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7386   /* shift right accumulator */
7387   AccRsh (shCount);
7388   /* or with result */
7389   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7390   /* back to result */
7391   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7392 }
7393
7394 /*-----------------------------------------------------------------*/
7395 /* genlshOne - left shift a one byte quantity by known count       */
7396 /*-----------------------------------------------------------------*/
7397 static void
7398 genlshOne (operand * result, operand * left, int shCount)
7399 {
7400   D(emitcode (";     genlshOne",""));
7401
7402   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7403 }
7404
7405 /*-----------------------------------------------------------------*/
7406 /* genlshTwo - left shift two bytes by known amount != 0           */
7407 /*-----------------------------------------------------------------*/
7408 static void
7409 genlshTwo (operand * result, operand * left, int shCount)
7410 {
7411   int size;
7412
7413   D(emitcode (";     genlshTwo",""));
7414
7415   size = getDataSize (result);
7416
7417   /* if shCount >= 8 */
7418   if (shCount >= 8)
7419     {
7420       shCount -= 8;
7421
7422       if (size > 1)
7423         {
7424           if (shCount)
7425             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7426           else
7427             movLeft2Result (left, LSB, result, MSB16, 0);
7428         }
7429       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7430     }
7431
7432   /*  1 <= shCount <= 7 */
7433   else
7434     {
7435       if (size == 1)
7436         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7437       else
7438         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7439     }
7440 }
7441
7442 /*-----------------------------------------------------------------*/
7443 /* shiftLLong - shift left one long from left to result            */
7444 /* offl = LSB or MSB16                                             */
7445 /*-----------------------------------------------------------------*/
7446 static void
7447 shiftLLong (operand * left, operand * result, int offr)
7448 {
7449   char *l;
7450   int size = AOP_SIZE (result);
7451
7452   if (size >= LSB + offr)
7453     {
7454       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7455       MOVA (l);
7456       emitcode ("add", "a,acc");
7457       if (sameRegs (AOP (left), AOP (result)) &&
7458           size >= MSB16 + offr && offr != LSB)
7459         emitcode ("xch", "a,%s",
7460                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7461       else
7462         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7463     }
7464
7465   if (size >= MSB16 + offr)
7466     {
7467       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7468         {
7469           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7470           MOVA (l);
7471         }
7472       emitcode ("rlc", "a");
7473       if (sameRegs (AOP (left), AOP (result)) &&
7474           size >= MSB24 + offr && offr != LSB)
7475         emitcode ("xch", "a,%s",
7476                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7477       else
7478         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7479     }
7480
7481   if (size >= MSB24 + offr)
7482     {
7483       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7484         {
7485           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7486           MOVA (l);
7487         }
7488       emitcode ("rlc", "a");
7489       if (sameRegs (AOP (left), AOP (result)) &&
7490           size >= MSB32 + offr && offr != LSB)
7491         emitcode ("xch", "a,%s",
7492                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7493       else
7494         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7495     }
7496
7497   if (size > MSB32 + offr)
7498     {
7499       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7500         {
7501           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7502           MOVA (l);
7503         }
7504       emitcode ("rlc", "a");
7505       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7506     }
7507   if (offr != LSB)
7508     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7509 }
7510
7511 /*-----------------------------------------------------------------*/
7512 /* genlshFour - shift four byte by a known amount != 0             */
7513 /*-----------------------------------------------------------------*/
7514 static void
7515 genlshFour (operand * result, operand * left, int shCount)
7516 {
7517   int size;
7518
7519   D(emitcode (";     genlshFour",""));
7520
7521   size = AOP_SIZE (result);
7522
7523   /* if shifting more that 3 bytes */
7524   if (shCount >= 24)
7525     {
7526       shCount -= 24;
7527       if (shCount)
7528         /* lowest order of left goes to the highest
7529            order of the destination */
7530         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7531       else
7532         movLeft2Result (left, LSB, result, MSB32, 0);
7533       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7534       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7535       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7536       return;
7537     }
7538
7539   /* more than two bytes */
7540   else if (shCount >= 16)
7541     {
7542       /* lower order two bytes goes to higher order two bytes */
7543       shCount -= 16;
7544       /* if some more remaining */
7545       if (shCount)
7546         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7547       else
7548         {
7549           movLeft2Result (left, MSB16, result, MSB32, 0);
7550           movLeft2Result (left, LSB, result, MSB24, 0);
7551         }
7552       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7553       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7554       return;
7555     }
7556
7557   /* if more than 1 byte */
7558   else if (shCount >= 8)
7559     {
7560       /* lower order three bytes goes to higher order  three bytes */
7561       shCount -= 8;
7562       if (size == 2)
7563         {
7564           if (shCount)
7565             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7566           else
7567             movLeft2Result (left, LSB, result, MSB16, 0);
7568         }
7569       else
7570         {                       /* size = 4 */
7571           if (shCount == 0)
7572             {
7573               movLeft2Result (left, MSB24, result, MSB32, 0);
7574               movLeft2Result (left, MSB16, result, MSB24, 0);
7575               movLeft2Result (left, LSB, result, MSB16, 0);
7576               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7577             }
7578           else if (shCount == 1)
7579             shiftLLong (left, result, MSB16);
7580           else
7581             {
7582               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7583               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7584               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7585               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7586             }
7587         }
7588     }
7589
7590   /* 1 <= shCount <= 7 */
7591   else if (shCount <= 2)
7592     {
7593       shiftLLong (left, result, LSB);
7594       if (shCount == 2)
7595         shiftLLong (result, result, LSB);
7596     }
7597   /* 3 <= shCount <= 7, optimize */
7598   else
7599     {
7600       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7601       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7602       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7603     }
7604 }
7605
7606 /*-----------------------------------------------------------------*/
7607 /* genLeftShiftLiteral - left shifting by known count              */
7608 /*-----------------------------------------------------------------*/
7609 static void
7610 genLeftShiftLiteral (operand * left,
7611                      operand * right,
7612                      operand * result,
7613                      iCode * ic)
7614 {
7615   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7616   int size;
7617
7618   D(emitcode (";     genLeftShiftLiteral",""));
7619
7620   freeAsmop (right, NULL, ic, TRUE);
7621
7622   aopOp (left, ic, FALSE);
7623   aopOp (result, ic, FALSE);
7624
7625   size = getSize (operandType (result));
7626
7627 #if VIEW_SIZE
7628   emitcode ("; shift left ", "result %d, left %d", size,
7629             AOP_SIZE (left));
7630 #endif
7631
7632   /* I suppose that the left size >= result size */
7633   if (shCount == 0)
7634     {
7635       while (size--)
7636         {
7637           movLeft2Result (left, size, result, size, 0);
7638         }
7639     }
7640
7641   else if (shCount >= (size * 8))
7642     while (size--)
7643       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7644   else
7645     {
7646       switch (size)
7647         {
7648         case 1:
7649           genlshOne (result, left, shCount);
7650           break;
7651
7652         case 2:
7653           genlshTwo (result, left, shCount);
7654           break;
7655
7656         case 4:
7657           genlshFour (result, left, shCount);
7658           break;
7659         default:
7660           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7661                   "*** ack! mystery literal shift!\n");
7662           break;
7663         }
7664     }
7665   freeAsmop (left, NULL, ic, TRUE);
7666   freeAsmop (result, NULL, ic, TRUE);
7667 }
7668
7669 /*-----------------------------------------------------------------*/
7670 /* genLeftShift - generates code for left shifting                 */
7671 /*-----------------------------------------------------------------*/
7672 static void
7673 genLeftShift (iCode * ic)
7674 {
7675   operand *left, *right, *result;
7676   int size, offset;
7677   char *l;
7678   symbol *tlbl, *tlbl1;
7679   bool pushedB;
7680
7681   D(emitcode (";     genLeftShift",""));
7682
7683   right = IC_RIGHT (ic);
7684   left = IC_LEFT (ic);
7685   result = IC_RESULT (ic);
7686
7687   aopOp (right, ic, FALSE);
7688
7689   /* if the shift count is known then do it
7690      as efficiently as possible */
7691   if (AOP_TYPE (right) == AOP_LIT)
7692     {
7693       genLeftShiftLiteral (left, right, result, ic);
7694       return;
7695     }
7696
7697   /* shift count is unknown then we have to form
7698      a loop get the loop count in B : Note: we take
7699      only the lower order byte since shifting
7700      more that 32 bits make no sense anyway, ( the
7701      largest size of an object can be only 32 bits ) */
7702
7703   pushedB = pushB ();
7704   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7705   emitcode ("inc", "b");
7706   freeAsmop (right, NULL, ic, TRUE);
7707   aopOp (left, ic, FALSE);
7708   aopOp (result, ic, FALSE);
7709
7710   /* now move the left to the result if they are not the same */
7711   if (!sameRegs (AOP (left), AOP (result)) &&
7712       AOP_SIZE (result) > 1)
7713     {
7714
7715       size = AOP_SIZE (result);
7716       offset = 0;
7717       while (size--)
7718         {
7719           l = aopGet (AOP (left), offset, FALSE, TRUE);
7720           if (*l == '@' && (IS_AOP_PREG (result)))
7721             {
7722
7723               emitcode ("mov", "a,%s", l);
7724               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7725             }
7726           else
7727             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7728           offset++;
7729         }
7730     }
7731
7732   tlbl = newiTempLabel (NULL);
7733   size = AOP_SIZE (result);
7734   offset = 0;
7735   tlbl1 = newiTempLabel (NULL);
7736
7737   /* if it is only one byte then */
7738   if (size == 1)
7739     {
7740       symbol *tlbl1 = newiTempLabel (NULL);
7741
7742       l = aopGet (AOP (left), 0, FALSE, FALSE);
7743       MOVA (l);
7744       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7745       emitcode ("", "%05d$:", tlbl->key + 100);
7746       emitcode ("add", "a,acc");
7747       emitcode ("", "%05d$:", tlbl1->key + 100);
7748       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7749       popB (pushedB);
7750       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7751       goto release;
7752     }
7753
7754   reAdjustPreg (AOP (result));
7755
7756   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7757   emitcode ("", "%05d$:", tlbl->key + 100);
7758   l = aopGet (AOP (result), offset, FALSE, FALSE);
7759   MOVA (l);
7760   emitcode ("add", "a,acc");
7761   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7762   while (--size)
7763     {
7764       l = aopGet (AOP (result), offset, FALSE, FALSE);
7765       MOVA (l);
7766       emitcode ("rlc", "a");
7767       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7768     }
7769   reAdjustPreg (AOP (result));
7770
7771   emitcode ("", "%05d$:", tlbl1->key + 100);
7772   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7773   popB (pushedB);
7774 release:
7775   freeAsmop (left, NULL, ic, TRUE);
7776   freeAsmop (result, NULL, ic, TRUE);
7777 }
7778
7779 /*-----------------------------------------------------------------*/
7780 /* genrshOne - right shift a one byte quantity by known count      */
7781 /*-----------------------------------------------------------------*/
7782 static void
7783 genrshOne (operand * result, operand * left,
7784            int shCount, int sign)
7785 {
7786   D(emitcode (";     genrshOne",""));
7787
7788   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7789 }
7790
7791 /*-----------------------------------------------------------------*/
7792 /* genrshTwo - right shift two bytes by known amount != 0          */
7793 /*-----------------------------------------------------------------*/
7794 static void
7795 genrshTwo (operand * result, operand * left,
7796            int shCount, int sign)
7797 {
7798   D(emitcode (";     genrshTwo",""));
7799
7800   /* if shCount >= 8 */
7801   if (shCount >= 8)
7802     {
7803       shCount -= 8;
7804       if (shCount)
7805         shiftR1Left2Result (left, MSB16, result, LSB,
7806                             shCount, sign);
7807       else
7808         movLeft2Result (left, MSB16, result, LSB, sign);
7809       addSign (result, MSB16, sign);
7810     }
7811
7812   /*  1 <= shCount <= 7 */
7813   else
7814     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7815 }
7816
7817 /*-----------------------------------------------------------------*/
7818 /* shiftRLong - shift right one long from left to result           */
7819 /* offl = LSB or MSB16                                             */
7820 /*-----------------------------------------------------------------*/
7821 static void
7822 shiftRLong (operand * left, int offl,
7823             operand * result, int sign)
7824 {
7825   int isSameRegs=sameRegs(AOP(left),AOP(result));
7826
7827   if (isSameRegs && offl>1) {
7828     // we are in big trouble, but this shouldn't happen
7829     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7830   }
7831
7832   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7833
7834   if (offl==MSB16) {
7835     // shift is > 8
7836     if (sign) {
7837       emitcode ("rlc", "a");
7838       emitcode ("subb", "a,acc");
7839       if (isSameRegs)
7840         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7841       else {
7842         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7843         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7844       }
7845     } else {
7846       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7847     }
7848   }
7849
7850   if (!sign) {
7851     emitcode ("clr", "c");
7852   } else {
7853     emitcode ("mov", "c,acc.7");
7854   }
7855
7856   emitcode ("rrc", "a");
7857
7858   if (isSameRegs && offl==MSB16) {
7859     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7860   } else {
7861     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7862     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7863   }
7864
7865   emitcode ("rrc", "a");
7866   if (isSameRegs && offl==1) {
7867     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7868   } else {
7869     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7870     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7871   }
7872   emitcode ("rrc", "a");
7873   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7874
7875   if (offl == LSB)
7876     {
7877       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7878       emitcode ("rrc", "a");
7879       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7880     }
7881 }
7882
7883 /*-----------------------------------------------------------------*/
7884 /* genrshFour - shift four byte by a known amount != 0             */
7885 /*-----------------------------------------------------------------*/
7886 static void
7887 genrshFour (operand * result, operand * left,
7888             int shCount, int sign)
7889 {
7890   D(emitcode (";     genrshFour",""));
7891
7892   /* if shifting more that 3 bytes */
7893   if (shCount >= 24)
7894     {
7895       shCount -= 24;
7896       if (shCount)
7897         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7898       else
7899         movLeft2Result (left, MSB32, result, LSB, sign);
7900       addSign (result, MSB16, sign);
7901     }
7902   else if (shCount >= 16)
7903     {
7904       shCount -= 16;
7905       if (shCount)
7906         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7907       else
7908         {
7909           movLeft2Result (left, MSB24, result, LSB, 0);
7910           movLeft2Result (left, MSB32, result, MSB16, sign);
7911         }
7912       addSign (result, MSB24, sign);
7913     }
7914   else if (shCount >= 8)
7915     {
7916       shCount -= 8;
7917       if (shCount == 1)
7918         shiftRLong (left, MSB16, result, sign);
7919       else if (shCount == 0)
7920         {
7921           movLeft2Result (left, MSB16, result, LSB, 0);
7922           movLeft2Result (left, MSB24, result, MSB16, 0);
7923           movLeft2Result (left, MSB32, result, MSB24, sign);
7924           addSign (result, MSB32, sign);
7925         }
7926       else
7927         {
7928           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
7929           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
7930           /* the last shift is signed */
7931           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
7932           addSign (result, MSB32, sign);
7933         }
7934     }
7935   else
7936     {                           /* 1 <= shCount <= 7 */
7937       if (shCount <= 2)
7938         {
7939           shiftRLong (left, LSB, result, sign);
7940           if (shCount == 2)
7941             shiftRLong (result, LSB, result, sign);
7942         }
7943       else
7944         {
7945           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
7946           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
7947           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
7948         }
7949     }
7950 }
7951
7952 /*-----------------------------------------------------------------*/
7953 /* genRightShiftLiteral - right shifting by known count            */
7954 /*-----------------------------------------------------------------*/
7955 static void
7956 genRightShiftLiteral (operand * left,
7957                       operand * right,
7958                       operand * result,
7959                       iCode * ic,
7960                       int sign)
7961 {
7962   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7963   int size;
7964
7965   D(emitcode (";     genRightShiftLiteral",""));
7966
7967   freeAsmop (right, NULL, ic, TRUE);
7968
7969   aopOp (left, ic, FALSE);
7970   aopOp (result, ic, FALSE);
7971
7972 #if VIEW_SIZE
7973   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
7974             AOP_SIZE (left));
7975 #endif
7976
7977   size = getDataSize (left);
7978   /* test the LEFT size !!! */
7979
7980   /* I suppose that the left size >= result size */
7981   if (shCount == 0)
7982     {
7983       size = getDataSize (result);
7984       while (size--)
7985         movLeft2Result (left, size, result, size, 0);
7986     }
7987
7988   else if (shCount >= (size * 8))
7989     {
7990       if (sign) {
7991         /* get sign in acc.7 */
7992         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
7993       }
7994       addSign (result, LSB, sign);
7995     }
7996   else
7997     {
7998       switch (size)
7999         {
8000         case 1:
8001           genrshOne (result, left, shCount, sign);
8002           break;
8003
8004         case 2:
8005           genrshTwo (result, left, shCount, sign);
8006           break;
8007
8008         case 4:
8009           genrshFour (result, left, shCount, sign);
8010           break;
8011         default:
8012           break;
8013         }
8014     }
8015   freeAsmop (left, NULL, ic, TRUE);
8016   freeAsmop (result, NULL, ic, TRUE);
8017 }
8018
8019 /*-----------------------------------------------------------------*/
8020 /* genSignedRightShift - right shift of signed number              */
8021 /*-----------------------------------------------------------------*/
8022 static void
8023 genSignedRightShift (iCode * ic)
8024 {
8025   operand *right, *left, *result;
8026   int size, offset;
8027   char *l;
8028   symbol *tlbl, *tlbl1;
8029   bool pushedB;
8030
8031   D(emitcode (";     genSignedRightShift",""));
8032
8033   /* we do it the hard way put the shift count in b
8034      and loop thru preserving the sign */
8035
8036   right = IC_RIGHT (ic);
8037   left = IC_LEFT (ic);
8038   result = IC_RESULT (ic);
8039
8040   aopOp (right, ic, FALSE);
8041
8042
8043   if (AOP_TYPE (right) == AOP_LIT)
8044     {
8045       genRightShiftLiteral (left, right, result, ic, 1);
8046       return;
8047     }
8048   /* shift count is unknown then we have to form
8049      a loop get the loop count in B : Note: we take
8050      only the lower order byte since shifting
8051      more that 32 bits make no sense anyway, ( the
8052      largest size of an object can be only 32 bits ) */
8053
8054   pushedB = pushB ();
8055   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
8056   emitcode ("inc", "b");
8057   freeAsmop (right, NULL, ic, TRUE);
8058   aopOp (left, ic, FALSE);
8059   aopOp (result, ic, FALSE);
8060
8061   /* now move the left to the result if they are not the
8062      same */
8063   if (!sameRegs (AOP (left), AOP (result)) &&
8064       AOP_SIZE (result) > 1)
8065     {
8066
8067       size = AOP_SIZE (result);
8068       offset = 0;
8069       while (size--)
8070         {
8071           l = aopGet (AOP (left), offset, FALSE, TRUE);
8072           if (*l == '@' && IS_AOP_PREG (result))
8073             {
8074
8075               emitcode ("mov", "a,%s", l);
8076               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8077             }
8078           else
8079             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
8080           offset++;
8081         }
8082     }
8083
8084   /* mov the highest order bit to OVR */
8085   tlbl = newiTempLabel (NULL);
8086   tlbl1 = newiTempLabel (NULL);
8087
8088   size = AOP_SIZE (result);
8089   offset = size - 1;
8090   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
8091   emitcode ("rlc", "a");
8092   emitcode ("mov", "ov,c");
8093   /* if it is only one byte then */
8094   if (size == 1)
8095     {
8096       l = aopGet (AOP (left), 0, FALSE, FALSE);
8097       MOVA (l);
8098       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8099       emitcode ("", "%05d$:", tlbl->key + 100);
8100       emitcode ("mov", "c,ov");
8101       emitcode ("rrc", "a");
8102       emitcode ("", "%05d$:", tlbl1->key + 100);
8103       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8104       popB (pushedB);
8105       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
8106       goto release;
8107     }
8108
8109   reAdjustPreg (AOP (result));
8110   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8111   emitcode ("", "%05d$:", tlbl->key + 100);
8112   emitcode ("mov", "c,ov");
8113   while (size--)
8114     {
8115       l = aopGet (AOP (result), offset, FALSE, FALSE);
8116       MOVA (l);
8117       emitcode ("rrc", "a");
8118       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
8119     }
8120   reAdjustPreg (AOP (result));
8121   emitcode ("", "%05d$:", tlbl1->key + 100);
8122   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8123   popB (pushedB);
8124
8125 release:
8126   freeAsmop (left, NULL, ic, TRUE);
8127   freeAsmop (result, NULL, ic, TRUE);
8128 }
8129
8130 /*-----------------------------------------------------------------*/
8131 /* genRightShift - generate code for right shifting                */
8132 /*-----------------------------------------------------------------*/
8133 static void
8134 genRightShift (iCode * ic)
8135 {
8136   operand *right, *left, *result;
8137   sym_link *letype;
8138   int size, offset;
8139   char *l;
8140   symbol *tlbl, *tlbl1;
8141   bool pushedB;
8142
8143   D(emitcode (";     genRightShift",""));
8144
8145   /* if signed then we do it the hard way preserve the
8146      sign bit moving it inwards */
8147   letype = getSpec (operandType (IC_LEFT (ic)));
8148
8149   if (!SPEC_USIGN (letype))
8150     {
8151       genSignedRightShift (ic);
8152       return;
8153     }
8154
8155   /* signed & unsigned types are treated the same : i.e. the
8156      signed is NOT propagated inwards : quoting from the
8157      ANSI - standard : "for E1 >> E2, is equivalent to division
8158      by 2**E2 if unsigned or if it has a non-negative value,
8159      otherwise the result is implementation defined ", MY definition
8160      is that the sign does not get propagated */
8161
8162   right = IC_RIGHT (ic);
8163   left = IC_LEFT (ic);
8164   result = IC_RESULT (ic);
8165
8166   aopOp (right, ic, FALSE);
8167
8168   /* if the shift count is known then do it
8169      as efficiently as possible */
8170   if (AOP_TYPE (right) == AOP_LIT)
8171     {
8172       genRightShiftLiteral (left, right, result, ic, 0);
8173       return;
8174     }
8175
8176   /* shift count is unknown then we have to form
8177      a loop get the loop count in B : Note: we take
8178      only the lower order byte since shifting
8179      more that 32 bits make no sense anyway, ( the
8180      largest size of an object can be only 32 bits ) */
8181
8182   pushedB = pushB ();
8183   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
8184   emitcode ("inc", "b");
8185   freeAsmop (right, NULL, ic, TRUE);
8186   aopOp (left, ic, FALSE);
8187   aopOp (result, ic, FALSE);
8188
8189   /* now move the left to the result if they are not the
8190      same */
8191   if (!sameRegs (AOP (left), AOP (result)) &&
8192       AOP_SIZE (result) > 1)
8193     {
8194
8195       size = AOP_SIZE (result);
8196       offset = 0;
8197       while (size--)
8198         {
8199           l = aopGet (AOP (left), offset, FALSE, TRUE);
8200           if (*l == '@' && IS_AOP_PREG (result))
8201             {
8202
8203               emitcode ("mov", "a,%s", l);
8204               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8205             }
8206           else
8207             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
8208           offset++;
8209         }
8210     }
8211
8212   tlbl = newiTempLabel (NULL);
8213   tlbl1 = newiTempLabel (NULL);
8214   size = AOP_SIZE (result);
8215   offset = size - 1;
8216
8217   /* if it is only one byte then */
8218   if (size == 1)
8219     {
8220       l = aopGet (AOP (left), 0, FALSE, FALSE);
8221       MOVA (l);
8222       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8223       emitcode ("", "%05d$:", tlbl->key + 100);
8224       CLRC;
8225       emitcode ("rrc", "a");
8226       emitcode ("", "%05d$:", tlbl1->key + 100);
8227       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8228       popB (pushedB);
8229       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
8230       goto release;
8231     }
8232
8233   reAdjustPreg (AOP (result));
8234   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8235   emitcode ("", "%05d$:", tlbl->key + 100);
8236   CLRC;
8237   while (size--)
8238     {
8239       l = aopGet (AOP (result), offset, FALSE, FALSE);
8240       MOVA (l);
8241       emitcode ("rrc", "a");
8242       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
8243     }
8244   reAdjustPreg (AOP (result));
8245
8246   emitcode ("", "%05d$:", tlbl1->key + 100);
8247   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8248   popB (pushedB);
8249
8250 release:
8251   freeAsmop (left, NULL, ic, TRUE);
8252   freeAsmop (result, NULL, ic, TRUE);
8253 }
8254
8255 /*-----------------------------------------------------------------*/
8256 /* emitPtrByteGet - emits code to get a byte into A through a      */
8257 /*                  pointer register (R0, R1, or DPTR). The        */
8258 /*                  original value of A can be preserved in B.     */
8259 /*-----------------------------------------------------------------*/
8260 static void
8261 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8262 {
8263   switch (p_type)
8264     {
8265     case IPOINTER:
8266     case POINTER:
8267       if (preserveAinB)
8268         emitcode ("mov", "b,a");
8269       emitcode ("mov", "a,@%s", rname);
8270       break;
8271
8272     case PPOINTER:
8273       if (preserveAinB)
8274         emitcode ("mov", "b,a");
8275       emitcode ("movx", "a,@%s", rname);
8276       break;
8277
8278     case FPOINTER:
8279       if (preserveAinB)
8280         emitcode ("mov", "b,a");
8281       emitcode ("movx", "a,@dptr");
8282       break;
8283
8284     case CPOINTER:
8285       if (preserveAinB)
8286         emitcode ("mov", "b,a");
8287       emitcode ("clr", "a");
8288       emitcode ("movc", "a,@a+dptr");
8289       break;
8290
8291     case GPOINTER:
8292       if (preserveAinB)
8293         {
8294           emitcode ("push", "b");
8295           emitcode ("push", "acc");
8296         }
8297       emitcode ("lcall", "__gptrget");
8298       if (preserveAinB)
8299         emitcode ("pop", "b");
8300       break;
8301     }
8302 }
8303
8304 /*-----------------------------------------------------------------*/
8305 /* emitPtrByteSet - emits code to set a byte from src through a    */
8306 /*                  pointer register (R0, R1, or DPTR).            */
8307 /*-----------------------------------------------------------------*/
8308 static void
8309 emitPtrByteSet (char *rname, int p_type, char *src)
8310 {
8311   switch (p_type)
8312     {
8313     case IPOINTER:
8314     case POINTER:
8315       if (*src=='@')
8316         {
8317           MOVA (src);
8318           emitcode ("mov", "@%s,a", rname);
8319         }
8320       else
8321         emitcode ("mov", "@%s,%s", rname, src);
8322       break;
8323
8324     case PPOINTER:
8325       MOVA (src);
8326       emitcode ("movx", "@%s,a", rname);
8327       break;
8328
8329     case FPOINTER:
8330       MOVA (src);
8331       emitcode ("movx", "@dptr,a");
8332       break;
8333
8334     case GPOINTER:
8335       MOVA (src);
8336       emitcode ("lcall", "__gptrput");
8337       break;
8338     }
8339 }
8340
8341 /*-----------------------------------------------------------------*/
8342 /* genUnpackBits - generates code for unpacking bits               */
8343 /*-----------------------------------------------------------------*/
8344 static void
8345 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8346 {
8347   int offset = 0;       /* result byte offset */
8348   int rsize;            /* result size */
8349   int rlen = 0;         /* remaining bitfield length */
8350   sym_link *etype;      /* bitfield type information */
8351   int blen;             /* bitfield length */
8352   int bstr;             /* bitfield starting bit within byte */
8353   char buffer[10];
8354
8355   D(emitcode (";     genUnpackBits",""));
8356
8357   etype = getSpec (operandType (result));
8358   rsize = getSize (operandType (result));
8359   blen = SPEC_BLEN (etype);
8360   bstr = SPEC_BSTR (etype);
8361
8362   if (ifx && blen <= 8)
8363     {
8364       emitPtrByteGet (rname, ptype, FALSE);
8365       if (blen == 1)
8366         {
8367           SNPRINTF (buffer, sizeof(buffer),
8368                     "acc.%d", bstr);
8369           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8370         }
8371       else
8372         {
8373           if (blen < 8)
8374             emitcode ("anl", "a,#0x%02x",
8375                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8376           genIfxJump (ifx, "a", NULL, NULL, NULL);
8377         }
8378       return;
8379     }
8380   wassert (!ifx);
8381
8382   /* If the bitfield length is less than a byte */
8383   if (blen < 8)
8384     {
8385       emitPtrByteGet (rname, ptype, FALSE);
8386       AccRsh (bstr);
8387       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8388       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8389       goto finish;
8390     }
8391
8392   /* Bit field did not fit in a byte. Copy all
8393      but the partial byte at the end.  */
8394   for (rlen=blen;rlen>=8;rlen-=8)
8395     {
8396       emitPtrByteGet (rname, ptype, FALSE);
8397       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8398       if (rlen>8)
8399         emitcode ("inc", "%s", rname);
8400     }
8401
8402   /* Handle the partial byte at the end */
8403   if (rlen)
8404     {
8405       emitPtrByteGet (rname, ptype, FALSE);
8406       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8407       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8408     }
8409
8410 finish:
8411   if (offset < rsize)
8412     {
8413       rsize -= offset;
8414       while (rsize--)
8415         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
8416     }
8417 }
8418
8419
8420 /*-----------------------------------------------------------------*/
8421 /* genDataPointerGet - generates code when ptr offset is known     */
8422 /*-----------------------------------------------------------------*/
8423 static void
8424 genDataPointerGet (operand * left,
8425                    operand * result,
8426                    iCode * ic)
8427 {
8428   char *l;
8429   char buffer[256];
8430   int size, offset = 0;
8431
8432   D(emitcode (";     genDataPointerGet",""));
8433
8434   aopOp (result, ic, TRUE);
8435
8436   /* get the string representation of the name */
8437   l = aopGet (AOP (left), 0, FALSE, TRUE);
8438   size = AOP_SIZE (result);
8439   while (size--)
8440     {
8441       if (offset)
8442         sprintf (buffer, "(%s + %d)", l + 1, offset);
8443       else
8444         sprintf (buffer, "%s", l + 1);
8445       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
8446     }
8447
8448   freeAsmop (left, NULL, ic, TRUE);
8449   freeAsmop (result, NULL, ic, TRUE);
8450 }
8451
8452 /*-----------------------------------------------------------------*/
8453 /* genNearPointerGet - emitcode for near pointer fetch             */
8454 /*-----------------------------------------------------------------*/
8455 static void
8456 genNearPointerGet (operand * left,
8457                    operand * result,
8458                    iCode * ic,
8459                    iCode * pi,
8460                    iCode * ifx)
8461 {
8462   asmop *aop = NULL;
8463   regs *preg = NULL;
8464   char *rname;
8465   sym_link *rtype, *retype;
8466   sym_link *ltype = operandType (left);
8467   char buffer[80];
8468
8469   D(emitcode (";     genNearPointerGet",""));
8470
8471   rtype = operandType (result);
8472   retype = getSpec (rtype);
8473
8474   aopOp (left, ic, FALSE);
8475
8476   /* if left is rematerialisable and
8477      result is not bitfield variable type and
8478      the left is pointer to data space i.e
8479      lower 128 bytes of space */
8480   if (AOP_TYPE (left) == AOP_IMMD &&
8481       !IS_BITFIELD (retype) &&
8482       DCL_TYPE (ltype) == POINTER)
8483     {
8484       genDataPointerGet (left, result, ic);
8485       return;
8486     }
8487
8488  /* if the value is already in a pointer register
8489      then don't need anything more */
8490   if (!AOP_INPREG (AOP (left)))
8491     {
8492       if (IS_AOP_PREG (left))
8493         {
8494           // Aha, it is a pointer, just in disguise.
8495           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8496           if (*rname != '@')
8497             {
8498               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8499                       __FILE__, __LINE__);
8500             }
8501           else
8502             {
8503               // Expected case.
8504               emitcode ("mov", "a%s,%s", rname + 1, rname);
8505               rname++;  // skip the '@'.
8506             }
8507         }
8508       else
8509         {
8510           /* otherwise get a free pointer register */
8511           aop = newAsmop (0);
8512           preg = getFreePtr (ic, &aop, FALSE);
8513           emitcode ("mov", "%s,%s",
8514                     preg->name,
8515                     aopGet (AOP (left), 0, FALSE, TRUE));
8516           rname = preg->name;
8517         }
8518     }
8519   else
8520     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8521
8522   //aopOp (result, ic, FALSE);
8523   aopOp (result, ic, result?TRUE:FALSE);
8524
8525   /* if bitfield then unpack the bits */
8526   if (IS_BITFIELD (retype))
8527     genUnpackBits (result, rname, POINTER, ifx);
8528   else
8529     {
8530       /* we have can just get the values */
8531       int size = AOP_SIZE (result);
8532       int offset = 0;
8533
8534       while (size--)
8535         {
8536           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8537             {
8538
8539               emitcode ("mov", "a,@%s", rname);
8540               if (!ifx)
8541               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8542             }
8543           else
8544             {
8545               sprintf (buffer, "@%s", rname);
8546               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8547             }
8548           offset++;
8549           if (size || pi)
8550             emitcode ("inc", "%s", rname);
8551         }
8552     }
8553
8554   /* now some housekeeping stuff */
8555   if (aop)       /* we had to allocate for this iCode */
8556     {
8557       if (pi) { /* post increment present */
8558         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8559       }
8560       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8561     }
8562   else
8563     {
8564       /* we did not allocate which means left
8565          already in a pointer register, then
8566          if size > 0 && this could be used again
8567          we have to point it back to where it
8568          belongs */
8569       if ((AOP_SIZE (result) > 1 &&
8570            !OP_SYMBOL (left)->remat &&
8571            (OP_SYMBOL (left)->liveTo > ic->seq ||
8572             ic->depth)) &&
8573           !pi)
8574         {
8575           int size = AOP_SIZE (result) - 1;
8576           while (size--)
8577             emitcode ("dec", "%s", rname);
8578         }
8579     }
8580
8581   if (ifx && !ifx->generated)
8582     {
8583       genIfxJump (ifx, "a", left, NULL, result);
8584     }
8585
8586   /* done */
8587   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8588   freeAsmop (left, NULL, ic, TRUE);
8589   if (pi) pi->generated = 1;
8590 }
8591
8592 /*-----------------------------------------------------------------*/
8593 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8594 /*-----------------------------------------------------------------*/
8595 static void
8596 genPagedPointerGet (operand * left,
8597                     operand * result,
8598                     iCode * ic,
8599                     iCode *pi,
8600                     iCode *ifx)
8601 {
8602   asmop *aop = NULL;
8603   regs *preg = NULL;
8604   char *rname;
8605   sym_link *rtype, *retype;
8606
8607   D(emitcode (";     genPagedPointerGet",""));
8608
8609   rtype = operandType (result);
8610   retype = getSpec (rtype);
8611
8612   aopOp (left, ic, FALSE);
8613
8614   /* if the value is already in a pointer register
8615      then don't need anything more */
8616   if (!AOP_INPREG (AOP (left)))
8617     {
8618       /* otherwise get a free pointer register */
8619       aop = newAsmop (0);
8620       preg = getFreePtr (ic, &aop, FALSE);
8621       emitcode ("mov", "%s,%s",
8622                 preg->name,
8623                 aopGet (AOP (left), 0, FALSE, TRUE));
8624       rname = preg->name;
8625     }
8626   else
8627     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8628
8629   aopOp (result, ic, FALSE);
8630
8631   /* if bitfield then unpack the bits */
8632   if (IS_BITFIELD (retype))
8633     genUnpackBits (result, rname, PPOINTER, ifx);
8634   else
8635     {
8636       /* we have can just get the values */
8637       int size = AOP_SIZE (result);
8638       int offset = 0;
8639
8640       while (size--)
8641         {
8642
8643           emitcode ("movx", "a,@%s", rname);
8644           if (!ifx)
8645           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8646
8647           offset++;
8648
8649           if (size || pi)
8650             emitcode ("inc", "%s", rname);
8651         }
8652     }
8653
8654   /* now some housekeeping stuff */
8655   if (aop) /* we had to allocate for this iCode */
8656     {
8657       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8658       freeAsmop (NULL, aop, ic, TRUE);
8659     }
8660   else
8661     {
8662       /* we did not allocate which means left
8663          already in a pointer register, then
8664          if size > 0 && this could be used again
8665          we have to point it back to where it
8666          belongs */
8667       if ((AOP_SIZE (result) > 1 &&
8668            !OP_SYMBOL (left)->remat &&
8669            (OP_SYMBOL (left)->liveTo > ic->seq ||
8670             ic->depth)) &&
8671           !pi)
8672         {
8673           int size = AOP_SIZE (result) - 1;
8674           while (size--)
8675             emitcode ("dec", "%s", rname);
8676         }
8677     }
8678
8679   if (ifx && !ifx->generated)
8680     {
8681       genIfxJump (ifx, "a", left, NULL, result);
8682     }
8683
8684   /* done */
8685   freeAsmop (left, NULL, ic, TRUE);
8686   freeAsmop (result, NULL, ic, TRUE);
8687   if (pi) pi->generated = 1;
8688
8689 }
8690
8691 /*--------------------------------------------------------------------*/
8692 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8693 /*--------------------------------------------------------------------*/
8694 static void
8695 loadDptrFromOperand (operand *op, bool loadBToo)
8696 {
8697   if (AOP_TYPE (op) != AOP_STR)
8698     {
8699       /* if this is rematerializable */
8700       if (AOP_TYPE (op) == AOP_IMMD)
8701         {
8702           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8703           if (loadBToo)
8704             {
8705               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8706                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8707               else
8708                 {
8709                   wassertl(FALSE, "need pointerCode");
8710                   emitcode ("", "; mov b,???");
8711                   /* genPointerGet and genPointerSet originally did different
8712                   ** things for this case. Both seem wrong.
8713                   ** from genPointerGet:
8714                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8715                   ** from genPointerSet:
8716                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8717                   */
8718                 }
8719             }
8720         }
8721       else if (AOP_TYPE (op) == AOP_DPTR)
8722         {
8723           if (loadBToo)
8724             {
8725               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8726               emitcode ("push", "acc");
8727               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8728               emitcode ("push", "acc");
8729               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8730               emitcode ("pop", "dph");
8731               emitcode ("pop", "dpl");
8732             }
8733           else
8734             {
8735               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8736               emitcode ("push", "acc");
8737               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8738               emitcode ("pop", "dpl");
8739             }
8740         }
8741       else
8742         {                       /* we need to get it byte by byte */
8743           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8744           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8745           if (loadBToo)
8746             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8747         }
8748     }
8749 }
8750
8751 /*-----------------------------------------------------------------*/
8752 /* genFarPointerGet - gget value from far space                    */
8753 /*-----------------------------------------------------------------*/
8754 static void
8755 genFarPointerGet (operand * left,
8756                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
8757 {
8758   int size, offset;
8759   sym_link *retype = getSpec (operandType (result));
8760
8761   D(emitcode (";     genFarPointerGet",""));
8762
8763   aopOp (left, ic, FALSE);
8764   loadDptrFromOperand (left, FALSE);
8765
8766   /* so dptr now contains the address */
8767   aopOp (result, ic, FALSE);
8768
8769   /* if bit then unpack */
8770   if (IS_BITFIELD (retype))
8771     genUnpackBits (result, "dptr", FPOINTER, ifx);
8772   else
8773     {
8774       size = AOP_SIZE (result);
8775       offset = 0;
8776
8777       while (size--)
8778         {
8779           emitcode ("movx", "a,@dptr");
8780           if (!ifx)
8781             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8782           if (size || pi)
8783             emitcode ("inc", "dptr");
8784         }
8785     }
8786
8787   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8788     {
8789     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8790     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8791     pi->generated = 1;
8792   }
8793
8794   if (ifx && !ifx->generated)
8795     {
8796       genIfxJump (ifx, "a", left, NULL, result);
8797     }
8798
8799   freeAsmop (left, NULL, ic, TRUE);
8800   freeAsmop (result, NULL, ic, TRUE);
8801 }
8802
8803 /*-----------------------------------------------------------------*/
8804 /* genCodePointerGet - gget value from code space                  */
8805 /*-----------------------------------------------------------------*/
8806 static void
8807 genCodePointerGet (operand * left,
8808                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
8809 {
8810   int size, offset;
8811   sym_link *retype = getSpec (operandType (result));
8812
8813   D(emitcode (";     genCodePointerGet",""));
8814
8815   aopOp (left, ic, FALSE);
8816   loadDptrFromOperand (left, FALSE);
8817
8818   /* so dptr now contains the address */
8819   aopOp (result, ic, FALSE);
8820
8821   /* if bit then unpack */
8822   if (IS_BITFIELD (retype))
8823     genUnpackBits (result, "dptr", CPOINTER, ifx);
8824   else
8825     {
8826       size = AOP_SIZE (result);
8827       offset = 0;
8828
8829       while (size--)
8830         {
8831           if (pi)
8832             {
8833               emitcode ("clr", "a");
8834               emitcode ("movc", "a,@a+dptr");
8835               if (!ifx)
8836               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8837               emitcode ("inc", "dptr");
8838             }
8839           else
8840             {
8841               emitcode ("mov", "a,#0x%02x", offset);
8842               emitcode ("movc", "a,@a+dptr");
8843               if (!ifx)
8844               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8845             }
8846         }
8847     }
8848
8849   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8850     {
8851     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8852     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8853     pi->generated = 1;
8854   }
8855
8856   if (ifx && !ifx->generated)
8857     {
8858       genIfxJump (ifx, "a", left, NULL, result);
8859     }
8860
8861   freeAsmop (left, NULL, ic, TRUE);
8862   freeAsmop (result, NULL, ic, TRUE);
8863 }
8864
8865 /*-----------------------------------------------------------------*/
8866 /* genGenPointerGet - gget value from generic pointer space        */
8867 /*-----------------------------------------------------------------*/
8868 static void
8869 genGenPointerGet (operand * left,
8870                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
8871 {
8872   int size, offset;
8873   sym_link *retype = getSpec (operandType (result));
8874
8875   D(emitcode (";     genGenPointerGet",""));
8876
8877   aopOp (left, ic, FALSE);
8878   loadDptrFromOperand (left, TRUE);
8879
8880   /* so dptr know contains the address */
8881   aopOp (result, ic, FALSE);
8882
8883   /* if bit then unpack */
8884   if (IS_BITFIELD (retype))
8885     genUnpackBits (result, "dptr", GPOINTER, ifx);
8886   else
8887     {
8888       size = AOP_SIZE (result);
8889       offset = 0;
8890
8891       while (size--)
8892         {
8893           emitcode ("lcall", "__gptrget");
8894           if (!ifx)
8895           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8896           if (size || pi)
8897             emitcode ("inc", "dptr");
8898         }
8899     }
8900
8901   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8902     {
8903     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8904     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8905     pi->generated = 1;
8906   }
8907
8908   if (ifx && !ifx->generated)
8909     {
8910       genIfxJump (ifx, "a", left, NULL, result);
8911     }
8912
8913
8914   freeAsmop (left, NULL, ic, TRUE);
8915   freeAsmop (result, NULL, ic, TRUE);
8916 }
8917
8918 /*-----------------------------------------------------------------*/
8919 /* genPointerGet - generate code for pointer get                   */
8920 /*-----------------------------------------------------------------*/
8921 static void
8922 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
8923 {
8924   operand *left, *result;
8925   sym_link *type, *etype;
8926   int p_type;
8927
8928   D(emitcode (";     genPointerGet",""));
8929
8930   left = IC_LEFT (ic);
8931   result = IC_RESULT (ic);
8932
8933   if (getSize (operandType (result))>1)
8934     ifx = NULL;
8935
8936   /* depending on the type of pointer we need to
8937      move it to the correct pointer register */
8938   type = operandType (left);
8939   etype = getSpec (type);
8940   /* if left is of type of pointer then it is simple */
8941   if (IS_PTR (type) && !IS_FUNC (type->next))
8942     p_type = DCL_TYPE (type);
8943   else
8944     {
8945       /* we have to go by the storage class */
8946       p_type = PTR_TYPE (SPEC_OCLS (etype));
8947     }
8948
8949   /* special case when cast remat */
8950   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
8951       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
8952           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
8953           type = operandType (left);
8954           p_type = DCL_TYPE (type);
8955   }
8956   /* now that we have the pointer type we assign
8957      the pointer values */
8958   switch (p_type)
8959     {
8960
8961     case POINTER:
8962     case IPOINTER:
8963       genNearPointerGet (left, result, ic, pi, ifx);
8964       break;
8965
8966     case PPOINTER:
8967       genPagedPointerGet (left, result, ic, pi, ifx);
8968       break;
8969
8970     case FPOINTER:
8971       genFarPointerGet (left, result, ic, pi, ifx);
8972       break;
8973
8974     case CPOINTER:
8975       genCodePointerGet (left, result, ic, pi, ifx);
8976       break;
8977
8978     case GPOINTER:
8979       genGenPointerGet (left, result, ic, pi, ifx);
8980       break;
8981     }
8982
8983 }
8984
8985
8986
8987 /*-----------------------------------------------------------------*/
8988 /* genPackBits - generates code for packed bit storage             */
8989 /*-----------------------------------------------------------------*/
8990 static void
8991 genPackBits (sym_link * etype,
8992              operand * right,
8993              char *rname, int p_type)
8994 {
8995   int offset = 0;       /* source byte offset */
8996   int rlen = 0;         /* remaining bitfield length */
8997   int blen;             /* bitfield length */
8998   int bstr;             /* bitfield starting bit within byte */
8999   int litval;           /* source literal value (if AOP_LIT) */
9000   unsigned char mask;   /* bitmask within current byte */
9001
9002   D(emitcode (";     genPackBits",""));
9003
9004   blen = SPEC_BLEN (etype);
9005   bstr = SPEC_BSTR (etype);
9006
9007   /* If the bitfield length is less than a byte */
9008   if (blen < 8)
9009     {
9010       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9011               (unsigned char) (0xFF >> (8 - bstr)));
9012
9013       if (AOP_TYPE (right) == AOP_LIT)
9014         {
9015           /* Case with a bitfield length <8 and literal source
9016           */
9017           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9018           litval <<= bstr;
9019           litval &= (~mask) & 0xff;
9020           emitPtrByteGet (rname, p_type, FALSE);
9021           if ((mask|litval)!=0xff)
9022             emitcode ("anl","a,#0x%02x", mask);
9023           if (litval)
9024             emitcode ("orl","a,#0x%02x", litval);
9025         }
9026       else
9027         {
9028           if ((blen==1) && (p_type!=GPOINTER))
9029             {
9030               /* Case with a bitfield length == 1 and no generic pointer
9031               */
9032               if (AOP_TYPE (right) == AOP_CRY)
9033                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9034               else
9035                 {
9036                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
9037                   emitcode ("rrc","a");
9038                 }
9039               emitPtrByteGet (rname, p_type, FALSE);
9040               emitcode ("mov","acc.%d,c",bstr);
9041             }
9042           else
9043             {
9044               bool pushedB;
9045               /* Case with a bitfield length < 8 and arbitrary source
9046               */
9047               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
9048               /* shift and mask source value */
9049               AccLsh (bstr);
9050               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9051
9052               pushedB = pushB ();
9053               /* transfer A to B and get next byte */
9054               emitPtrByteGet (rname, p_type, TRUE);
9055
9056               emitcode ("anl", "a,#0x%02x", mask);
9057               emitcode ("orl", "a,b");
9058               if (p_type == GPOINTER)
9059                 emitcode ("pop", "b");
9060
9061               popB (pushedB);
9062            }
9063         }
9064
9065       emitPtrByteSet (rname, p_type, "a");
9066       return;
9067     }
9068
9069   /* Bit length is greater than 7 bits. In this case, copy  */
9070   /* all except the partial byte at the end                 */
9071   for (rlen=blen;rlen>=8;rlen-=8)
9072     {
9073       emitPtrByteSet (rname, p_type,
9074                       aopGet (AOP (right), offset++, FALSE, TRUE) );
9075       if (rlen>8)
9076         emitcode ("inc", "%s", rname);
9077     }
9078
9079   /* If there was a partial byte at the end */
9080   if (rlen)
9081     {
9082       mask = (((unsigned char) -1 << rlen) & 0xff);
9083
9084       if (AOP_TYPE (right) == AOP_LIT)
9085         {
9086           /* Case with partial byte and literal source
9087           */
9088           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9089           litval >>= (blen-rlen);
9090           litval &= (~mask) & 0xff;
9091           emitPtrByteGet (rname, p_type, FALSE);
9092           if ((mask|litval)!=0xff)
9093             emitcode ("anl","a,#0x%02x", mask);
9094           if (litval)
9095             emitcode ("orl","a,#0x%02x", litval);
9096         }
9097       else
9098         {
9099           bool pushedB;
9100           /* Case with partial byte and arbitrary source
9101           */
9102           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
9103           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9104
9105           pushedB = pushB ();
9106           /* transfer A to B and get next byte */
9107           emitPtrByteGet (rname, p_type, TRUE);
9108
9109           emitcode ("anl", "a,#0x%02x", mask);
9110           emitcode ("orl", "a,b");
9111           if (p_type == GPOINTER)
9112             emitcode ("pop", "b");
9113
9114           popB (pushedB);
9115         }
9116       emitPtrByteSet (rname, p_type, "a");
9117     }
9118
9119 }
9120
9121
9122 /*-----------------------------------------------------------------*/
9123 /* genDataPointerSet - remat pointer to data space                 */
9124 /*-----------------------------------------------------------------*/
9125 static void
9126 genDataPointerSet (operand * right,
9127                    operand * result,
9128                    iCode * ic)
9129 {
9130   int size, offset = 0;
9131   char *l, buffer[256];
9132
9133   D(emitcode (";     genDataPointerSet",""));
9134
9135   aopOp (right, ic, FALSE);
9136
9137   l = aopGet (AOP (result), 0, FALSE, TRUE);
9138   size = AOP_SIZE (right);
9139   while (size--)
9140     {
9141       if (offset)
9142         sprintf (buffer, "(%s + %d)", l + 1, offset);
9143       else
9144         sprintf (buffer, "%s", l + 1);
9145       emitcode ("mov", "%s,%s", buffer,
9146                 aopGet (AOP (right), offset++, FALSE, FALSE));
9147     }
9148
9149   freeAsmop (right, NULL, ic, TRUE);
9150   freeAsmop (result, NULL, ic, TRUE);
9151 }
9152
9153 /*-----------------------------------------------------------------*/
9154 /* genNearPointerSet - emitcode for near pointer put                */
9155 /*-----------------------------------------------------------------*/
9156 static void
9157 genNearPointerSet (operand * right,
9158                    operand * result,
9159                    iCode * ic,
9160                    iCode * pi)
9161 {
9162   asmop *aop = NULL;
9163   regs *preg = NULL;
9164   char *rname, *l;
9165   sym_link *retype, *letype;
9166   sym_link *ptype = operandType (result);
9167
9168   D(emitcode (";     genNearPointerSet",""));
9169
9170   retype = getSpec (operandType (right));
9171   letype = getSpec (ptype);
9172   aopOp (result, ic, FALSE);
9173
9174   /* if the result is rematerializable &
9175      in data space & not a bit variable */
9176   if (AOP_TYPE (result) == AOP_IMMD &&
9177       DCL_TYPE (ptype) == POINTER &&
9178       !IS_BITVAR (retype) &&
9179       !IS_BITVAR (letype))
9180     {
9181       genDataPointerSet (right, result, ic);
9182       return;
9183     }
9184
9185   /* if the value is already in a pointer register
9186      then don't need anything more */
9187   if (!AOP_INPREG (AOP (result)))
9188     {
9189         if (
9190             //AOP_TYPE (result) == AOP_STK
9191             IS_AOP_PREG(result)
9192             )
9193         {
9194             // Aha, it is a pointer, just in disguise.
9195             rname = aopGet (AOP (result), 0, FALSE, FALSE);
9196             if (*rname != '@')
9197             {
9198                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9199                         __FILE__, __LINE__);
9200             }
9201             else
9202             {
9203                 // Expected case.
9204                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9205                 rname++;  // skip the '@'.
9206             }
9207         }
9208         else
9209         {
9210             /* otherwise get a free pointer register */
9211             aop = newAsmop (0);
9212             preg = getFreePtr (ic, &aop, FALSE);
9213             emitcode ("mov", "%s,%s",
9214                       preg->name,
9215                       aopGet (AOP (result), 0, FALSE, TRUE));
9216             rname = preg->name;
9217         }
9218     }
9219     else
9220     {
9221         rname = aopGet (AOP (result), 0, FALSE, FALSE);
9222     }
9223
9224   aopOp (right, ic, FALSE);
9225
9226   /* if bitfield then unpack the bits */
9227   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9228     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9229   else
9230     {
9231       /* we have can just get the values */
9232       int size = AOP_SIZE (right);
9233       int offset = 0;
9234
9235       while (size--)
9236         {
9237           l = aopGet (AOP (right), offset, FALSE, TRUE);
9238           if (*l == '@')
9239             {
9240               MOVA (l);
9241               emitcode ("mov", "@%s,a", rname);
9242             }
9243           else
9244             emitcode ("mov", "@%s,%s", rname, l);
9245           if (size || pi)
9246             emitcode ("inc", "%s", rname);
9247           offset++;
9248         }
9249     }
9250
9251   /* now some housekeeping stuff */
9252   if (aop) /* we had to allocate for this iCode */
9253     {
9254       if (pi)
9255         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9256       freeAsmop (NULL, aop, ic, TRUE);
9257     }
9258   else
9259     {
9260       /* we did not allocate which means left
9261          already in a pointer register, then
9262          if size > 0 && this could be used again
9263          we have to point it back to where it
9264          belongs */
9265       if ((AOP_SIZE (right) > 1 &&
9266            !OP_SYMBOL (result)->remat &&
9267            (OP_SYMBOL (result)->liveTo > ic->seq ||
9268             ic->depth)) &&
9269           !pi)
9270         {
9271           int size = AOP_SIZE (right) - 1;
9272           while (size--)
9273             emitcode ("dec", "%s", rname);
9274         }
9275     }
9276
9277   /* done */
9278   if (pi) pi->generated = 1;
9279   freeAsmop (result, NULL, ic, TRUE);
9280   freeAsmop (right, NULL, ic, TRUE);
9281 }
9282
9283 /*-----------------------------------------------------------------*/
9284 /* genPagedPointerSet - emitcode for Paged pointer put             */
9285 /*-----------------------------------------------------------------*/
9286 static void
9287 genPagedPointerSet (operand * right,
9288                     operand * result,
9289                     iCode * ic,
9290                     iCode * pi)
9291 {
9292   asmop *aop = NULL;
9293   regs *preg = NULL;
9294   char *rname, *l;
9295   sym_link *retype, *letype;
9296
9297   D(emitcode (";     genPagedPointerSet",""));
9298
9299   retype = getSpec (operandType (right));
9300   letype = getSpec (operandType (result));
9301
9302   aopOp (result, ic, FALSE);
9303
9304   /* if the value is already in a pointer register
9305      then don't need anything more */
9306   if (!AOP_INPREG (AOP (result)))
9307     {
9308       /* otherwise get a free pointer register */
9309       aop = newAsmop (0);
9310       preg = getFreePtr (ic, &aop, FALSE);
9311       emitcode ("mov", "%s,%s",
9312                 preg->name,
9313                 aopGet (AOP (result), 0, FALSE, TRUE));
9314       rname = preg->name;
9315     }
9316   else
9317     rname = aopGet (AOP (result), 0, FALSE, FALSE);
9318
9319   aopOp (right, ic, FALSE);
9320
9321   /* if bitfield then unpack the bits */
9322   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9323     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9324   else
9325     {
9326       /* we have can just get the values */
9327       int size = AOP_SIZE (right);
9328       int offset = 0;
9329
9330       while (size--)
9331         {
9332           l = aopGet (AOP (right), offset, FALSE, TRUE);
9333
9334           MOVA (l);
9335           emitcode ("movx", "@%s,a", rname);
9336
9337           if (size || pi)
9338             emitcode ("inc", "%s", rname);
9339
9340           offset++;
9341         }
9342     }
9343
9344   /* now some housekeeping stuff */
9345   if (aop) /* we had to allocate for this iCode */
9346     {
9347       if (pi)
9348         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9349       freeAsmop (NULL, aop, ic, TRUE);
9350     }
9351   else
9352     {
9353       /* we did not allocate which means left
9354          already in a pointer register, then
9355          if size > 0 && this could be used again
9356          we have to point it back to where it
9357          belongs */
9358       if (AOP_SIZE (right) > 1 &&
9359           !OP_SYMBOL (result)->remat &&
9360           (OP_SYMBOL (result)->liveTo > ic->seq ||
9361            ic->depth))
9362         {
9363           int size = AOP_SIZE (right) - 1;
9364           while (size--)
9365             emitcode ("dec", "%s", rname);
9366         }
9367     }
9368
9369   /* done */
9370   if (pi) pi->generated = 1;
9371   freeAsmop (result, NULL, ic, TRUE);
9372   freeAsmop (right, NULL, ic, TRUE);
9373
9374
9375 }
9376
9377 /*-----------------------------------------------------------------*/
9378 /* genFarPointerSet - set value from far space                     */
9379 /*-----------------------------------------------------------------*/
9380 static void
9381 genFarPointerSet (operand * right,
9382                   operand * result, iCode * ic, iCode * pi)
9383 {
9384   int size, offset;
9385   sym_link *retype = getSpec (operandType (right));
9386   sym_link *letype = getSpec (operandType (result));
9387
9388   D(emitcode (";     genFarPointerSet",""));
9389
9390   aopOp (result, ic, FALSE);
9391   loadDptrFromOperand (result, FALSE);
9392
9393   /* so dptr know contains the address */
9394   aopOp (right, ic, FALSE);
9395
9396   /* if bit then unpack */
9397   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9398     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9399   else
9400     {
9401       size = AOP_SIZE (right);
9402       offset = 0;
9403
9404       while (size--)
9405         {
9406           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9407           MOVA (l);
9408           emitcode ("movx", "@dptr,a");
9409           if (size || pi)
9410             emitcode ("inc", "dptr");
9411         }
9412     }
9413   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9414     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9415     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9416     pi->generated=1;
9417   }
9418   freeAsmop (result, NULL, ic, TRUE);
9419   freeAsmop (right, NULL, ic, TRUE);
9420 }
9421
9422 /*-----------------------------------------------------------------*/
9423 /* genGenPointerSet - set value from generic pointer space         */
9424 /*-----------------------------------------------------------------*/
9425 static void
9426 genGenPointerSet (operand * right,
9427                   operand * result, iCode * ic, iCode * pi)
9428 {
9429   int size, offset;
9430   sym_link *retype = getSpec (operandType (right));
9431   sym_link *letype = getSpec (operandType (result));
9432
9433   D(emitcode (";     genGenPointerSet",""));
9434
9435   aopOp (result, ic, FALSE);
9436   loadDptrFromOperand (result, TRUE);
9437
9438   /* so dptr know contains the address */
9439   aopOp (right, ic, FALSE);
9440
9441   /* if bit then unpack */
9442   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9443     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9444   else
9445     {
9446       size = AOP_SIZE (right);
9447       offset = 0;
9448
9449       while (size--)
9450         {
9451           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9452           MOVA (l);
9453           emitcode ("lcall", "__gptrput");
9454           if (size || pi)
9455             emitcode ("inc", "dptr");
9456         }
9457     }
9458
9459   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9460     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9461     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9462     pi->generated=1;
9463   }
9464   freeAsmop (result, NULL, ic, TRUE);
9465   freeAsmop (right, NULL, ic, TRUE);
9466 }
9467
9468 /*-----------------------------------------------------------------*/
9469 /* genPointerSet - stores the value into a pointer location        */
9470 /*-----------------------------------------------------------------*/
9471 static void
9472 genPointerSet (iCode * ic, iCode *pi)
9473 {
9474   operand *right, *result;
9475   sym_link *type, *etype;
9476   int p_type;
9477
9478   D(emitcode (";     genPointerSet",""));
9479
9480   right = IC_RIGHT (ic);
9481   result = IC_RESULT (ic);
9482
9483   /* depending on the type of pointer we need to
9484      move it to the correct pointer register */
9485   type = operandType (result);
9486   etype = getSpec (type);
9487   /* if left is of type of pointer then it is simple */
9488   if (IS_PTR (type) && !IS_FUNC (type->next))
9489     {
9490       p_type = DCL_TYPE (type);
9491     }
9492   else
9493     {
9494       /* we have to go by the storage class */
9495       p_type = PTR_TYPE (SPEC_OCLS (etype));
9496     }
9497
9498   /* special case when cast remat */
9499   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9500       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9501           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9502           type = operandType (result);
9503           p_type = DCL_TYPE (type);
9504   }
9505   /* now that we have the pointer type we assign
9506      the pointer values */
9507   switch (p_type)
9508     {
9509
9510     case POINTER:
9511     case IPOINTER:
9512       genNearPointerSet (right, result, ic, pi);
9513       break;
9514
9515     case PPOINTER:
9516       genPagedPointerSet (right, result, ic, pi);
9517       break;
9518
9519     case FPOINTER:
9520       genFarPointerSet (right, result, ic, pi);
9521       break;
9522
9523     case GPOINTER:
9524       genGenPointerSet (right, result, ic, pi);
9525       break;
9526
9527     default:
9528       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9529               "genPointerSet: illegal pointer type");
9530     }
9531
9532 }
9533
9534 /*-----------------------------------------------------------------*/
9535 /* genIfx - generate code for Ifx statement                        */
9536 /*-----------------------------------------------------------------*/
9537 static void
9538 genIfx (iCode * ic, iCode * popIc)
9539 {
9540   operand *cond = IC_COND (ic);
9541   int isbit = 0;
9542
9543   D(emitcode (";     genIfx",""));
9544
9545   aopOp (cond, ic, FALSE);
9546
9547   /* get the value into acc */
9548   if (AOP_TYPE (cond) != AOP_CRY)
9549     toBoolean (cond);
9550   else
9551     isbit = 1;
9552   /* the result is now in the accumulator */
9553   freeAsmop (cond, NULL, ic, TRUE);
9554
9555   /* if there was something to be popped then do it */
9556   if (popIc)
9557     genIpop (popIc);
9558
9559   /* if the condition is a bit variable */
9560   if (isbit && IS_ITEMP (cond) &&
9561       SPIL_LOC (cond))
9562     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9563   else if (isbit && !IS_ITEMP (cond))
9564     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9565   else
9566     genIfxJump (ic, "a", NULL, NULL, NULL);
9567
9568   ic->generated = 1;
9569 }
9570
9571 /*-----------------------------------------------------------------*/
9572 /* genAddrOf - generates code for address of                       */
9573 /*-----------------------------------------------------------------*/
9574 static void
9575 genAddrOf (iCode * ic)
9576 {
9577   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9578   int size, offset;
9579
9580   D(emitcode (";     genAddrOf",""));
9581
9582   aopOp (IC_RESULT (ic), ic, FALSE);
9583
9584   /* if the operand is on the stack then we
9585      need to get the stack offset of this
9586      variable */
9587   if (sym->onStack)
9588     {
9589       /* if it has an offset then we need to compute
9590          it */
9591       if (sym->stack)
9592         {
9593           emitcode ("mov", "a,_bp");
9594           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9595                                          ((char) (sym->stack - _G.nRegsSaved)) :
9596                                          ((char) sym->stack)) & 0xff);
9597           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9598         }
9599       else
9600         {
9601           /* we can just move _bp */
9602           aopPut (AOP (IC_RESULT (ic)), "_bp", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9603         }
9604       /* fill the result with zero */
9605       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9606
9607       offset = 1;
9608       while (size--)
9609         {
9610           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9611         }
9612
9613       goto release;
9614     }
9615
9616   /* object not on stack then we need the name */
9617   size = AOP_SIZE (IC_RESULT (ic));
9618   offset = 0;
9619
9620   while (size--)
9621     {
9622       char s[SDCC_NAME_MAX];
9623       if (offset)
9624         sprintf (s, "#(%s >> %d)",
9625                  sym->rname,
9626                  offset * 8);
9627       else
9628         sprintf (s, "#%s", sym->rname);
9629       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9630     }
9631
9632 release:
9633   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9634
9635 }
9636
9637 /*-----------------------------------------------------------------*/
9638 /* genFarFarAssign - assignment when both are in far space         */
9639 /*-----------------------------------------------------------------*/
9640 static void
9641 genFarFarAssign (operand * result, operand * right, iCode * ic)
9642 {
9643   int size = AOP_SIZE (right);
9644   int offset = 0;
9645   char *l;
9646
9647   D(emitcode (";     genFarFarAssign",""));
9648
9649   /* first push the right side on to the stack */
9650   while (size--)
9651     {
9652       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9653       MOVA (l);
9654       emitcode ("push", "acc");
9655     }
9656
9657   freeAsmop (right, NULL, ic, FALSE);
9658   /* now assign DPTR to result */
9659   aopOp (result, ic, FALSE);
9660   size = AOP_SIZE (result);
9661   while (size--)
9662     {
9663       emitcode ("pop", "acc");
9664       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9665     }
9666   freeAsmop (result, NULL, ic, FALSE);
9667
9668 }
9669
9670 /*-----------------------------------------------------------------*/
9671 /* genAssign - generate code for assignment                        */
9672 /*-----------------------------------------------------------------*/
9673 static void
9674 genAssign (iCode * ic)
9675 {
9676   operand *result, *right;
9677   int size, offset;
9678   unsigned long lit = 0L;
9679
9680   D(emitcode(";     genAssign",""));
9681
9682   result = IC_RESULT (ic);
9683   right = IC_RIGHT (ic);
9684
9685   /* if they are the same */
9686   if (operandsEqu (result, right) &&
9687       !isOperandVolatile (result, FALSE) &&
9688       !isOperandVolatile (right, FALSE))
9689     return;
9690
9691   aopOp (right, ic, FALSE);
9692
9693   /* special case both in far space */
9694   if (AOP_TYPE (right) == AOP_DPTR &&
9695       IS_TRUE_SYMOP (result) &&
9696       isOperandInFarSpace (result))
9697     {
9698
9699       genFarFarAssign (result, right, ic);
9700       return;
9701     }
9702
9703   aopOp (result, ic, TRUE);
9704
9705   /* if they are the same registers */
9706   if (sameRegs (AOP (right), AOP (result)) &&
9707       !isOperandVolatile (result, FALSE) &&
9708       !isOperandVolatile (right, FALSE))
9709     goto release;
9710
9711   /* if the result is a bit */
9712   if (AOP_TYPE (result) == AOP_CRY)
9713     {
9714
9715       /* if the right size is a literal then
9716          we know what the value is */
9717       if (AOP_TYPE (right) == AOP_LIT)
9718         {
9719           if (((int) operandLitValue (right)))
9720             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9721           else
9722             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9723           goto release;
9724         }
9725
9726       /* the right is also a bit variable */
9727       if (AOP_TYPE (right) == AOP_CRY)
9728         {
9729           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9730           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9731           goto release;
9732         }
9733
9734       /* we need to or */
9735       toBoolean (right);
9736       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9737       goto release;
9738     }
9739
9740   /* bit variables done */
9741   /* general case */
9742   size = AOP_SIZE (result);
9743   offset = 0;
9744   if (AOP_TYPE (right) == AOP_LIT)
9745     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9746   if ((size > 1) &&
9747       (AOP_TYPE (result) != AOP_REG) &&
9748       (AOP_TYPE (right) == AOP_LIT) &&
9749       !IS_FLOAT (operandType (right)) &&
9750       (lit < 256L))
9751     {
9752       while ((size) && (lit))
9753         {
9754           aopPut (AOP (result),
9755                   aopGet (AOP (right), offset, FALSE, FALSE),
9756                   offset,
9757                   isOperandVolatile (result, FALSE));
9758           lit >>= 8;
9759           offset++;
9760           size--;
9761         }
9762       emitcode ("clr", "a");
9763       while (size--)
9764         {
9765           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
9766           offset++;
9767         }
9768     }
9769   else
9770     {
9771       while (size--)
9772         {
9773           aopPut (AOP (result),
9774                   aopGet (AOP (right), offset, FALSE, FALSE),
9775                   offset,
9776                   isOperandVolatile (result, FALSE));
9777           offset++;
9778         }
9779     }
9780
9781 release:
9782   freeAsmop (right, NULL, ic, TRUE);
9783   freeAsmop (result, NULL, ic, TRUE);
9784 }
9785
9786 /*-----------------------------------------------------------------*/
9787 /* genJumpTab - genrates code for jump table                       */
9788 /*-----------------------------------------------------------------*/
9789 static void
9790 genJumpTab (iCode * ic)
9791 {
9792   symbol *jtab,*jtablo,*jtabhi;
9793   char *l;
9794   unsigned int count;
9795
9796   D(emitcode (";     genJumpTab",""));
9797
9798   count = elementsInSet( IC_JTLABELS (ic) );
9799
9800   if( count <= 16 )
9801     {
9802       /* this algorithm needs 9 cycles and 7 + 3*n bytes
9803          if the switch argument is in a register.
9804          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
9805       /* (MB) What if peephole converts ljmp to sjmp or ret ???
9806          How will multiply by three be updated ???*/
9807       aopOp (IC_JTCOND (ic), ic, FALSE);
9808       /* get the condition into accumulator */
9809       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9810       MOVA (l);
9811       /* multiply by three */
9812       emitcode ("add", "a,acc");
9813       emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9814       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9815
9816       jtab = newiTempLabel (NULL);
9817       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9818       emitcode ("jmp", "@a+dptr");
9819       emitcode ("", "%05d$:", jtab->key + 100);
9820       /* now generate the jump labels */
9821       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9822            jtab = setNextItem (IC_JTLABELS (ic)))
9823         emitcode ("ljmp", "%05d$", jtab->key + 100);
9824     }
9825   else
9826     {
9827       /* this algorithm needs 14 cycles and 13 + 2*n bytes
9828          if the switch argument is in a register.
9829          For n>6 this algorithm may be more compact */
9830       jtablo = newiTempLabel (NULL);
9831       jtabhi = newiTempLabel (NULL);
9832
9833       /* get the condition into accumulator.
9834          Using b as temporary storage, if register push/pop is needed */
9835       aopOp (IC_JTCOND (ic), ic, FALSE);
9836       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9837       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
9838           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
9839         {
9840           // (MB) what if B is in use???
9841           wassertl(!_G.BInUse, "B was in use");
9842           emitcode ("mov", "b,%s", l);
9843           l = "b";
9844         }
9845       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9846       MOVA (l);
9847       if( count <= 112 )
9848         {
9849           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
9850           emitcode ("movc", "a,@a+pc");
9851           emitcode ("push", "acc");
9852
9853           MOVA (l);
9854           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
9855           emitcode ("movc", "a,@a+pc");
9856           emitcode ("push", "acc");
9857         }
9858       else
9859         {
9860           /* this scales up to n<=255, but needs two more bytes
9861              and changes dptr */
9862           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
9863           emitcode ("movc", "a,@a+dptr");
9864           emitcode ("push", "acc");
9865
9866           MOVA (l);
9867           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
9868           emitcode ("movc", "a,@a+dptr");
9869           emitcode ("push", "acc");
9870         }
9871
9872       emitcode ("ret", "");
9873
9874       /* now generate jump table, LSB */
9875       emitcode ("", "%05d$:", jtablo->key + 100);
9876       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9877            jtab = setNextItem (IC_JTLABELS (ic)))
9878         emitcode (".db", "%05d$", jtab->key + 100);
9879
9880       /* now generate jump table, MSB */
9881       emitcode ("", "%05d$:", jtabhi->key + 100);
9882       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9883            jtab = setNextItem (IC_JTLABELS (ic)))
9884          emitcode (".db", "%05d$>>8", jtab->key + 100);
9885     }
9886 }
9887
9888 /*-----------------------------------------------------------------*/
9889 /* genCast - gen code for casting                                  */
9890 /*-----------------------------------------------------------------*/
9891 static void
9892 genCast (iCode * ic)
9893 {
9894   operand *result = IC_RESULT (ic);
9895   sym_link *ctype = operandType (IC_LEFT (ic));
9896   sym_link *rtype = operandType (IC_RIGHT (ic));
9897   operand *right = IC_RIGHT (ic);
9898   int size, offset;
9899
9900   D(emitcode(";     genCast",""));
9901
9902   /* if they are equivalent then do nothing */
9903   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9904     return;
9905
9906   aopOp (right, ic, FALSE);
9907   aopOp (result, ic, FALSE);
9908
9909   /* if the result is a bit (and not a bitfield) */
9910   // if (AOP_TYPE (result) == AOP_CRY)
9911   if (IS_BITVAR (OP_SYMBOL (result)->type)
9912       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
9913     {
9914       /* if the right size is a literal then
9915          we know what the value is */
9916       if (AOP_TYPE (right) == AOP_LIT)
9917         {
9918           if (((int) operandLitValue (right)))
9919             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9920           else
9921             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9922
9923           goto release;
9924         }
9925
9926       /* the right is also a bit variable */
9927       if (AOP_TYPE (right) == AOP_CRY)
9928         {
9929           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9930           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9931           goto release;
9932         }
9933
9934       /* we need to or */
9935       toBoolean (right);
9936       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9937       goto release;
9938     }
9939
9940
9941   /* if they are the same size : or less */
9942   if (AOP_SIZE (result) <= AOP_SIZE (right))
9943     {
9944
9945       /* if they are in the same place */
9946       if (sameRegs (AOP (right), AOP (result)))
9947         goto release;
9948
9949       /* if they in different places then copy */
9950       size = AOP_SIZE (result);
9951       offset = 0;
9952       while (size--)
9953         {
9954           aopPut (AOP (result),
9955                   aopGet (AOP (right), offset, FALSE, FALSE),
9956                   offset,
9957                   isOperandVolatile (result, FALSE));
9958           offset++;
9959         }
9960       goto release;
9961     }
9962
9963
9964   /* if the result is of type pointer */
9965   if (IS_PTR (ctype))
9966     {
9967
9968       int p_type;
9969       sym_link *type = operandType (right);
9970       sym_link *etype = getSpec (type);
9971
9972       /* pointer to generic pointer */
9973       if (IS_GENPTR (ctype))
9974         {
9975           if (IS_PTR (type))
9976             p_type = DCL_TYPE (type);
9977           else
9978             {
9979               if (SPEC_SCLS(etype)==S_REGISTER) {
9980                 // let's assume it is a generic pointer
9981                 p_type=GPOINTER;
9982               } else {
9983                 /* we have to go by the storage class */
9984                 p_type = PTR_TYPE (SPEC_OCLS (etype));
9985               }
9986             }
9987
9988           /* the first two bytes are known */
9989           size = GPTRSIZE - 1;
9990           offset = 0;
9991           while (size--)
9992             {
9993               aopPut (AOP (result),
9994                       aopGet (AOP (right), offset, FALSE, FALSE),
9995                       offset,
9996                       isOperandVolatile (result, FALSE));
9997               offset++;
9998             }
9999           /* the last byte depending on type */
10000             {
10001                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10002                 char gpValStr[10];
10003
10004                 if (gpVal == -1)
10005                 {
10006                     // pointerTypeToGPByte will have bitched.
10007                     exit(1);
10008                 }
10009
10010                 sprintf(gpValStr, "#0x%d", gpVal);
10011                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10012             }
10013           goto release;
10014         }
10015
10016       /* just copy the pointers */
10017       size = AOP_SIZE (result);
10018       offset = 0;
10019       while (size--)
10020         {
10021           aopPut (AOP (result),
10022                   aopGet (AOP (right), offset, FALSE, FALSE),
10023                   offset,
10024                   isOperandVolatile (result, FALSE));
10025           offset++;
10026         }
10027       goto release;
10028     }
10029
10030   /* so we now know that the size of destination is greater
10031      than the size of the source */
10032   /* we move to result for the size of source */
10033   size = AOP_SIZE (right);
10034   offset = 0;
10035   while (size--)
10036     {
10037       aopPut (AOP (result),
10038               aopGet (AOP (right), offset, FALSE, FALSE),
10039               offset,
10040               isOperandVolatile (result, FALSE));
10041       offset++;
10042     }
10043
10044   /* now depending on the sign of the source && destination */
10045   size = AOP_SIZE (result) - AOP_SIZE (right);
10046   /* if unsigned or not an integral type */
10047   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10048     {
10049       while (size--)
10050         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
10051     }
10052   else
10053     {
10054       /* we need to extend the sign :{ */
10055       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
10056                         FALSE, FALSE);
10057       MOVA (l);
10058       emitcode ("rlc", "a");
10059       emitcode ("subb", "a,acc");
10060       while (size--)
10061         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
10062     }
10063
10064   /* we are done hurray !!!! */
10065
10066 release:
10067   freeAsmop (right, NULL, ic, TRUE);
10068   freeAsmop (result, NULL, ic, TRUE);
10069
10070 }
10071
10072 /*-----------------------------------------------------------------*/
10073 /* genDjnz - generate decrement & jump if not zero instrucion      */
10074 /*-----------------------------------------------------------------*/
10075 static int
10076 genDjnz (iCode * ic, iCode * ifx)
10077 {
10078   symbol *lbl, *lbl1;
10079   if (!ifx)
10080     return 0;
10081
10082   D(emitcode (";     genDjnz",""));
10083
10084   /* if the if condition has a false label
10085      then we cannot save */
10086   if (IC_FALSE (ifx))
10087     return 0;
10088
10089   /* if the minus is not of the form
10090      a = a - 1 */
10091   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10092       !IS_OP_LITERAL (IC_RIGHT (ic)))
10093     return 0;
10094
10095   if (operandLitValue (IC_RIGHT (ic)) != 1)
10096     return 0;
10097
10098   /* if the size of this greater than one then no
10099      saving */
10100   if (getSize (operandType (IC_RESULT (ic))) > 1)
10101     return 0;
10102
10103   /* otherwise we can save BIG */
10104   lbl = newiTempLabel (NULL);
10105   lbl1 = newiTempLabel (NULL);
10106
10107   aopOp (IC_RESULT (ic), ic, FALSE);
10108
10109   if (AOP_NEEDSACC(IC_RESULT(ic)))
10110   {
10111       /* If the result is accessed indirectly via
10112        * the accumulator, we must explicitly write
10113        * it back after the decrement.
10114        */
10115       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
10116
10117       if (strcmp(rByte, "a"))
10118       {
10119            /* Something is hopelessly wrong */
10120            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10121                    __FILE__, __LINE__);
10122            /* We can just give up; the generated code will be inefficient,
10123             * but what the hey.
10124             */
10125            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10126            return 0;
10127       }
10128       emitcode ("dec", "%s", rByte);
10129       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10130       emitcode ("jnz", "%05d$", lbl->key + 100);
10131   }
10132   else if (IS_AOP_PREG (IC_RESULT (ic)))
10133     {
10134       emitcode ("dec", "%s",
10135                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
10136       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
10137       emitcode ("jnz", "%05d$", lbl->key + 100);
10138     }
10139   else
10140     {
10141       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
10142                 lbl->key + 100);
10143     }
10144   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10145   emitcode ("", "%05d$:", lbl->key + 100);
10146   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10147   emitcode ("", "%05d$:", lbl1->key + 100);
10148
10149   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10150   ifx->generated = 1;
10151   return 1;
10152 }
10153
10154 /*-----------------------------------------------------------------*/
10155 /* genReceive - generate code for a receive iCode                  */
10156 /*-----------------------------------------------------------------*/
10157 static void
10158 genReceive (iCode * ic)
10159 {
10160     int size = getSize (operandType (IC_RESULT (ic)));
10161     int offset = 0;
10162   D(emitcode (";     genReceive",""));
10163
10164   if (ic->argreg == 1) { /* first parameter */
10165       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10166           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10167            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
10168
10169           regs *tempRegs[4];
10170           int receivingA = 0;
10171           int roffset = 0;
10172
10173           for (offset = 0; offset<size; offset++)
10174             if (!strcmp (fReturn[offset], "a"))
10175               receivingA = 1;
10176
10177           if (!receivingA)
10178             {
10179               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10180                 {
10181                   for (offset = size-1; offset>0; offset--)
10182                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10183                   emitcode("mov","a,%s", fReturn[0]);
10184                   _G.accInUse++;
10185                   aopOp (IC_RESULT (ic), ic, FALSE);
10186                   _G.accInUse--;
10187                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
10188                           isOperandVolatile (IC_RESULT (ic), FALSE));
10189                   for (offset = 1; offset<size; offset++)
10190                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
10191                             isOperandVolatile (IC_RESULT (ic), FALSE));
10192                   goto release;
10193                 }
10194             }
10195           else
10196             {
10197               if (getTempRegs(tempRegs, size, ic))
10198                 {
10199                   for (offset = 0; offset<size; offset++)
10200                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10201                   aopOp (IC_RESULT (ic), ic, FALSE);
10202                   for (offset = 0; offset<size; offset++)
10203                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
10204                             isOperandVolatile (IC_RESULT (ic), FALSE));
10205                   goto release;
10206                 }
10207             }
10208
10209           offset = fReturnSizeMCS51 - size;
10210           while (size--) {
10211               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10212                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10213               offset++;
10214           }
10215           aopOp (IC_RESULT (ic), ic, FALSE);
10216           size = AOP_SIZE (IC_RESULT (ic));
10217           offset = 0;
10218           while (size--) {
10219               emitcode ("pop", "acc");
10220               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10221           }
10222
10223       } else {
10224           _G.accInUse++;
10225           aopOp (IC_RESULT (ic), ic, FALSE);
10226           _G.accInUse--;
10227           assignResultValue (IC_RESULT (ic));
10228       }
10229   } else { /* second receive onwards */
10230       int rb1off ;
10231       aopOp (IC_RESULT (ic), ic, FALSE);
10232       rb1off = ic->argreg;
10233       while (size--) {
10234           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10235       }
10236   }
10237
10238 release:
10239   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10240 }
10241
10242 /*-----------------------------------------------------------------*/
10243 /* genDummyRead - generate code for dummy read of volatiles        */
10244 /*-----------------------------------------------------------------*/
10245 static void
10246 genDummyRead (iCode * ic)
10247 {
10248   operand *op;
10249   int size, offset;
10250
10251   D(emitcode(";     genDummyRead",""));
10252
10253   op = IC_RIGHT (ic);
10254   if (op && IS_SYMOP (op))
10255     {
10256       aopOp (op, ic, FALSE);
10257
10258       /* if the result is a bit */
10259       if (AOP_TYPE (op) == AOP_CRY)
10260         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10261       else
10262         {
10263           /* bit variables done */
10264           /* general case */
10265           size = AOP_SIZE (op);
10266           offset = 0;
10267           while (size--)
10268           {
10269             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10270             offset++;
10271           }
10272         }
10273
10274       freeAsmop (op, NULL, ic, TRUE);
10275     }
10276
10277   op = IC_LEFT (ic);
10278   if (op && IS_SYMOP (op))
10279     {
10280       aopOp (op, ic, FALSE);
10281
10282       /* if the result is a bit */
10283       if (AOP_TYPE (op) == AOP_CRY)
10284         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10285       else
10286         {
10287           /* bit variables done */
10288           /* general case */
10289           size = AOP_SIZE (op);
10290           offset = 0;
10291           while (size--)
10292           {
10293             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10294             offset++;
10295           }
10296         }
10297
10298       freeAsmop (op, NULL, ic, TRUE);
10299     }
10300 }
10301
10302 /*-----------------------------------------------------------------*/
10303 /* genCritical - generate code for start of a critical sequence    */
10304 /*-----------------------------------------------------------------*/
10305 static void
10306 genCritical (iCode *ic)
10307 {
10308   symbol *tlbl = newiTempLabel (NULL);
10309
10310   D(emitcode(";     genCritical",""));
10311
10312   if (IC_RESULT (ic))
10313     {
10314       aopOp (IC_RESULT (ic), ic, TRUE);
10315       aopPut (AOP (IC_RESULT (ic)), one, 0, 0);
10316       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10317       aopPut (AOP (IC_RESULT (ic)), zero, 0, 0);
10318       emitcode ("", "%05d$:", (tlbl->key + 100));
10319       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10320     }
10321   else
10322     {
10323       emitcode ("setb", "c");
10324       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10325       emitcode ("clr", "c");
10326       emitcode ("", "%05d$:", (tlbl->key + 100));
10327       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10328     }
10329 }
10330
10331 /*-----------------------------------------------------------------*/
10332 /* genEndCritical - generate code for end of a critical sequence   */
10333 /*-----------------------------------------------------------------*/
10334 static void
10335 genEndCritical (iCode *ic)
10336 {
10337   D(emitcode(";     genEndCritical",""));
10338
10339   if (IC_RIGHT (ic))
10340     {
10341       aopOp (IC_RIGHT (ic), ic, FALSE);
10342       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10343         {
10344           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10345           emitcode ("mov", "ea,c");
10346         }
10347       else
10348         {
10349           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10350             MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
10351           emitcode ("rrc", "a");
10352           emitcode ("mov", "ea,c");
10353         }
10354       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10355     }
10356   else
10357     {
10358       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10359       emitcode ("mov", "ea,c");
10360     }
10361 }
10362
10363 /*-----------------------------------------------------------------*/
10364 /* gen51Code - generate code for 8051 based controllers            */
10365 /*-----------------------------------------------------------------*/
10366 void
10367 gen51Code (iCode * lic)
10368 {
10369   iCode *ic;
10370   int cln = 0;
10371   /* int cseq = 0; */
10372
10373   _G.currentFunc = NULL;
10374   lineHead = lineCurr = NULL;
10375
10376   /* print the allocation information */
10377   if (allocInfo && currFunc)
10378     printAllocInfo (currFunc, codeOutFile);
10379   /* if debug information required */
10380   if (options.debug && currFunc)
10381     {
10382       debugFile->writeFunction (currFunc, lic);
10383     }
10384   /* stack pointer name */
10385   if (options.useXstack)
10386     spname = "_spx";
10387   else
10388     spname = "sp";
10389
10390
10391   for (ic = lic; ic; ic = ic->next)
10392     {
10393       _G.current_iCode = ic;
10394
10395       if (ic->lineno && cln != ic->lineno)
10396         {
10397           if (options.debug)
10398             {
10399               debugFile->writeCLine (ic);
10400             }
10401           if (!options.noCcodeInAsm) {
10402             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10403                       printCLine(ic->filename, ic->lineno));
10404           }
10405           cln = ic->lineno;
10406         }
10407       #if 0
10408       if (ic->seqPoint && ic->seqPoint != cseq)
10409         {
10410           emitcode ("", "; sequence point %d", ic->seqPoint);
10411           cseq = ic->seqPoint;
10412         }
10413       #endif
10414       if (options.iCodeInAsm) {
10415         char regsInUse[80];
10416         int i;
10417
10418         for (i=0; i<8; i++) {
10419           sprintf (&regsInUse[i],
10420                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10421         }
10422         regsInUse[i]=0;
10423         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10424       }
10425       /* if the result is marked as
10426          spilt and rematerializable or code for
10427          this has already been generated then
10428          do nothing */
10429       if (resultRemat (ic) || ic->generated)
10430         continue;
10431
10432       /* depending on the operation */
10433       switch (ic->op)
10434         {
10435         case '!':
10436           genNot (ic);
10437           break;
10438
10439         case '~':
10440           genCpl (ic);
10441           break;
10442
10443         case UNARYMINUS:
10444           genUminus (ic);
10445           break;
10446
10447         case IPUSH:
10448           genIpush (ic);
10449           break;
10450
10451         case IPOP:
10452           /* IPOP happens only when trying to restore a
10453              spilt live range, if there is an ifx statement
10454              following this pop then the if statement might
10455              be using some of the registers being popped which
10456              would destory the contents of the register so
10457              we need to check for this condition and handle it */
10458           if (ic->next &&
10459               ic->next->op == IFX &&
10460               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10461             genIfx (ic->next, ic);
10462           else
10463             genIpop (ic);
10464           break;
10465
10466         case CALL:
10467           genCall (ic);
10468           break;
10469
10470         case PCALL:
10471           genPcall (ic);
10472           break;
10473
10474         case FUNCTION:
10475           genFunction (ic);
10476           break;
10477
10478         case ENDFUNCTION:
10479           genEndFunction (ic);
10480           break;
10481
10482         case RETURN:
10483           genRet (ic);
10484           break;
10485
10486         case LABEL:
10487           genLabel (ic);
10488           break;
10489
10490         case GOTO:
10491           genGoto (ic);
10492           break;
10493
10494         case '+':
10495           genPlus (ic);
10496           break;
10497
10498         case '-':
10499           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10500             genMinus (ic);
10501           break;
10502
10503         case '*':
10504           genMult (ic);
10505           break;
10506
10507         case '/':
10508           genDiv (ic);
10509           break;
10510
10511         case '%':
10512           genMod (ic);
10513           break;
10514
10515         case '>':
10516           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10517           break;
10518
10519         case '<':
10520           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10521           break;
10522
10523         case LE_OP:
10524         case GE_OP:
10525         case NE_OP:
10526
10527           /* note these two are xlated by algebraic equivalence
10528              during parsing SDCC.y */
10529           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10530                   "got '>=' or '<=' shouldn't have come here");
10531           break;
10532
10533         case EQ_OP:
10534           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10535           break;
10536
10537         case AND_OP:
10538           genAndOp (ic);
10539           break;
10540
10541         case OR_OP:
10542           genOrOp (ic);
10543           break;
10544
10545         case '^':
10546           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10547           break;
10548
10549         case '|':
10550           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10551           break;
10552
10553         case BITWISEAND:
10554           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10555           break;
10556
10557         case INLINEASM:
10558           genInline (ic);
10559           break;
10560
10561         case RRC:
10562           genRRC (ic);
10563           break;
10564
10565         case RLC:
10566           genRLC (ic);
10567           break;
10568
10569         case GETHBIT:
10570           genGetHbit (ic);
10571           break;
10572
10573         case LEFT_OP:
10574           genLeftShift (ic);
10575           break;
10576
10577         case RIGHT_OP:
10578           genRightShift (ic);
10579           break;
10580
10581         case GET_VALUE_AT_ADDRESS:
10582           genPointerGet (ic,
10583                          hasInc (IC_LEFT (ic), ic,
10584                                  getSize (operandType (IC_RESULT (ic)))),
10585                          ifxForOp (IC_RESULT (ic), ic) );
10586           break;
10587
10588         case '=':
10589           if (POINTER_SET (ic))
10590             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10591           else
10592             genAssign (ic);
10593           break;
10594
10595         case IFX:
10596           genIfx (ic, NULL);
10597           break;
10598
10599         case ADDRESS_OF:
10600           genAddrOf (ic);
10601           break;
10602
10603         case JUMPTABLE:
10604           genJumpTab (ic);
10605           break;
10606
10607         case CAST:
10608           genCast (ic);
10609           break;
10610
10611         case RECEIVE:
10612           genReceive (ic);
10613           break;
10614
10615         case SEND:
10616           addSet (&_G.sendSet, ic);
10617           break;
10618
10619         case DUMMY_READ_VOLATILE:
10620           genDummyRead (ic);
10621           break;
10622
10623         case CRITICAL:
10624           genCritical (ic);
10625           break;
10626
10627         case ENDCRITICAL:
10628           genEndCritical (ic);
10629           break;
10630
10631         case SWAP:
10632           genSwap (ic);
10633           break;
10634
10635         default:
10636           ic = ic;
10637         }
10638     }
10639
10640   _G.current_iCode = NULL;
10641
10642   /* now we are ready to call the
10643      peep hole optimizer */
10644   if (!options.nopeep)
10645     peepHole (&lineHead);
10646
10647   /* now do the actual printing */
10648   printLine (lineHead, codeOutFile);
10649   return;
10650 }