* support/regression/tests/bug1185672.c: added
[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 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
68
69 #define R0INB   _G.bu.bs.r0InB
70 #define R1INB   _G.bu.bs.r1InB
71 #define OPINB   _G.bu.bs.OpInB
72 #define BINUSE  _G.bu.BInUse
73
74 static struct
75   {
76     short r0Pushed;
77     short r1Pushed;
78     union
79       {
80         struct
81           {
82             short r0InB : 2;//2 so we can see it overflow
83             short r1InB : 2;//2 so we can see it overflow
84             short OpInB : 2;//2 so we can see it overflow
85           } bs;
86         short BInUse;
87       } bu;
88     short accInUse;
89     short inLine;
90     short debugLine;
91     short nRegsSaved;
92     set *sendSet;
93     iCode *current_iCode;
94     symbol *currentFunc;
95   }
96 _G;
97
98 static char *rb1regs[] = {
99     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
100 };
101
102 extern int mcs51_ptrRegReq;
103 extern int mcs51_nRegs;
104 extern FILE *codeOutFile;
105 static void saveRBank (int, iCode *, bool);
106
107 #define RESULTONSTACK(x) \
108                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
109                          IC_RESULT(x)->aop->type == AOP_STK )
110
111 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
112 #define CLRC     emitcode("clr","c")
113 #define SETC     emitcode("setb","c")
114
115 static lineNode *lineHead = NULL;
116 static lineNode *lineCurr = NULL;
117
118 static unsigned char SLMask[] =
119 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
120  0xE0, 0xC0, 0x80, 0x00};
121 static unsigned char SRMask[] =
122 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
123  0x07, 0x03, 0x01, 0x00};
124
125 #define LSB     0
126 #define MSB16   1
127 #define MSB24   2
128 #define MSB32   3
129
130 /*-----------------------------------------------------------------*/
131 /* emitcode - writes the code into a file : for now it is simple    */
132 /*-----------------------------------------------------------------*/
133 static void
134 emitcode (char *inst, const char *fmt,...)
135 {
136   va_list ap;
137   char lb[INITIAL_INLINEASM];
138   char *lbp = lb;
139
140   va_start (ap, fmt);
141
142   if (inst && *inst)
143     {
144       if (fmt && *fmt)
145           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
146       else
147           SNPRINTF (lb, sizeof(lb), "%s", inst);
148       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
149     }
150   else
151       tvsprintf (lb, sizeof(lb), fmt, ap);
152
153   while (isspace (*lbp))
154       lbp++;
155
156   if (lbp && *lbp)
157       lineCurr = (lineCurr ?
158                   connectLine (lineCurr, newLineNode (lb)) :
159                   (lineHead = newLineNode (lb)));
160   lineCurr->isInline = _G.inLine;
161   lineCurr->isDebug = _G.debugLine;
162   lineCurr->ic = _G.current_iCode;
163   lineCurr->isComment = (*lbp==';');
164   va_end (ap);
165 }
166
167 /*-----------------------------------------------------------------*/
168 /* mcs51_emitDebuggerSymbol - associate the current code location  */
169 /*   with a debugger symbol                                        */
170 /*-----------------------------------------------------------------*/
171 void
172 mcs51_emitDebuggerSymbol (char * debugSym)
173 {
174   _G.debugLine = 1;
175   emitcode ("", "%s ==.", debugSym);
176   _G.debugLine = 0;
177 }
178
179 /*-----------------------------------------------------------------*/
180 /* mova - moves specified value into accumulator                   */
181 /*-----------------------------------------------------------------*/
182 static void
183 mova (const char *x)
184 {
185   /* do some early peephole optimization */
186   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
187     return;
188
189   emitcode("mov","a,%s", x);
190 }
191
192 /*-----------------------------------------------------------------*/
193 /* pushB - saves register B if necessary                           */
194 /*-----------------------------------------------------------------*/
195 static bool
196 pushB (void)
197 {
198   bool pushedB = FALSE;
199
200   if (BINUSE)
201     {
202       emitcode ("push", "b");
203 //    printf("B was in use !\n");
204       pushedB = TRUE;
205     }
206   else
207     {
208       OPINB++;
209     }
210   return pushedB;
211 }
212
213 /*-----------------------------------------------------------------*/
214 /* popB - restores value of register B if necessary                */
215 /*-----------------------------------------------------------------*/
216 static void
217 popB (bool pushedB)
218 {
219   if (pushedB)
220     {
221       emitcode ("pop", "b");
222     }
223   else
224     {
225       OPINB--;
226     }
227 }
228
229 /*-----------------------------------------------------------------*/
230 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
231 /*-----------------------------------------------------------------*/
232 static regs *
233 getFreePtr (iCode * ic, asmop ** aopp, bool result)
234 {
235   bool r0iu, r1iu;
236   bool r0ou, r1ou;
237
238   /* the logic: if r0 & r1 used in the instruction
239      then we are in trouble otherwise */
240
241   /* first check if r0 & r1 are used by this
242      instruction, in which case we are in trouble */
243   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
244   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
245   if (r0iu && r1iu) {
246       goto endOfWorld;
247     }
248
249   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
250   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
251
252   /* if no usage of r0 then return it */
253   if (!r0iu && !r0ou)
254     {
255       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
256       (*aopp)->type = AOP_R0;
257
258       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
259     }
260
261   /* if no usage of r1 then return it */
262   if (!r1iu && !r1ou)
263     {
264       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
265       (*aopp)->type = AOP_R1;
266
267       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
268     }
269
270   /* now we know they both have usage */
271   /* if r0 not used in this instruction */
272   if (!r0iu)
273     {
274       /* push it if not already pushed */
275       if (ic->op == IPUSH)
276         {
277           emitcode ("mov", "b,%s",
278                     mcs51_regWithIdx (R0_IDX)->dname);
279           R0INB++;
280         }
281       else if (!_G.r0Pushed)
282         {
283           emitcode ("push", "%s",
284                     mcs51_regWithIdx (R0_IDX)->dname);
285           _G.r0Pushed++;
286         }
287
288       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
289       (*aopp)->type = AOP_R0;
290
291       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
292     }
293
294   /* if r1 not used then */
295
296   if (!r1iu)
297     {
298       /* push it if not already pushed */
299       if (ic->op == IPUSH)
300         {
301           emitcode ("mov", "b,%s",
302                     mcs51_regWithIdx (R1_IDX)->dname);
303           R1INB++;
304         }
305       else if (!_G.r1Pushed)
306         {
307           emitcode ("push", "%s",
308                     mcs51_regWithIdx (R1_IDX)->dname);
309           _G.r1Pushed++;
310         }
311
312       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
313       (*aopp)->type = AOP_R1;
314       return mcs51_regWithIdx (R1_IDX);
315     }
316 endOfWorld:
317   /* I said end of world, but not quite end of world yet */
318   if (result) {
319     /* we can push it on the stack */
320     (*aopp)->type = AOP_STK;
321     return NULL;
322   } else {
323     /* in the case that result AND left AND right needs a pointer reg
324        we can safely use the result's */
325     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
326       (*aopp)->type = AOP_R0;
327       return mcs51_regWithIdx (R0_IDX);
328     }
329     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
330       (*aopp)->type = AOP_R1;
331       return mcs51_regWithIdx (R1_IDX);
332     }
333   }
334
335   /* now this is REALLY the end of the world */
336   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
337           "getFreePtr should never reach here");
338   exit (1);
339 }
340
341
342 /*-----------------------------------------------------------------*/
343 /* getTempRegs - initialize an array of pointers to GPR registers */
344 /*               that are not in use. Returns 1 if the requested   */
345 /*               number of registers were available, 0 otherwise.  */
346 /*-----------------------------------------------------------------*/
347 int
348 getTempRegs(regs **tempRegs, int size, iCode *ic)
349 {
350   bitVect * freeRegs;
351   int i;
352   int offset;
353
354   if (!ic)
355     ic = _G.current_iCode;
356   if (!ic)
357     return 0;
358   if (!_G.currentFunc)
359     return 0;
360
361   freeRegs = newBitVect(8);
362   bitVectSetBit (freeRegs, R2_IDX);
363   bitVectSetBit (freeRegs, R3_IDX);
364   bitVectSetBit (freeRegs, R4_IDX);
365   bitVectSetBit (freeRegs, R5_IDX);
366   bitVectSetBit (freeRegs, R6_IDX);
367   bitVectSetBit (freeRegs, R7_IDX);
368
369   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
370     {
371       bitVect * newfreeRegs;
372       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
373       freeBitVect(freeRegs);
374       freeRegs = newfreeRegs;
375     }
376   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
377
378   offset = 0;
379   for (i=0; i<freeRegs->size; i++)
380     {
381       if (bitVectBitValue(freeRegs,i))
382         tempRegs[offset++] = mcs51_regWithIdx(i);
383       if (offset>=size)
384         {
385           freeBitVect(freeRegs);
386           return 1;
387         }
388     }
389
390   freeBitVect(freeRegs);
391   return 1;
392 }
393
394
395 /*-----------------------------------------------------------------*/
396 /* newAsmop - creates a new asmOp                                  */
397 /*-----------------------------------------------------------------*/
398 static asmop *
399 newAsmop (short type)
400 {
401   asmop *aop;
402
403   aop = Safe_calloc (1, sizeof (asmop));
404   aop->type = type;
405   return aop;
406 }
407
408 /*-----------------------------------------------------------------*/
409 /* pointerCode - returns the code for a pointer type               */
410 /*-----------------------------------------------------------------*/
411 static int
412 pointerCode (sym_link * etype)
413 {
414
415   return PTR_TYPE (SPEC_OCLS (etype));
416
417 }
418
419 /*-----------------------------------------------------------------*/
420 /* leftRightUseAcc - returns size of accumulator use by operands   */
421 /*-----------------------------------------------------------------*/
422 static int
423 leftRightUseAcc(iCode *ic)
424 {
425   operand *op;
426   int size;
427   int accuseSize = 0;
428   int accuse = 0;
429
430   if (!ic)
431     {
432       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
433               "null iCode pointer");
434       return 0;
435     }
436
437   if (ic->op == IFX)
438     {
439       op = IC_COND (ic);
440       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
441         {
442           accuse = 1;
443           size = getSize (OP_SYMBOL (op)->type);
444           if (size>accuseSize)
445             accuseSize = size;
446         }
447     }
448   else if (ic->op == JUMPTABLE)
449     {
450       op = IC_JTCOND (ic);
451       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
452         {
453           accuse = 1;
454           size = getSize (OP_SYMBOL (op)->type);
455           if (size>accuseSize)
456             accuseSize = size;
457         }
458     }
459   else
460     {
461       op = IC_LEFT (ic);
462       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
463         {
464           accuse = 1;
465           size = getSize (OP_SYMBOL (op)->type);
466           if (size>accuseSize)
467             accuseSize = size;
468         }
469       op = IC_RIGHT (ic);
470       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
471         {
472           accuse = 1;
473           size = getSize (OP_SYMBOL (op)->type);
474           if (size>accuseSize)
475             accuseSize = size;
476         }
477     }
478
479   if (accuseSize)
480     return accuseSize;
481   else
482     return accuse;
483 }
484
485 /*-----------------------------------------------------------------*/
486 /* aopForSym - for a true symbol                                   */
487 /*-----------------------------------------------------------------*/
488 static asmop *
489 aopForSym (iCode * ic, symbol * sym, bool result)
490 {
491   asmop *aop;
492   memmap *space;
493
494   wassertl (ic != NULL, "Got a null iCode");
495   wassertl (sym != NULL, "Got a null symbol");
496
497   space = SPEC_OCLS (sym->etype);
498
499   /* if already has one */
500   if (sym->aop)
501     return sym->aop;
502
503   /* assign depending on the storage class */
504   /* if it is on the stack or indirectly addressable */
505   /* space we need to assign either r0 or r1 to it   */
506   if (sym->onStack || sym->iaccess)
507     {
508       sym->aop = aop = newAsmop (0);
509       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
510       aop->size = getSize (sym->type);
511
512       /* now assign the address of the variable to
513          the pointer register */
514       if (aop->type != AOP_STK)
515         {
516
517           if (sym->onStack)
518             {
519               char offset = ((sym->stack < 0) ?
520                          ((char) (sym->stack - _G.nRegsSaved)) :
521                          ((char) sym->stack)) & 0xff;
522               if (_G.accInUse || leftRightUseAcc (ic))
523                 emitcode ("push", "acc");
524
525               if ((offset >= -3) && (offset <= 3))
526                 {
527                   emitcode ("mov", "%s,%s",
528                             aop->aopu.aop_ptr->name, SYM_BP (sym));
529                   while (offset < 0)
530                     {
531                       emitcode ("dec", aop->aopu.aop_ptr->name);
532                       offset++;
533                     }
534                   while (offset > 0)
535                     {
536                       emitcode ("inc", aop->aopu.aop_ptr->name);
537                       offset--;
538                     }
539                 }
540               else
541                 {
542                   emitcode ("mov", "a,%s", SYM_BP (sym));
543                   emitcode ("add", "a,#0x%02x", offset);
544                   emitcode ("mov", "%s,a",
545                             aop->aopu.aop_ptr->name);
546                 }
547               if (_G.accInUse || leftRightUseAcc (ic))
548                 emitcode ("pop", "acc");
549             }
550           else
551             emitcode ("mov", "%s,#%s",
552                       aop->aopu.aop_ptr->name,
553                       sym->rname);
554           aop->paged = space->paged;
555         }
556       else
557         aop->aopu.aop_stk = sym->stack;
558       return aop;
559     }
560
561   /* if in bit space */
562   if (IN_BITSPACE (space))
563     {
564       sym->aop = aop = newAsmop (AOP_CRY);
565       aop->aopu.aop_dir = sym->rname;
566       aop->size = getSize (sym->type);
567       return aop;
568     }
569   /* if it is in direct space */
570   if (IN_DIRSPACE (space))
571     {
572       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
573       //printTypeChainRaw(sym->type, NULL);
574       //printf("space = %s\n", space ? space->sname : "NULL");
575       sym->aop = aop = newAsmop (AOP_DIR);
576       aop->aopu.aop_dir = sym->rname;
577       aop->size = getSize (sym->type);
578       return aop;
579     }
580
581   /* special case for a function */
582   if (IS_FUNC (sym->type))
583     {
584       sym->aop = aop = newAsmop (AOP_IMMD);
585       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
586       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
587       aop->size = FPTRSIZE;
588       return aop;
589     }
590
591   /* only remaining is far space */
592   /* in which case DPTR gets the address */
593   sym->aop = aop = newAsmop (AOP_DPTR);
594   emitcode ("mov", "dptr,#%s", sym->rname);
595   aop->size = getSize (sym->type);
596
597   /* if it is in code space */
598   if (IN_CODESPACE (space))
599     aop->code = 1;
600
601   return aop;
602 }
603
604 /*-----------------------------------------------------------------*/
605 /* aopForRemat - rematerialzes an object                           */
606 /*-----------------------------------------------------------------*/
607 static asmop *
608 aopForRemat (symbol * sym)
609 {
610   iCode *ic = sym->rematiCode;
611   asmop *aop = newAsmop (AOP_IMMD);
612   int ptr_type = 0;
613   int val = 0;
614
615   for (;;)
616     {
617       if (ic->op == '+')
618         val += (int) operandLitValue (IC_RIGHT (ic));
619       else if (ic->op == '-')
620         val -= (int) operandLitValue (IC_RIGHT (ic));
621       else if (IS_CAST_ICODE(ic)) {
622               sym_link *from_type = operandType(IC_RIGHT(ic));
623               aop->aopu.aop_immd.from_cast_remat = 1;
624               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
625               ptr_type = DCL_TYPE(from_type);
626               if (ptr_type == IPOINTER) {
627                 // bug #481053
628                 ptr_type = POINTER;
629               }
630               continue ;
631       } else break;
632
633       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
634     }
635
636   if (val)
637     sprintf (buffer, "(%s %c 0x%04x)",
638              OP_SYMBOL (IC_LEFT (ic))->rname,
639              val >= 0 ? '+' : '-',
640              abs (val) & 0xffff);
641   else
642     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
643
644   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
645   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
646   /* set immd2 field if required */
647   if (aop->aopu.aop_immd.from_cast_remat) {
648           sprintf(buffer,"#0x%02x",ptr_type);
649           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
650           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
651   }
652
653   return aop;
654 }
655
656 /*-----------------------------------------------------------------*/
657 /* regsInCommon - two operands have some registers in common       */
658 /*-----------------------------------------------------------------*/
659 static bool
660 regsInCommon (operand * op1, operand * op2)
661 {
662   symbol *sym1, *sym2;
663   int i;
664
665   /* if they have registers in common */
666   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
667     return FALSE;
668
669   sym1 = OP_SYMBOL (op1);
670   sym2 = OP_SYMBOL (op2);
671
672   if (sym1->nRegs == 0 || sym2->nRegs == 0)
673     return FALSE;
674
675   for (i = 0; i < sym1->nRegs; i++)
676     {
677       int j;
678       if (!sym1->regs[i])
679         continue;
680
681       for (j = 0; j < sym2->nRegs; j++)
682         {
683           if (!sym2->regs[j])
684             continue;
685
686           if (sym2->regs[j] == sym1->regs[i])
687             return TRUE;
688         }
689     }
690
691   return FALSE;
692 }
693
694 /*-----------------------------------------------------------------*/
695 /* operandsEqu - equivalent                                        */
696 /*-----------------------------------------------------------------*/
697 static bool
698 operandsEqu (operand * op1, operand * op2)
699 {
700   symbol *sym1, *sym2;
701
702   /* if they're not symbols */
703   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
704     return FALSE;
705
706   sym1 = OP_SYMBOL (op1);
707   sym2 = OP_SYMBOL (op2);
708
709   /* if both are itemps & one is spilt
710      and the other is not then false */
711   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
712       sym1->isspilt != sym2->isspilt)
713     return FALSE;
714
715   /* if they are the same */
716   if (sym1 == sym2)
717     return TRUE;
718
719   /* if they have the same rname */
720   if (sym1->rname[0] && sym2->rname[0]
721       && strcmp (sym1->rname, sym2->rname) == 0)
722     return TRUE;
723
724   /* if left is a tmp & right is not */
725   if (IS_ITEMP (op1) &&
726       !IS_ITEMP (op2) &&
727       sym1->isspilt &&
728       (sym1->usl.spillLoc == sym2))
729     return TRUE;
730
731   if (IS_ITEMP (op2) &&
732       !IS_ITEMP (op1) &&
733       sym2->isspilt &&
734       sym1->level > 0 &&
735       (sym2->usl.spillLoc == sym1))
736     return TRUE;
737
738   return FALSE;
739 }
740
741 /*-----------------------------------------------------------------*/
742 /* sameRegs - two asmops have the same registers                   */
743 /*-----------------------------------------------------------------*/
744 static bool
745 sameRegs (asmop * aop1, asmop * aop2)
746 {
747   int i;
748
749   if (aop1 == aop2)
750     return TRUE;
751
752   if (aop1->type != AOP_REG ||
753       aop2->type != AOP_REG)
754     return FALSE;
755
756   if (aop1->size != aop2->size)
757     return FALSE;
758
759   for (i = 0; i < aop1->size; i++)
760     if (aop1->aopu.aop_reg[i] !=
761         aop2->aopu.aop_reg[i])
762       return FALSE;
763
764   return TRUE;
765 }
766
767 /*-----------------------------------------------------------------*/
768 /* aopOp - allocates an asmop for an operand  :                    */
769 /*-----------------------------------------------------------------*/
770 static void
771 aopOp (operand * op, iCode * ic, bool result)
772 {
773   asmop *aop;
774   symbol *sym;
775   int i;
776
777   if (!op)
778     return;
779
780   /* if this a literal */
781   if (IS_OP_LITERAL (op))
782     {
783       op->aop = aop = newAsmop (AOP_LIT);
784       aop->aopu.aop_lit = op->operand.valOperand;
785       aop->size = getSize (operandType (op));
786       return;
787     }
788
789   /* if already has a asmop then continue */
790   if (op->aop )
791     return;
792
793   /* if the underlying symbol has a aop */
794   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
795     {
796       op->aop = OP_SYMBOL (op)->aop;
797       return;
798     }
799
800   /* if this is a true symbol */
801   if (IS_TRUE_SYMOP (op))
802     {
803       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
804       return;
805     }
806
807   /* this is a temporary : this has
808      only five choices :
809      a) register
810      b) spillocation
811      c) rematerialize
812      d) conditional
813      e) can be a return use only */
814
815   sym = OP_SYMBOL (op);
816
817   /* if the type is a conditional */
818   if (sym->regType == REG_CND)
819     {
820       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
821       aop->size = 0;
822       return;
823     }
824
825   /* if it is spilt then two situations
826      a) is rematerialize
827      b) has a spill location */
828   if (sym->isspilt || sym->nRegs == 0)
829     {
830
831       /* rematerialize it NOW */
832       if (sym->remat)
833         {
834           sym->aop = op->aop = aop =
835             aopForRemat (sym);
836           aop->size = getSize (sym->type);
837           return;
838         }
839
840       if (sym->accuse)
841         {
842           int i;
843           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
844           aop->size = getSize (sym->type);
845           for (i = 0; i < 2; i++)
846             aop->aopu.aop_str[i] = accUse[i];
847           return;
848         }
849
850       if (sym->ruonly)
851         {
852           unsigned i;
853
854           aop = op->aop = sym->aop = newAsmop (AOP_STR);
855           aop->size = getSize (sym->type);
856           for (i = 0; i < fReturnSizeMCS51; i++)
857             aop->aopu.aop_str[i] = fReturn[i];
858           return;
859         }
860
861       if (sym->usl.spillLoc)
862         {
863           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
864             {
865               /* force a new aop if sizes differ */
866               sym->usl.spillLoc->aop = NULL;
867             }
868           sym->aop = op->aop = aop =
869                      aopForSym (ic, sym->usl.spillLoc, result);
870           aop->size = getSize (sym->type);
871           return;
872         }
873
874       /* else must be a dummy iTemp */
875       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
876       aop->size = getSize (sym->type);
877       return;
878     }
879
880   /* must be in a register */
881   sym->aop = op->aop = aop = newAsmop (AOP_REG);
882   aop->size = sym->nRegs;
883   for (i = 0; i < sym->nRegs; i++)
884     aop->aopu.aop_reg[i] = sym->regs[i];
885 }
886
887 /*-----------------------------------------------------------------*/
888 /* freeAsmop - free up the asmop given to an operand               */
889 /*----------------------------------------------------------------*/
890 static void
891 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
892 {
893   asmop *aop;
894
895   if (!op)
896     aop = aaop;
897   else
898     aop = op->aop;
899
900   if (!aop)
901     return;
902
903   if (aop->freed)
904     goto dealloc;
905
906   aop->freed = 1;
907
908   /* depending on the asmop type only three cases need work AOP_RO
909      , AOP_R1 && AOP_STK */
910   switch (aop->type)
911     {
912     case AOP_R0:
913       if (R0INB)
914         {
915           emitcode ("mov", "r0,b");
916           R0INB--;
917         }
918       else if (_G.r0Pushed)
919         {
920           if (pop)
921             {
922               emitcode ("pop", "ar0");
923               _G.r0Pushed--;
924             }
925         }
926       bitVectUnSetBit (ic->rUsed, R0_IDX);
927       break;
928
929     case AOP_R1:
930       if (R1INB)
931         {
932           emitcode ("mov", "r1,b");
933           R1INB--;
934         }
935       if (_G.r1Pushed)
936         {
937           if (pop)
938             {
939               emitcode ("pop", "ar1");
940               _G.r1Pushed--;
941             }
942         }
943       bitVectUnSetBit (ic->rUsed, R1_IDX);
944       break;
945
946     case AOP_STK:
947       {
948         int sz = aop->size;
949         int stk = aop->aopu.aop_stk + aop->size - 1;
950         bitVectUnSetBit (ic->rUsed, R0_IDX);
951         bitVectUnSetBit (ic->rUsed, R1_IDX);
952
953         getFreePtr (ic, &aop, FALSE);
954
955         if (stk)
956           {
957             emitcode ("mov", "a,_bp");
958             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
959             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
960           }
961         else
962           {
963             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
964           }
965
966         while (sz--)
967           {
968             emitcode ("pop", "acc");
969             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
970             if (!sz)
971               break;
972             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
973           }
974         op->aop = aop;
975         freeAsmop (op, NULL, ic, TRUE);
976         if (_G.r1Pushed)
977           {
978             emitcode ("pop", "ar1");
979             _G.r1Pushed--;
980           }
981
982         if (_G.r0Pushed)
983           {
984             emitcode ("pop", "ar0");
985             _G.r0Pushed--;
986           }
987       }
988     }
989
990 dealloc:
991   /* all other cases just dealloc */
992   if (op)
993     {
994       op->aop = NULL;
995       if (IS_SYMOP (op))
996         {
997           OP_SYMBOL (op)->aop = NULL;
998           /* if the symbol has a spill */
999           if (SPIL_LOC (op))
1000             SPIL_LOC (op)->aop = NULL;
1001         }
1002     }
1003 }
1004
1005 /*------------------------------------------------------------------*/
1006 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1007 /*                      pop r0 or r1 off stack if pushed            */
1008 /*------------------------------------------------------------------*/
1009 static void
1010 freeForBranchAsmop (operand * op)
1011 {
1012   asmop *aop;
1013
1014   if (!op)
1015     return;
1016
1017   aop = op->aop;
1018
1019   if (!aop)
1020     return;
1021
1022   if (aop->freed)
1023     return;
1024
1025   switch (aop->type)
1026     {
1027     case AOP_R0:
1028       if (R0INB)
1029         {
1030           emitcode ("mov", "r0,b");
1031         }
1032       else if (_G.r0Pushed)
1033         {
1034           emitcode ("pop", "ar0");
1035         }
1036       break;
1037
1038     case AOP_R1:
1039       if (R1INB)
1040         {
1041           emitcode ("mov", "r1,b");
1042         }
1043       else if (_G.r1Pushed)
1044         {
1045           emitcode ("pop", "ar1");
1046         }
1047       break;
1048
1049     case AOP_STK:
1050       {
1051         int sz = aop->size;
1052         int stk = aop->aopu.aop_stk + aop->size - 1;
1053
1054         emitcode ("mov", "b,r0");
1055         if (stk)
1056           {
1057             emitcode ("mov", "a,_bp");
1058             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1059             emitcode ("mov", "r0,a");
1060           }
1061         else
1062           {
1063             emitcode ("mov", "r0,_bp");
1064           }
1065
1066         while (sz--)
1067           {
1068             emitcode ("pop", "acc");
1069             emitcode ("mov", "@r0,a");
1070             if (!sz)
1071               break;
1072             emitcode ("dec", "r0");
1073           }
1074         emitcode ("mov", "r0,b");
1075       }
1076     }
1077
1078 }
1079
1080 /*-----------------------------------------------------------------*/
1081 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1082 /*                 clobber the accumulator                         */
1083 /*-----------------------------------------------------------------*/
1084 static bool
1085 aopGetUsesAcc (asmop *aop, int offset)
1086 {
1087   if (offset > (aop->size - 1))
1088     return FALSE;
1089
1090   switch (aop->type)
1091     {
1092
1093     case AOP_R0:
1094     case AOP_R1:
1095       if (aop->paged)
1096         return TRUE;
1097       return FALSE;
1098     case AOP_DPTR:
1099       return TRUE;
1100     case AOP_IMMD:
1101       return FALSE;
1102     case AOP_DIR:
1103       return FALSE;
1104     case AOP_REG:
1105       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1106       return FALSE;
1107     case AOP_CRY:
1108       return TRUE;
1109     case AOP_ACC:
1110       if (offset)
1111         return FALSE;
1112       return TRUE;
1113     case AOP_LIT:
1114       return FALSE;
1115     case AOP_STR:
1116       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1117         return TRUE;
1118       return FALSE;
1119     case AOP_DUMMY:
1120       return FALSE;
1121     default:
1122       /* Error case --- will have been caught already */
1123       wassert(0);
1124       return FALSE;
1125     }
1126 }
1127
1128 /*-----------------------------------------------------------------*/
1129 /* aopGet - for fetching value of the aop                          */
1130 /*-----------------------------------------------------------------*/
1131 static char *
1132 aopGet (asmop * aop, int offset, bool bit16, bool dname)
1133 {
1134   char *s = buffer;
1135   char *rs;
1136
1137   /* offset is greater than
1138      size then zero */
1139   if (offset > (aop->size - 1) &&
1140       aop->type != AOP_LIT)
1141     return zero;
1142
1143   /* depending on type */
1144   switch (aop->type)
1145     {
1146     case AOP_DUMMY:
1147       return zero;
1148
1149     case AOP_R0:
1150     case AOP_R1:
1151       /* if we need to increment it */
1152       while (offset > aop->coff)
1153         {
1154           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1155           aop->coff++;
1156         }
1157
1158       while (offset < aop->coff)
1159         {
1160           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1161           aop->coff--;
1162         }
1163
1164       aop->coff = offset;
1165       if (aop->paged)
1166         {
1167           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1168           return (dname ? "acc" : "a");
1169         }
1170       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1171       rs = Safe_calloc (1, strlen (s) + 1);
1172       strcpy (rs, s);
1173       return rs;
1174
1175     case AOP_DPTR:
1176       if (aop->code && aop->coff==0 && offset>=1) {
1177         emitcode ("mov", "a,#0x%02x", offset);
1178         emitcode ("movc", "a,@a+dptr");
1179         return (dname ? "acc" : "a");
1180       }
1181
1182       while (offset > aop->coff)
1183         {
1184           emitcode ("inc", "dptr");
1185           aop->coff++;
1186         }
1187
1188       while (offset < aop->coff)
1189         {
1190           emitcode ("lcall", "__decdptr");
1191           aop->coff--;
1192         }
1193
1194       aop->coff = offset;
1195       if (aop->code)
1196         {
1197           emitcode ("clr", "a");
1198           emitcode ("movc", "a,@a+dptr");
1199         }
1200       else
1201         {
1202           emitcode ("movx", "a,@dptr");
1203         }
1204       return (dname ? "acc" : "a");
1205
1206
1207     case AOP_IMMD:
1208       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1209               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1210       } else if (bit16)
1211         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1212       else if (offset)
1213         sprintf (s, "#(%s >> %d)",
1214                  aop->aopu.aop_immd.aop_immd1,
1215                  offset * 8);
1216       else
1217         sprintf (s, "#%s",
1218                  aop->aopu.aop_immd.aop_immd1);
1219       rs = Safe_calloc (1, strlen (s) + 1);
1220       strcpy (rs, s);
1221       return rs;
1222
1223     case AOP_DIR:
1224       if (offset)
1225         sprintf (s, "(%s + %d)",
1226                  aop->aopu.aop_dir,
1227                  offset);
1228       else
1229         sprintf (s, "%s", aop->aopu.aop_dir);
1230       rs = Safe_calloc (1, strlen (s) + 1);
1231       strcpy (rs, s);
1232       return rs;
1233
1234     case AOP_REG:
1235       if (dname)
1236         return aop->aopu.aop_reg[offset]->dname;
1237       else
1238         return aop->aopu.aop_reg[offset]->name;
1239
1240     case AOP_CRY:
1241       emitcode ("clr", "a");
1242       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1243       emitcode ("rlc", "a");
1244       return (dname ? "acc" : "a");
1245
1246     case AOP_ACC:
1247       if (!offset && dname)
1248         return "acc";
1249       return aop->aopu.aop_str[offset];
1250
1251     case AOP_LIT:
1252       return aopLiteral (aop->aopu.aop_lit, offset);
1253
1254     case AOP_STR:
1255       aop->coff = offset;
1256       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1257           dname)
1258         return "acc";
1259
1260       return aop->aopu.aop_str[offset];
1261
1262     }
1263
1264   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1265           "aopget got unsupported aop->type");
1266   exit (1);
1267 }
1268 /*-----------------------------------------------------------------*/
1269 /* aopPut - puts a string for a aop and indicates if acc is in use */
1270 /*-----------------------------------------------------------------*/
1271 static bool
1272 aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
1273 {
1274   char *d = buffer;
1275   bool accuse = FALSE;
1276
1277   if (aop->size && offset > (aop->size - 1))
1278     {
1279       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1280               "aopPut got offset > aop->size");
1281       exit (1);
1282     }
1283
1284   /* will assign value to value */
1285   /* depending on where it is ofcourse */
1286   switch (aop->type)
1287     {
1288     case AOP_DUMMY:
1289       MOVA (s);         /* read s in case it was volatile */
1290       accuse = TRUE;
1291       break;
1292
1293     case AOP_DIR:
1294       if (offset)
1295         sprintf (d, "(%s + %d)",
1296                  aop->aopu.aop_dir, offset);
1297       else
1298         sprintf (d, "%s", aop->aopu.aop_dir);
1299
1300       if (strcmp (d, s) ||
1301           bvolatile)
1302           emitcode ("mov", "%s,%s", d, s);
1303       if (!strcmp (d, "acc"))
1304           accuse = TRUE;
1305
1306       break;
1307
1308     case AOP_REG:
1309       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1310           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1311         {
1312           if (*s == '@' ||
1313               strcmp (s, "r0") == 0 ||
1314               strcmp (s, "r1") == 0 ||
1315               strcmp (s, "r2") == 0 ||
1316               strcmp (s, "r3") == 0 ||
1317               strcmp (s, "r4") == 0 ||
1318               strcmp (s, "r5") == 0 ||
1319               strcmp (s, "r6") == 0 ||
1320               strcmp (s, "r7") == 0)
1321             emitcode ("mov", "%s,%s",
1322                       aop->aopu.aop_reg[offset]->dname, s);
1323           else
1324             emitcode ("mov", "%s,%s",
1325                       aop->aopu.aop_reg[offset]->name, s);
1326         }
1327       break;
1328
1329     case AOP_DPTR:
1330       if (aop->code)
1331         {
1332           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1333                   "aopPut writing to code space");
1334           exit (1);
1335         }
1336
1337       while (offset > aop->coff)
1338         {
1339           aop->coff++;
1340           emitcode ("inc", "dptr");
1341         }
1342
1343       while (offset < aop->coff)
1344         {
1345           aop->coff--;
1346           emitcode ("lcall", "__decdptr");
1347         }
1348
1349       aop->coff = offset;
1350
1351       /* if not in accumulator */
1352       MOVA (s);
1353
1354       emitcode ("movx", "@dptr,a");
1355       break;
1356
1357     case AOP_R0:
1358     case AOP_R1:
1359       while (offset > aop->coff)
1360         {
1361           aop->coff++;
1362           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1363         }
1364       while (offset < aop->coff)
1365         {
1366           aop->coff--;
1367           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1368         }
1369       aop->coff = offset;
1370
1371       if (aop->paged)
1372         {
1373           MOVA (s);
1374           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1375
1376         }
1377       else if (*s == '@')
1378         {
1379           MOVA (s);
1380           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1381         }
1382       else if (strcmp (s, "r0") == 0 ||
1383                strcmp (s, "r1") == 0 ||
1384                strcmp (s, "r2") == 0 ||
1385                strcmp (s, "r3") == 0 ||
1386                strcmp (s, "r4") == 0 ||
1387                strcmp (s, "r5") == 0 ||
1388                strcmp (s, "r6") == 0 ||
1389                strcmp (s, "r7") == 0)
1390         {
1391           char buffer[10];
1392           sprintf (buffer, "a%s", s);
1393           emitcode ("mov", "@%s,%s",
1394                     aop->aopu.aop_ptr->name, buffer);
1395         }
1396       else
1397         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1398
1399       break;
1400
1401     case AOP_STK:
1402       if (strcmp (s, "a") == 0)
1403         emitcode ("push", "acc");
1404       else
1405         if (*s=='@') {
1406           MOVA(s);
1407           emitcode ("push", "acc");
1408         } else {
1409           emitcode ("push", s);
1410         }
1411
1412       break;
1413
1414     case AOP_CRY:
1415       /* if not bit variable */
1416       if (!aop->aopu.aop_dir)
1417         {
1418           /* inefficient: move carry into A and use jz/jnz */
1419           emitcode ("clr", "a");
1420           emitcode ("rlc", "a");
1421           accuse = TRUE;
1422         }
1423       else
1424         {
1425           if (s == zero)
1426             emitcode ("clr", "%s", aop->aopu.aop_dir);
1427           else if (s == one)
1428             emitcode ("setb", "%s", aop->aopu.aop_dir);
1429           else if (!strcmp (s, "c"))
1430             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1431           else
1432             {
1433               MOVA (s);
1434               /* set C, if a >= 1 */
1435               emitcode ("add", "a,#0xff");
1436               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1437             }
1438         }
1439       break;
1440
1441     case AOP_STR:
1442       aop->coff = offset;
1443       if (strcmp (aop->aopu.aop_str[offset], s) ||
1444           bvolatile)
1445         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1446       break;
1447
1448     case AOP_ACC:
1449       accuse = TRUE;
1450       aop->coff = offset;
1451       if (!offset && (strcmp (s, "acc") == 0) &&
1452           !bvolatile)
1453         break;
1454
1455       if (strcmp (aop->aopu.aop_str[offset], s) &&
1456           !bvolatile)
1457         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1458       break;
1459
1460     default:
1461       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1462               "aopPut got unsupported aop->type");
1463       exit (1);
1464     }
1465
1466     return accuse;
1467 }
1468
1469
1470 #if 0
1471 /*-----------------------------------------------------------------*/
1472 /* pointToEnd :- points to the last byte of the operand            */
1473 /*-----------------------------------------------------------------*/
1474 static void
1475 pointToEnd (asmop * aop)
1476 {
1477   int count;
1478   if (!aop)
1479     return;
1480
1481   aop->coff = count = (aop->size - 1);
1482   switch (aop->type)
1483     {
1484     case AOP_R0:
1485     case AOP_R1:
1486       while (count--)
1487         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1488       break;
1489     case AOP_DPTR:
1490       while (count--)
1491         emitcode ("inc", "dptr");
1492       break;
1493     }
1494
1495 }
1496 #endif
1497
1498 /*-----------------------------------------------------------------*/
1499 /* reAdjustPreg - points a register back to where it should        */
1500 /*-----------------------------------------------------------------*/
1501 static void
1502 reAdjustPreg (asmop * aop)
1503 {
1504   if ((aop->coff==0) || aop->size <= 1)
1505     return;
1506
1507   switch (aop->type)
1508     {
1509     case AOP_R0:
1510     case AOP_R1:
1511       while (aop->coff--)
1512         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1513       break;
1514     case AOP_DPTR:
1515       while (aop->coff--)
1516         {
1517           emitcode ("lcall", "__decdptr");
1518         }
1519       break;
1520     }
1521   aop->coff = 0;
1522 }
1523
1524 #define AOP(op) op->aop
1525 #define AOP_TYPE(op) AOP(op)->type
1526 #define AOP_SIZE(op) AOP(op)->size
1527 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1528                        AOP_TYPE(x) == AOP_R0))
1529
1530 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1531                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
1532
1533 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1534                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
1535                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
1536
1537
1538 /*-----------------------------------------------------------------*/
1539 /* opIsGptr: returns non-zero if the passed operand is       */
1540 /* a generic pointer type.             */
1541 /*-----------------------------------------------------------------*/
1542 static int
1543 opIsGptr (operand * op)
1544 {
1545   sym_link *type = operandType (op);
1546
1547   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1548     {
1549       return 1;
1550     }
1551   return 0;
1552 }
1553
1554 /*-----------------------------------------------------------------*/
1555 /* getDataSize - get the operand data size                         */
1556 /*-----------------------------------------------------------------*/
1557 static int
1558 getDataSize (operand * op)
1559 {
1560   int size;
1561   size = AOP_SIZE (op);
1562   if (size == GPTRSIZE)
1563     {
1564       sym_link *type = operandType (op);
1565       if (IS_GENPTR (type))
1566         {
1567           /* generic pointer; arithmetic operations
1568            * should ignore the high byte (pointer type).
1569            */
1570           size--;
1571         }
1572     }
1573   return size;
1574 }
1575
1576 /*-----------------------------------------------------------------*/
1577 /* outAcc - output Acc                                             */
1578 /*-----------------------------------------------------------------*/
1579 static void
1580 outAcc (operand * result)
1581 {
1582   int size, offset;
1583   size = getDataSize (result);
1584   if (size)
1585     {
1586       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
1587       size--;
1588       offset = 1;
1589       /* unsigned or positive */
1590       while (size--)
1591         {
1592           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
1593         }
1594     }
1595 }
1596
1597 /*-----------------------------------------------------------------*/
1598 /* outBitC - output a bit C                                        */
1599 /*-----------------------------------------------------------------*/
1600 static void
1601 outBitC (operand * result)
1602 {
1603   /* if the result is bit */
1604   if (AOP_TYPE (result) == AOP_CRY)
1605     aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
1606   else
1607     {
1608       emitcode ("clr", "a");
1609       emitcode ("rlc", "a");
1610       outAcc (result);
1611     }
1612 }
1613
1614 /*-----------------------------------------------------------------*/
1615 /* toBoolean - emit code for orl a,operator(sizeop)                */
1616 /*-----------------------------------------------------------------*/
1617 static void
1618 toBoolean (operand * oper)
1619 {
1620   int size = AOP_SIZE (oper) - 1;
1621   int offset = 1;
1622   bool AccUsed = FALSE;
1623   bool pushedB;
1624
1625   while (!AccUsed && size--)
1626     {
1627       AccUsed |= aopGetUsesAcc(AOP (oper), offset++);
1628     }
1629
1630   size = AOP_SIZE (oper) - 1;
1631   offset = 1;
1632   MOVA (aopGet (AOP (oper), 0, FALSE, FALSE));
1633   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1634     {
1635       pushedB = pushB ();
1636       emitcode("mov", "b,a");
1637       while (--size)
1638         {
1639           MOVA (aopGet (AOP (oper), offset++, FALSE, FALSE));
1640           emitcode ("orl", "b,a");
1641         }
1642       MOVA (aopGet (AOP (oper), offset++, FALSE, FALSE));
1643       emitcode ("orl", "a,b");
1644       popB (pushedB);
1645     }
1646   else
1647     {
1648       while (size--)
1649         {
1650           emitcode ("orl", "a,%s", aopGet (AOP (oper), offset++, FALSE, FALSE));
1651         }
1652     }
1653 }
1654
1655
1656 /*-----------------------------------------------------------------*/
1657 /* genNot - generate code for ! operation                          */
1658 /*-----------------------------------------------------------------*/
1659 static void
1660 genNot (iCode * ic)
1661 {
1662   symbol *tlbl;
1663
1664   D(emitcode (";     genNot",""));
1665
1666   /* assign asmOps to operand & result */
1667   aopOp (IC_LEFT (ic), ic, FALSE);
1668   aopOp (IC_RESULT (ic), ic, TRUE);
1669
1670   /* if in bit space then a special case */
1671   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1672     {
1673       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1674       emitcode ("cpl", "c");
1675       outBitC (IC_RESULT (ic));
1676       goto release;
1677     }
1678
1679   toBoolean (IC_LEFT (ic));
1680
1681   tlbl = newiTempLabel (NULL);
1682   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1683   emitcode ("", "%05d$:", tlbl->key + 100);
1684   outBitC (IC_RESULT (ic));
1685
1686 release:
1687   /* release the aops */
1688   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1689   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1690 }
1691
1692
1693 /*-----------------------------------------------------------------*/
1694 /* genCpl - generate code for complement                           */
1695 /*-----------------------------------------------------------------*/
1696 static void
1697 genCpl (iCode * ic)
1698 {
1699   int offset = 0;
1700   int size;
1701   symbol *tlbl;
1702   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1703
1704   D(emitcode (";", "genCpl"));
1705
1706   /* assign asmOps to operand & result */
1707   aopOp (IC_LEFT (ic), ic, FALSE);
1708   aopOp (IC_RESULT (ic), ic, TRUE);
1709
1710   /* special case if in bit space */
1711   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1712     {
1713       char *l;
1714
1715       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1716           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1717         {
1718           /* promotion rules are responsible for this strange result:
1719              bit -> int -> ~int -> bit
1720              uchar -> int -> ~int -> bit
1721           */
1722           werror(W_COMPLEMENT);
1723           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1724           goto release;
1725         }
1726
1727       tlbl=newiTempLabel(NULL);
1728       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, FALSE);
1729       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
1730           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1731           IS_AOP_PREG (IC_LEFT (ic)))
1732         {
1733           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1734         }
1735       else
1736         {
1737           MOVA (l);
1738           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1739         }
1740       emitcode ("", "%05d$:", tlbl->key + 100);
1741       outBitC (IC_RESULT(ic));
1742       goto release;
1743     }
1744
1745   size = AOP_SIZE (IC_RESULT (ic));
1746   while (size--)
1747     {
1748       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1749       MOVA (l);
1750       emitcode ("cpl", "a");
1751       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1752     }
1753
1754
1755 release:
1756   /* release the aops */
1757   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1758   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1759 }
1760
1761 /*-----------------------------------------------------------------*/
1762 /* genUminusFloat - unary minus for floating points                */
1763 /*-----------------------------------------------------------------*/
1764 static void
1765 genUminusFloat (operand * op, operand * result)
1766 {
1767   int size, offset = 0;
1768   char *l;
1769
1770   D(emitcode (";     genUminusFloat",""));
1771
1772   /* for this we just copy and then flip the bit */
1773
1774   size = AOP_SIZE (op) - 1;
1775
1776   while (size--)
1777     {
1778       aopPut (AOP (result),
1779               aopGet (AOP (op), offset, FALSE, FALSE),
1780               offset,
1781               isOperandVolatile (result, FALSE));
1782       offset++;
1783     }
1784
1785   l = aopGet (AOP (op), offset, FALSE, FALSE);
1786
1787   MOVA (l);
1788
1789   emitcode ("cpl", "acc.7");
1790   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
1791 }
1792
1793 /*-----------------------------------------------------------------*/
1794 /* genUminus - unary minus code generation                         */
1795 /*-----------------------------------------------------------------*/
1796 static void
1797 genUminus (iCode * ic)
1798 {
1799   int offset, size;
1800   sym_link *optype, *rtype;
1801
1802
1803   D(emitcode (";     genUminus",""));
1804
1805   /* assign asmops */
1806   aopOp (IC_LEFT (ic), ic, FALSE);
1807   aopOp (IC_RESULT (ic), ic, TRUE);
1808
1809   /* if both in bit space then special
1810      case */
1811   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1812       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1813     {
1814
1815       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1816       emitcode ("cpl", "c");
1817       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1818       goto release;
1819     }
1820
1821   optype = operandType (IC_LEFT (ic));
1822   rtype = operandType (IC_RESULT (ic));
1823
1824   /* if float then do float stuff */
1825   if (IS_FLOAT (optype))
1826     {
1827       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1828       goto release;
1829     }
1830
1831   /* otherwise subtract from zero */
1832   size = AOP_SIZE (IC_LEFT (ic));
1833   offset = 0;
1834   //CLRC ;
1835   while (size--)
1836     {
1837       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1838       if (!strcmp (l, "a"))
1839         {
1840           if (offset == 0)
1841             SETC;
1842           emitcode ("cpl", "a");
1843           emitcode ("addc", "a,#0");
1844         }
1845       else
1846         {
1847           if (offset == 0)
1848             CLRC;
1849           emitcode ("clr", "a");
1850           emitcode ("subb", "a,%s", l);
1851         }
1852       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1853     }
1854
1855   /* if any remaining bytes in the result */
1856   /* we just need to propagate the sign   */
1857   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1858     {
1859       emitcode ("rlc", "a");
1860       emitcode ("subb", "a,acc");
1861       while (size--)
1862         aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1863     }
1864
1865 release:
1866   /* release the aops */
1867   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1868   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1869 }
1870
1871 /*-----------------------------------------------------------------*/
1872 /* saveRegisters - will look for a call and save the registers     */
1873 /*-----------------------------------------------------------------*/
1874 static void
1875 saveRegisters (iCode * lic)
1876 {
1877   int i;
1878   iCode *ic;
1879   bitVect *rsave;
1880
1881   /* look for call */
1882   for (ic = lic; ic; ic = ic->next)
1883     if (ic->op == CALL || ic->op == PCALL)
1884       break;
1885
1886   if (!ic)
1887     {
1888       fprintf (stderr, "found parameter push with no function call\n");
1889       return;
1890     }
1891
1892   /* if the registers have been saved already or don't need to be then
1893      do nothing */
1894   if (ic->regsSaved)
1895     return;
1896   if (IS_SYMOP(IC_LEFT(ic)) &&
1897       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1898        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1899     return;
1900
1901   /* save the registers in use at this time but skip the
1902      ones for the result */
1903   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1904                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1905
1906   ic->regsSaved = 1;
1907   if (options.useXstack)
1908     {
1909       int count = bitVectnBitsOn (rsave);
1910
1911       if (count == 1)
1912         {
1913           i = bitVectFirstBit (rsave);
1914           emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1915           emitcode ("mov", "r0,%s", spname);
1916           emitcode ("inc", "%s", spname);// allocate before use
1917           emitcode ("movx", "@r0,a");
1918           if (bitVectBitValue (rsave, R0_IDX))
1919             emitcode ("mov", "r0,a");
1920         }
1921       else if (count != 0)
1922         {
1923           if (bitVectBitValue (rsave, R0_IDX))
1924             {
1925               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1926             }
1927           emitcode ("mov", "r0,%s", spname);
1928           MOVA ("r0");
1929           emitcode ("add", "a,#%d", count);
1930           emitcode ("mov", "%s,a", spname);
1931           for (i = 0; i < mcs51_nRegs; i++)
1932             {
1933               if (bitVectBitValue (rsave, i))
1934                 {
1935                   if (i == R0_IDX)
1936                     {
1937                       emitcode ("pop", "acc");
1938                       emitcode ("push", "acc");
1939                     }
1940                   else
1941                     {
1942                       emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1943                     }
1944                   emitcode ("movx", "@r0,a");
1945                   if (--count)
1946                     {
1947                       emitcode ("inc", "r0");
1948                     }
1949                 }
1950             }
1951           if (bitVectBitValue (rsave, R0_IDX))
1952             {
1953               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1954             }
1955         }
1956     }
1957   else
1958     for (i = 0; i < mcs51_nRegs; i++)
1959       {
1960         if (bitVectBitValue (rsave, i))
1961           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1962       }
1963 }
1964
1965 /*-----------------------------------------------------------------*/
1966 /* unsaveRegisters - pop the pushed registers                      */
1967 /*-----------------------------------------------------------------*/
1968 static void
1969 unsaveRegisters (iCode * ic)
1970 {
1971   int i;
1972   bitVect *rsave;
1973
1974   /* restore the registers in use at this time but skip the
1975      ones for the result */
1976   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1977                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1978
1979   if (options.useXstack)
1980     {
1981       int count = bitVectnBitsOn (rsave);
1982
1983       if (count == 1)
1984         {
1985           emitcode ("mov", "r0,%s", spname);
1986           emitcode ("dec", "r0");
1987           emitcode ("movx", "a,@r0");
1988           i = bitVectFirstBit (rsave);
1989           emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1990           emitcode ("dec", "%s", spname);
1991         }
1992       else if (count != 0)
1993         {
1994           emitcode ("mov", "r0,%s", spname);
1995           for (i = mcs51_nRegs; i >= 0; i--)
1996             {
1997               if (bitVectBitValue (rsave, i))
1998                 {
1999                   emitcode ("dec", "r0");
2000                   emitcode ("movx", "a,@r0");
2001                   if (i != R0_IDX)
2002                     emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
2003                   else
2004                     emitcode ("push", "acc");
2005                 }
2006             }
2007           emitcode ("mov", "%s,r0", spname);
2008           if (bitVectBitValue (rsave, R0_IDX))
2009             {
2010               emitcode ("pop", "ar0");
2011             }
2012         }
2013     }
2014   else
2015     for (i = mcs51_nRegs; i >= 0; i--)
2016       {
2017         if (bitVectBitValue (rsave, i))
2018           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2019       }
2020 }
2021
2022
2023 /*-----------------------------------------------------------------*/
2024 /* pushSide -                */
2025 /*-----------------------------------------------------------------*/
2026 static void
2027 pushSide (operand * oper, int size)
2028 {
2029   int offset = 0;
2030   while (size--)
2031     {
2032       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE);
2033       if (AOP_TYPE (oper) != AOP_REG &&
2034           AOP_TYPE (oper) != AOP_DIR &&
2035           strcmp (l, "a"))
2036         {
2037           MOVA (l);
2038           emitcode ("push", "acc");
2039         }
2040       else
2041           emitcode ("push", "%s", l);
2042         }
2043     }
2044
2045 /*-----------------------------------------------------------------*/
2046 /* assignResultValue - also indicates if acc is in use afterwards  */
2047 /*-----------------------------------------------------------------*/
2048 static bool
2049 assignResultValue (operand * oper)
2050 {
2051   int offset = 0;
2052   int size = AOP_SIZE (oper);
2053   bool accuse = FALSE;
2054
2055   while (size--)
2056     {
2057       accuse |= aopPut (AOP (oper), fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2058       offset++;
2059     }
2060   return accuse;
2061 }
2062
2063
2064 /*-----------------------------------------------------------------*/
2065 /* genXpush - pushes onto the external stack                       */
2066 /*-----------------------------------------------------------------*/
2067 static void
2068 genXpush (iCode * ic)
2069 {
2070   asmop *aop = newAsmop (0);
2071   regs *r;
2072   int size, offset = 0;
2073
2074   D(emitcode (";     genXpush",""));
2075
2076   aopOp (IC_LEFT (ic), ic, FALSE);
2077   r = getFreePtr (ic, &aop, FALSE);
2078
2079   size = AOP_SIZE (IC_LEFT (ic));
2080
2081   if (size == 1)
2082     {
2083       MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
2084       emitcode ("mov", "%s,%s", r->name, spname);
2085       emitcode ("inc", "%s", spname); // allocate space first
2086       emitcode ("movx", "@%s,a", r->name);
2087     }
2088   else
2089     {
2090       // allocate space first
2091       emitcode ("mov", "%s,%s", r->name, spname);
2092       MOVA (r->name);
2093       emitcode ("add", "a,#%d", size);
2094       emitcode ("mov", "%s,a", spname);
2095
2096       while (size--)
2097         {
2098           MOVA (aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, FALSE));
2099           emitcode ("movx", "@%s,a", r->name);
2100           emitcode ("inc", "%s", r->name);
2101         }
2102     }
2103
2104   freeAsmop (NULL, aop, ic, TRUE);
2105   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2106 }
2107
2108 /*-----------------------------------------------------------------*/
2109 /* genIpush - generate code for pushing this gets a little complex */
2110 /*-----------------------------------------------------------------*/
2111 static void
2112 genIpush (iCode * ic)
2113 {
2114   int size, offset = 0;
2115   char *l;
2116
2117   D(emitcode (";     genIpush",""));
2118
2119   /* if this is not a parm push : ie. it is spill push
2120      and spill push is always done on the local stack */
2121   if (!ic->parmPush)
2122     {
2123
2124       /* and the item is spilt then do nothing */
2125       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2126         return;
2127
2128       aopOp (IC_LEFT (ic), ic, FALSE);
2129       size = AOP_SIZE (IC_LEFT (ic));
2130       /* push it on the stack */
2131       while (size--)
2132         {
2133           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2134           if (*l == '#')
2135             {
2136               MOVA (l);
2137               l = "acc";
2138             }
2139           emitcode ("push", "%s", l);
2140         }
2141       return;
2142     }
2143
2144   /* this is a paramter push: in this case we call
2145      the routine to find the call and save those
2146      registers that need to be saved */
2147   saveRegisters (ic);
2148
2149   /* if use external stack then call the external
2150      stack pushing routine */
2151   if (options.useXstack)
2152     {
2153       genXpush (ic);
2154       return;
2155     }
2156
2157   /* then do the push */
2158   aopOp (IC_LEFT (ic), ic, FALSE);
2159
2160   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2161   size = AOP_SIZE (IC_LEFT (ic));
2162
2163   while (size--)
2164     {
2165       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2166       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2167           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2168           strcmp (l, "a"))
2169         {
2170           MOVA (l);
2171           emitcode ("push", "acc");
2172         }
2173       else
2174           emitcode ("push", "%s", l);
2175     }
2176
2177   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2178 }
2179
2180 /*-----------------------------------------------------------------*/
2181 /* genIpop - recover the registers: can happen only for spilling   */
2182 /*-----------------------------------------------------------------*/
2183 static void
2184 genIpop (iCode * ic)
2185 {
2186   int size, offset;
2187
2188   D(emitcode (";     genIpop",""));
2189
2190   /* if the temp was not pushed then */
2191   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2192     return;
2193
2194   aopOp (IC_LEFT (ic), ic, FALSE);
2195   size = AOP_SIZE (IC_LEFT (ic));
2196   offset = (size - 1);
2197   while (size--)
2198     emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2199                                    FALSE, TRUE));
2200
2201   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2202 }
2203
2204 /*-----------------------------------------------------------------*/
2205 /* saveRBank - saves an entire register bank on the stack          */
2206 /*-----------------------------------------------------------------*/
2207 static void
2208 saveRBank (int bank, iCode * ic, bool pushPsw)
2209 {
2210   int i;
2211   int count = mcs51_nRegs + (pushPsw ? 1 : 0);
2212   asmop *aop = NULL;
2213   regs *r = NULL;
2214
2215   if (options.useXstack)
2216     {
2217       if (!ic)
2218       {
2219           /* Assume r0 is available for use. */
2220           r = mcs51_regWithIdx (R0_IDX);;
2221       }
2222       else
2223       {
2224           aop = newAsmop (0);
2225           r = getFreePtr (ic, &aop, FALSE);
2226       }
2227       // allocate space first
2228       emitcode ("mov", "%s,%s", r->name, spname);
2229       MOVA (r->name);
2230       emitcode ("add", "a,#%d", count);
2231       emitcode ("mov", "%s,a", spname);
2232     }
2233
2234   for (i = 0; i < mcs51_nRegs; i++)
2235     {
2236       if (options.useXstack)
2237         {
2238           emitcode ("mov", "a,(%s+%d)",
2239                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2240           emitcode ("movx", "@%s,a", r->name);
2241           if (--count)
2242             emitcode ("inc", "%s", r->name);
2243         }
2244       else
2245         emitcode ("push", "(%s+%d)",
2246                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2247     }
2248
2249   if (pushPsw)
2250     {
2251       if (options.useXstack)
2252         {
2253           emitcode ("mov", "a,psw");
2254           emitcode ("movx", "@%s,a", r->name);
2255
2256         }
2257       else
2258         {
2259           emitcode ("push", "psw");
2260         }
2261
2262       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2263     }
2264
2265   if (aop)
2266     {
2267       freeAsmop (NULL, aop, ic, TRUE);
2268     }
2269
2270   if (ic)
2271   {
2272     ic->bankSaved = 1;
2273   }
2274 }
2275
2276 /*-----------------------------------------------------------------*/
2277 /* unsaveRBank - restores the register bank from stack             */
2278 /*-----------------------------------------------------------------*/
2279 static void
2280 unsaveRBank (int bank, iCode * ic, bool popPsw)
2281 {
2282   int i;
2283   asmop *aop = NULL;
2284   regs *r = NULL;
2285
2286   if (options.useXstack)
2287     {
2288       if (!ic)
2289         {
2290           /* Assume r0 is available for use. */
2291           r = mcs51_regWithIdx (R0_IDX);;
2292         }
2293       else
2294         {
2295           aop = newAsmop (0);
2296           r = getFreePtr (ic, &aop, FALSE);
2297         }
2298       emitcode ("mov", "%s,%s", r->name, spname);
2299     }
2300
2301   if (popPsw)
2302     {
2303       if (options.useXstack)
2304         {
2305           emitcode ("dec", "%s", r->name);
2306           emitcode ("movx", "a,@%s", r->name);
2307           emitcode ("mov", "psw,a");
2308         }
2309       else
2310         {
2311           emitcode ("pop", "psw");
2312         }
2313     }
2314
2315   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2316     {
2317       if (options.useXstack)
2318         {
2319           emitcode ("dec", "%s", r->name);
2320           emitcode ("movx", "a,@%s", r->name);
2321           emitcode ("mov", "(%s+%d),a",
2322                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2323         }
2324       else
2325         {
2326           emitcode ("pop", "(%s+%d)",
2327                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2328         }
2329     }
2330
2331   if (options.useXstack)
2332     {
2333       emitcode ("mov", "%s,%s", spname, r->name);
2334     }
2335
2336   if (aop)
2337     {
2338       freeAsmop (NULL, aop, ic, TRUE);
2339     }
2340 }
2341
2342 /*-----------------------------------------------------------------*/
2343 /* genSend - gen code for SEND                                     */
2344 /*-----------------------------------------------------------------*/
2345 static void genSend(set *sendSet)
2346 {
2347     iCode *sic;
2348     int rb1_count = 0 ;
2349
2350     for (sic = setFirstItem (sendSet); sic;
2351          sic = setNextItem (sendSet)) {
2352           int size, offset = 0;
2353           aopOp (IC_LEFT (sic), sic, FALSE);
2354           size = AOP_SIZE (IC_LEFT (sic));
2355
2356           if (sic->argreg == 1) {
2357               while (size--) {
2358                   char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2359                                     FALSE, FALSE);
2360                   if (strcmp (l, fReturn[offset]))
2361                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2362                   offset++;
2363               }
2364               rb1_count = 0;
2365           } else {
2366               while (size--) {
2367                   emitcode ("mov","b1_%d,%s",rb1_count++,
2368                             aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE));
2369               }
2370           }
2371           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2372     }
2373 }
2374
2375 /*-----------------------------------------------------------------*/
2376 /* genCall - generates a call statement                            */
2377 /*-----------------------------------------------------------------*/
2378 static void
2379 genCall (iCode * ic)
2380 {
2381   sym_link *dtype;
2382 //  bool restoreBank = FALSE;
2383   bool swapBanks = FALSE;
2384   bool accuse = FALSE;
2385   bool accPushed = FALSE;
2386
2387   D(emitcode(";     genCall",""));
2388
2389   dtype = operandType (IC_LEFT (ic));
2390   /* if send set is not empty then assign */
2391   if (_G.sendSet)
2392     {
2393         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2394             genSend(reverseSet(_G.sendSet));
2395         } else {
2396             genSend(_G.sendSet);
2397         }
2398
2399       _G.sendSet = NULL;
2400     }
2401
2402   /* if we are calling a not _naked function that is not using
2403      the same register bank then we need to save the
2404      destination registers on the stack */
2405   dtype = operandType (IC_LEFT (ic));
2406   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2407       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2408        !IFFUNC_ISISR (dtype))
2409   {
2410       swapBanks = TRUE;
2411   }
2412
2413   /* if caller saves & we have not saved then */
2414   if (!ic->regsSaved)
2415       saveRegisters (ic);
2416
2417   if (swapBanks)
2418   {
2419         emitcode ("mov", "psw,#0x%02x",
2420            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2421   }
2422
2423   /* make the call */
2424   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2425                             OP_SYMBOL (IC_LEFT (ic))->rname :
2426                             OP_SYMBOL (IC_LEFT (ic))->name));
2427
2428   if (swapBanks)
2429   {
2430        emitcode ("mov", "psw,#0x%02x",
2431           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2432   }
2433
2434   /* if we need assign a result value */
2435   if ((IS_ITEMP (IC_RESULT (ic)) &&
2436        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2437         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2438         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2439       IS_TRUE_SYMOP (IC_RESULT (ic)))
2440     {
2441
2442       _G.accInUse++;
2443       aopOp (IC_RESULT (ic), ic, FALSE);
2444       _G.accInUse--;
2445
2446       accuse = assignResultValue (IC_RESULT (ic));
2447
2448       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2449     }
2450
2451   /* adjust the stack for parameters if required */
2452   if (ic->parmBytes)
2453     {
2454       int i;
2455       if (ic->parmBytes > 3)
2456         {
2457           if (accuse)
2458             {
2459               emitcode ("push", "acc");
2460               accPushed = TRUE;
2461             }
2462
2463           emitcode ("mov", "a,%s", spname);
2464           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2465           emitcode ("mov", "%s,a", spname);
2466
2467           /* unsaveRegisters from xstack needs acc, but */
2468           /* unsaveRegisters from stack needs this popped */
2469           if (accPushed && !options.useXstack)
2470             {
2471               emitcode ("pop", "acc");
2472               accPushed = FALSE;
2473             }
2474         }
2475       else
2476         for (i = 0; i < ic->parmBytes; i++)
2477           emitcode ("dec", "%s", spname);
2478     }
2479
2480   /* if we hade saved some registers then unsave them */
2481   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2482     {
2483       if (accuse && !accPushed && options.useXstack)
2484         {
2485           /* xstack needs acc, but doesn't touch normal stack */
2486           emitcode ("push", "acc");
2487           accPushed = TRUE;
2488         }
2489       unsaveRegisters (ic);
2490     }
2491
2492 //  /* if register bank was saved then pop them */
2493 //  if (restoreBank)
2494 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2495
2496   if (accPushed)
2497     emitcode ("pop", "acc");
2498 }
2499
2500 /*-----------------------------------------------------------------*/
2501 /* -10l - generates a call by pointer statement                */
2502 /*-----------------------------------------------------------------*/
2503 static void
2504 genPcall (iCode * ic)
2505 {
2506   sym_link *dtype;
2507   symbol *rlbl = newiTempLabel (NULL);
2508 //  bool restoreBank=FALSE;
2509   bool swapBanks = FALSE;
2510
2511   D(emitcode(";     genPCall",""));
2512
2513   /* if caller saves & we have not saved then */
2514   if (!ic->regsSaved)
2515     saveRegisters (ic);
2516
2517   /* if we are calling a not _naked function that is not using
2518      the same register bank then we need to save the
2519      destination registers on the stack */
2520   dtype = operandType (IC_LEFT (ic))->next;
2521   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2522       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2523       !IFFUNC_ISISR (dtype))
2524   {
2525 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2526 //    restoreBank=TRUE;
2527       swapBanks = TRUE;
2528       // need caution message to user here
2529   }
2530
2531   /* push the return address on to the stack */
2532   emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2533   emitcode ("push", "acc");
2534   emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2535   emitcode ("push", "acc");
2536
2537   /* now push the calling address */
2538   aopOp (IC_LEFT (ic), ic, FALSE);
2539
2540   pushSide (IC_LEFT (ic), FPTRSIZE);
2541
2542   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2543
2544   /* if send set is not empty the assign */
2545   if (_G.sendSet)
2546     {
2547         genSend(reverseSet(_G.sendSet));
2548         _G.sendSet = NULL;
2549     }
2550
2551   if (swapBanks)
2552   {
2553         emitcode ("mov", "psw,#0x%02x",
2554            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2555   }
2556
2557   /* make the call */
2558   emitcode ("ret", "");
2559   emitcode ("", "%05d$:", (rlbl->key + 100));
2560
2561
2562   if (swapBanks)
2563   {
2564        emitcode ("mov", "psw,#0x%02x",
2565           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2566   }
2567
2568   /* if we need assign a result value */
2569   if ((IS_ITEMP (IC_RESULT (ic)) &&
2570        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2571         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2572       IS_TRUE_SYMOP (IC_RESULT (ic)))
2573     {
2574
2575       _G.accInUse++;
2576       aopOp (IC_RESULT (ic), ic, FALSE);
2577       _G.accInUse--;
2578
2579       assignResultValue (IC_RESULT (ic));
2580
2581       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2582     }
2583
2584   /* adjust the stack for parameters if
2585      required */
2586   if (ic->parmBytes)
2587     {
2588       int i;
2589       if (ic->parmBytes > 3)
2590         {
2591           emitcode ("mov", "a,%s", spname);
2592           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2593           emitcode ("mov", "%s,a", spname);
2594         }
2595       else
2596         for (i = 0; i < ic->parmBytes; i++)
2597           emitcode ("dec", "%s", spname);
2598
2599     }
2600
2601 //  /* if register bank was saved then unsave them */
2602 //  if (restoreBank)
2603 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2604
2605   /* if we hade saved some registers then
2606      unsave them */
2607   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2608     unsaveRegisters (ic);
2609 }
2610
2611 /*-----------------------------------------------------------------*/
2612 /* resultRemat - result  is rematerializable                       */
2613 /*-----------------------------------------------------------------*/
2614 static int
2615 resultRemat (iCode * ic)
2616 {
2617   if (SKIP_IC (ic) || ic->op == IFX)
2618     return 0;
2619
2620   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2621     {
2622       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2623       if (sym->remat && !POINTER_SET (ic))
2624         return 1;
2625     }
2626
2627   return 0;
2628 }
2629
2630 #if defined(__BORLANDC__) || defined(_MSC_VER)
2631 #define STRCASECMP stricmp
2632 #else
2633 #define STRCASECMP strcasecmp
2634 #endif
2635
2636 /*-----------------------------------------------------------------*/
2637 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2638 /*-----------------------------------------------------------------*/
2639 static int
2640 regsCmp(void *p1, void *p2)
2641 {
2642   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2643 }
2644
2645 static bool
2646 inExcludeList (char *s)
2647 {
2648   const char *p = setFirstItem(options.excludeRegsSet);
2649
2650   if (p == NULL || STRCASECMP(p, "none") == 0)
2651     return FALSE;
2652
2653
2654   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2655 }
2656
2657 /*-----------------------------------------------------------------*/
2658 /* genFunction - generated code for function entry                 */
2659 /*-----------------------------------------------------------------*/
2660 static void
2661 genFunction (iCode * ic)
2662 {
2663   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
2664   sym_link *ftype;
2665   bool     switchedPSW = FALSE;
2666   int      calleesaves_saved_register = -1;
2667   int      stackAdjust = sym->stack;
2668   int      accIsFree = sym->recvSize < 4;
2669   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2670   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
2671
2672   _G.nRegsSaved = 0;
2673   /* create the function header */
2674   emitcode (";", "-----------------------------------------");
2675   emitcode (";", " function %s", sym->name);
2676   emitcode (";", "-----------------------------------------");
2677
2678   emitcode ("", "%s:", sym->rname);
2679   ftype = operandType (IC_LEFT (ic));
2680   _G.currentFunc = sym;
2681
2682   if (IFFUNC_ISNAKED(ftype))
2683   {
2684       emitcode(";", "naked function: no prologue.");
2685       return;
2686   }
2687
2688   /* here we need to generate the equates for the
2689      register bank if required */
2690   if (FUNC_REGBANK (ftype) != rbank)
2691     {
2692       int i;
2693
2694       rbank = FUNC_REGBANK (ftype);
2695       for (i = 0; i < mcs51_nRegs; i++)
2696         {
2697           if (strcmp (regs8051[i].base, "0") == 0)
2698             emitcode ("", "%s = 0x%02x",
2699                       regs8051[i].dname,
2700                       8 * rbank + regs8051[i].offset);
2701           else
2702             emitcode ("", "%s = %s + 0x%02x",
2703                       regs8051[i].dname,
2704                       regs8051[i].base,
2705                       8 * rbank + regs8051[i].offset);
2706         }
2707     }
2708
2709   /* if this is an interrupt service routine then
2710      save acc, b, dpl, dph  */
2711   if (IFFUNC_ISISR (sym->type))
2712     {
2713
2714       if (!inExcludeList ("acc"))
2715         emitcode ("push", "acc");
2716       if (!inExcludeList ("b"))
2717         emitcode ("push", "b");
2718       if (!inExcludeList ("dpl"))
2719         emitcode ("push", "dpl");
2720       if (!inExcludeList ("dph"))
2721         emitcode ("push", "dph");
2722       /* if this isr has no bank i.e. is going to
2723          run with bank 0 , then we need to save more
2724          registers :-) */
2725       if (!FUNC_REGBANK (sym->type))
2726         {
2727
2728           /* if this function does not call any other
2729              function then we can be economical and
2730              save only those registers that are used */
2731           if (!IFFUNC_HASFCALL(sym->type))
2732             {
2733               int i;
2734
2735               /* if any registers used */
2736               if (sym->regsUsed)
2737                 {
2738                   /* save the registers used */
2739                   for (i = 0; i < sym->regsUsed->size; i++)
2740                     {
2741                       if (bitVectBitValue (sym->regsUsed, i))
2742                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2743                     }
2744                 }
2745             }
2746           else
2747             {
2748
2749               /* this function has a function call. We cannot
2750                  determines register usage so we will have to push the
2751                  entire bank */
2752                 saveRBank (0, ic, FALSE);
2753                 if (options.parms_in_bank1) {
2754                     int i;
2755                     for (i=0; i < 8 ; i++ ) {
2756                         emitcode ("push","%s",rb1regs[i]);
2757                     }
2758                 }
2759             }
2760         }
2761         else
2762         {
2763             /* This ISR uses a non-zero bank.
2764              *
2765              * We assume that the bank is available for our
2766              * exclusive use.
2767              *
2768              * However, if this ISR calls a function which uses some
2769              * other bank, we must save that bank entirely.
2770              */
2771             unsigned long banksToSave = 0;
2772
2773             if (IFFUNC_HASFCALL(sym->type))
2774             {
2775
2776 #define MAX_REGISTER_BANKS 4
2777
2778                 iCode *i;
2779                 int ix;
2780
2781                 for (i = ic; i; i = i->next)
2782                 {
2783                     if (i->op == ENDFUNCTION)
2784                     {
2785                         /* we got to the end OK. */
2786                         break;
2787                     }
2788
2789                     if (i->op == CALL)
2790                     {
2791                         sym_link *dtype;
2792
2793                         dtype = operandType (IC_LEFT(i));
2794                         if (dtype
2795                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2796                         {
2797                              /* Mark this bank for saving. */
2798                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2799                              {
2800                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2801                              }
2802                              else
2803                              {
2804                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2805                              }
2806
2807                              /* And note that we don't need to do it in
2808                               * genCall.
2809                               */
2810                              i->bankSaved = 1;
2811                         }
2812                     }
2813                     if (i->op == PCALL)
2814                     {
2815                         /* This is a mess; we have no idea what
2816                          * register bank the called function might
2817                          * use.
2818                          *
2819                          * The only thing I can think of to do is
2820                          * throw a warning and hope.
2821                          */
2822                         werror(W_FUNCPTR_IN_USING_ISR);
2823                     }
2824                 }
2825
2826                 if (banksToSave && options.useXstack)
2827                 {
2828                     /* Since we aren't passing it an ic,
2829                      * saveRBank will assume r0 is available to abuse.
2830                      *
2831                      * So switch to our (trashable) bank now, so
2832                      * the caller's R0 isn't trashed.
2833                      */
2834                     emitcode ("push", "psw");
2835                     emitcode ("mov", "psw,#0x%02x",
2836                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2837                     switchedPSW = TRUE;
2838                 }
2839
2840                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2841                 {
2842                      if (banksToSave & (1 << ix))
2843                      {
2844                          saveRBank(ix, NULL, FALSE);
2845                      }
2846                 }
2847             }
2848             // TODO: this needs a closer look
2849             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2850         }
2851
2852       /* Set the register bank to the desired value if nothing else */
2853       /* has done so yet. */
2854       if (!switchedPSW)
2855         {
2856           emitcode ("push", "psw");
2857           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2858         }
2859     }
2860   else
2861     {
2862       /* This is a non-ISR function. The caller has already switched register */
2863       /* banks, if necessary, so just handle the callee-saves option. */
2864
2865       /* if callee-save to be used for this function
2866          then save the registers being used in this function */
2867       if (IFFUNC_CALLEESAVES(sym->type))
2868         {
2869           int i;
2870
2871           /* if any registers used */
2872           if (sym->regsUsed)
2873             {
2874               /* save the registers used */
2875               for (i = 0; i < sym->regsUsed->size; i++)
2876                 {
2877                   if (bitVectBitValue (sym->regsUsed, i))
2878                     {
2879                       /* remember one saved register for later usage */
2880                       if (calleesaves_saved_register < 0)
2881                         calleesaves_saved_register = i;
2882                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2883                       _G.nRegsSaved++;
2884                     }
2885                 }
2886             }
2887         }
2888     }
2889
2890
2891   if (fReentrant)
2892     {
2893       if (options.useXstack)
2894         {
2895           emitcode ("mov", "r0,%s", spname);
2896           emitcode ("inc", "%s", spname);
2897           emitcode ("xch", "a,_bpx");
2898           emitcode ("movx", "@r0,a");
2899           emitcode ("inc", "r0");
2900           emitcode ("mov", "a,r0");
2901           emitcode ("xch", "a,_bpx");
2902           emitcode ("push", "_bp");     /* save the callers stack  */
2903           emitcode ("mov", "_bp,sp");
2904         }
2905       else
2906         {
2907           /* set up the stack */
2908           emitcode ("push", "_bp");     /* save the callers stack  */
2909           emitcode ("mov", "_bp,sp");
2910         }
2911     }
2912
2913   /* For some cases it is worthwhile to perform a RECEIVE iCode */
2914   /* before setting up the stack frame completely. */
2915   if (ric && ric->argreg == 1 && IC_RESULT (ric))
2916     {
2917       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
2918
2919       if (rsym->isitmp)
2920         {
2921           if (rsym && rsym->regType == REG_CND)
2922             rsym = NULL;
2923           if (rsym && (rsym->accuse || rsym->ruonly))
2924             rsym = NULL;
2925           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
2926             rsym = rsym->usl.spillLoc;
2927         }
2928
2929       /* If the RECEIVE operand immediately spills to the first entry on the */
2930       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
2931       /* rather than the usual @r0/r1 machinations. */
2932       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
2933         {
2934           int ofs;
2935
2936           _G.current_iCode = ric;
2937           D(emitcode (";     genReceive",""));
2938           for (ofs=0; ofs < sym->recvSize; ofs++)
2939             {
2940               if (!strcmp (fReturn[ofs], "a"))
2941                 emitcode ("push", "acc");
2942               else
2943                 emitcode ("push", fReturn[ofs]);
2944             }
2945           stackAdjust -= sym->recvSize;
2946           if (stackAdjust<0)
2947             {
2948               assert (stackAdjust>=0);
2949               stackAdjust = 0;
2950             }
2951           _G.current_iCode = ic;
2952           ric->generated = 1;
2953           accIsFree = 1;
2954         }
2955       /* If the RECEIVE operand is 4 registers, we can do the moves now */
2956       /* to free up the accumulator. */
2957       else if (rsym && rsym->nRegs && sym->recvSize == 4)
2958         {
2959           int ofs;
2960
2961           _G.current_iCode = ric;
2962           D(emitcode (";     genReceive",""));
2963           for (ofs=0; ofs < sym->recvSize; ofs++)
2964             {
2965               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
2966             }
2967           _G.current_iCode = ic;
2968           ric->generated = 1;
2969           accIsFree = 1;
2970         }
2971     }
2972
2973   /* adjust the stack for the function */
2974   if (stackAdjust)
2975     {
2976       int i = stackAdjust;
2977       if (i > 256)
2978         werror (W_STACK_OVERFLOW, sym->name);
2979
2980       if (i > 3 && accIsFree)
2981         {
2982           emitcode ("mov", "a,sp");
2983           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2984           emitcode ("mov", "sp,a");
2985         }
2986       else if (i > 5)
2987         {
2988           /* The accumulator is not free, so we will need another register */
2989           /* to clobber. No need to worry about a possible conflict with */
2990           /* the above early RECEIVE optimizations since they would have */
2991           /* freed the accumulator if they were generated. */
2992
2993           if (IFFUNC_CALLEESAVES(sym->type))
2994             {
2995               /* if it's a callee-saves function we need a saved register */
2996               if (calleesaves_saved_register >= 0)
2997                 {
2998                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2999                   emitcode ("mov", "a,sp");
3000                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3001                   emitcode ("mov", "sp,a");
3002                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3003                 }
3004               else
3005                 /* do it the hard way */
3006                 while (i--)
3007                   emitcode ("inc", "sp");
3008             }
3009           else
3010             {
3011               /* not callee-saves, we can clobber r0 */
3012               emitcode ("mov", "r0,a");
3013               emitcode ("mov", "a,sp");
3014               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3015               emitcode ("mov", "sp,a");
3016               emitcode ("mov", "a,r0");
3017             }
3018         }
3019       else
3020         while (i--)
3021           emitcode ("inc", "sp");
3022     }
3023
3024   if (sym->xstack)
3025     {
3026       char i = ((char) sym->xstack & 0xff);
3027
3028       if (i > 3 && accIsFree)
3029         {
3030           emitcode ("mov", "a,_spx");
3031           emitcode ("add", "a,#0x%02x", i);
3032           emitcode ("mov", "_spx,a");
3033         }
3034       else if (i > 5)
3035         {
3036           emitcode ("push", "acc");
3037           emitcode ("mov", "a,_spx");
3038           emitcode ("add", "a,#0x%02x", i);
3039           emitcode ("mov", "_spx,a");
3040           emitcode ("pop", "acc");
3041         }
3042       else
3043         {
3044           while (i--)
3045             emitcode ("inc", "_spx");
3046         }
3047     }
3048
3049   /* if critical function then turn interrupts off */
3050   if (IFFUNC_ISCRITICAL (ftype))
3051     {
3052       symbol *tlbl = newiTempLabel (NULL);
3053       emitcode ("setb", "c");
3054       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3055       emitcode ("clr", "c");
3056       emitcode ("", "%05d$:", (tlbl->key + 100));
3057       emitcode ("push", "psw"); /* save old ea via c in psw */
3058     }
3059 }
3060
3061 /*-----------------------------------------------------------------*/
3062 /* genEndFunction - generates epilogue for functions               */
3063 /*-----------------------------------------------------------------*/
3064 static void
3065 genEndFunction (iCode * ic)
3066 {
3067   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3068   lineNode *lnp = lineCurr;
3069   bitVect  *regsUsed;
3070   bitVect  *regsUsedPrologue;
3071   bitVect  *regsUnneeded;
3072   int      idx;
3073
3074   _G.currentFunc = NULL;
3075   if (IFFUNC_ISNAKED(sym->type))
3076   {
3077       emitcode(";", "naked function: no epilogue.");
3078       if (options.debug && currFunc)
3079         debugFile->writeEndFunction (currFunc, ic, 0);
3080       return;
3081   }
3082
3083   if (IFFUNC_ISCRITICAL (sym->type))
3084     {
3085       emitcode ("pop", "psw"); /* restore ea via c in psw */
3086       emitcode ("mov", "ea,c");
3087     }
3088
3089   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3090     {
3091       emitcode ("mov", "sp,_bp");
3092       emitcode ("pop", "_bp");
3093
3094       if (options.useXstack)
3095         {
3096           emitcode ("xch", "a,_bpx");
3097           emitcode ("mov", "r0,a");
3098           emitcode ("dec", "r0");
3099           emitcode ("movx", "a,@r0");
3100           emitcode ("xch", "a,_bpx");
3101           emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3102         }
3103     }
3104
3105   /* restore the register bank  */
3106   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3107   {
3108     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3109      || !options.useXstack)
3110     {
3111         /* Special case of ISR using non-zero bank with useXstack
3112          * is handled below.
3113          */
3114         emitcode ("pop", "psw");
3115     }
3116   }
3117
3118   if (IFFUNC_ISISR (sym->type))
3119     {
3120
3121       /* now we need to restore the registers */
3122       /* if this isr has no bank i.e. is going to
3123          run with bank 0 , then we need to save more
3124          registers :-) */
3125       if (!FUNC_REGBANK (sym->type))
3126         {
3127           /* if this function does not call any other
3128              function then we can be economical and
3129              save only those registers that are used */
3130           if (!IFFUNC_HASFCALL(sym->type))
3131             {
3132               int i;
3133
3134               /* if any registers used */
3135               if (sym->regsUsed)
3136                 {
3137                   /* save the registers used */
3138                   for (i = sym->regsUsed->size; i >= 0; i--)
3139                     {
3140                       if (bitVectBitValue (sym->regsUsed, i))
3141                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3142                     }
3143                 }
3144             }
3145           else
3146             {
3147               if (options.parms_in_bank1) {
3148                   int i;
3149                   for (i = 7 ; i >= 0 ; i-- ) {
3150                       emitcode ("pop","%s",rb1regs[i]);
3151                   }
3152               }
3153               /* this function has  a function call cannot
3154                  determines register usage so we will have to pop the
3155                  entire bank */
3156               unsaveRBank (0, ic, FALSE);
3157             }
3158         }
3159         else
3160         {
3161             /* This ISR uses a non-zero bank.
3162              *
3163              * Restore any register banks saved by genFunction
3164              * in reverse order.
3165              */
3166             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3167             int ix;
3168
3169             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3170             {
3171                 if (savedBanks & (1 << ix))
3172                 {
3173                     unsaveRBank(ix, NULL, FALSE);
3174                 }
3175             }
3176
3177             if (options.useXstack)
3178             {
3179                 /* Restore bank AFTER calling unsaveRBank,
3180                  * since it can trash r0.
3181                  */
3182                 emitcode ("pop", "psw");
3183             }
3184         }
3185
3186       if (!inExcludeList ("dph"))
3187         emitcode ("pop", "dph");
3188       if (!inExcludeList ("dpl"))
3189         emitcode ("pop", "dpl");
3190       if (!inExcludeList ("b"))
3191         emitcode ("pop", "b");
3192       if (!inExcludeList ("acc"))
3193         emitcode ("pop", "acc");
3194
3195       /* if debug then send end of function */
3196       if (options.debug && currFunc)
3197         {
3198           debugFile->writeEndFunction (currFunc, ic, 1);
3199         }
3200
3201       emitcode ("reti", "");
3202     }
3203   else
3204     {
3205       if (IFFUNC_CALLEESAVES(sym->type))
3206         {
3207           int i;
3208
3209           /* if any registers used */
3210           if (sym->regsUsed)
3211             {
3212               /* save the registers used */
3213               for (i = sym->regsUsed->size; i >= 0; i--)
3214                 {
3215                   if (bitVectBitValue (sym->regsUsed, i) ||
3216                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3217                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3218                 }
3219             }
3220           else if (mcs51_ptrRegReq)
3221             {
3222               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3223               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3224             }
3225
3226         }
3227
3228       /* if debug then send end of function */
3229       if (options.debug && currFunc)
3230         {
3231           debugFile->writeEndFunction (currFunc, ic, 1);
3232         }
3233
3234       emitcode ("ret", "");
3235     }
3236
3237   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3238     return;
3239
3240   /* If this was an interrupt handler using bank 0 that called another */
3241   /* function, then all registers must be saved; nothing to optimized. */
3242   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3243       && !FUNC_REGBANK(sym->type))
3244     return;
3245
3246   /* There are no push/pops to optimize if not callee-saves or ISR */
3247   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3248     return;
3249
3250   /* If there were stack parameters, we cannot optimize without also    */
3251   /* fixing all of the stack offsets; this is too dificult to consider. */
3252   if (FUNC_HASSTACKPARM(sym->type))
3253     return;
3254
3255   /* Compute the registers actually used */
3256   regsUsed = newBitVect (mcs51_nRegs);
3257   regsUsedPrologue = newBitVect (mcs51_nRegs);
3258   while (lnp)
3259     {
3260       if (lnp->ic && lnp->ic->op == FUNCTION)
3261         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3262       else
3263         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3264
3265       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3266           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3267         break;
3268       if (!lnp->prev)
3269         break;
3270       lnp = lnp->prev;
3271     }
3272
3273   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3274       && !bitVectBitValue (regsUsed, CND_IDX))
3275     {
3276       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3277       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3278           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3279         bitVectUnSetBit (regsUsed, CND_IDX);
3280     }
3281   else
3282     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3283
3284   /* If this was an interrupt handler that called another function */
3285   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3286   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3287     {
3288       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3289       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3290       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3291       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3292       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3293     }
3294
3295   /* Remove the unneeded push/pops */
3296   regsUnneeded = newBitVect (mcs51_nRegs);
3297   while (lnp)
3298     {
3299       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3300         {
3301           if (!strncmp(lnp->line, "push", 4))
3302             {
3303               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3304               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3305                 {
3306                   connectLine (lnp->prev, lnp->next);
3307                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3308                 }
3309             }
3310           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3311             {
3312               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3313               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3314                 {
3315                   connectLine (lnp->prev, lnp->next);
3316                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3317                 }
3318             }
3319         }
3320       lnp = lnp->next;
3321     }
3322
3323   for (idx = 0; idx < regsUnneeded->size; idx++)
3324     if (bitVectBitValue (regsUnneeded, idx))
3325       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3326
3327   freeBitVect (regsUnneeded);
3328   freeBitVect (regsUsed);
3329   freeBitVect (regsUsedPrologue);
3330 }
3331
3332 /*-----------------------------------------------------------------*/
3333 /* genRet - generate code for return statement                     */
3334 /*-----------------------------------------------------------------*/
3335 static void
3336 genRet (iCode * ic)
3337 {
3338   int size, offset = 0, pushed = 0;
3339
3340   D(emitcode (";     genRet",""));
3341
3342   /* if we have no return value then
3343      just generate the "ret" */
3344   if (!IC_LEFT (ic))
3345     goto jumpret;
3346
3347   /* we have something to return then
3348      move the return value into place */
3349   aopOp (IC_LEFT (ic), ic, FALSE);
3350   size = AOP_SIZE (IC_LEFT (ic));
3351
3352   while (size--)
3353     {
3354       char *l;
3355       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3356         {
3357           /* #NOCHANGE */
3358           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3359                       FALSE, TRUE);
3360           emitcode ("push", "%s", l);
3361           pushed++;
3362         }
3363       else
3364         {
3365           l = aopGet (AOP (IC_LEFT (ic)), offset,
3366                       FALSE, FALSE);
3367           if (strcmp (fReturn[offset], l))
3368             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3369         }
3370     }
3371
3372   if (pushed)
3373     {
3374       while (pushed)
3375         {
3376           pushed--;
3377           if (strcmp (fReturn[pushed], "a"))
3378             emitcode ("pop", fReturn[pushed]);
3379           else
3380             emitcode ("pop", "acc");
3381         }
3382     }
3383   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3384
3385 jumpret:
3386   /* generate a jump to the return label
3387      if the next is not the return statement */
3388   if (!(ic->next && ic->next->op == LABEL &&
3389         IC_LABEL (ic->next) == returnLabel))
3390
3391     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3392
3393 }
3394
3395 /*-----------------------------------------------------------------*/
3396 /* genLabel - generates a label                                    */
3397 /*-----------------------------------------------------------------*/
3398 static void
3399 genLabel (iCode * ic)
3400 {
3401   /* special case never generate */
3402   if (IC_LABEL (ic) == entryLabel)
3403     return;
3404
3405   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3406 }
3407
3408 /*-----------------------------------------------------------------*/
3409 /* genGoto - generates a ljmp                                      */
3410 /*-----------------------------------------------------------------*/
3411 static void
3412 genGoto (iCode * ic)
3413 {
3414   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3415 }
3416
3417 /*-----------------------------------------------------------------*/
3418 /* findLabelBackwards: walks back through the iCode chain looking  */
3419 /* for the given label. Returns number of iCode instructions     */
3420 /* between that label and given ic.          */
3421 /* Returns zero if label not found.          */
3422 /*-----------------------------------------------------------------*/
3423 static int
3424 findLabelBackwards (iCode * ic, int key)
3425 {
3426   int count = 0;
3427
3428   while (ic->prev)
3429     {
3430       ic = ic->prev;
3431       count++;
3432
3433       /* If we have any pushes or pops, we cannot predict the distance.
3434          I don't like this at all, this should be dealt with in the
3435          back-end */
3436       if (ic->op == IPUSH || ic->op == IPOP) {
3437         return 0;
3438       }
3439
3440       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3441         {
3442           return count;
3443         }
3444     }
3445
3446   return 0;
3447 }
3448
3449 /*-----------------------------------------------------------------*/
3450 /* genPlusIncr :- does addition with increment if possible         */
3451 /*-----------------------------------------------------------------*/
3452 static bool
3453 genPlusIncr (iCode * ic)
3454 {
3455   unsigned int icount;
3456   unsigned int size = getDataSize (IC_RESULT (ic));
3457
3458   /* will try to generate an increment */
3459   /* if the right side is not a literal
3460      we cannot */
3461   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3462     return FALSE;
3463
3464   /* if the literal value of the right hand side
3465      is greater than 4 then it is not worth it */
3466   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3467     return FALSE;
3468
3469   D(emitcode (";     genPlusIncr",""));
3470
3471   /* if increment >=16 bits in register or direct space */
3472   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3473       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3474       (size > 1) &&
3475       (icount == 1))
3476     {
3477       symbol *tlbl;
3478       int emitTlbl;
3479       int labelRange;
3480
3481       /* If the next instruction is a goto and the goto target
3482        * is < 10 instructions previous to this, we can generate
3483        * jumps straight to that target.
3484        */
3485       if (ic->next && ic->next->op == GOTO
3486           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3487           && labelRange <= 10)
3488         {
3489           emitcode (";", "tail increment optimized");
3490           tlbl = IC_LABEL (ic->next);
3491           emitTlbl = 0;
3492         }
3493       else
3494         {
3495           tlbl = newiTempLabel (NULL);
3496           emitTlbl = 1;
3497         }
3498       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3499       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3500           IS_AOP_PREG (IC_RESULT (ic)))
3501         emitcode ("cjne", "%s,#0x00,%05d$",
3502                   aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3503                   tlbl->key + 100);
3504       else
3505         {
3506           emitcode ("clr", "a");
3507           emitcode ("cjne", "a,%s,%05d$",
3508                     aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3509                     tlbl->key + 100);
3510         }
3511
3512       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3513       if (size > 2)
3514         {
3515           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3516               IS_AOP_PREG (IC_RESULT (ic)))
3517             emitcode ("cjne", "%s,#0x00,%05d$",
3518                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3519                       tlbl->key + 100);
3520           else
3521             emitcode ("cjne", "a,%s,%05d$",
3522                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3523                       tlbl->key + 100);
3524
3525           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3526         }
3527       if (size > 3)
3528         {
3529           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3530               IS_AOP_PREG (IC_RESULT (ic)))
3531             emitcode ("cjne", "%s,#0x00,%05d$",
3532                       aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3533                       tlbl->key + 100);
3534           else
3535             {
3536               emitcode ("cjne", "a,%s,%05d$",
3537                         aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3538                         tlbl->key + 100);
3539             }
3540           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3541         }
3542
3543       if (emitTlbl)
3544         {
3545           emitcode ("", "%05d$:", tlbl->key + 100);
3546         }
3547       return TRUE;
3548     }
3549
3550   /* if the sizes are greater than 1 then we cannot */
3551   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3552       AOP_SIZE (IC_LEFT (ic)) > 1)
3553     return FALSE;
3554
3555   /* we can if the aops of the left & result match or
3556      if they are in registers and the registers are the
3557      same */
3558   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3559     {
3560
3561       if (icount > 3)
3562         {
3563           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3564           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3565           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3566         }
3567       else
3568         {
3569
3570           while (icount--)
3571             emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3572         }
3573
3574       return TRUE;
3575     }
3576
3577   return FALSE;
3578 }
3579
3580 /*-----------------------------------------------------------------*/
3581 /* outBitAcc - output a bit in acc                                 */
3582 /*-----------------------------------------------------------------*/
3583 static void
3584 outBitAcc (operand * result)
3585 {
3586   symbol *tlbl = newiTempLabel (NULL);
3587   /* if the result is a bit */
3588   if (AOP_TYPE (result) == AOP_CRY)
3589     {
3590       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
3591     }
3592   else
3593     {
3594       emitcode ("jz", "%05d$", tlbl->key + 100);
3595       emitcode ("mov", "a,%s", one);
3596       emitcode ("", "%05d$:", tlbl->key + 100);
3597       outAcc (result);
3598     }
3599 }
3600
3601 /*-----------------------------------------------------------------*/
3602 /* genPlusBits - generates code for addition of two bits           */
3603 /*-----------------------------------------------------------------*/
3604 static void
3605 genPlusBits (iCode * ic)
3606 {
3607   D(emitcode (";     genPlusBits",""));
3608
3609   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3610     {
3611       symbol *lbl = newiTempLabel (NULL);
3612       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3613       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3614       emitcode ("cpl", "c");
3615       emitcode ("", "%05d$:", (lbl->key + 100));
3616       outBitC (IC_RESULT (ic));
3617     }
3618   else
3619     {
3620       emitcode ("clr", "a");
3621       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3622       emitcode ("rlc", "a");
3623       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3624       emitcode ("addc", "a,#0x00");
3625       outAcc (IC_RESULT (ic));
3626     }
3627 }
3628
3629 #if 0
3630 /* This is the original version of this code.
3631
3632  * This is being kept around for reference,
3633  * because I am not entirely sure I got it right...
3634  */
3635 static void
3636 adjustArithmeticResult (iCode * ic)
3637 {
3638   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3639       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3640       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3641     aopPut (AOP (IC_RESULT (ic)),
3642             aopGet (AOP (IC_LEFT (ic)), 2, FALSE, FALSE),
3643             2,
3644             isOperandVolatile (IC_RESULT (ic), FALSE));
3645
3646   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3647       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3648       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3649     aopPut (AOP (IC_RESULT (ic)),
3650             aopGet (AOP (IC_RIGHT (ic)), 2, FALSE, FALSE),
3651             2,
3652             isOperandVolatile (IC_RESULT (ic), FALSE));
3653
3654   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3655       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3656       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3657       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3658       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3659     {
3660       char buffer[5];
3661       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3662       aopPut (AOP (IC_RESULT (ic)), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3663     }
3664 }
3665 #else
3666 /* This is the pure and virtuous version of this code.
3667  * I'm pretty certain it's right, but not enough to toss the old
3668  * code just yet...
3669  */
3670 static void
3671 adjustArithmeticResult (iCode * ic)
3672 {
3673   if (opIsGptr (IC_RESULT (ic)) &&
3674       opIsGptr (IC_LEFT (ic)) &&
3675       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3676     {
3677       aopPut (AOP (IC_RESULT (ic)),
3678               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3679               GPTRSIZE - 1,
3680               isOperandVolatile (IC_RESULT (ic), FALSE));
3681     }
3682
3683   if (opIsGptr (IC_RESULT (ic)) &&
3684       opIsGptr (IC_RIGHT (ic)) &&
3685       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3686     {
3687       aopPut (AOP (IC_RESULT (ic)),
3688               aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3689               GPTRSIZE - 1,
3690               isOperandVolatile (IC_RESULT (ic), FALSE));
3691     }
3692
3693   if (opIsGptr (IC_RESULT (ic)) &&
3694       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3695       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3696       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3697       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3698     {
3699       char buffer[5];
3700       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3701       aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3702     }
3703 }
3704 #endif
3705
3706 /*-----------------------------------------------------------------*/
3707 /* genPlus - generates code for addition                           */
3708 /*-----------------------------------------------------------------*/
3709 static void
3710 genPlus (iCode * ic)
3711 {
3712   int size, offset = 0;
3713   int skip_bytes = 0;
3714   char *add = "add";
3715   asmop *leftOp, *rightOp;
3716   operand * op;
3717
3718   /* special cases :- */
3719
3720   D(emitcode (";     genPlus",""));
3721
3722   aopOp (IC_LEFT (ic), ic, FALSE);
3723   aopOp (IC_RIGHT (ic), ic, FALSE);
3724   aopOp (IC_RESULT (ic), ic, TRUE);
3725
3726   /* if literal, literal on the right or
3727      if left requires ACC or right is already
3728      in ACC */
3729   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3730       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3731       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3732     {
3733       operand *t = IC_RIGHT (ic);
3734       IC_RIGHT (ic) = IC_LEFT (ic);
3735       IC_LEFT (ic) = t;
3736     }
3737
3738   /* if both left & right are in bit
3739      space */
3740   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3741       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3742     {
3743       genPlusBits (ic);
3744       goto release;
3745     }
3746
3747   /* if left in bit space & right literal */
3748   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3749       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3750     {
3751       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3752       /* if result in bit space */
3753       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3754         {
3755           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3756             emitcode ("cpl", "c");
3757           outBitC (IC_RESULT (ic));
3758         }
3759       else
3760         {
3761           size = getDataSize (IC_RESULT (ic));
3762           while (size--)
3763             {
3764               MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE));
3765               emitcode ("addc", "a,#00");
3766               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3767             }
3768         }
3769       goto release;
3770     }
3771
3772   /* if I can do an increment instead
3773      of add then GOOD for ME */
3774   if (genPlusIncr (ic) == TRUE)
3775     goto release;
3776
3777   size = getDataSize (IC_RESULT (ic));
3778   leftOp = AOP(IC_LEFT(ic));
3779   rightOp = AOP(IC_RIGHT(ic));
3780   op=IC_LEFT(ic);
3781
3782   /* if this is an add for an array access
3783      at a 256 byte boundary */
3784   if ( 2 == size
3785        && AOP_TYPE (op) == AOP_IMMD
3786        && IS_SYMOP (op)
3787        && IS_SPEC (OP_SYM_ETYPE (op))
3788        && SPEC_ABSA (OP_SYM_ETYPE (op))
3789        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3790      )
3791     {
3792       D(emitcode (";     genPlus aligned array",""));
3793       aopPut (AOP (IC_RESULT (ic)),
3794               aopGet (rightOp, 0, FALSE, FALSE),
3795               0,
3796               isOperandVolatile (IC_RESULT (ic), FALSE));
3797
3798       if( 1 == getDataSize (IC_RIGHT (ic)) )
3799         {
3800           aopPut (AOP (IC_RESULT (ic)),
3801                   aopGet (leftOp, 1, FALSE, FALSE),
3802                   1,
3803                   isOperandVolatile (IC_RESULT (ic), FALSE));
3804         }
3805       else
3806         {
3807           MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
3808           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3809           aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3810         }
3811       goto release;
3812     }
3813
3814   /* if the lower bytes of a literal are zero skip the addition */
3815   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3816     {
3817        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3818               (skip_bytes+1 < size))
3819          {
3820            skip_bytes++;
3821          }
3822        if (skip_bytes)
3823          D(emitcode (";     genPlus shortcut",""));
3824     }
3825
3826   while (size--)
3827     {
3828       if( offset >= skip_bytes )
3829         {
3830           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3831             {
3832               bool pushedB;
3833               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3834               pushedB = pushB ();
3835               emitcode("xch", "a,b");
3836               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3837               emitcode (add, "a,b");
3838               popB (pushedB);
3839             }
3840           else if (aopGetUsesAcc (leftOp, offset))
3841             {
3842               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3843               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3844             }
3845           else
3846             {
3847               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3848               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3849             }
3850           aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3851           add = "addc";  /* further adds must propagate carry */
3852         }
3853       else
3854         {
3855           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3856               isOperandVolatile (IC_RESULT (ic), FALSE))
3857             {
3858               /* just move */
3859               aopPut (AOP (IC_RESULT (ic)),
3860                       aopGet (leftOp, offset, FALSE, FALSE),
3861                       offset,
3862                       isOperandVolatile (IC_RESULT (ic), FALSE));
3863             }
3864         }
3865       offset++;
3866     }
3867
3868   adjustArithmeticResult (ic);
3869
3870 release:
3871   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3872   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3873   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3874 }
3875
3876 /*-----------------------------------------------------------------*/
3877 /* genMinusDec :- does subtraction with deccrement if possible     */
3878 /*-----------------------------------------------------------------*/
3879 static bool
3880 genMinusDec (iCode * ic)
3881 {
3882   unsigned int icount;
3883   unsigned int size = getDataSize (IC_RESULT (ic));
3884
3885   /* will try to generate an increment */
3886   /* if the right side is not a literal
3887      we cannot */
3888   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3889     return FALSE;
3890
3891   /* if the literal value of the right hand side
3892      is greater than 4 then it is not worth it */
3893   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3894     return FALSE;
3895
3896   D(emitcode (";     genMinusDec",""));
3897
3898   /* if decrement >=16 bits in register or direct space */
3899   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3900       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3901       (size > 1) &&
3902       (icount == 1))
3903     {
3904       symbol *tlbl;
3905       int emitTlbl;
3906       int labelRange;
3907
3908       /* If the next instruction is a goto and the goto target
3909        * is <= 10 instructions previous to this, we can generate
3910        * jumps straight to that target.
3911        */
3912       if (ic->next && ic->next->op == GOTO
3913           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3914           && labelRange <= 10)
3915         {
3916           emitcode (";", "tail decrement optimized");
3917           tlbl = IC_LABEL (ic->next);
3918           emitTlbl = 0;
3919         }
3920       else
3921         {
3922           tlbl = newiTempLabel (NULL);
3923           emitTlbl = 1;
3924         }
3925
3926       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3927       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3928           IS_AOP_PREG (IC_RESULT (ic)))
3929         emitcode ("cjne", "%s,#0xff,%05d$"
3930                   ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3931                   ,tlbl->key + 100);
3932       else
3933         {
3934           emitcode ("mov", "a,#0xff");
3935           emitcode ("cjne", "a,%s,%05d$"
3936                     ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3937                     ,tlbl->key + 100);
3938         }
3939       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3940       if (size > 2)
3941         {
3942           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3943               IS_AOP_PREG (IC_RESULT (ic)))
3944             emitcode ("cjne", "%s,#0xff,%05d$"
3945                       ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3946                       ,tlbl->key + 100);
3947           else
3948             {
3949               emitcode ("cjne", "a,%s,%05d$"
3950                         ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3951                         ,tlbl->key + 100);
3952             }
3953           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3954         }
3955       if (size > 3)
3956         {
3957           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3958               IS_AOP_PREG (IC_RESULT (ic)))
3959             emitcode ("cjne", "%s,#0xff,%05d$"
3960                       ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3961                       ,tlbl->key + 100);
3962           else
3963             {
3964               emitcode ("cjne", "a,%s,%05d$"
3965                         ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3966                         ,tlbl->key + 100);
3967             }
3968           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3969         }
3970       if (emitTlbl)
3971         {
3972           emitcode ("", "%05d$:", tlbl->key + 100);
3973         }
3974       return TRUE;
3975     }
3976
3977   /* if the sizes are greater than 1 then we cannot */
3978   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3979       AOP_SIZE (IC_LEFT (ic)) > 1)
3980     return FALSE;
3981
3982   /* we can if the aops of the left & result match or
3983      if they are in registers and the registers are the
3984      same */
3985   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3986     {
3987
3988       while (icount--)
3989         emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
3990
3991       return TRUE;
3992     }
3993
3994   return FALSE;
3995 }
3996
3997 /*-----------------------------------------------------------------*/
3998 /* addSign - complete with sign                                    */
3999 /*-----------------------------------------------------------------*/
4000 static void
4001 addSign (operand * result, int offset, int sign)
4002 {
4003   int size = (getDataSize (result) - offset);
4004   if (size > 0)
4005     {
4006       if (sign)
4007         {
4008           emitcode ("rlc", "a");
4009           emitcode ("subb", "a,acc");
4010           while (size--)
4011             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4012         }
4013       else
4014         while (size--)
4015           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4016     }
4017 }
4018
4019 /*-----------------------------------------------------------------*/
4020 /* genMinusBits - generates code for subtraction  of two bits      */
4021 /*-----------------------------------------------------------------*/
4022 static void
4023 genMinusBits (iCode * ic)
4024 {
4025   symbol *lbl = newiTempLabel (NULL);
4026
4027   D(emitcode (";     genMinusBits",""));
4028
4029   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4030     {
4031       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4032       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4033       emitcode ("cpl", "c");
4034       emitcode ("", "%05d$:", (lbl->key + 100));
4035       outBitC (IC_RESULT (ic));
4036     }
4037   else
4038     {
4039       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4040       emitcode ("subb", "a,acc");
4041       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4042       emitcode ("inc", "a");
4043       emitcode ("", "%05d$:", (lbl->key + 100));
4044       aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4045       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4046     }
4047 }
4048
4049 /*-----------------------------------------------------------------*/
4050 /* genMinus - generates code for subtraction                       */
4051 /*-----------------------------------------------------------------*/
4052 static void
4053 genMinus (iCode * ic)
4054 {
4055   int size, offset = 0;
4056
4057   D(emitcode (";     genMinus",""));
4058
4059   aopOp (IC_LEFT (ic), ic, FALSE);
4060   aopOp (IC_RIGHT (ic), ic, FALSE);
4061   aopOp (IC_RESULT (ic), ic, TRUE);
4062
4063   /* special cases :- */
4064   /* if both left & right are in bit space */
4065   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4066       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4067     {
4068       genMinusBits (ic);
4069       goto release;
4070     }
4071
4072   /* if I can do an decrement instead
4073      of subtract then GOOD for ME */
4074   if (genMinusDec (ic) == TRUE)
4075     goto release;
4076
4077   size = getDataSize (IC_RESULT (ic));
4078
4079   /* if literal, add a,#-lit, else normal subb */
4080   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4081     {
4082       unsigned long lit = 0L;
4083
4084       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4085       lit = -(long) lit;
4086
4087       while (size--)
4088         {
4089           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE));
4090           /* first add without previous c */
4091           if (!offset) {
4092             if (!size && lit== (unsigned long) -1) {
4093               emitcode ("dec", "a");
4094             } else {
4095               emitcode ("add", "a,#0x%02x",
4096                         (unsigned int) (lit & 0x0FFL));
4097             }
4098           } else {
4099             emitcode ("addc", "a,#0x%02x",
4100                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4101           }
4102           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4103         }
4104     }
4105   else
4106     {
4107       asmop *leftOp, *rightOp;
4108
4109       leftOp = AOP(IC_LEFT(ic));
4110       rightOp = AOP(IC_RIGHT(ic));
4111
4112       while (size--)
4113         {
4114           if (aopGetUsesAcc(rightOp, offset)) {
4115             if (aopGetUsesAcc(leftOp, offset)) {
4116               bool pushedB;
4117
4118               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4119               pushedB = pushB ();
4120               emitcode ("mov", "b,a");
4121               if (offset == 0)
4122                 CLRC;
4123               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4124               emitcode ("subb", "a,b");
4125               popB (pushedB);
4126             } else {
4127               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4128               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4129               if (offset == 0) {
4130                 emitcode( "setb", "c");
4131               }
4132               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4133               emitcode("cpl", "a");
4134             }
4135           } else {
4136             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4137             if (offset == 0)
4138               CLRC;
4139             emitcode ("subb", "a,%s",
4140                       aopGet(rightOp, offset, FALSE, TRUE));
4141           }
4142
4143           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4144         }
4145     }
4146
4147
4148   adjustArithmeticResult (ic);
4149
4150 release:
4151   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4152   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4153   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4154 }
4155
4156
4157 /*-----------------------------------------------------------------*/
4158 /* genMultbits :- multiplication of bits                           */
4159 /*-----------------------------------------------------------------*/
4160 static void
4161 genMultbits (operand * left,
4162              operand * right,
4163              operand * result)
4164 {
4165   D(emitcode (";     genMultbits",""));
4166
4167   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4168   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4169   outBitC (result);
4170 }
4171
4172 /*-----------------------------------------------------------------*/
4173 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4174 /*-----------------------------------------------------------------*/
4175 static void
4176 genMultOneByte (operand * left,
4177                 operand * right,
4178                 operand * result)
4179 {
4180   symbol *lbl;
4181   int size = AOP_SIZE (result);
4182   bool runtimeSign, compiletimeSign;
4183   bool lUnsigned, rUnsigned, pushedB;
4184
4185   D(emitcode (";     genMultOneByte",""));
4186
4187   if (size < 1 || size > 2)
4188     {
4189       /* this should never happen */
4190       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4191                AOP_SIZE(result), __FILE__, lineno);
4192       exit (1);
4193     }
4194
4195   /* (if two literals: the value is computed before) */
4196   /* if one literal, literal on the right */
4197   if (AOP_TYPE (left) == AOP_LIT)
4198     {
4199       operand *t = right;
4200       right = left;
4201       left = t;
4202       /* emitcode (";", "swapped left and right"); */
4203     }
4204   /* if no literal, unsigned on the right: shorter code */
4205   if (   AOP_TYPE (right) != AOP_LIT
4206       && SPEC_USIGN (getSpec (operandType (left))))
4207     {
4208       operand *t = right;
4209       right = left;
4210       left = t;
4211     }
4212
4213   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4214   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4215
4216   pushedB = pushB ();
4217
4218   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4219                    no need to take care about the signedness! */
4220       || (lUnsigned && rUnsigned))
4221     {
4222       /* just an unsigned 8 * 8 = 8 multiply
4223          or 8u * 8u = 16u */
4224       /* emitcode (";","unsigned"); */
4225       /* TODO: check for accumulator clash between left & right aops? */
4226
4227       if (AOP_TYPE (right) == AOP_LIT)
4228         {
4229           /* moving to accumulator first helps peepholes */
4230           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4231           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4232         }
4233       else
4234         {
4235           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4236           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4237         }
4238
4239       emitcode ("mul", "ab");
4240       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4241       if (size == 2)
4242         aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4243
4244       popB (pushedB);
4245       return;
4246     }
4247
4248   /* we have to do a signed multiply */
4249   /* emitcode (";", "signed"); */
4250
4251   /* now sign adjust for both left & right */
4252
4253   /* let's see what's needed: */
4254   /* apply negative sign during runtime */
4255   runtimeSign = FALSE;
4256   /* negative sign from literals */
4257   compiletimeSign = FALSE;
4258
4259   if (!lUnsigned)
4260     {
4261       if (AOP_TYPE(left) == AOP_LIT)
4262         {
4263           /* signed literal */
4264           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4265           if (val < 0)
4266             compiletimeSign = TRUE;
4267         }
4268       else
4269         /* signed but not literal */
4270         runtimeSign = TRUE;
4271     }
4272
4273   if (!rUnsigned)
4274     {
4275       if (AOP_TYPE(right) == AOP_LIT)
4276         {
4277           /* signed literal */
4278           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4279           if (val < 0)
4280             compiletimeSign ^= TRUE;
4281         }
4282       else
4283         /* signed but not literal */
4284         runtimeSign = TRUE;
4285     }
4286
4287   /* initialize F0, which stores the runtime sign */
4288   if (runtimeSign)
4289     {
4290       if (compiletimeSign)
4291         emitcode ("setb", "F0"); /* set sign flag */
4292       else
4293         emitcode ("clr", "F0"); /* reset sign flag */
4294     }
4295
4296   /* save the signs of the operands */
4297   if (AOP_TYPE(right) == AOP_LIT)
4298     {
4299       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4300
4301       if (!rUnsigned && val < 0)
4302         emitcode ("mov", "b,#0x%02x", -val);
4303       else
4304         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4305     }
4306   else /* ! literal */
4307     {
4308       if (rUnsigned)  /* emitcode (";", "signed"); */
4309
4310         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4311       else
4312         {
4313           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4314           lbl = newiTempLabel (NULL);
4315           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4316           emitcode ("cpl", "F0"); /* complement sign flag */
4317           emitcode ("cpl", "a");  /* 2's complement */
4318           emitcode ("inc", "a");
4319           emitcode ("", "%05d$:", (lbl->key + 100));
4320           emitcode ("mov", "b,a");
4321         }
4322     }
4323
4324   if (AOP_TYPE(left) == AOP_LIT)
4325     {
4326       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4327
4328       if (!lUnsigned && val < 0)
4329         emitcode ("mov", "a,#0x%02x", -val);
4330       else
4331         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4332     }
4333   else /* ! literal */
4334     {
4335       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4336
4337       if (!lUnsigned)
4338         {
4339           lbl = newiTempLabel (NULL);
4340           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4341           emitcode ("cpl", "F0"); /* complement sign flag */
4342           emitcode ("cpl", "a"); /* 2's complement */
4343           emitcode ("inc", "a");
4344           emitcode ("", "%05d$:", (lbl->key + 100));
4345         }
4346     }
4347
4348   /* now the multiplication */
4349   emitcode ("mul", "ab");
4350   if (runtimeSign || compiletimeSign)
4351     {
4352       lbl = newiTempLabel (NULL);
4353       if (runtimeSign)
4354         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4355       emitcode ("cpl", "a"); /* lsb 2's complement */
4356       if (size != 2)
4357         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4358       else
4359         {
4360           emitcode ("add", "a,#1"); /* this sets carry flag */
4361           emitcode ("xch", "a,b");
4362           emitcode ("cpl", "a"); /* msb 2's complement */
4363           emitcode ("addc", "a,#0");
4364           emitcode ("xch", "a,b");
4365         }
4366       emitcode ("", "%05d$:", (lbl->key + 100));
4367     }
4368   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4369   if (size == 2)
4370     aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4371
4372   popB (pushedB);
4373 }
4374
4375 /*-----------------------------------------------------------------*/
4376 /* genMult - generates code for multiplication                     */
4377 /*-----------------------------------------------------------------*/
4378 static void
4379 genMult (iCode * ic)
4380 {
4381   operand *left = IC_LEFT (ic);
4382   operand *right = IC_RIGHT (ic);
4383   operand *result = IC_RESULT (ic);
4384
4385   D(emitcode (";     genMult",""));
4386
4387   /* assign the amsops */
4388   aopOp (left, ic, FALSE);
4389   aopOp (right, ic, FALSE);
4390   aopOp (result, ic, TRUE);
4391
4392   /* special cases first */
4393   /* both are bits */
4394   if (AOP_TYPE (left) == AOP_CRY &&
4395       AOP_TYPE (right) == AOP_CRY)
4396     {
4397       genMultbits (left, right, result);
4398       goto release;
4399     }
4400
4401   /* if both are of size == 1 */
4402 #if 0 // one of them can be a sloc shared with the result
4403     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4404 #else
4405   if (getSize(operandType(left)) == 1 &&
4406       getSize(operandType(right)) == 1)
4407 #endif
4408     {
4409       genMultOneByte (left, right, result);
4410       goto release;
4411     }
4412
4413   /* should have been converted to function call */
4414     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4415              getSize(OP_SYMBOL(right)->type));
4416   assert (0);
4417
4418 release:
4419   freeAsmop (result, NULL, ic, TRUE);
4420   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4421   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4422 }
4423
4424 /*-----------------------------------------------------------------*/
4425 /* genDivbits :- division of bits                                  */
4426 /*-----------------------------------------------------------------*/
4427 static void
4428 genDivbits (operand * left,
4429             operand * right,
4430             operand * result)
4431 {
4432   char *l;
4433   bool pushedB;
4434
4435   D(emitcode (";     genDivbits",""));
4436
4437   pushedB = pushB ();
4438
4439   /* the result must be bit */
4440   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4441   l = aopGet (AOP (left), 0, FALSE, FALSE);
4442
4443   MOVA (l);
4444
4445   emitcode ("div", "ab");
4446   emitcode ("rrc", "a");
4447
4448   popB (pushedB);
4449
4450   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4451 }
4452
4453 /*-----------------------------------------------------------------*/
4454 /* genDivOneByte : 8 bit division                                  */
4455 /*-----------------------------------------------------------------*/
4456 static void
4457 genDivOneByte (operand * left,
4458                operand * right,
4459                operand * result)
4460 {
4461   bool lUnsigned, rUnsigned, pushedB;
4462   bool runtimeSign, compiletimeSign;
4463   symbol *lbl;
4464   int size, offset;
4465
4466   D(emitcode (";     genDivOneByte",""));
4467
4468   /* Why is it necessary that genDivOneByte() can return an int result?
4469      Have a look at:
4470
4471         volatile unsigned char uc;
4472         volatile signed char sc1, sc2;
4473         volatile int i;
4474
4475         uc  = 255;
4476         sc1 = -1;
4477         i = uc / sc1;
4478
4479      Or:
4480
4481         sc1 = -128;
4482         sc2 = -1;
4483         i = sc1 / sc2;
4484
4485      In all cases a one byte result would overflow, the following cast to int
4486      would return the wrong result.
4487
4488      Two possible solution:
4489         a) cast operands to int, if ((unsigned) / (signed)) or
4490            ((signed) / (signed))
4491         b) return an 16 bit signed int; this is what we're doing here!
4492   */
4493
4494   size = AOP_SIZE (result) - 1;
4495   offset = 1;
4496   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4497   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4498
4499   pushedB = pushB ();
4500
4501   /* signed or unsigned */
4502   if (lUnsigned && rUnsigned)
4503     {
4504       /* unsigned is easy */
4505       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4506       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4507       emitcode ("div", "ab");
4508       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4509       while (size--)
4510         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4511
4512       popB (pushedB);
4513       return;
4514     }
4515
4516   /* signed is a little bit more difficult */
4517
4518   /* now sign adjust for both left & right */
4519
4520   /* let's see what's needed: */
4521   /* apply negative sign during runtime */
4522   runtimeSign = FALSE;
4523   /* negative sign from literals */
4524   compiletimeSign = FALSE;
4525
4526   if (!lUnsigned)
4527     {
4528       if (AOP_TYPE(left) == AOP_LIT)
4529         {
4530           /* signed literal */
4531           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4532           if (val < 0)
4533             compiletimeSign = TRUE;
4534         }
4535       else
4536         /* signed but not literal */
4537         runtimeSign = TRUE;
4538     }
4539
4540   if (!rUnsigned)
4541     {
4542       if (AOP_TYPE(right) == AOP_LIT)
4543         {
4544           /* signed literal */
4545           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4546           if (val < 0)
4547             compiletimeSign ^= TRUE;
4548         }
4549       else
4550         /* signed but not literal */
4551         runtimeSign = TRUE;
4552     }
4553
4554   /* initialize F0, which stores the runtime sign */
4555   if (runtimeSign)
4556     {
4557       if (compiletimeSign)
4558         emitcode ("setb", "F0"); /* set sign flag */
4559       else
4560         emitcode ("clr", "F0"); /* reset sign flag */
4561     }
4562
4563   /* save the signs of the operands */
4564   if (AOP_TYPE(right) == AOP_LIT)
4565     {
4566       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4567
4568       if (!rUnsigned && val < 0)
4569         emitcode ("mov", "b,#0x%02x", -val);
4570       else
4571         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4572     }
4573   else /* ! literal */
4574     {
4575       if (rUnsigned)
4576         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4577       else
4578         {
4579           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4580           lbl = newiTempLabel (NULL);
4581           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4582           emitcode ("cpl", "F0"); /* complement sign flag */
4583           emitcode ("cpl", "a");  /* 2's complement */
4584           emitcode ("inc", "a");
4585           emitcode ("", "%05d$:", (lbl->key + 100));
4586           emitcode ("mov", "b,a");
4587         }
4588     }
4589
4590   if (AOP_TYPE(left) == AOP_LIT)
4591     {
4592       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4593
4594       if (!lUnsigned && val < 0)
4595         emitcode ("mov", "a,#0x%02x", -val);
4596       else
4597         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4598     }
4599   else /* ! literal */
4600     {
4601       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4602
4603       if (!lUnsigned)
4604         {
4605           lbl = newiTempLabel (NULL);
4606           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4607           emitcode ("cpl", "F0"); /* complement sign flag */
4608           emitcode ("cpl", "a");  /* 2's complement */
4609           emitcode ("inc", "a");
4610           emitcode ("", "%05d$:", (lbl->key + 100));
4611         }
4612     }
4613
4614   /* now the division */
4615   emitcode ("div", "ab");
4616
4617   if (runtimeSign || compiletimeSign)
4618     {
4619       lbl = newiTempLabel (NULL);
4620       if (runtimeSign)
4621         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4622       emitcode ("cpl", "a"); /* lsb 2's complement */
4623       emitcode ("inc", "a");
4624       emitcode ("", "%05d$:", (lbl->key + 100));
4625
4626       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4627       if (size > 0)
4628         {
4629           /* msb is 0x00 or 0xff depending on the sign */
4630           if (runtimeSign)
4631             {
4632               emitcode ("mov", "c,F0");
4633               emitcode ("subb", "a,acc");
4634               while (size--)
4635                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4636             }
4637           else /* compiletimeSign */
4638             while (size--)
4639               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4640         }
4641     }
4642   else
4643     {
4644       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4645       while (size--)
4646         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4647     }
4648
4649   popB (pushedB);
4650 }
4651
4652 /*-----------------------------------------------------------------*/
4653 /* genDiv - generates code for division                            */
4654 /*-----------------------------------------------------------------*/
4655 static void
4656 genDiv (iCode * ic)
4657 {
4658   operand *left = IC_LEFT (ic);
4659   operand *right = IC_RIGHT (ic);
4660   operand *result = IC_RESULT (ic);
4661
4662   D(emitcode (";     genDiv",""));
4663
4664   /* assign the amsops */
4665   aopOp (left, ic, FALSE);
4666   aopOp (right, ic, FALSE);
4667   aopOp (result, ic, TRUE);
4668
4669   /* special cases first */
4670   /* both are bits */
4671   if (AOP_TYPE (left) == AOP_CRY &&
4672       AOP_TYPE (right) == AOP_CRY)
4673     {
4674       genDivbits (left, right, result);
4675       goto release;
4676     }
4677
4678   /* if both are of size == 1 */
4679   if (AOP_SIZE (left) == 1 &&
4680       AOP_SIZE (right) == 1)
4681     {
4682       genDivOneByte (left, right, result);
4683       goto release;
4684     }
4685
4686   /* should have been converted to function call */
4687   assert (0);
4688 release:
4689   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4690   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4691   freeAsmop (result, NULL, ic, TRUE);
4692 }
4693
4694 /*-----------------------------------------------------------------*/
4695 /* genModbits :- modulus of bits                                   */
4696 /*-----------------------------------------------------------------*/
4697 static void
4698 genModbits (operand * left,
4699             operand * right,
4700             operand * result)
4701 {
4702   char *l;
4703   bool pushedB;
4704
4705   D(emitcode (";     genModbits",""));
4706
4707   pushedB = pushB ();
4708
4709   /* the result must be bit */
4710   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4711   l = aopGet (AOP (left), 0, FALSE, FALSE);
4712
4713   MOVA (l);
4714
4715   emitcode ("div", "ab");
4716   emitcode ("mov", "a,b");
4717   emitcode ("rrc", "a");
4718
4719   popB (pushedB);
4720
4721   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4722 }
4723
4724 /*-----------------------------------------------------------------*/
4725 /* genModOneByte : 8 bit modulus                                   */
4726 /*-----------------------------------------------------------------*/
4727 static void
4728 genModOneByte (operand * left,
4729                operand * right,
4730                operand * result)
4731 {
4732   bool lUnsigned, rUnsigned, pushedB;
4733   bool runtimeSign, compiletimeSign;
4734   symbol *lbl;
4735   int size, offset;
4736
4737   D(emitcode (";     genModOneByte",""));
4738
4739   size = AOP_SIZE (result) - 1;
4740   offset = 1;
4741   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4742   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4743
4744   /* if right is a literal, check it for 2^n */
4745   if (AOP_TYPE(right) == AOP_LIT)
4746     {
4747       unsigned char val = abs((int) operandLitValue(right));
4748       symbol *lbl2 = NULL;
4749
4750       switch (val)
4751         {
4752           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
4753           case 2:
4754           case 4:
4755           case 8:
4756           case 16:
4757           case 32:
4758           case 64:
4759           case 128:
4760             if (lUnsigned)
4761               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
4762                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
4763               /* because iCode should have been changed to genAnd  */
4764               /* see file "SDCCopt.c", function "convertToFcall()" */
4765
4766             MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4767             emitcode ("mov", "c,acc.7");
4768             emitcode ("anl", "a,#0x%02x", val - 1);
4769             lbl = newiTempLabel (NULL);
4770             emitcode ("jz", "%05d$", (lbl->key + 100));
4771             emitcode ("jnc", "%05d$", (lbl->key + 100));
4772             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
4773             if (size)
4774               {
4775                 int size2 = size;
4776                 int offs2 = offset;
4777
4778                 aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4779                 while (size2--)
4780                   aopPut (AOP (result), "#0xff", offs2++, isOperandVolatile (result, FALSE));
4781                 lbl2 = newiTempLabel (NULL);
4782                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
4783               }
4784             emitcode ("", "%05d$:", (lbl->key + 100));
4785             aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4786             while (size--)
4787               aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4788             if (lbl2)
4789               {
4790                 emitcode ("", "%05d$:", (lbl2->key + 100));
4791               }
4792             return;
4793
4794           default:
4795             break;
4796         }
4797     }
4798
4799   pushedB = pushB ();
4800
4801   /* signed or unsigned */
4802   if (lUnsigned && rUnsigned)
4803     {
4804       /* unsigned is easy */
4805       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4806       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4807       emitcode ("div", "ab");
4808       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4809       while (size--)
4810         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4811
4812       popB (pushedB);
4813       return;
4814     }
4815
4816   /* signed is a little bit more difficult */
4817
4818   /* now sign adjust for both left & right */
4819
4820   /* modulus: sign of the right operand has no influence on the result! */
4821   if (AOP_TYPE(right) == AOP_LIT)
4822     {
4823       signed char val = (char) operandLitValue(right);
4824
4825       if (!rUnsigned && val < 0)
4826         emitcode ("mov", "b,#0x%02x", -val);
4827       else
4828         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4829     }
4830   else /* not literal */
4831     {
4832       if (rUnsigned)
4833         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4834       else
4835         {
4836           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4837           lbl = newiTempLabel (NULL);
4838           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4839           emitcode ("cpl", "a"); /* 2's complement */
4840           emitcode ("inc", "a");
4841           emitcode ("", "%05d$:", (lbl->key + 100));
4842           emitcode ("mov", "b,a");
4843         }
4844     }
4845
4846   /* let's see what's needed: */
4847   /* apply negative sign during runtime */
4848   runtimeSign = FALSE;
4849   /* negative sign from literals */
4850   compiletimeSign = FALSE;
4851
4852   /* sign adjust left side */
4853   if (AOP_TYPE(left) == AOP_LIT)
4854     {
4855       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4856
4857       if (!lUnsigned && val < 0)
4858         {
4859           compiletimeSign = TRUE; /* set sign flag */
4860           emitcode ("mov", "a,#0x%02x", -val);
4861         }
4862       else
4863         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4864     }
4865   else /* ! literal */
4866     {
4867       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4868
4869       if (!lUnsigned)
4870         {
4871           runtimeSign = TRUE;
4872           emitcode ("clr", "F0"); /* clear sign flag */
4873
4874           lbl = newiTempLabel (NULL);
4875           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4876           emitcode ("setb", "F0"); /* set sign flag */
4877           emitcode ("cpl", "a");   /* 2's complement */
4878           emitcode ("inc", "a");
4879           emitcode ("", "%05d$:", (lbl->key + 100));
4880         }
4881     }
4882
4883   /* now the modulus */
4884   emitcode ("div", "ab");
4885
4886   if (runtimeSign || compiletimeSign)
4887     {
4888       emitcode ("mov", "a,b");
4889       lbl = newiTempLabel (NULL);
4890       if (runtimeSign)
4891         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4892       emitcode ("cpl", "a"); /* 2's complement */
4893       emitcode ("inc", "a");
4894       emitcode ("", "%05d$:", (lbl->key + 100));
4895
4896       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4897       if (size > 0)
4898         {
4899           /* msb is 0x00 or 0xff depending on the sign */
4900           if (runtimeSign)
4901             {
4902               emitcode ("mov", "c,F0");
4903               emitcode ("subb", "a,acc");
4904               while (size--)
4905                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4906             }
4907           else /* compiletimeSign */
4908             while (size--)
4909               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4910         }
4911     }
4912   else
4913     {
4914       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4915       while (size--)
4916         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4917     }
4918
4919   popB (pushedB);
4920 }
4921
4922 /*-----------------------------------------------------------------*/
4923 /* genMod - generates code for division                            */
4924 /*-----------------------------------------------------------------*/
4925 static void
4926 genMod (iCode * ic)
4927 {
4928   operand *left = IC_LEFT (ic);
4929   operand *right = IC_RIGHT (ic);
4930   operand *result = IC_RESULT (ic);
4931
4932   D(emitcode (";     genMod",""));
4933
4934   /* assign the asmops */
4935   aopOp (left, ic, FALSE);
4936   aopOp (right, ic, FALSE);
4937   aopOp (result, ic, TRUE);
4938
4939   /* special cases first */
4940   /* both are bits */
4941   if (AOP_TYPE (left) == AOP_CRY &&
4942       AOP_TYPE (right) == AOP_CRY)
4943     {
4944       genModbits (left, right, result);
4945       goto release;
4946     }
4947
4948   /* if both are of size == 1 */
4949   if (AOP_SIZE (left) == 1 &&
4950       AOP_SIZE (right) == 1)
4951     {
4952       genModOneByte (left, right, result);
4953       goto release;
4954     }
4955
4956   /* should have been converted to function call */
4957   assert (0);
4958
4959 release:
4960   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4961   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4962   freeAsmop (result, NULL, ic, TRUE);
4963 }
4964
4965 /*-----------------------------------------------------------------*/
4966 /* genIfxJump :- will create a jump depending on the ifx           */
4967 /*-----------------------------------------------------------------*/
4968 static void
4969 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
4970 {
4971   symbol *jlbl;
4972   symbol *tlbl = newiTempLabel (NULL);
4973   char *inst;
4974
4975   D(emitcode (";     genIfxJump",""));
4976
4977   /* if true label then we jump if condition
4978      supplied is true */
4979   if (IC_TRUE (ic))
4980     {
4981       jlbl = IC_TRUE (ic);
4982       inst = ((strcmp (jval, "a") == 0 ? "jz" :
4983                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
4984     }
4985   else
4986     {
4987       /* false label is present */
4988       jlbl = IC_FALSE (ic);
4989       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
4990                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
4991     }
4992   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
4993     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
4994   else
4995     emitcode (inst, "%05d$", tlbl->key + 100);
4996   freeForBranchAsmop (result);
4997   freeForBranchAsmop (right);
4998   freeForBranchAsmop (left);
4999   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5000   emitcode ("", "%05d$:", tlbl->key + 100);
5001
5002   /* mark the icode as generated */
5003   ic->generated = 1;
5004 }
5005
5006 /*-----------------------------------------------------------------*/
5007 /* genCmp :- greater or less than comparison                       */
5008 /*-----------------------------------------------------------------*/
5009 static void
5010 genCmp (operand * left, operand * right,
5011         operand * result, iCode * ifx, int sign, iCode *ic)
5012 {
5013   int size, offset = 0;
5014   unsigned long lit = 0L;
5015   bool rightInB;
5016
5017   D(emitcode (";     genCmp",""));
5018
5019   /* if left & right are bit variables */
5020   if (AOP_TYPE (left) == AOP_CRY &&
5021       AOP_TYPE (right) == AOP_CRY)
5022     {
5023       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5024       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5025     }
5026   else
5027     {
5028       /* subtract right from left if at the
5029          end the carry flag is set then we know that
5030          left is greater than right */
5031       size = max (AOP_SIZE (left), AOP_SIZE (right));
5032
5033       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5034       if ((size == 1) && !sign &&
5035           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5036         {
5037           symbol *lbl = newiTempLabel (NULL);
5038           emitcode ("cjne", "%s,%s,%05d$",
5039                     aopGet (AOP (left), offset, FALSE, FALSE),
5040                     aopGet (AOP (right), offset, FALSE, FALSE),
5041                     lbl->key + 100);
5042           emitcode ("", "%05d$:", lbl->key + 100);
5043         }
5044       else
5045         {
5046           if (AOP_TYPE (right) == AOP_LIT)
5047             {
5048               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5049               /* optimize if(x < 0) or if(x >= 0) */
5050               if (lit == 0L)
5051                 {
5052                   if (!sign)
5053                     {
5054                       CLRC;
5055                     }
5056                   else
5057                     {
5058                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
5059                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5060                         {
5061                           genIfxJump (ifx, "acc.7", left, right, result);
5062                           freeAsmop (right, NULL, ic, TRUE);
5063                           freeAsmop (left, NULL, ic, TRUE);
5064
5065                           return;
5066                         }
5067                       else
5068                         emitcode ("rlc", "a");
5069                     }
5070                   goto release;
5071                 }
5072             }
5073           CLRC;
5074           while (size--)
5075             {
5076               bool pushedB = FALSE;
5077               rightInB = aopGetUsesAcc(AOP (right), offset);
5078               if (rightInB)
5079                 {
5080                   pushedB = pushB ();
5081                   emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5082                 }
5083               MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5084               if (sign && size == 0)
5085                 {
5086                   emitcode ("xrl", "a,#0x80");
5087                   if (AOP_TYPE (right) == AOP_LIT)
5088                     {
5089                       unsigned long lit = (unsigned long)
5090                       floatFromVal (AOP (right)->aopu.aop_lit);
5091                       emitcode ("subb", "a,#0x%02x",
5092                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5093                     }
5094                   else
5095                     {
5096                       if (!rightInB)
5097                         {
5098                           pushedB = pushB ();
5099                           rightInB++;
5100                           emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5101                         }
5102                       emitcode ("xrl", "b,#0x80");
5103                       emitcode ("subb", "a,b");
5104                     }
5105                 }
5106               else
5107                 {
5108                   if (rightInB)
5109                     emitcode ("subb", "a,b");
5110                   else
5111                     emitcode ("subb", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5112                 }
5113               if (rightInB)
5114                 popB (pushedB);
5115               offset++;
5116             }
5117         }
5118     }
5119
5120 release:
5121   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5122   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5123   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5124     {
5125       outBitC (result);
5126     }
5127   else
5128     {
5129       /* if the result is used in the next
5130          ifx conditional branch then generate
5131          code a little differently */
5132       if (ifx)
5133         genIfxJump (ifx, "c", NULL, NULL, result);
5134       else
5135         outBitC (result);
5136       /* leave the result in acc */
5137     }
5138 }
5139
5140 /*-----------------------------------------------------------------*/
5141 /* genCmpGt :- greater than comparison                             */
5142 /*-----------------------------------------------------------------*/
5143 static void
5144 genCmpGt (iCode * ic, iCode * ifx)
5145 {
5146   operand *left, *right, *result;
5147   sym_link *letype, *retype;
5148   int sign;
5149
5150   D(emitcode (";     genCmpGt",""));
5151
5152   left = IC_LEFT (ic);
5153   right = IC_RIGHT (ic);
5154   result = IC_RESULT (ic);
5155
5156   letype = getSpec (operandType (left));
5157   retype = getSpec (operandType (right));
5158   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5159            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5160   /* assign the amsops */
5161   aopOp (left, ic, FALSE);
5162   aopOp (right, ic, FALSE);
5163   aopOp (result, ic, TRUE);
5164
5165   genCmp (right, left, result, ifx, sign, ic);
5166
5167   freeAsmop (result, NULL, ic, TRUE);
5168 }
5169
5170 /*-----------------------------------------------------------------*/
5171 /* genCmpLt - less than comparisons                                */
5172 /*-----------------------------------------------------------------*/
5173 static void
5174 genCmpLt (iCode * ic, iCode * ifx)
5175 {
5176   operand *left, *right, *result;
5177   sym_link *letype, *retype;
5178   int sign;
5179
5180   D(emitcode (";     genCmpLt",""));
5181
5182   left = IC_LEFT (ic);
5183   right = IC_RIGHT (ic);
5184   result = IC_RESULT (ic);
5185
5186   letype = getSpec (operandType (left));
5187   retype = getSpec (operandType (right));
5188   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5189            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5190   /* assign the amsops */
5191   aopOp (left, ic, FALSE);
5192   aopOp (right, ic, FALSE);
5193   aopOp (result, ic, TRUE);
5194
5195   genCmp (left, right, result, ifx, sign,ic);
5196
5197   freeAsmop (result, NULL, ic, TRUE);
5198 }
5199
5200 /*-----------------------------------------------------------------*/
5201 /* gencjneshort - compare and jump if not equal                    */
5202 /*-----------------------------------------------------------------*/
5203 static void
5204 gencjneshort (operand * left, operand * right, symbol * lbl)
5205 {
5206   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5207   int offset = 0;
5208   unsigned long lit = 0L;
5209
5210   /* if the left side is a literal or
5211      if the right is in a pointer register and left
5212      is not */
5213   if ((AOP_TYPE (left) == AOP_LIT) ||
5214       (AOP_TYPE (left) == AOP_IMMD) ||
5215       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5216     {
5217       operand *t = right;
5218       right = left;
5219       left = t;
5220     }
5221
5222   if (AOP_TYPE (right) == AOP_LIT)
5223     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5224
5225   /* if the right side is a literal then anything goes */
5226   if (AOP_TYPE (right) == AOP_LIT &&
5227       AOP_TYPE (left) != AOP_DIR  &&
5228       AOP_TYPE (left) != AOP_IMMD)
5229     {
5230       while (size--)
5231         {
5232           emitcode ("cjne", "%s,%s,%05d$",
5233                     aopGet (AOP (left), offset, FALSE, FALSE),
5234                     aopGet (AOP (right), offset, FALSE, FALSE),
5235                     lbl->key + 100);
5236           offset++;
5237         }
5238     }
5239
5240   /* if the right side is in a register or in direct space or
5241      if the left is a pointer register & right is not */
5242   else if (AOP_TYPE (right) == AOP_REG ||
5243            AOP_TYPE (right) == AOP_DIR ||
5244            AOP_TYPE (right) == AOP_LIT ||
5245            AOP_TYPE (right) == AOP_IMMD ||
5246            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5247            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5248     {
5249       while (size--)
5250         {
5251           MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5252           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5253               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5254             emitcode ("jnz", "%05d$", lbl->key + 100);
5255           else
5256             emitcode ("cjne", "a,%s,%05d$",
5257                       aopGet (AOP (right), offset, FALSE, TRUE),
5258                       lbl->key + 100);
5259           offset++;
5260         }
5261     }
5262   else
5263     {
5264       /* right is a pointer reg need both a & b */
5265       while (size--)
5266         {
5267           char *l;
5268           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5269           wassertl(!BINUSE, "B was in use");
5270           l = aopGet (AOP (left), offset, FALSE, FALSE);
5271           if (strcmp (l, "b"))
5272             emitcode ("mov", "b,%s", l);
5273           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5274           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5275           offset++;
5276         }
5277     }
5278 }
5279
5280 /*-----------------------------------------------------------------*/
5281 /* gencjne - compare and jump if not equal                         */
5282 /*-----------------------------------------------------------------*/
5283 static void
5284 gencjne (operand * left, operand * right, symbol * lbl)
5285 {
5286   symbol *tlbl = newiTempLabel (NULL);
5287
5288   gencjneshort (left, right, lbl);
5289
5290   emitcode ("mov", "a,%s", one);
5291   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5292   emitcode ("", "%05d$:", lbl->key + 100);
5293   emitcode ("clr", "a");
5294   emitcode ("", "%05d$:", tlbl->key + 100);
5295 }
5296
5297 /*-----------------------------------------------------------------*/
5298 /* genCmpEq - generates code for equal to                          */
5299 /*-----------------------------------------------------------------*/
5300 static void
5301 genCmpEq (iCode * ic, iCode * ifx)
5302 {
5303   operand *left, *right, *result;
5304
5305   D(emitcode (";     genCmpEq",""));
5306
5307   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5308   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5309   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5310
5311   /* if literal, literal on the right or
5312      if the right is in a pointer register and left
5313      is not */
5314   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5315       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5316     {
5317       operand *t = IC_RIGHT (ic);
5318       IC_RIGHT (ic) = IC_LEFT (ic);
5319       IC_LEFT (ic) = t;
5320     }
5321
5322   if (ifx && !AOP_SIZE (result))
5323     {
5324       symbol *tlbl;
5325       /* if they are both bit variables */
5326       if (AOP_TYPE (left) == AOP_CRY &&
5327           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5328         {
5329           if (AOP_TYPE (right) == AOP_LIT)
5330             {
5331               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5332               if (lit == 0L)
5333                 {
5334                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5335                   emitcode ("cpl", "c");
5336                 }
5337               else if (lit == 1L)
5338                 {
5339                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5340                 }
5341               else
5342                 {
5343                   emitcode ("clr", "c");
5344                 }
5345               /* AOP_TYPE(right) == AOP_CRY */
5346             }
5347           else
5348             {
5349               symbol *lbl = newiTempLabel (NULL);
5350               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5351               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5352               emitcode ("cpl", "c");
5353               emitcode ("", "%05d$:", (lbl->key + 100));
5354             }
5355           /* if true label then we jump if condition
5356              supplied is true */
5357           tlbl = newiTempLabel (NULL);
5358           if (IC_TRUE (ifx))
5359             {
5360               emitcode ("jnc", "%05d$", tlbl->key + 100);
5361               freeForBranchAsmop (result);
5362               freeForBranchAsmop (right);
5363               freeForBranchAsmop (left);
5364               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5365             }
5366           else
5367             {
5368               emitcode ("jc", "%05d$", tlbl->key + 100);
5369               freeForBranchAsmop (result);
5370               freeForBranchAsmop (right);
5371               freeForBranchAsmop (left);
5372               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5373             }
5374           emitcode ("", "%05d$:", tlbl->key + 100);
5375         }
5376       else
5377         {
5378           tlbl = newiTempLabel (NULL);
5379           gencjneshort (left, right, tlbl);
5380           if (IC_TRUE (ifx))
5381             {
5382               freeForBranchAsmop (result);
5383               freeForBranchAsmop (right);
5384               freeForBranchAsmop (left);
5385               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5386               emitcode ("", "%05d$:", tlbl->key + 100);
5387             }
5388           else
5389             {
5390               symbol *lbl = newiTempLabel (NULL);
5391               emitcode ("sjmp", "%05d$", lbl->key + 100);
5392               emitcode ("", "%05d$:", tlbl->key + 100);
5393               freeForBranchAsmop (result);
5394               freeForBranchAsmop (right);
5395               freeForBranchAsmop (left);
5396               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5397               emitcode ("", "%05d$:", lbl->key + 100);
5398             }
5399         }
5400       /* mark the icode as generated */
5401       ifx->generated = 1;
5402       goto release;
5403     }
5404
5405   /* if they are both bit variables */
5406   if (AOP_TYPE (left) == AOP_CRY &&
5407       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5408     {
5409       if (AOP_TYPE (right) == AOP_LIT)
5410         {
5411           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5412           if (lit == 0L)
5413             {
5414               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5415               emitcode ("cpl", "c");
5416             }
5417           else if (lit == 1L)
5418             {
5419               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5420             }
5421           else
5422             {
5423               emitcode ("clr", "c");
5424             }
5425           /* AOP_TYPE(right) == AOP_CRY */
5426         }
5427       else
5428         {
5429           symbol *lbl = newiTempLabel (NULL);
5430           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5431           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5432           emitcode ("cpl", "c");
5433           emitcode ("", "%05d$:", (lbl->key + 100));
5434         }
5435       /* c = 1 if egal */
5436       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5437         {
5438           outBitC (result);
5439           goto release;
5440         }
5441       if (ifx)
5442         {
5443           genIfxJump (ifx, "c", left, right, result);
5444           goto release;
5445         }
5446       /* if the result is used in an arithmetic operation
5447          then put the result in place */
5448       outBitC (result);
5449     }
5450   else
5451     {
5452       gencjne (left, right, newiTempLabel (NULL));
5453       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5454         {
5455           aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
5456           goto release;
5457         }
5458       if (ifx)
5459         {
5460           genIfxJump (ifx, "a", left, right, result);
5461           goto release;
5462         }
5463       /* if the result is used in an arithmetic operation
5464          then put the result in place */
5465       if (AOP_TYPE (result) != AOP_CRY)
5466         outAcc (result);
5467       /* leave the result in acc */
5468     }
5469
5470 release:
5471   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5472   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5473   freeAsmop (result, NULL, ic, TRUE);
5474 }
5475
5476 /*-----------------------------------------------------------------*/
5477 /* ifxForOp - returns the icode containing the ifx for operand     */
5478 /*-----------------------------------------------------------------*/
5479 static iCode *
5480 ifxForOp (operand * op, iCode * ic)
5481 {
5482   /* if true symbol then needs to be assigned */
5483   if (IS_TRUE_SYMOP (op))
5484     return NULL;
5485
5486   /* if this has register type condition and
5487      the next instruction is ifx with the same operand
5488      and live to of the operand is upto the ifx only then */
5489   if (ic->next &&
5490       ic->next->op == IFX &&
5491       IC_COND (ic->next)->key == op->key &&
5492       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5493     return ic->next;
5494
5495   return NULL;
5496 }
5497
5498 /*-----------------------------------------------------------------*/
5499 /* hasInc - operand is incremented before any other use            */
5500 /*-----------------------------------------------------------------*/
5501 static iCode *
5502 hasInc (operand *op, iCode *ic,int osize)
5503 {
5504   sym_link *type = operandType(op);
5505   sym_link *retype = getSpec (type);
5506   iCode *lic = ic->next;
5507   int isize ;
5508
5509   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5510   if (!IS_SYMOP(op)) return NULL;
5511
5512   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5513   if (IS_AGGREGATE(type->next)) return NULL;
5514   if (osize != (isize = getSize(type->next))) return NULL;
5515
5516   while (lic) {
5517     /* if operand of the form op = op + <sizeof *op> */
5518     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5519         isOperandEqual(IC_RESULT(lic),op) &&
5520         isOperandLiteral(IC_RIGHT(lic)) &&
5521         operandLitValue(IC_RIGHT(lic)) == isize) {
5522       return lic;
5523     }
5524     /* if the operand used or deffed */
5525     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5526       return NULL;
5527     }
5528     /* if GOTO or IFX */
5529     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5530     lic = lic->next;
5531   }
5532   return NULL;
5533 }
5534
5535 /*-----------------------------------------------------------------*/
5536 /* genAndOp - for && operation                                     */
5537 /*-----------------------------------------------------------------*/
5538 static void
5539 genAndOp (iCode * ic)
5540 {
5541   operand *left, *right, *result;
5542   symbol *tlbl;
5543
5544   D(emitcode (";     genAndOp",""));
5545
5546   /* note here that && operations that are in an
5547      if statement are taken away by backPatchLabels
5548      only those used in arthmetic operations remain */
5549   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5550   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5551   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5552
5553   /* if both are bit variables */
5554   if (AOP_TYPE (left) == AOP_CRY &&
5555       AOP_TYPE (right) == AOP_CRY)
5556     {
5557       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5558       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5559       outBitC (result);
5560     }
5561   else
5562     {
5563       tlbl = newiTempLabel (NULL);
5564       toBoolean (left);
5565       emitcode ("jz", "%05d$", tlbl->key + 100);
5566       toBoolean (right);
5567       emitcode ("", "%05d$:", tlbl->key + 100);
5568       outBitAcc (result);
5569     }
5570
5571   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5572   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5573   freeAsmop (result, NULL, ic, TRUE);
5574 }
5575
5576
5577 /*-----------------------------------------------------------------*/
5578 /* genOrOp - for || operation                                      */
5579 /*-----------------------------------------------------------------*/
5580 static void
5581 genOrOp (iCode * ic)
5582 {
5583   operand *left, *right, *result;
5584   symbol *tlbl;
5585
5586   D(emitcode (";     genOrOp",""));
5587
5588   /* note here that || operations that are in an
5589      if statement are taken away by backPatchLabels
5590      only those used in arthmetic operations remain */
5591   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5592   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5593   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5594
5595   /* if both are bit variables */
5596   if (AOP_TYPE (left) == AOP_CRY &&
5597       AOP_TYPE (right) == AOP_CRY)
5598     {
5599       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5600       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5601       outBitC (result);
5602     }
5603   else
5604     {
5605       tlbl = newiTempLabel (NULL);
5606       toBoolean (left);
5607       emitcode ("jnz", "%05d$", tlbl->key + 100);
5608       toBoolean (right);
5609       emitcode ("", "%05d$:", tlbl->key + 100);
5610       outBitAcc (result);
5611     }
5612
5613   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5614   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5615   freeAsmop (result, NULL, ic, TRUE);
5616 }
5617
5618 /*-----------------------------------------------------------------*/
5619 /* isLiteralBit - test if lit == 2^n                               */
5620 /*-----------------------------------------------------------------*/
5621 static int
5622 isLiteralBit (unsigned long lit)
5623 {
5624   unsigned long pw[32] =
5625   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5626    0x100L, 0x200L, 0x400L, 0x800L,
5627    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5628    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5629    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5630    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5631    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5632   int idx;
5633
5634   for (idx = 0; idx < 32; idx++)
5635     if (lit == pw[idx])
5636       return idx + 1;
5637   return 0;
5638 }
5639
5640 /*-----------------------------------------------------------------*/
5641 /* continueIfTrue -                                                */
5642 /*-----------------------------------------------------------------*/
5643 static void
5644 continueIfTrue (iCode * ic)
5645 {
5646   if (IC_TRUE (ic))
5647     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5648   ic->generated = 1;
5649 }
5650
5651 /*-----------------------------------------------------------------*/
5652 /* jmpIfTrue -                                                     */
5653 /*-----------------------------------------------------------------*/
5654 static void
5655 jumpIfTrue (iCode * ic)
5656 {
5657   if (!IC_TRUE (ic))
5658     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5659   ic->generated = 1;
5660 }
5661
5662 /*-----------------------------------------------------------------*/
5663 /* jmpTrueOrFalse -                                                */
5664 /*-----------------------------------------------------------------*/
5665 static void
5666 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5667 {
5668   // ugly but optimized by peephole
5669   if (IC_TRUE (ic))
5670     {
5671       symbol *nlbl = newiTempLabel (NULL);
5672       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5673       emitcode ("", "%05d$:", tlbl->key + 100);
5674       freeForBranchAsmop (result);
5675       freeForBranchAsmop (right);
5676       freeForBranchAsmop (left);
5677       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5678       emitcode ("", "%05d$:", nlbl->key + 100);
5679     }
5680   else
5681     {
5682       freeForBranchAsmop (result);
5683       freeForBranchAsmop (right);
5684       freeForBranchAsmop (left);
5685       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5686       emitcode ("", "%05d$:", tlbl->key + 100);
5687     }
5688   ic->generated = 1;
5689 }
5690
5691 /*-----------------------------------------------------------------*/
5692 /* genAnd  - code for and                                          */
5693 /*-----------------------------------------------------------------*/
5694 static void
5695 genAnd (iCode * ic, iCode * ifx)
5696 {
5697   operand *left, *right, *result;
5698   int size, offset = 0;
5699   unsigned long lit = 0L;
5700   int bytelit = 0;
5701   char buffer[10];
5702
5703   D(emitcode (";     genAnd",""));
5704
5705   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5706   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5707   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5708
5709 #ifdef DEBUG_TYPE
5710   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5711             AOP_TYPE (result),
5712             AOP_TYPE (left), AOP_TYPE (right));
5713   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5714             AOP_SIZE (result),
5715             AOP_SIZE (left), AOP_SIZE (right));
5716 #endif
5717
5718   /* if left is a literal & right is not then exchange them */
5719   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5720       AOP_NEEDSACC (left))
5721     {
5722       operand *tmp = right;
5723       right = left;
5724       left = tmp;
5725     }
5726
5727   /* if result = right then exchange left and right */
5728   if (sameRegs (AOP (result), AOP (right)))
5729     {
5730       operand *tmp = right;
5731       right = left;
5732       left = tmp;
5733     }
5734
5735   /* if right is bit then exchange them */
5736   if (AOP_TYPE (right) == AOP_CRY &&
5737       AOP_TYPE (left) != AOP_CRY)
5738     {
5739       operand *tmp = right;
5740       right = left;
5741       left = tmp;
5742     }
5743   if (AOP_TYPE (right) == AOP_LIT)
5744     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5745
5746   size = AOP_SIZE (result);
5747
5748   // if(bit & yy)
5749   // result = bit & yy;
5750   if (AOP_TYPE (left) == AOP_CRY)
5751     {
5752       // c = bit & literal;
5753       if (AOP_TYPE (right) == AOP_LIT)
5754         {
5755           if (lit & 1)
5756             {
5757               if (size && sameRegs (AOP (result), AOP (left)))
5758                 // no change
5759                 goto release;
5760               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5761             }
5762           else
5763             {
5764               // bit(result) = 0;
5765               if (size && (AOP_TYPE (result) == AOP_CRY))
5766                 {
5767                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5768                   goto release;
5769                 }
5770               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5771                 {
5772                   jumpIfTrue (ifx);
5773                   goto release;
5774                 }
5775               emitcode ("clr", "c");
5776             }
5777         }
5778       else
5779         {
5780           if (AOP_TYPE (right) == AOP_CRY)
5781             {
5782               // c = bit & bit;
5783               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5784               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5785             }
5786           else
5787             {
5788               // c = bit & val;
5789               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
5790               // c = lsb
5791               emitcode ("rrc", "a");
5792               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5793             }
5794         }
5795       // bit = c
5796       // val = c
5797       if (size)
5798         outBitC (result);
5799       // if(bit & ...)
5800       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5801         genIfxJump (ifx, "c", left, right, result);
5802       goto release;
5803     }
5804
5805   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5806   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5807   if ((AOP_TYPE (right) == AOP_LIT) &&
5808       (AOP_TYPE (result) == AOP_CRY) &&
5809       (AOP_TYPE (left) != AOP_CRY))
5810     {
5811       int posbit = isLiteralBit (lit);
5812       /* left &  2^n */
5813       if (posbit)
5814         {
5815           posbit--;
5816           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE));
5817           // bit = left & 2^n
5818           if (size)
5819             {
5820               switch (posbit & 0x07)
5821                 {
5822                   case 0: emitcode ("rrc", "a");
5823                           break;
5824                   case 7: emitcode ("rlc", "a");
5825                           break;
5826                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
5827                           break;
5828                 }
5829             }
5830           // if(left &  2^n)
5831           else
5832             {
5833               if (ifx)
5834                 {
5835                   SNPRINTF (buffer, sizeof(buffer),
5836                             "acc.%d", posbit & 0x07);
5837                   genIfxJump (ifx, buffer, left, right, result);
5838                 }
5839               else
5840                 {// what is this case? just found it in ds390/gen.c
5841                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
5842                 }
5843               goto release;
5844             }
5845         }
5846       else
5847         {
5848           symbol *tlbl = newiTempLabel (NULL);
5849           int sizel = AOP_SIZE (left);
5850           if (size)
5851             emitcode ("setb", "c");
5852           while (sizel--)
5853             {
5854               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5855                 {
5856                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5857                   // byte ==  2^n ?
5858                   if ((posbit = isLiteralBit (bytelit)) != 0)
5859                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5860                   else
5861                     {
5862                       if (bytelit != 0x0FFL)
5863                         emitcode ("anl", "a,%s",
5864                                   aopGet (AOP (right), offset, FALSE, TRUE));
5865                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5866                     }
5867                 }
5868               offset++;
5869             }
5870           // bit = left & literal
5871           if (size)
5872             {
5873               emitcode ("clr", "c");
5874               emitcode ("", "%05d$:", tlbl->key + 100);
5875             }
5876           // if(left & literal)
5877           else
5878             {
5879               if (ifx)
5880                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5881               else
5882                 emitcode ("", "%05d$:", tlbl->key + 100);
5883               goto release;
5884             }
5885         }
5886       outBitC (result);
5887       goto release;
5888     }
5889
5890   /* if left is same as result */
5891   if (sameRegs (AOP (result), AOP (left)))
5892     {
5893       for (; size--; offset++)
5894         {
5895           if (AOP_TYPE (right) == AOP_LIT)
5896             {
5897               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5898               if (bytelit == 0x0FF)
5899                 {
5900                   /* dummy read of volatile operand */
5901                   if (isOperandVolatile (left, FALSE))
5902                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5903                   else
5904                     continue;
5905                 }
5906               else if (bytelit == 0)
5907                 {
5908                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5909                 }
5910               else if (IS_AOP_PREG (result))
5911                 {
5912                   MOVA (aopGet (AOP (left), offset, FALSE, TRUE));
5913                   emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5914                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5915                 }
5916               else
5917                 emitcode ("anl", "%s,%s",
5918                           aopGet (AOP (left), offset, FALSE, TRUE),
5919                           aopGet (AOP (right), offset, FALSE, FALSE));
5920             }
5921           else
5922             {
5923               if (AOP_TYPE (left) == AOP_ACC && offset == 0)
5924                 {
5925                   emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5926                 }
5927               else
5928                 {
5929                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5930                   if (IS_AOP_PREG (result))
5931                     {
5932                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5933                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5934                     }
5935                   else
5936                     emitcode ("anl", "%s,a",
5937                               aopGet (AOP (left), offset, FALSE, TRUE));
5938                 }
5939             }
5940         }
5941     }
5942   else
5943     {
5944       // left & result in different registers
5945       if (AOP_TYPE (result) == AOP_CRY)
5946         {
5947           // result = bit
5948           // if(size), result in bit
5949           // if(!size && ifx), conditional oper: if(left & right)
5950           symbol *tlbl = newiTempLabel (NULL);
5951           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5952           if (size)
5953             emitcode ("setb", "c");
5954           while (sizer--)
5955             {
5956               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
5957                   && AOP_TYPE(left)==AOP_ACC)
5958                 {
5959                   if (offset)
5960                     emitcode("mov", "a,b");
5961                   emitcode ("anl", "a,%s",
5962                             aopGet (AOP (right), offset, FALSE, FALSE));
5963                 } else {
5964                   if (AOP_TYPE(left)==AOP_ACC)
5965                     {
5966                       if (!offset)
5967                         {
5968                           bool pushedB = pushB ();
5969                           emitcode("mov", "b,a");
5970                           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5971                           emitcode("anl", "a,b");
5972                           popB (pushedB);
5973                         }
5974                       else
5975                         {
5976                           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5977                           emitcode("anl", "a,b");
5978                         }
5979                 } else {
5980                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5981                   emitcode ("anl", "a,%s",
5982                             aopGet (AOP (left), offset, FALSE, FALSE));
5983                 }
5984               }
5985               emitcode ("jnz", "%05d$", tlbl->key + 100);
5986               offset++;
5987             }
5988           if (size)
5989             {
5990               CLRC;
5991               emitcode ("", "%05d$:", tlbl->key + 100);
5992               outBitC (result);
5993             }
5994           else if (ifx)
5995             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5996           else
5997             emitcode ("", "%05d$:", tlbl->key + 100);
5998         }
5999       else
6000         {
6001           for (; (size--); offset++)
6002             {
6003               // normal case
6004               // result = left & right
6005               if (AOP_TYPE (right) == AOP_LIT)
6006                 {
6007                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6008                   if (bytelit == 0x0FF)
6009                     {
6010                       aopPut (AOP (result),
6011                               aopGet (AOP (left), offset, FALSE, FALSE),
6012                               offset,
6013                               isOperandVolatile (result, FALSE));
6014                       continue;
6015                     }
6016                   else if (bytelit == 0)
6017                     {
6018                       /* dummy read of volatile operand */
6019                       if (isOperandVolatile (left, FALSE))
6020                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6021                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
6022                       continue;
6023                     }
6024                   else if (AOP_TYPE (left) == AOP_ACC)
6025                     {
6026                       if (!offset)
6027                         {
6028                           emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6029                           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6030                           continue;
6031                         }
6032                       else
6033                         {
6034                           emitcode ("anl", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6035                           aopPut (AOP (result), "b", offset, isOperandVolatile (result, FALSE));
6036                           continue;
6037                         }
6038                     }
6039                 }
6040               // faster than result <- left, anl result,right
6041               // and better if result is SFR
6042               if (AOP_TYPE (left) == AOP_ACC)
6043                 {
6044                   if (offset)
6045                     emitcode("mov", "a,b");
6046                   emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6047                 }
6048               else
6049                 {
6050                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6051                   emitcode ("anl", "a,%s",
6052                             aopGet (AOP (left), offset, FALSE, FALSE));
6053                 }
6054               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6055             }
6056         }
6057     }
6058
6059 release:
6060   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6061   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6062   freeAsmop (result, NULL, ic, TRUE);
6063 }
6064
6065 /*-----------------------------------------------------------------*/
6066 /* genOr  - code for or                                            */
6067 /*-----------------------------------------------------------------*/
6068 static void
6069 genOr (iCode * ic, iCode * ifx)
6070 {
6071   operand *left, *right, *result;
6072   int size, offset = 0;
6073   unsigned long lit = 0L;
6074   int bytelit = 0;
6075
6076   D(emitcode (";     genOr",""));
6077
6078   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6079   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6080   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6081
6082 #ifdef DEBUG_TYPE
6083   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6084             AOP_TYPE (result),
6085             AOP_TYPE (left), AOP_TYPE (right));
6086   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6087             AOP_SIZE (result),
6088             AOP_SIZE (left), AOP_SIZE (right));
6089 #endif
6090
6091   /* if left is a literal & right is not then exchange them */
6092   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6093       AOP_NEEDSACC (left))
6094     {
6095       operand *tmp = right;
6096       right = left;
6097       left = tmp;
6098     }
6099
6100   /* if result = right then exchange them */
6101   if (sameRegs (AOP (result), AOP (right)))
6102     {
6103       operand *tmp = right;
6104       right = left;
6105       left = tmp;
6106     }
6107
6108   /* if right is bit then exchange them */
6109   if (AOP_TYPE (right) == AOP_CRY &&
6110       AOP_TYPE (left) != AOP_CRY)
6111     {
6112       operand *tmp = right;
6113       right = left;
6114       left = tmp;
6115     }
6116   if (AOP_TYPE (right) == AOP_LIT)
6117     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6118
6119   size = AOP_SIZE (result);
6120
6121   // if(bit | yy)
6122   // xx = bit | yy;
6123   if (AOP_TYPE (left) == AOP_CRY)
6124     {
6125       if (AOP_TYPE (right) == AOP_LIT)
6126         {
6127           // c = bit | literal;
6128           if (lit)
6129             {
6130               // lit != 0 => result = 1
6131               if (AOP_TYPE (result) == AOP_CRY)
6132                 {
6133                   if (size)
6134                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6135                   else if (ifx)
6136                     continueIfTrue (ifx);
6137                   goto release;
6138                 }
6139               emitcode ("setb", "c");
6140             }
6141           else
6142             {
6143               // lit == 0 => result = left
6144               if (size && sameRegs (AOP (result), AOP (left)))
6145                 goto release;
6146               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6147             }
6148         }
6149       else
6150         {
6151           if (AOP_TYPE (right) == AOP_CRY)
6152             {
6153               // c = bit | bit;
6154               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6155               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6156             }
6157           else
6158             {
6159               // c = bit | val;
6160               symbol *tlbl = newiTempLabel (NULL);
6161               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6162                 emitcode ("setb", "c");
6163               emitcode ("jb", "%s,%05d$",
6164                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6165               toBoolean (right);
6166               emitcode ("jnz", "%05d$", tlbl->key + 100);
6167               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6168                 {
6169                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6170                   goto release;
6171                 }
6172               else
6173                 {
6174                   CLRC;
6175                   emitcode ("", "%05d$:", tlbl->key + 100);
6176                 }
6177             }
6178         }
6179       // bit = c
6180       // val = c
6181       if (size)
6182         outBitC (result);
6183       // if(bit | ...)
6184       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6185         genIfxJump (ifx, "c", left, right, result);
6186       goto release;
6187     }
6188
6189   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6190   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6191   if ((AOP_TYPE (right) == AOP_LIT) &&
6192       (AOP_TYPE (result) == AOP_CRY) &&
6193       (AOP_TYPE (left) != AOP_CRY))
6194     {
6195       if (lit)
6196         {
6197           // result = 1
6198           if (size)
6199             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6200           else
6201             continueIfTrue (ifx);
6202           goto release;
6203         }
6204       else
6205         {
6206           // lit = 0, result = boolean(left)
6207           if (size)
6208             emitcode ("setb", "c");
6209           toBoolean (right);
6210           if (size)
6211             {
6212               symbol *tlbl = newiTempLabel (NULL);
6213               emitcode ("jnz", "%05d$", tlbl->key + 100);
6214               CLRC;
6215               emitcode ("", "%05d$:", tlbl->key + 100);
6216             }
6217           else
6218             {
6219               genIfxJump (ifx, "a", left, right, result);
6220               goto release;
6221             }
6222         }
6223       outBitC (result);
6224       goto release;
6225     }
6226
6227   /* if left is same as result */
6228   if (sameRegs (AOP (result), AOP (left)))
6229     {
6230       for (; size--; offset++)
6231         {
6232           if (AOP_TYPE (right) == AOP_LIT)
6233             {
6234               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6235               if (bytelit == 0)
6236                 {
6237                   /* dummy read of volatile operand */
6238                   if (isOperandVolatile (left, FALSE))
6239                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6240                   else
6241                     continue;
6242                 }
6243               else if (bytelit == 0x0FF)
6244                 {
6245                   aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6246                 }
6247               else if (IS_AOP_PREG (left))
6248                 {
6249                   MOVA (aopGet (AOP (left), offset, FALSE, TRUE));
6250                   emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6251                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6252                 }
6253               else
6254                 {
6255                   emitcode ("orl", "%s,%s",
6256                             aopGet (AOP (left), offset, FALSE, TRUE),
6257                             aopGet (AOP (right), offset, FALSE, FALSE));
6258                 }
6259             }
6260           else
6261             {
6262               if (AOP_TYPE (left) == AOP_ACC)
6263                 {
6264                   if (offset)
6265                     emitcode("mov", "a,b");
6266                   emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6267                 }
6268               else
6269                 {
6270                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6271                   if (IS_AOP_PREG (left))
6272                     {
6273                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6274                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6275                     }
6276                   else
6277                     {
6278                       emitcode ("orl", "%s,a",
6279                                 aopGet (AOP (left), offset, FALSE, TRUE));
6280                     }
6281                 }
6282             }
6283         }
6284     }
6285   else
6286     {
6287       // left & result in different registers
6288       if (AOP_TYPE (result) == AOP_CRY)
6289         {
6290           // result = bit
6291           // if(size), result in bit
6292           // if(!size && ifx), conditional oper: if(left | right)
6293           symbol *tlbl = newiTempLabel (NULL);
6294           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6295           if (size)
6296             emitcode ("setb", "c");
6297           while (sizer--)
6298             {
6299               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6300                 if (offset)
6301                   emitcode("mov", "a,b");
6302                 emitcode ("orl", "a,%s",
6303                           aopGet (AOP (right), offset, FALSE, FALSE));
6304               } else {
6305                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6306                 emitcode ("orl", "a,%s",
6307                           aopGet (AOP (left), offset, FALSE, FALSE));
6308               }
6309               emitcode ("jnz", "%05d$", tlbl->key + 100);
6310               offset++;
6311             }
6312           if (size)
6313             {
6314               CLRC;
6315               emitcode ("", "%05d$:", tlbl->key + 100);
6316               outBitC (result);
6317             }
6318           else if (ifx)
6319             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6320           else
6321             emitcode ("", "%05d$:", tlbl->key + 100);
6322         }
6323       else
6324         {
6325           for (; (size--); offset++)
6326             {
6327               // normal case
6328               // result = left | right
6329               if (AOP_TYPE (right) == AOP_LIT)
6330                 {
6331                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6332                   if (bytelit == 0)
6333                     {
6334                       aopPut (AOP (result),
6335                               aopGet (AOP (left), offset, FALSE, FALSE),
6336                               offset,
6337                               isOperandVolatile (result, FALSE));
6338                       continue;
6339                     }
6340                   else if (bytelit == 0x0FF)
6341                     {
6342                       /* dummy read of volatile operand */
6343                       if (isOperandVolatile (left, FALSE))
6344                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6345                       aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6346                       continue;
6347                     }
6348                 }
6349               // faster than result <- left, anl result,right
6350               // and better if result is SFR
6351               if (AOP_TYPE (left) == AOP_ACC)
6352                 {
6353                   if (offset)
6354                     emitcode("mov", "a,b");
6355                   emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6356                 }
6357               else
6358                 {
6359                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6360                   emitcode ("orl", "a,%s",
6361                             aopGet (AOP (left), offset, FALSE, FALSE));
6362                 }
6363               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6364             }
6365         }
6366     }
6367
6368 release:
6369   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6370   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6371   freeAsmop (result, NULL, ic, TRUE);
6372 }
6373
6374 /*-----------------------------------------------------------------*/
6375 /* genXor - code for xclusive or                                   */
6376 /*-----------------------------------------------------------------*/
6377 static void
6378 genXor (iCode * ic, iCode * ifx)
6379 {
6380   operand *left, *right, *result;
6381   int size, offset = 0;
6382   unsigned long lit = 0L;
6383   int bytelit = 0;
6384
6385   D(emitcode (";     genXor",""));
6386
6387   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6388   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6389   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6390
6391 #ifdef DEBUG_TYPE
6392   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6393             AOP_TYPE (result),
6394             AOP_TYPE (left), AOP_TYPE (right));
6395   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6396             AOP_SIZE (result),
6397             AOP_SIZE (left), AOP_SIZE (right));
6398 #endif
6399
6400   /* if left is a literal & right is not ||
6401      if left needs acc & right does not */
6402   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6403       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6404     {
6405       operand *tmp = right;
6406       right = left;
6407       left = tmp;
6408     }
6409
6410   /* if result = right then exchange them */
6411   if (sameRegs (AOP (result), AOP (right)))
6412     {
6413       operand *tmp = right;
6414       right = left;
6415       left = tmp;
6416     }
6417
6418   /* if right is bit then exchange them */
6419   if (AOP_TYPE (right) == AOP_CRY &&
6420       AOP_TYPE (left) != AOP_CRY)
6421     {
6422       operand *tmp = right;
6423       right = left;
6424       left = tmp;
6425     }
6426   if (AOP_TYPE (right) == AOP_LIT)
6427     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6428
6429   size = AOP_SIZE (result);
6430
6431   // if(bit ^ yy)
6432   // xx = bit ^ yy;
6433   if (AOP_TYPE (left) == AOP_CRY)
6434     {
6435       if (AOP_TYPE (right) == AOP_LIT)
6436         {
6437           // c = bit & literal;
6438           if (lit >> 1)
6439             {
6440               // lit>>1  != 0 => result = 1
6441               if (AOP_TYPE (result) == AOP_CRY)
6442                 {
6443                   if (size)
6444                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6445                   else if (ifx)
6446                     continueIfTrue (ifx);
6447                   goto release;
6448                 }
6449               emitcode ("setb", "c");
6450             }
6451           else
6452             {
6453               // lit == (0 or 1)
6454               if (lit == 0)
6455                 {
6456                   // lit == 0, result = left
6457                   if (size && sameRegs (AOP (result), AOP (left)))
6458                     goto release;
6459                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6460                 }
6461               else
6462                 {
6463                   // lit == 1, result = not(left)
6464                   if (size && sameRegs (AOP (result), AOP (left)))
6465                     {
6466                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6467                       goto release;
6468                     }
6469                   else
6470                     {
6471                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6472                       emitcode ("cpl", "c");
6473                     }
6474                 }
6475             }
6476
6477         }
6478       else
6479         {
6480           // right != literal
6481           symbol *tlbl = newiTempLabel (NULL);
6482           if (AOP_TYPE (right) == AOP_CRY)
6483             {
6484               // c = bit ^ bit;
6485               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6486             }
6487           else
6488             {
6489               int sizer = AOP_SIZE (right);
6490               // c = bit ^ val
6491               // if val>>1 != 0, result = 1
6492               emitcode ("setb", "c");
6493               while (sizer)
6494                 {
6495                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
6496                   if (sizer == 1)
6497                     // test the msb of the lsb
6498                     emitcode ("anl", "a,#0xfe");
6499                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6500                   sizer--;
6501                 }
6502               // val = (0,1)
6503               emitcode ("rrc", "a");
6504             }
6505           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6506           emitcode ("cpl", "c");
6507           emitcode ("", "%05d$:", (tlbl->key + 100));
6508         }
6509       // bit = c
6510       // val = c
6511       if (size)
6512         outBitC (result);
6513       // if(bit | ...)
6514       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6515         genIfxJump (ifx, "c", left, right, result);
6516       goto release;
6517     }
6518
6519   /* if left is same as result */
6520   if (sameRegs (AOP (result), AOP (left)))
6521     {
6522       for (; size--; offset++)
6523         {
6524           if (AOP_TYPE (right) == AOP_LIT)
6525             {
6526               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6527               if (bytelit == 0)
6528                 {
6529                   /* dummy read of volatile operand */
6530                   if (isOperandVolatile (left, FALSE))
6531                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6532                   else
6533                     continue;
6534                 }
6535               else if (IS_AOP_PREG (left))
6536                 {
6537                   MOVA (aopGet (AOP (left), offset, FALSE, TRUE));
6538                   emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6539                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6540                 }
6541               else
6542                 {
6543                   emitcode ("xrl", "%s,%s",
6544                             aopGet (AOP (left), offset, FALSE, TRUE),
6545                             aopGet (AOP (right), offset, FALSE, FALSE));
6546                 }
6547             }
6548           else
6549             {
6550               if (AOP_TYPE (left) == AOP_ACC)
6551                 {
6552                   if (offset)
6553                     emitcode("mov", "a,b");
6554                   emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6555                 }
6556               else
6557                 {
6558                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6559                   if (IS_AOP_PREG (left))
6560                     {
6561                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6562                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6563                     }
6564                   else
6565                     emitcode ("xrl", "%s,a",
6566                               aopGet (AOP (left), offset, FALSE, TRUE));
6567                 }
6568             }
6569         }
6570     }
6571   else
6572     {
6573       // left & result in different registers
6574       if (AOP_TYPE (result) == AOP_CRY)
6575         {
6576           // result = bit
6577           // if(size), result in bit
6578           // if(!size && ifx), conditional oper: if(left ^ right)
6579           symbol *tlbl = newiTempLabel (NULL);
6580           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6581           if (size)
6582             emitcode ("setb", "c");
6583           while (sizer--)
6584             {
6585               if ((AOP_TYPE (right) == AOP_LIT) &&
6586                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6587                 {
6588                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6589                 }
6590               else
6591                 {
6592                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6593                     if (offset)
6594                       emitcode("mov", "a,b");
6595                     emitcode ("xrl", "a,%s",
6596                               aopGet (AOP (right), offset, FALSE, FALSE));
6597                   } else {
6598                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6599                     emitcode ("xrl", "a,%s",
6600                               aopGet (AOP (left), offset, FALSE, FALSE));
6601                   }
6602                 }
6603               emitcode ("jnz", "%05d$", tlbl->key + 100);
6604               offset++;
6605             }
6606           if (size)
6607             {
6608               CLRC;
6609               emitcode ("", "%05d$:", tlbl->key + 100);
6610               outBitC (result);
6611             }
6612           else if (ifx)
6613             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6614         }
6615       else
6616         {
6617           for (; (size--); offset++)
6618             {
6619               // normal case
6620               // result = left & right
6621               if (AOP_TYPE (right) == AOP_LIT)
6622                 {
6623                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6624                   if (bytelit == 0)
6625                     {
6626                       aopPut (AOP (result),
6627                               aopGet (AOP (left), offset, FALSE, FALSE),
6628                               offset,
6629                               isOperandVolatile (result, FALSE));
6630                       continue;
6631                     }
6632                 }
6633               // faster than result <- left, anl result,right
6634               // and better if result is SFR
6635               if (AOP_TYPE (left) == AOP_ACC)
6636                 {
6637                   if (offset)
6638                     emitcode("mov", "a,b");
6639                   emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6640                 }
6641               else
6642                 {
6643                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6644                   emitcode ("xrl", "a,%s",
6645                             aopGet (AOP (left), offset, FALSE, TRUE));
6646                 }
6647               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6648             }
6649         }
6650     }
6651
6652 release:
6653   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6654   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6655   freeAsmop (result, NULL, ic, TRUE);
6656 }
6657
6658 /*-----------------------------------------------------------------*/
6659 /* genInline - write the inline code out                           */
6660 /*-----------------------------------------------------------------*/
6661 static void
6662 genInline (iCode * ic)
6663 {
6664   char *buffer, *bp, *bp1;
6665
6666   D(emitcode (";     genInline",""));
6667
6668   _G.inLine += (!options.asmpeep);
6669
6670   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6671   strcpy (buffer, IC_INLINE (ic));
6672
6673   /* emit each line as a code */
6674   while (*bp)
6675     {
6676       if (*bp == '\n')
6677         {
6678           *bp++ = '\0';
6679           emitcode (bp1, "");
6680           bp1 = bp;
6681         }
6682       else
6683         {
6684           /* Add \n for labels, not dirs such as c:\mydir */
6685           if ( (*bp == ':') && (isspace(bp[1])) )
6686             {
6687               bp++;
6688               *bp = '\0';
6689               bp++;
6690               emitcode (bp1, "");
6691               bp1 = bp;
6692             }
6693           else
6694             bp++;
6695         }
6696     }
6697   if (bp1 != bp)
6698     emitcode (bp1, "");
6699   /*     emitcode("",buffer); */
6700   _G.inLine -= (!options.asmpeep);
6701 }
6702
6703 /*-----------------------------------------------------------------*/
6704 /* genRRC - rotate right with carry                                */
6705 /*-----------------------------------------------------------------*/
6706 static void
6707 genRRC (iCode * ic)
6708 {
6709   operand *left, *result;
6710   int size, offset = 0;
6711   char *l;
6712
6713   D(emitcode (";     genRRC",""));
6714
6715   /* rotate right with carry */
6716   left = IC_LEFT (ic);
6717   result = IC_RESULT (ic);
6718   aopOp (left, ic, FALSE);
6719   aopOp (result, ic, FALSE);
6720
6721   /* move it to the result */
6722   size = AOP_SIZE (result);
6723   offset = size - 1;
6724   if (size == 1) { /* special case for 1 byte */
6725       l = aopGet (AOP (left), offset, FALSE, FALSE);
6726       MOVA (l);
6727       emitcode ("rr", "a");
6728       goto release;
6729   }
6730   /* no need to clear carry, bit7 will be written later */
6731   while (size--)
6732     {
6733       l = aopGet (AOP (left), offset, FALSE, FALSE);
6734       MOVA (l);
6735       emitcode ("rrc", "a");
6736       if (AOP_SIZE (result) > 1)
6737         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6738     }
6739   /* now we need to put the carry into the
6740      highest order byte of the result */
6741   if (AOP_SIZE (result) > 1)
6742     {
6743       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6744       MOVA (l);
6745     }
6746   emitcode ("mov", "acc.7,c");
6747  release:
6748   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6749   freeAsmop (left, NULL, ic, TRUE);
6750   freeAsmop (result, NULL, ic, TRUE);
6751 }
6752
6753 /*-----------------------------------------------------------------*/
6754 /* genRLC - generate code for rotate left with carry               */
6755 /*-----------------------------------------------------------------*/
6756 static void
6757 genRLC (iCode * ic)
6758 {
6759   operand *left, *result;
6760   int size, offset = 0;
6761   char *l;
6762
6763   D(emitcode (";     genRLC",""));
6764
6765   /* rotate right with carry */
6766   left = IC_LEFT (ic);
6767   result = IC_RESULT (ic);
6768   aopOp (left, ic, FALSE);
6769   aopOp (result, ic, FALSE);
6770
6771   /* move it to the result */
6772   size = AOP_SIZE (result);
6773   offset = 0;
6774   if (size--)
6775     {
6776       l = aopGet (AOP (left), offset, FALSE, FALSE);
6777       MOVA (l);
6778       if (size == 0) { /* special case for 1 byte */
6779               emitcode("rl","a");
6780               goto release;
6781       }
6782       emitcode("rlc","a"); /* bit0 will be written later */
6783       if (AOP_SIZE (result) > 1)
6784         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6785       while (size--)
6786         {
6787           l = aopGet (AOP (left), offset, FALSE, FALSE);
6788           MOVA (l);
6789           emitcode ("rlc", "a");
6790           if (AOP_SIZE (result) > 1)
6791             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6792         }
6793     }
6794   /* now we need to put the carry into the
6795      highest order byte of the result */
6796   if (AOP_SIZE (result) > 1)
6797     {
6798       l = aopGet (AOP (result), 0, FALSE, FALSE);
6799       MOVA (l);
6800     }
6801   emitcode ("mov", "acc.0,c");
6802  release:
6803   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6804   freeAsmop (left, NULL, ic, TRUE);
6805   freeAsmop (result, NULL, ic, TRUE);
6806 }
6807
6808 /*-----------------------------------------------------------------*/
6809 /* genGetHbit - generates code get highest order bit               */
6810 /*-----------------------------------------------------------------*/
6811 static void
6812 genGetHbit (iCode * ic)
6813 {
6814   operand *left, *result;
6815
6816   D(emitcode (";     genGetHbit",""));
6817
6818   left = IC_LEFT (ic);
6819   result = IC_RESULT (ic);
6820   aopOp (left, ic, FALSE);
6821   aopOp (result, ic, FALSE);
6822
6823   /* get the highest order byte into a */
6824   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6825   if (AOP_TYPE (result) == AOP_CRY)
6826     {
6827       emitcode ("rlc", "a");
6828       outBitC (result);
6829     }
6830   else
6831     {
6832       emitcode ("rl", "a");
6833       emitcode ("anl", "a,#0x01");
6834       outAcc (result);
6835     }
6836
6837
6838   freeAsmop (left, NULL, ic, TRUE);
6839   freeAsmop (result, NULL, ic, TRUE);
6840 }
6841
6842 /*-----------------------------------------------------------------*/
6843 /* genSwap - generates code to swap nibbles or bytes               */
6844 /*-----------------------------------------------------------------*/
6845 static void
6846 genSwap (iCode * ic)
6847 {
6848   operand *left, *result;
6849
6850   D(emitcode (";     genSwap",""));
6851
6852   left = IC_LEFT (ic);
6853   result = IC_RESULT (ic);
6854   aopOp (left, ic, FALSE);
6855   aopOp (result, ic, FALSE);
6856
6857   switch (AOP_SIZE (left))
6858     {
6859     case 1: /* swap nibbles in byte */
6860       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6861       emitcode ("swap", "a");
6862       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6863       break;
6864     case 2: /* swap bytes in word */
6865       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6866         {
6867           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6868           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6869                   0, isOperandVolatile (result, FALSE));
6870           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6871         }
6872       else if (operandsEqu (left, result))
6873         {
6874           char * reg = "a";
6875           bool pushedB = FALSE, leftInB = FALSE;
6876
6877           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6878           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6879             {
6880               pushedB = pushB ();
6881               emitcode ("mov", "b,a");
6882               reg = "b";
6883               leftInB = TRUE;
6884             }
6885           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6886                   0, isOperandVolatile (result, FALSE));
6887           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6888
6889           if (leftInB)
6890             popB (pushedB);
6891         }
6892       else
6893         {
6894           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6895                   0, isOperandVolatile (result, FALSE));
6896           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6897                   1, isOperandVolatile (result, FALSE));
6898         }
6899       break;
6900     default:
6901       wassertl(FALSE, "unsupported SWAP operand size");
6902     }
6903
6904   freeAsmop (left, NULL, ic, TRUE);
6905   freeAsmop (result, NULL, ic, TRUE);
6906 }
6907
6908
6909 /*-----------------------------------------------------------------*/
6910 /* AccRol - rotate left accumulator by known count                 */
6911 /*-----------------------------------------------------------------*/
6912 static void
6913 AccRol (int shCount)
6914 {
6915   shCount &= 0x0007;            // shCount : 0..7
6916
6917   switch (shCount)
6918     {
6919     case 0:
6920       break;
6921     case 1:
6922       emitcode ("rl", "a");
6923       break;
6924     case 2:
6925       emitcode ("rl", "a");
6926       emitcode ("rl", "a");
6927       break;
6928     case 3:
6929       emitcode ("swap", "a");
6930       emitcode ("rr", "a");
6931       break;
6932     case 4:
6933       emitcode ("swap", "a");
6934       break;
6935     case 5:
6936       emitcode ("swap", "a");
6937       emitcode ("rl", "a");
6938       break;
6939     case 6:
6940       emitcode ("rr", "a");
6941       emitcode ("rr", "a");
6942       break;
6943     case 7:
6944       emitcode ("rr", "a");
6945       break;
6946     }
6947 }
6948
6949 /*-----------------------------------------------------------------*/
6950 /* AccLsh - left shift accumulator by known count                  */
6951 /*-----------------------------------------------------------------*/
6952 static void
6953 AccLsh (int shCount)
6954 {
6955   if (shCount != 0)
6956     {
6957       if (shCount == 1)
6958         emitcode ("add", "a,acc");
6959       else if (shCount == 2)
6960         {
6961           emitcode ("add", "a,acc");
6962           emitcode ("add", "a,acc");
6963         }
6964       else
6965         {
6966           /* rotate left accumulator */
6967           AccRol (shCount);
6968           /* and kill the lower order bits */
6969           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6970         }
6971     }
6972 }
6973
6974 /*-----------------------------------------------------------------*/
6975 /* AccRsh - right shift accumulator by known count                 */
6976 /*-----------------------------------------------------------------*/
6977 static void
6978 AccRsh (int shCount)
6979 {
6980   if (shCount != 0)
6981     {
6982       if (shCount == 1)
6983         {
6984           CLRC;
6985           emitcode ("rrc", "a");
6986         }
6987       else
6988         {
6989           /* rotate right accumulator */
6990           AccRol (8 - shCount);
6991           /* and kill the higher order bits */
6992           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6993         }
6994     }
6995 }
6996
6997 /*-----------------------------------------------------------------*/
6998 /* AccSRsh - signed right shift accumulator by known count                 */
6999 /*-----------------------------------------------------------------*/
7000 static void
7001 AccSRsh (int shCount)
7002 {
7003   symbol *tlbl;
7004   if (shCount != 0)
7005     {
7006       if (shCount == 1)
7007         {
7008           emitcode ("mov", "c,acc.7");
7009           emitcode ("rrc", "a");
7010         }
7011       else if (shCount == 2)
7012         {
7013           emitcode ("mov", "c,acc.7");
7014           emitcode ("rrc", "a");
7015           emitcode ("mov", "c,acc.7");
7016           emitcode ("rrc", "a");
7017         }
7018       else
7019         {
7020           tlbl = newiTempLabel (NULL);
7021           /* rotate right accumulator */
7022           AccRol (8 - shCount);
7023           /* and kill the higher order bits */
7024           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7025           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7026           emitcode ("orl", "a,#0x%02x",
7027                     (unsigned char) ~SRMask[shCount]);
7028           emitcode ("", "%05d$:", tlbl->key + 100);
7029         }
7030     }
7031 }
7032
7033 /*-----------------------------------------------------------------*/
7034 /* shiftR1Left2Result - shift right one byte from left to result   */
7035 /*-----------------------------------------------------------------*/
7036 static void
7037 shiftR1Left2Result (operand * left, int offl,
7038                     operand * result, int offr,
7039                     int shCount, int sign)
7040 {
7041   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7042   /* shift right accumulator */
7043   if (sign)
7044     AccSRsh (shCount);
7045   else
7046     AccRsh (shCount);
7047   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7048 }
7049
7050 /*-----------------------------------------------------------------*/
7051 /* shiftL1Left2Result - shift left one byte from left to result    */
7052 /*-----------------------------------------------------------------*/
7053 static void
7054 shiftL1Left2Result (operand * left, int offl,
7055                     operand * result, int offr, int shCount)
7056 {
7057   char *l;
7058   l = aopGet (AOP (left), offl, FALSE, FALSE);
7059   MOVA (l);
7060   /* shift left accumulator */
7061   AccLsh (shCount);
7062   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7063 }
7064
7065 /*-----------------------------------------------------------------*/
7066 /* movLeft2Result - move byte from left to result                  */
7067 /*-----------------------------------------------------------------*/
7068 static void
7069 movLeft2Result (operand * left, int offl,
7070                 operand * result, int offr, int sign)
7071 {
7072   char *l;
7073   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7074     {
7075       l = aopGet (AOP (left), offl, FALSE, FALSE);
7076
7077       if (*l == '@' && (IS_AOP_PREG (result)))
7078         {
7079           emitcode ("mov", "a,%s", l);
7080           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7081         }
7082       else
7083         {
7084           if (!sign)
7085             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
7086           else
7087             {
7088               /* MSB sign in acc.7 ! */
7089               if (getDataSize (left) == offl + 1)
7090                 {
7091                   emitcode ("mov", "a,%s", l);
7092                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7093                 }
7094             }
7095         }
7096     }
7097 }
7098
7099 /*-----------------------------------------------------------------*/
7100 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7101 /*-----------------------------------------------------------------*/
7102 static void
7103 AccAXRrl1 (char *x)
7104 {
7105   emitcode ("rrc", "a");
7106   emitcode ("xch", "a,%s", x);
7107   emitcode ("rrc", "a");
7108   emitcode ("xch", "a,%s", x);
7109 }
7110
7111 /*-----------------------------------------------------------------*/
7112 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7113 /*-----------------------------------------------------------------*/
7114 static void
7115 AccAXLrl1 (char *x)
7116 {
7117   emitcode ("xch", "a,%s", x);
7118   emitcode ("rlc", "a");
7119   emitcode ("xch", "a,%s", x);
7120   emitcode ("rlc", "a");
7121 }
7122
7123 /*-----------------------------------------------------------------*/
7124 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7125 /*-----------------------------------------------------------------*/
7126 static void
7127 AccAXLsh1 (char *x)
7128 {
7129   emitcode ("xch", "a,%s", x);
7130   emitcode ("add", "a,acc");
7131   emitcode ("xch", "a,%s", x);
7132   emitcode ("rlc", "a");
7133 }
7134
7135 /*-----------------------------------------------------------------*/
7136 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7137 /*-----------------------------------------------------------------*/
7138 static void
7139 AccAXLsh (char *x, int shCount)
7140 {
7141   switch (shCount)
7142     {
7143     case 0:
7144       break;
7145     case 1:
7146       AccAXLsh1 (x);
7147       break;
7148     case 2:
7149       AccAXLsh1 (x);
7150       AccAXLsh1 (x);
7151       break;
7152     case 3:
7153     case 4:
7154     case 5:                     // AAAAABBB:CCCCCDDD
7155
7156       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7157
7158       emitcode ("anl", "a,#0x%02x",
7159                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7160
7161       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7162
7163       AccRol (shCount);         // DDDCCCCC:BBB00000
7164
7165       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7166
7167       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7168
7169       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7170
7171       emitcode ("anl", "a,#0x%02x",
7172                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7173
7174       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7175
7176       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7177
7178       break;
7179     case 6:                     // AAAAAABB:CCCCCCDD
7180       emitcode ("anl", "a,#0x%02x",
7181                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7182       emitcode ("mov", "c,acc.0");      // c = B
7183       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7184 #if 0 // REMOVE ME
7185       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7186       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7187 #else
7188       emitcode("rrc","a");
7189       emitcode("xch","a,%s", x);
7190       emitcode("rrc","a");
7191       emitcode("mov","c,acc.0"); //<< get correct bit
7192       emitcode("xch","a,%s", x);
7193
7194       emitcode("rrc","a");
7195       emitcode("xch","a,%s", x);
7196       emitcode("rrc","a");
7197       emitcode("xch","a,%s", x);
7198 #endif
7199       break;
7200     case 7:                     // a:x <<= 7
7201
7202       emitcode ("anl", "a,#0x%02x",
7203                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7204
7205       emitcode ("mov", "c,acc.0");      // c = B
7206
7207       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7208
7209       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7210
7211       break;
7212     default:
7213       break;
7214     }
7215 }
7216
7217 /*-----------------------------------------------------------------*/
7218 /* AccAXRsh - right shift a:x known count (0..7)                   */
7219 /*-----------------------------------------------------------------*/
7220 static void
7221 AccAXRsh (char *x, int shCount)
7222 {
7223   switch (shCount)
7224     {
7225     case 0:
7226       break;
7227     case 1:
7228       CLRC;
7229       AccAXRrl1 (x);            // 0->a:x
7230
7231       break;
7232     case 2:
7233       CLRC;
7234       AccAXRrl1 (x);            // 0->a:x
7235
7236       CLRC;
7237       AccAXRrl1 (x);            // 0->a:x
7238
7239       break;
7240     case 3:
7241     case 4:
7242     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7243
7244       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7245
7246       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7247
7248       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7249
7250       emitcode ("anl", "a,#0x%02x",
7251                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7252
7253       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7254
7255       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7256
7257       emitcode ("anl", "a,#0x%02x",
7258                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7259
7260       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7261
7262       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7263
7264       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7265
7266       break;
7267     case 6:                     // AABBBBBB:CCDDDDDD
7268
7269       emitcode ("mov", "c,acc.7");
7270       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7271
7272       emitcode ("mov", "c,acc.7");
7273       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7274
7275       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7276
7277       emitcode ("anl", "a,#0x%02x",
7278                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7279
7280       break;
7281     case 7:                     // ABBBBBBB:CDDDDDDD
7282
7283       emitcode ("mov", "c,acc.7");      // c = A
7284
7285       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7286
7287       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7288
7289       emitcode ("anl", "a,#0x%02x",
7290                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7291
7292       break;
7293     default:
7294       break;
7295     }
7296 }
7297
7298 /*-----------------------------------------------------------------*/
7299 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7300 /*-----------------------------------------------------------------*/
7301 static void
7302 AccAXRshS (char *x, int shCount)
7303 {
7304   symbol *tlbl;
7305   switch (shCount)
7306     {
7307     case 0:
7308       break;
7309     case 1:
7310       emitcode ("mov", "c,acc.7");
7311       AccAXRrl1 (x);            // s->a:x
7312
7313       break;
7314     case 2:
7315       emitcode ("mov", "c,acc.7");
7316       AccAXRrl1 (x);            // s->a:x
7317
7318       emitcode ("mov", "c,acc.7");
7319       AccAXRrl1 (x);            // s->a:x
7320
7321       break;
7322     case 3:
7323     case 4:
7324     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7325
7326       tlbl = newiTempLabel (NULL);
7327       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7328
7329       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7330
7331       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7332
7333       emitcode ("anl", "a,#0x%02x",
7334                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7335
7336       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7337
7338       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7339
7340       emitcode ("anl", "a,#0x%02x",
7341                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7342
7343       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7344
7345       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7346
7347       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7348
7349       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7350       emitcode ("orl", "a,#0x%02x",
7351                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7352
7353       emitcode ("", "%05d$:", tlbl->key + 100);
7354       break;                    // SSSSAAAA:BBBCCCCC
7355
7356     case 6:                     // AABBBBBB:CCDDDDDD
7357
7358       tlbl = newiTempLabel (NULL);
7359       emitcode ("mov", "c,acc.7");
7360       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7361
7362       emitcode ("mov", "c,acc.7");
7363       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7364
7365       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7366
7367       emitcode ("anl", "a,#0x%02x",
7368                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7369
7370       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7371       emitcode ("orl", "a,#0x%02x",
7372                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7373
7374       emitcode ("", "%05d$:", tlbl->key + 100);
7375       break;
7376     case 7:                     // ABBBBBBB:CDDDDDDD
7377
7378       tlbl = newiTempLabel (NULL);
7379       emitcode ("mov", "c,acc.7");      // c = A
7380
7381       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7382
7383       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7384
7385       emitcode ("anl", "a,#0x%02x",
7386                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7387
7388       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7389       emitcode ("orl", "a,#0x%02x",
7390                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7391
7392       emitcode ("", "%05d$:", tlbl->key + 100);
7393       break;
7394     default:
7395       break;
7396     }
7397 }
7398
7399 /*-----------------------------------------------------------------*/
7400 /* shiftL2Left2Result - shift left two bytes from left to result   */
7401 /*-----------------------------------------------------------------*/
7402 static void
7403 shiftL2Left2Result (operand * left, int offl,
7404                     operand * result, int offr, int shCount)
7405 {
7406   if (sameRegs (AOP (result), AOP (left)) &&
7407       ((offl + MSB16) == offr))
7408     {
7409       /* don't crash result[offr] */
7410       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7411       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7412     }
7413   else
7414     {
7415       movLeft2Result (left, offl, result, offr, 0);
7416       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7417     }
7418   /* ax << shCount (x = lsb(result)) */
7419   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7420   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7421 }
7422
7423
7424 /*-----------------------------------------------------------------*/
7425 /* shiftR2Left2Result - shift right two bytes from left to result  */
7426 /*-----------------------------------------------------------------*/
7427 static void
7428 shiftR2Left2Result (operand * left, int offl,
7429                     operand * result, int offr,
7430                     int shCount, int sign)
7431 {
7432   if (sameRegs (AOP (result), AOP (left)) &&
7433       ((offl + MSB16) == offr))
7434     {
7435       /* don't crash result[offr] */
7436       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7437       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7438     }
7439   else
7440     {
7441       movLeft2Result (left, offl, result, offr, 0);
7442       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7443     }
7444   /* a:x >> shCount (x = lsb(result)) */
7445   if (sign)
7446     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7447   else
7448     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7449   if (getDataSize (result) > 1)
7450     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7451 }
7452
7453 /*-----------------------------------------------------------------*/
7454 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7455 /*-----------------------------------------------------------------*/
7456 static void
7457 shiftLLeftOrResult (operand * left, int offl,
7458                     operand * result, int offr, int shCount)
7459 {
7460   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7461   /* shift left accumulator */
7462   AccLsh (shCount);
7463   /* or with result */
7464   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7465   /* back to result */
7466   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7467 }
7468
7469 /*-----------------------------------------------------------------*/
7470 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7471 /*-----------------------------------------------------------------*/
7472 static void
7473 shiftRLeftOrResult (operand * left, int offl,
7474                     operand * result, int offr, int shCount)
7475 {
7476   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7477   /* shift right accumulator */
7478   AccRsh (shCount);
7479   /* or with result */
7480   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7481   /* back to result */
7482   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7483 }
7484
7485 /*-----------------------------------------------------------------*/
7486 /* genlshOne - left shift a one byte quantity by known count       */
7487 /*-----------------------------------------------------------------*/
7488 static void
7489 genlshOne (operand * result, operand * left, int shCount)
7490 {
7491   D(emitcode (";     genlshOne",""));
7492
7493   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7494 }
7495
7496 /*-----------------------------------------------------------------*/
7497 /* genlshTwo - left shift two bytes by known amount != 0           */
7498 /*-----------------------------------------------------------------*/
7499 static void
7500 genlshTwo (operand * result, operand * left, int shCount)
7501 {
7502   int size;
7503
7504   D(emitcode (";     genlshTwo",""));
7505
7506   size = getDataSize (result);
7507
7508   /* if shCount >= 8 */
7509   if (shCount >= 8)
7510     {
7511       shCount -= 8;
7512
7513       if (size > 1)
7514         {
7515           if (shCount)
7516             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7517           else
7518             movLeft2Result (left, LSB, result, MSB16, 0);
7519         }
7520       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7521     }
7522
7523   /*  1 <= shCount <= 7 */
7524   else
7525     {
7526       if (size == 1)
7527         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7528       else
7529         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7530     }
7531 }
7532
7533 /*-----------------------------------------------------------------*/
7534 /* shiftLLong - shift left one long from left to result            */
7535 /* offl = LSB or MSB16                                             */
7536 /*-----------------------------------------------------------------*/
7537 static void
7538 shiftLLong (operand * left, operand * result, int offr)
7539 {
7540   char *l;
7541   int size = AOP_SIZE (result);
7542
7543   if (size >= LSB + offr)
7544     {
7545       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7546       MOVA (l);
7547       emitcode ("add", "a,acc");
7548       if (sameRegs (AOP (left), AOP (result)) &&
7549           size >= MSB16 + offr && offr != LSB)
7550         emitcode ("xch", "a,%s",
7551                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7552       else
7553         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7554     }
7555
7556   if (size >= MSB16 + offr)
7557     {
7558       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7559         {
7560           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7561           MOVA (l);
7562         }
7563       emitcode ("rlc", "a");
7564       if (sameRegs (AOP (left), AOP (result)) &&
7565           size >= MSB24 + offr && offr != LSB)
7566         emitcode ("xch", "a,%s",
7567                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7568       else
7569         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7570     }
7571
7572   if (size >= MSB24 + offr)
7573     {
7574       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7575         {
7576           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7577           MOVA (l);
7578         }
7579       emitcode ("rlc", "a");
7580       if (sameRegs (AOP (left), AOP (result)) &&
7581           size >= MSB32 + offr && offr != LSB)
7582         emitcode ("xch", "a,%s",
7583                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7584       else
7585         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7586     }
7587
7588   if (size > MSB32 + offr)
7589     {
7590       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7591         {
7592           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7593           MOVA (l);
7594         }
7595       emitcode ("rlc", "a");
7596       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7597     }
7598   if (offr != LSB)
7599     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7600 }
7601
7602 /*-----------------------------------------------------------------*/
7603 /* genlshFour - shift four byte by a known amount != 0             */
7604 /*-----------------------------------------------------------------*/
7605 static void
7606 genlshFour (operand * result, operand * left, int shCount)
7607 {
7608   int size;
7609
7610   D(emitcode (";     genlshFour",""));
7611
7612   size = AOP_SIZE (result);
7613
7614   /* if shifting more that 3 bytes */
7615   if (shCount >= 24)
7616     {
7617       shCount -= 24;
7618       if (shCount)
7619         /* lowest order of left goes to the highest
7620            order of the destination */
7621         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7622       else
7623         movLeft2Result (left, LSB, result, MSB32, 0);
7624       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7625       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7626       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7627       return;
7628     }
7629
7630   /* more than two bytes */
7631   else if (shCount >= 16)
7632     {
7633       /* lower order two bytes goes to higher order two bytes */
7634       shCount -= 16;
7635       /* if some more remaining */
7636       if (shCount)
7637         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7638       else
7639         {
7640           movLeft2Result (left, MSB16, result, MSB32, 0);
7641           movLeft2Result (left, LSB, result, MSB24, 0);
7642         }
7643       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7644       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7645       return;
7646     }
7647
7648   /* if more than 1 byte */
7649   else if (shCount >= 8)
7650     {
7651       /* lower order three bytes goes to higher order  three bytes */
7652       shCount -= 8;
7653       if (size == 2)
7654         {
7655           if (shCount)
7656             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7657           else
7658             movLeft2Result (left, LSB, result, MSB16, 0);
7659         }
7660       else
7661         {                       /* size = 4 */
7662           if (shCount == 0)
7663             {
7664               movLeft2Result (left, MSB24, result, MSB32, 0);
7665               movLeft2Result (left, MSB16, result, MSB24, 0);
7666               movLeft2Result (left, LSB, result, MSB16, 0);
7667               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7668             }
7669           else if (shCount == 1)
7670             shiftLLong (left, result, MSB16);
7671           else
7672             {
7673               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7674               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7675               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7676               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7677             }
7678         }
7679     }
7680
7681   /* 1 <= shCount <= 7 */
7682   else if (shCount <= 2)
7683     {
7684       shiftLLong (left, result, LSB);
7685       if (shCount == 2)
7686         shiftLLong (result, result, LSB);
7687     }
7688   /* 3 <= shCount <= 7, optimize */
7689   else
7690     {
7691       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7692       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7693       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7694     }
7695 }
7696
7697 /*-----------------------------------------------------------------*/
7698 /* genLeftShiftLiteral - left shifting by known count              */
7699 /*-----------------------------------------------------------------*/
7700 static void
7701 genLeftShiftLiteral (operand * left,
7702                      operand * right,
7703                      operand * result,
7704                      iCode * ic)
7705 {
7706   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7707   int size;
7708
7709   D(emitcode (";     genLeftShiftLiteral",""));
7710
7711   freeAsmop (right, NULL, ic, TRUE);
7712
7713   aopOp (left, ic, FALSE);
7714   aopOp (result, ic, FALSE);
7715
7716   size = getSize (operandType (result));
7717
7718 #if VIEW_SIZE
7719   emitcode ("; shift left ", "result %d, left %d", size,
7720             AOP_SIZE (left));
7721 #endif
7722
7723   /* I suppose that the left size >= result size */
7724   if (shCount == 0)
7725     {
7726       while (size--)
7727         {
7728           movLeft2Result (left, size, result, size, 0);
7729         }
7730     }
7731
7732   else if (shCount >= (size * 8))
7733     while (size--)
7734       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7735   else
7736     {
7737       switch (size)
7738         {
7739         case 1:
7740           genlshOne (result, left, shCount);
7741           break;
7742
7743         case 2:
7744           genlshTwo (result, left, shCount);
7745           break;
7746
7747         case 4:
7748           genlshFour (result, left, shCount);
7749           break;
7750         default:
7751           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7752                   "*** ack! mystery literal shift!\n");
7753           break;
7754         }
7755     }
7756   freeAsmop (left, NULL, ic, TRUE);
7757   freeAsmop (result, NULL, ic, TRUE);
7758 }
7759
7760 /*-----------------------------------------------------------------*/
7761 /* genLeftShift - generates code for left shifting                 */
7762 /*-----------------------------------------------------------------*/
7763 static void
7764 genLeftShift (iCode * ic)
7765 {
7766   operand *left, *right, *result;
7767   int size, offset;
7768   char *l;
7769   symbol *tlbl, *tlbl1;
7770   bool pushedB;
7771
7772   D(emitcode (";     genLeftShift",""));
7773
7774   right = IC_RIGHT (ic);
7775   left = IC_LEFT (ic);
7776   result = IC_RESULT (ic);
7777
7778   aopOp (right, ic, FALSE);
7779
7780   /* if the shift count is known then do it
7781      as efficiently as possible */
7782   if (AOP_TYPE (right) == AOP_LIT)
7783     {
7784       genLeftShiftLiteral (left, right, result, ic);
7785       return;
7786     }
7787
7788   /* shift count is unknown then we have to form
7789      a loop get the loop count in B : Note: we take
7790      only the lower order byte since shifting
7791      more that 32 bits make no sense anyway, ( the
7792      largest size of an object can be only 32 bits ) */
7793
7794   pushedB = pushB ();
7795   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7796   emitcode ("inc", "b");
7797   freeAsmop (right, NULL, ic, TRUE);
7798   aopOp (left, ic, FALSE);
7799   aopOp (result, ic, FALSE);
7800
7801   /* now move the left to the result if they are not the same */
7802   if (!sameRegs (AOP (left), AOP (result)) &&
7803       AOP_SIZE (result) > 1)
7804     {
7805
7806       size = AOP_SIZE (result);
7807       offset = 0;
7808       while (size--)
7809         {
7810           l = aopGet (AOP (left), offset, FALSE, TRUE);
7811           if (*l == '@' && (IS_AOP_PREG (result)))
7812             {
7813
7814               emitcode ("mov", "a,%s", l);
7815               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7816             }
7817           else
7818             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7819           offset++;
7820         }
7821     }
7822
7823   tlbl = newiTempLabel (NULL);
7824   size = AOP_SIZE (result);
7825   offset = 0;
7826   tlbl1 = newiTempLabel (NULL);
7827
7828   /* if it is only one byte then */
7829   if (size == 1)
7830     {
7831       symbol *tlbl1 = newiTempLabel (NULL);
7832
7833       l = aopGet (AOP (left), 0, FALSE, FALSE);
7834       MOVA (l);
7835       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7836       emitcode ("", "%05d$:", tlbl->key + 100);
7837       emitcode ("add", "a,acc");
7838       emitcode ("", "%05d$:", tlbl1->key + 100);
7839       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7840       popB (pushedB);
7841       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7842       goto release;
7843     }
7844
7845   reAdjustPreg (AOP (result));
7846
7847   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7848   emitcode ("", "%05d$:", tlbl->key + 100);
7849   l = aopGet (AOP (result), offset, FALSE, FALSE);
7850   MOVA (l);
7851   emitcode ("add", "a,acc");
7852   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7853   while (--size)
7854     {
7855       l = aopGet (AOP (result), offset, FALSE, FALSE);
7856       MOVA (l);
7857       emitcode ("rlc", "a");
7858       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7859     }
7860   reAdjustPreg (AOP (result));
7861
7862   emitcode ("", "%05d$:", tlbl1->key + 100);
7863   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7864   popB (pushedB);
7865 release:
7866   freeAsmop (left, NULL, ic, TRUE);
7867   freeAsmop (result, NULL, ic, TRUE);
7868 }
7869
7870 /*-----------------------------------------------------------------*/
7871 /* genrshOne - right shift a one byte quantity by known count      */
7872 /*-----------------------------------------------------------------*/
7873 static void
7874 genrshOne (operand * result, operand * left,
7875            int shCount, int sign)
7876 {
7877   D(emitcode (";     genrshOne",""));
7878
7879   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7880 }
7881
7882 /*-----------------------------------------------------------------*/
7883 /* genrshTwo - right shift two bytes by known amount != 0          */
7884 /*-----------------------------------------------------------------*/
7885 static void
7886 genrshTwo (operand * result, operand * left,
7887            int shCount, int sign)
7888 {
7889   D(emitcode (";     genrshTwo",""));
7890
7891   /* if shCount >= 8 */
7892   if (shCount >= 8)
7893     {
7894       shCount -= 8;
7895       if (shCount)
7896         shiftR1Left2Result (left, MSB16, result, LSB,
7897                             shCount, sign);
7898       else
7899         movLeft2Result (left, MSB16, result, LSB, sign);
7900       addSign (result, MSB16, sign);
7901     }
7902
7903   /*  1 <= shCount <= 7 */
7904   else
7905     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7906 }
7907
7908 /*-----------------------------------------------------------------*/
7909 /* shiftRLong - shift right one long from left to result           */
7910 /* offl = LSB or MSB16                                             */
7911 /*-----------------------------------------------------------------*/
7912 static void
7913 shiftRLong (operand * left, int offl,
7914             operand * result, int sign)
7915 {
7916   int isSameRegs=sameRegs(AOP(left),AOP(result));
7917
7918   if (isSameRegs && offl>1) {
7919     // we are in big trouble, but this shouldn't happen
7920     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7921   }
7922
7923   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7924
7925   if (offl==MSB16) {
7926     // shift is > 8
7927     if (sign) {
7928       emitcode ("rlc", "a");
7929       emitcode ("subb", "a,acc");
7930       if (isSameRegs)
7931         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7932       else {
7933         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7934         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7935       }
7936     } else {
7937       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7938     }
7939   }
7940
7941   if (!sign) {
7942     emitcode ("clr", "c");
7943   } else {
7944     emitcode ("mov", "c,acc.7");
7945   }
7946
7947   emitcode ("rrc", "a");
7948
7949   if (isSameRegs && offl==MSB16) {
7950     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7951   } else {
7952     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7953     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7954   }
7955
7956   emitcode ("rrc", "a");
7957   if (isSameRegs && offl==1) {
7958     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7959   } else {
7960     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7961     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7962   }
7963   emitcode ("rrc", "a");
7964   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7965
7966   if (offl == LSB)
7967     {
7968       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7969       emitcode ("rrc", "a");
7970       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7971     }
7972 }
7973
7974 /*-----------------------------------------------------------------*/
7975 /* genrshFour - shift four byte by a known amount != 0             */
7976 /*-----------------------------------------------------------------*/
7977 static void
7978 genrshFour (operand * result, operand * left,
7979             int shCount, int sign)
7980 {
7981   D(emitcode (";     genrshFour",""));
7982
7983   /* if shifting more that 3 bytes */
7984   if (shCount >= 24)
7985     {
7986       shCount -= 24;
7987       if (shCount)
7988         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7989       else
7990         movLeft2Result (left, MSB32, result, LSB, sign);
7991       addSign (result, MSB16, sign);
7992     }
7993   else if (shCount >= 16)
7994     {
7995       shCount -= 16;
7996       if (shCount)
7997         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7998       else
7999         {
8000           movLeft2Result (left, MSB24, result, LSB, 0);
8001           movLeft2Result (left, MSB32, result, MSB16, sign);
8002         }
8003       addSign (result, MSB24, sign);
8004     }
8005   else if (shCount >= 8)
8006     {
8007       shCount -= 8;
8008       if (shCount == 1)
8009         shiftRLong (left, MSB16, result, sign);
8010       else if (shCount == 0)
8011         {
8012           movLeft2Result (left, MSB16, result, LSB, 0);
8013           movLeft2Result (left, MSB24, result, MSB16, 0);
8014           movLeft2Result (left, MSB32, result, MSB24, sign);
8015           addSign (result, MSB32, sign);
8016         }
8017       else
8018         {
8019           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8020           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8021           /* the last shift is signed */
8022           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8023           addSign (result, MSB32, sign);
8024         }
8025     }
8026   else
8027     {                           /* 1 <= shCount <= 7 */
8028       if (shCount <= 2)
8029         {
8030           shiftRLong (left, LSB, result, sign);
8031           if (shCount == 2)
8032             shiftRLong (result, LSB, result, sign);
8033         }
8034       else
8035         {
8036           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8037           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8038           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8039         }
8040     }
8041 }
8042
8043 /*-----------------------------------------------------------------*/
8044 /* genRightShiftLiteral - right shifting by known count            */
8045 /*-----------------------------------------------------------------*/
8046 static void
8047 genRightShiftLiteral (operand * left,
8048                       operand * right,
8049                       operand * result,
8050                       iCode * ic,
8051                       int sign)
8052 {
8053   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8054   int size;
8055
8056   D(emitcode (";     genRightShiftLiteral",""));
8057
8058   freeAsmop (right, NULL, ic, TRUE);
8059
8060   aopOp (left, ic, FALSE);
8061   aopOp (result, ic, FALSE);
8062
8063 #if VIEW_SIZE
8064   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8065             AOP_SIZE (left));
8066 #endif
8067
8068   size = getDataSize (left);
8069   /* test the LEFT size !!! */
8070
8071   /* I suppose that the left size >= result size */
8072   if (shCount == 0)
8073     {
8074       size = getDataSize (result);
8075       while (size--)
8076         movLeft2Result (left, size, result, size, 0);
8077     }
8078
8079   else if (shCount >= (size * 8))
8080     {
8081       if (sign) {
8082         /* get sign in acc.7 */
8083         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
8084       }
8085       addSign (result, LSB, sign);
8086     }
8087   else
8088     {
8089       switch (size)
8090         {
8091         case 1:
8092           genrshOne (result, left, shCount, sign);
8093           break;
8094
8095         case 2:
8096           genrshTwo (result, left, shCount, sign);
8097           break;
8098
8099         case 4:
8100           genrshFour (result, left, shCount, sign);
8101           break;
8102         default:
8103           break;
8104         }
8105     }
8106   freeAsmop (left, NULL, ic, TRUE);
8107   freeAsmop (result, NULL, ic, TRUE);
8108 }
8109
8110 /*-----------------------------------------------------------------*/
8111 /* genSignedRightShift - right shift of signed number              */
8112 /*-----------------------------------------------------------------*/
8113 static void
8114 genSignedRightShift (iCode * ic)
8115 {
8116   operand *right, *left, *result;
8117   int size, offset;
8118   char *l;
8119   symbol *tlbl, *tlbl1;
8120   bool pushedB;
8121
8122   D(emitcode (";     genSignedRightShift",""));
8123
8124   /* we do it the hard way put the shift count in b
8125      and loop thru preserving the sign */
8126
8127   right = IC_RIGHT (ic);
8128   left = IC_LEFT (ic);
8129   result = IC_RESULT (ic);
8130
8131   aopOp (right, ic, FALSE);
8132
8133
8134   if (AOP_TYPE (right) == AOP_LIT)
8135     {
8136       genRightShiftLiteral (left, right, result, ic, 1);
8137       return;
8138     }
8139   /* shift count is unknown then we have to form
8140      a loop get the loop count in B : Note: we take
8141      only the lower order byte since shifting
8142      more that 32 bits make no sense anyway, ( the
8143      largest size of an object can be only 32 bits ) */
8144
8145   pushedB = pushB ();
8146   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
8147   emitcode ("inc", "b");
8148   freeAsmop (right, NULL, ic, TRUE);
8149   aopOp (left, ic, FALSE);
8150   aopOp (result, ic, FALSE);
8151
8152   /* now move the left to the result if they are not the
8153      same */
8154   if (!sameRegs (AOP (left), AOP (result)) &&
8155       AOP_SIZE (result) > 1)
8156     {
8157
8158       size = AOP_SIZE (result);
8159       offset = 0;
8160       while (size--)
8161         {
8162           l = aopGet (AOP (left), offset, FALSE, TRUE);
8163           if (*l == '@' && IS_AOP_PREG (result))
8164             {
8165
8166               emitcode ("mov", "a,%s", l);
8167               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8168             }
8169           else
8170             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
8171           offset++;
8172         }
8173     }
8174
8175   /* mov the highest order bit to OVR */
8176   tlbl = newiTempLabel (NULL);
8177   tlbl1 = newiTempLabel (NULL);
8178
8179   size = AOP_SIZE (result);
8180   offset = size - 1;
8181   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
8182   emitcode ("rlc", "a");
8183   emitcode ("mov", "ov,c");
8184   /* if it is only one byte then */
8185   if (size == 1)
8186     {
8187       l = aopGet (AOP (left), 0, FALSE, FALSE);
8188       MOVA (l);
8189       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8190       emitcode ("", "%05d$:", tlbl->key + 100);
8191       emitcode ("mov", "c,ov");
8192       emitcode ("rrc", "a");
8193       emitcode ("", "%05d$:", tlbl1->key + 100);
8194       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8195       popB (pushedB);
8196       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
8197       goto release;
8198     }
8199
8200   reAdjustPreg (AOP (result));
8201   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8202   emitcode ("", "%05d$:", tlbl->key + 100);
8203   emitcode ("mov", "c,ov");
8204   while (size--)
8205     {
8206       l = aopGet (AOP (result), offset, FALSE, FALSE);
8207       MOVA (l);
8208       emitcode ("rrc", "a");
8209       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
8210     }
8211   reAdjustPreg (AOP (result));
8212   emitcode ("", "%05d$:", tlbl1->key + 100);
8213   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8214   popB (pushedB);
8215
8216 release:
8217   freeAsmop (left, NULL, ic, TRUE);
8218   freeAsmop (result, NULL, ic, TRUE);
8219 }
8220
8221 /*-----------------------------------------------------------------*/
8222 /* genRightShift - generate code for right shifting                */
8223 /*-----------------------------------------------------------------*/
8224 static void
8225 genRightShift (iCode * ic)
8226 {
8227   operand *right, *left, *result;
8228   sym_link *letype;
8229   int size, offset;
8230   char *l;
8231   symbol *tlbl, *tlbl1;
8232   bool pushedB;
8233
8234   D(emitcode (";     genRightShift",""));
8235
8236   /* if signed then we do it the hard way preserve the
8237      sign bit moving it inwards */
8238   letype = getSpec (operandType (IC_LEFT (ic)));
8239
8240   if (!SPEC_USIGN (letype))
8241     {
8242       genSignedRightShift (ic);
8243       return;
8244     }
8245
8246   /* signed & unsigned types are treated the same : i.e. the
8247      signed is NOT propagated inwards : quoting from the
8248      ANSI - standard : "for E1 >> E2, is equivalent to division
8249      by 2**E2 if unsigned or if it has a non-negative value,
8250      otherwise the result is implementation defined ", MY definition
8251      is that the sign does not get propagated */
8252
8253   right = IC_RIGHT (ic);
8254   left = IC_LEFT (ic);
8255   result = IC_RESULT (ic);
8256
8257   aopOp (right, ic, FALSE);
8258
8259   /* if the shift count is known then do it
8260      as efficiently as possible */
8261   if (AOP_TYPE (right) == AOP_LIT)
8262     {
8263       genRightShiftLiteral (left, right, result, ic, 0);
8264       return;
8265     }
8266
8267   /* shift count is unknown then we have to form
8268      a loop get the loop count in B : Note: we take
8269      only the lower order byte since shifting
8270      more that 32 bits make no sense anyway, ( the
8271      largest size of an object can be only 32 bits ) */
8272
8273   pushedB = pushB ();
8274   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
8275   emitcode ("inc", "b");
8276   freeAsmop (right, NULL, ic, TRUE);
8277   aopOp (left, ic, FALSE);
8278   aopOp (result, ic, FALSE);
8279
8280   /* now move the left to the result if they are not the
8281      same */
8282   if (!sameRegs (AOP (left), AOP (result)) &&
8283       AOP_SIZE (result) > 1)
8284     {
8285
8286       size = AOP_SIZE (result);
8287       offset = 0;
8288       while (size--)
8289         {
8290           l = aopGet (AOP (left), offset, FALSE, TRUE);
8291           if (*l == '@' && IS_AOP_PREG (result))
8292             {
8293
8294               emitcode ("mov", "a,%s", l);
8295               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8296             }
8297           else
8298             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
8299           offset++;
8300         }
8301     }
8302
8303   tlbl = newiTempLabel (NULL);
8304   tlbl1 = newiTempLabel (NULL);
8305   size = AOP_SIZE (result);
8306   offset = size - 1;
8307
8308   /* if it is only one byte then */
8309   if (size == 1)
8310     {
8311       l = aopGet (AOP (left), 0, FALSE, FALSE);
8312       MOVA (l);
8313       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8314       emitcode ("", "%05d$:", tlbl->key + 100);
8315       CLRC;
8316       emitcode ("rrc", "a");
8317       emitcode ("", "%05d$:", tlbl1->key + 100);
8318       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8319       popB (pushedB);
8320       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
8321       goto release;
8322     }
8323
8324   reAdjustPreg (AOP (result));
8325   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8326   emitcode ("", "%05d$:", tlbl->key + 100);
8327   CLRC;
8328   while (size--)
8329     {
8330       l = aopGet (AOP (result), offset, FALSE, FALSE);
8331       MOVA (l);
8332       emitcode ("rrc", "a");
8333       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
8334     }
8335   reAdjustPreg (AOP (result));
8336
8337   emitcode ("", "%05d$:", tlbl1->key + 100);
8338   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8339   popB (pushedB);
8340
8341 release:
8342   freeAsmop (left, NULL, ic, TRUE);
8343   freeAsmop (result, NULL, ic, TRUE);
8344 }
8345
8346 /*-----------------------------------------------------------------*/
8347 /* emitPtrByteGet - emits code to get a byte into A through a      */
8348 /*                  pointer register (R0, R1, or DPTR). The        */
8349 /*                  original value of A can be preserved in B.     */
8350 /*-----------------------------------------------------------------*/
8351 static void
8352 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8353 {
8354   switch (p_type)
8355     {
8356     case IPOINTER:
8357     case POINTER:
8358       if (preserveAinB)
8359         emitcode ("mov", "b,a");
8360       emitcode ("mov", "a,@%s", rname);
8361       break;
8362
8363     case PPOINTER:
8364       if (preserveAinB)
8365         emitcode ("mov", "b,a");
8366       emitcode ("movx", "a,@%s", rname);
8367       break;
8368
8369     case FPOINTER:
8370       if (preserveAinB)
8371         emitcode ("mov", "b,a");
8372       emitcode ("movx", "a,@dptr");
8373       break;
8374
8375     case CPOINTER:
8376       if (preserveAinB)
8377         emitcode ("mov", "b,a");
8378       emitcode ("clr", "a");
8379       emitcode ("movc", "a,@a+dptr");
8380       break;
8381
8382     case GPOINTER:
8383       if (preserveAinB)
8384         {
8385           emitcode ("push", "b");
8386           emitcode ("push", "acc");
8387         }
8388       emitcode ("lcall", "__gptrget");
8389       if (preserveAinB)
8390         emitcode ("pop", "b");
8391       break;
8392     }
8393 }
8394
8395 /*-----------------------------------------------------------------*/
8396 /* emitPtrByteSet - emits code to set a byte from src through a    */
8397 /*                  pointer register (R0, R1, or DPTR).            */
8398 /*-----------------------------------------------------------------*/
8399 static void
8400 emitPtrByteSet (char *rname, int p_type, char *src)
8401 {
8402   switch (p_type)
8403     {
8404     case IPOINTER:
8405     case POINTER:
8406       if (*src=='@')
8407         {
8408           MOVA (src);
8409           emitcode ("mov", "@%s,a", rname);
8410         }
8411       else
8412         emitcode ("mov", "@%s,%s", rname, src);
8413       break;
8414
8415     case PPOINTER:
8416       MOVA (src);
8417       emitcode ("movx", "@%s,a", rname);
8418       break;
8419
8420     case FPOINTER:
8421       MOVA (src);
8422       emitcode ("movx", "@dptr,a");
8423       break;
8424
8425     case GPOINTER:
8426       MOVA (src);
8427       emitcode ("lcall", "__gptrput");
8428       break;
8429     }
8430 }
8431
8432 /*-----------------------------------------------------------------*/
8433 /* genUnpackBits - generates code for unpacking bits               */
8434 /*-----------------------------------------------------------------*/
8435 static void
8436 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8437 {
8438   int offset = 0;       /* result byte offset */
8439   int rsize;            /* result size */
8440   int rlen = 0;         /* remaining bitfield length */
8441   sym_link *etype;      /* bitfield type information */
8442   int blen;             /* bitfield length */
8443   int bstr;             /* bitfield starting bit within byte */
8444   char buffer[10];
8445
8446   D(emitcode (";     genUnpackBits",""));
8447
8448   etype = getSpec (operandType (result));
8449   rsize = getSize (operandType (result));
8450   blen = SPEC_BLEN (etype);
8451   bstr = SPEC_BSTR (etype);
8452
8453   if (ifx && blen <= 8)
8454     {
8455       emitPtrByteGet (rname, ptype, FALSE);
8456       if (blen == 1)
8457         {
8458           SNPRINTF (buffer, sizeof(buffer),
8459                     "acc.%d", bstr);
8460           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8461         }
8462       else
8463         {
8464           if (blen < 8)
8465             emitcode ("anl", "a,#0x%02x",
8466                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8467           genIfxJump (ifx, "a", NULL, NULL, NULL);
8468         }
8469       return;
8470     }
8471   wassert (!ifx);
8472
8473   /* If the bitfield length is less than a byte */
8474   if (blen < 8)
8475     {
8476       emitPtrByteGet (rname, ptype, FALSE);
8477       AccRsh (bstr);
8478       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8479       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8480       goto finish;
8481     }
8482
8483   /* Bit field did not fit in a byte. Copy all
8484      but the partial byte at the end.  */
8485   for (rlen=blen;rlen>=8;rlen-=8)
8486     {
8487       emitPtrByteGet (rname, ptype, FALSE);
8488       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8489       if (rlen>8)
8490         emitcode ("inc", "%s", rname);
8491     }
8492
8493   /* Handle the partial byte at the end */
8494   if (rlen)
8495     {
8496       emitPtrByteGet (rname, ptype, FALSE);
8497       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8498       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8499     }
8500
8501 finish:
8502   if (offset < rsize)
8503     {
8504       rsize -= offset;
8505       while (rsize--)
8506         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
8507     }
8508 }
8509
8510
8511 /*-----------------------------------------------------------------*/
8512 /* genDataPointerGet - generates code when ptr offset is known     */
8513 /*-----------------------------------------------------------------*/
8514 static void
8515 genDataPointerGet (operand * left,
8516                    operand * result,
8517                    iCode * ic)
8518 {
8519   char *l;
8520   char buffer[256];
8521   int size, offset = 0;
8522
8523   D(emitcode (";     genDataPointerGet",""));
8524
8525   aopOp (result, ic, TRUE);
8526
8527   /* get the string representation of the name */
8528   l = aopGet (AOP (left), 0, FALSE, TRUE);
8529   size = AOP_SIZE (result);
8530   while (size--)
8531     {
8532       if (offset)
8533         sprintf (buffer, "(%s + %d)", l + 1, offset);
8534       else
8535         sprintf (buffer, "%s", l + 1);
8536       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
8537     }
8538
8539   freeAsmop (left, NULL, ic, TRUE);
8540   freeAsmop (result, NULL, ic, TRUE);
8541 }
8542
8543 /*-----------------------------------------------------------------*/
8544 /* genNearPointerGet - emitcode for near pointer fetch             */
8545 /*-----------------------------------------------------------------*/
8546 static void
8547 genNearPointerGet (operand * left,
8548                    operand * result,
8549                    iCode * ic,
8550                    iCode * pi,
8551                    iCode * ifx)
8552 {
8553   asmop *aop = NULL;
8554   regs *preg = NULL;
8555   char *rname;
8556   sym_link *rtype, *retype;
8557   sym_link *ltype = operandType (left);
8558   char buffer[80];
8559
8560   D(emitcode (";     genNearPointerGet",""));
8561
8562   rtype = operandType (result);
8563   retype = getSpec (rtype);
8564
8565   aopOp (left, ic, FALSE);
8566
8567   /* if left is rematerialisable and
8568      result is not bitfield variable type and
8569      the left is pointer to data space i.e
8570      lower 128 bytes of space */
8571   if (AOP_TYPE (left) == AOP_IMMD &&
8572       !IS_BITFIELD (retype) &&
8573       DCL_TYPE (ltype) == POINTER)
8574     {
8575       genDataPointerGet (left, result, ic);
8576       return;
8577     }
8578
8579  /* if the value is already in a pointer register
8580      then don't need anything more */
8581   if (!AOP_INPREG (AOP (left)))
8582     {
8583       if (IS_AOP_PREG (left))
8584         {
8585           // Aha, it is a pointer, just in disguise.
8586           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8587           if (*rname != '@')
8588             {
8589               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8590                       __FILE__, __LINE__);
8591             }
8592           else
8593             {
8594               // Expected case.
8595               emitcode ("mov", "a%s,%s", rname + 1, rname);
8596               rname++;  // skip the '@'.
8597             }
8598         }
8599       else
8600         {
8601           /* otherwise get a free pointer register */
8602           aop = newAsmop (0);
8603           preg = getFreePtr (ic, &aop, FALSE);
8604           emitcode ("mov", "%s,%s",
8605                     preg->name,
8606                     aopGet (AOP (left), 0, FALSE, TRUE));
8607           rname = preg->name;
8608         }
8609     }
8610   else
8611     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8612
8613   //aopOp (result, ic, FALSE);
8614   aopOp (result, ic, result?TRUE:FALSE);
8615
8616   /* if bitfield then unpack the bits */
8617   if (IS_BITFIELD (retype))
8618     genUnpackBits (result, rname, POINTER, ifx);
8619   else
8620     {
8621       /* we have can just get the values */
8622       int size = AOP_SIZE (result);
8623       int offset = 0;
8624
8625       while (size--)
8626         {
8627           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8628             {
8629
8630               emitcode ("mov", "a,@%s", rname);
8631               if (!ifx)
8632               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8633             }
8634           else
8635             {
8636               sprintf (buffer, "@%s", rname);
8637               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8638             }
8639           offset++;
8640           if (size || pi)
8641             emitcode ("inc", "%s", rname);
8642         }
8643     }
8644
8645   /* now some housekeeping stuff */
8646   if (aop)       /* we had to allocate for this iCode */
8647     {
8648       if (pi) { /* post increment present */
8649         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8650       }
8651       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8652     }
8653   else
8654     {
8655       /* we did not allocate which means left
8656          already in a pointer register, then
8657          if size > 0 && this could be used again
8658          we have to point it back to where it
8659          belongs */
8660       if ((AOP_SIZE (result) > 1 &&
8661            !OP_SYMBOL (left)->remat &&
8662            (OP_SYMBOL (left)->liveTo > ic->seq ||
8663             ic->depth)) &&
8664           !pi)
8665         {
8666           int size = AOP_SIZE (result) - 1;
8667           while (size--)
8668             emitcode ("dec", "%s", rname);
8669         }
8670     }
8671
8672   if (ifx && !ifx->generated)
8673     {
8674       genIfxJump (ifx, "a", left, NULL, result);
8675     }
8676
8677   /* done */
8678   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8679   freeAsmop (left, NULL, ic, TRUE);
8680   if (pi) pi->generated = 1;
8681 }
8682
8683 /*-----------------------------------------------------------------*/
8684 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8685 /*-----------------------------------------------------------------*/
8686 static void
8687 genPagedPointerGet (operand * left,
8688                     operand * result,
8689                     iCode * ic,
8690                     iCode *pi,
8691                     iCode *ifx)
8692 {
8693   asmop *aop = NULL;
8694   regs *preg = NULL;
8695   char *rname;
8696   sym_link *rtype, *retype;
8697
8698   D(emitcode (";     genPagedPointerGet",""));
8699
8700   rtype = operandType (result);
8701   retype = getSpec (rtype);
8702
8703   aopOp (left, ic, FALSE);
8704
8705   /* if the value is already in a pointer register
8706      then don't need anything more */
8707   if (!AOP_INPREG (AOP (left)))
8708     {
8709       /* otherwise get a free pointer register */
8710       aop = newAsmop (0);
8711       preg = getFreePtr (ic, &aop, FALSE);
8712       emitcode ("mov", "%s,%s",
8713                 preg->name,
8714                 aopGet (AOP (left), 0, FALSE, TRUE));
8715       rname = preg->name;
8716     }
8717   else
8718     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8719
8720   aopOp (result, ic, FALSE);
8721
8722   /* if bitfield then unpack the bits */
8723   if (IS_BITFIELD (retype))
8724     genUnpackBits (result, rname, PPOINTER, ifx);
8725   else
8726     {
8727       /* we have can just get the values */
8728       int size = AOP_SIZE (result);
8729       int offset = 0;
8730
8731       while (size--)
8732         {
8733
8734           emitcode ("movx", "a,@%s", rname);
8735           if (!ifx)
8736           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8737
8738           offset++;
8739
8740           if (size || pi)
8741             emitcode ("inc", "%s", rname);
8742         }
8743     }
8744
8745   /* now some housekeeping stuff */
8746   if (aop) /* we had to allocate for this iCode */
8747     {
8748       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8749       freeAsmop (NULL, aop, ic, TRUE);
8750     }
8751   else
8752     {
8753       /* we did not allocate which means left
8754          already in a pointer register, then
8755          if size > 0 && this could be used again
8756          we have to point it back to where it
8757          belongs */
8758       if ((AOP_SIZE (result) > 1 &&
8759            !OP_SYMBOL (left)->remat &&
8760            (OP_SYMBOL (left)->liveTo > ic->seq ||
8761             ic->depth)) &&
8762           !pi)
8763         {
8764           int size = AOP_SIZE (result) - 1;
8765           while (size--)
8766             emitcode ("dec", "%s", rname);
8767         }
8768     }
8769
8770   if (ifx && !ifx->generated)
8771     {
8772       genIfxJump (ifx, "a", left, NULL, result);
8773     }
8774
8775   /* done */
8776   freeAsmop (left, NULL, ic, TRUE);
8777   freeAsmop (result, NULL, ic, TRUE);
8778   if (pi) pi->generated = 1;
8779
8780 }
8781
8782 /*--------------------------------------------------------------------*/
8783 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8784 /*--------------------------------------------------------------------*/
8785 static void
8786 loadDptrFromOperand (operand *op, bool loadBToo)
8787 {
8788   if (AOP_TYPE (op) != AOP_STR)
8789     {
8790       /* if this is rematerializable */
8791       if (AOP_TYPE (op) == AOP_IMMD)
8792         {
8793           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8794           if (loadBToo)
8795             {
8796               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8797                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8798               else
8799                 {
8800                   wassertl(FALSE, "need pointerCode");
8801                   emitcode ("", "; mov b,???");
8802                   /* genPointerGet and genPointerSet originally did different
8803                   ** things for this case. Both seem wrong.
8804                   ** from genPointerGet:
8805                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8806                   ** from genPointerSet:
8807                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8808                   */
8809                 }
8810             }
8811         }
8812       else if (AOP_TYPE (op) == AOP_DPTR)
8813         {
8814           if (loadBToo)
8815             {
8816               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8817               emitcode ("push", "acc");
8818               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8819               emitcode ("push", "acc");
8820               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8821               emitcode ("pop", "dph");
8822               emitcode ("pop", "dpl");
8823             }
8824           else
8825             {
8826               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8827               emitcode ("push", "acc");
8828               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8829               emitcode ("pop", "dpl");
8830             }
8831         }
8832       else
8833         {                       /* we need to get it byte by byte */
8834           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8835           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8836           if (loadBToo)
8837             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8838         }
8839     }
8840 }
8841
8842 /*-----------------------------------------------------------------*/
8843 /* genFarPointerGet - gget value from far space                    */
8844 /*-----------------------------------------------------------------*/
8845 static void
8846 genFarPointerGet (operand * left,
8847                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
8848 {
8849   int size, offset;
8850   sym_link *retype = getSpec (operandType (result));
8851
8852   D(emitcode (";     genFarPointerGet",""));
8853
8854   aopOp (left, ic, FALSE);
8855   loadDptrFromOperand (left, FALSE);
8856
8857   /* so dptr now contains the address */
8858   aopOp (result, ic, FALSE);
8859
8860   /* if bit then unpack */
8861   if (IS_BITFIELD (retype))
8862     genUnpackBits (result, "dptr", FPOINTER, ifx);
8863   else
8864     {
8865       size = AOP_SIZE (result);
8866       offset = 0;
8867
8868       while (size--)
8869         {
8870           emitcode ("movx", "a,@dptr");
8871           if (!ifx)
8872             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8873           if (size || pi)
8874             emitcode ("inc", "dptr");
8875         }
8876     }
8877
8878   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8879     {
8880     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8881     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8882     pi->generated = 1;
8883   }
8884
8885   if (ifx && !ifx->generated)
8886     {
8887       genIfxJump (ifx, "a", left, NULL, result);
8888     }
8889
8890   freeAsmop (left, NULL, ic, TRUE);
8891   freeAsmop (result, NULL, ic, TRUE);
8892 }
8893
8894 /*-----------------------------------------------------------------*/
8895 /* genCodePointerGet - gget value from code space                  */
8896 /*-----------------------------------------------------------------*/
8897 static void
8898 genCodePointerGet (operand * left,
8899                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
8900 {
8901   int size, offset;
8902   sym_link *retype = getSpec (operandType (result));
8903
8904   D(emitcode (";     genCodePointerGet",""));
8905
8906   aopOp (left, ic, FALSE);
8907   loadDptrFromOperand (left, FALSE);
8908
8909   /* so dptr now contains the address */
8910   aopOp (result, ic, FALSE);
8911
8912   /* if bit then unpack */
8913   if (IS_BITFIELD (retype))
8914     genUnpackBits (result, "dptr", CPOINTER, ifx);
8915   else
8916     {
8917       size = AOP_SIZE (result);
8918       offset = 0;
8919
8920       while (size--)
8921         {
8922           if (pi)
8923             {
8924               emitcode ("clr", "a");
8925               emitcode ("movc", "a,@a+dptr");
8926               if (!ifx)
8927               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8928               emitcode ("inc", "dptr");
8929             }
8930           else
8931             {
8932               emitcode ("mov", "a,#0x%02x", offset);
8933               emitcode ("movc", "a,@a+dptr");
8934               if (!ifx)
8935               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8936             }
8937         }
8938     }
8939
8940   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8941     {
8942     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8943     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8944     pi->generated = 1;
8945   }
8946
8947   if (ifx && !ifx->generated)
8948     {
8949       genIfxJump (ifx, "a", left, NULL, result);
8950     }
8951
8952   freeAsmop (left, NULL, ic, TRUE);
8953   freeAsmop (result, NULL, ic, TRUE);
8954 }
8955
8956 /*-----------------------------------------------------------------*/
8957 /* genGenPointerGet - gget value from generic pointer space        */
8958 /*-----------------------------------------------------------------*/
8959 static void
8960 genGenPointerGet (operand * left,
8961                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
8962 {
8963   int size, offset;
8964   sym_link *retype = getSpec (operandType (result));
8965
8966   D(emitcode (";     genGenPointerGet",""));
8967
8968   aopOp (left, ic, FALSE);
8969   loadDptrFromOperand (left, TRUE);
8970
8971   /* so dptr know contains the address */
8972   aopOp (result, ic, FALSE);
8973
8974   /* if bit then unpack */
8975   if (IS_BITFIELD (retype))
8976     genUnpackBits (result, "dptr", GPOINTER, ifx);
8977   else
8978     {
8979       size = AOP_SIZE (result);
8980       offset = 0;
8981
8982       while (size--)
8983         {
8984           emitcode ("lcall", "__gptrget");
8985           if (!ifx)
8986           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8987           if (size || pi)
8988             emitcode ("inc", "dptr");
8989         }
8990     }
8991
8992   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8993     {
8994     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8995     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8996     pi->generated = 1;
8997   }
8998
8999   if (ifx && !ifx->generated)
9000     {
9001       genIfxJump (ifx, "a", left, NULL, result);
9002     }
9003
9004
9005   freeAsmop (left, NULL, ic, TRUE);
9006   freeAsmop (result, NULL, ic, TRUE);
9007 }
9008
9009 /*-----------------------------------------------------------------*/
9010 /* genPointerGet - generate code for pointer get                   */
9011 /*-----------------------------------------------------------------*/
9012 static void
9013 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9014 {
9015   operand *left, *result;
9016   sym_link *type, *etype;
9017   int p_type;
9018
9019   D(emitcode (";     genPointerGet",""));
9020
9021   left = IC_LEFT (ic);
9022   result = IC_RESULT (ic);
9023
9024   if (getSize (operandType (result))>1)
9025     ifx = NULL;
9026
9027   /* depending on the type of pointer we need to
9028      move it to the correct pointer register */
9029   type = operandType (left);
9030   etype = getSpec (type);
9031   /* if left is of type of pointer then it is simple */
9032   if (IS_PTR (type) && !IS_FUNC (type->next))
9033     p_type = DCL_TYPE (type);
9034   else
9035     {
9036       /* we have to go by the storage class */
9037       p_type = PTR_TYPE (SPEC_OCLS (etype));
9038     }
9039
9040   /* special case when cast remat */
9041   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9042       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9043           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9044           type = operandType (left);
9045           p_type = DCL_TYPE (type);
9046   }
9047   /* now that we have the pointer type we assign
9048      the pointer values */
9049   switch (p_type)
9050     {
9051
9052     case POINTER:
9053     case IPOINTER:
9054       genNearPointerGet (left, result, ic, pi, ifx);
9055       break;
9056
9057     case PPOINTER:
9058       genPagedPointerGet (left, result, ic, pi, ifx);
9059       break;
9060
9061     case FPOINTER:
9062       genFarPointerGet (left, result, ic, pi, ifx);
9063       break;
9064
9065     case CPOINTER:
9066       genCodePointerGet (left, result, ic, pi, ifx);
9067       break;
9068
9069     case GPOINTER:
9070       genGenPointerGet (left, result, ic, pi, ifx);
9071       break;
9072     }
9073
9074 }
9075
9076
9077
9078 /*-----------------------------------------------------------------*/
9079 /* genPackBits - generates code for packed bit storage             */
9080 /*-----------------------------------------------------------------*/
9081 static void
9082 genPackBits (sym_link * etype,
9083              operand * right,
9084              char *rname, int p_type)
9085 {
9086   int offset = 0;       /* source byte offset */
9087   int rlen = 0;         /* remaining bitfield length */
9088   int blen;             /* bitfield length */
9089   int bstr;             /* bitfield starting bit within byte */
9090   int litval;           /* source literal value (if AOP_LIT) */
9091   unsigned char mask;   /* bitmask within current byte */
9092
9093   D(emitcode (";     genPackBits",""));
9094
9095   blen = SPEC_BLEN (etype);
9096   bstr = SPEC_BSTR (etype);
9097
9098   /* If the bitfield length is less than a byte */
9099   if (blen < 8)
9100     {
9101       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9102               (unsigned char) (0xFF >> (8 - bstr)));
9103
9104       if (AOP_TYPE (right) == AOP_LIT)
9105         {
9106           /* Case with a bitfield length <8 and literal source
9107           */
9108           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9109           litval <<= bstr;
9110           litval &= (~mask) & 0xff;
9111           emitPtrByteGet (rname, p_type, FALSE);
9112           if ((mask|litval)!=0xff)
9113             emitcode ("anl","a,#0x%02x", mask);
9114           if (litval)
9115             emitcode ("orl","a,#0x%02x", litval);
9116         }
9117       else
9118         {
9119           if ((blen==1) && (p_type!=GPOINTER))
9120             {
9121               /* Case with a bitfield length == 1 and no generic pointer
9122               */
9123               if (AOP_TYPE (right) == AOP_CRY)
9124                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9125               else
9126                 {
9127                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
9128                   emitcode ("rrc","a");
9129                 }
9130               emitPtrByteGet (rname, p_type, FALSE);
9131               emitcode ("mov","acc.%d,c",bstr);
9132             }
9133           else
9134             {
9135               bool pushedB;
9136               /* Case with a bitfield length < 8 and arbitrary source
9137               */
9138               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
9139               /* shift and mask source value */
9140               AccLsh (bstr);
9141               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9142
9143               pushedB = pushB ();
9144               /* transfer A to B and get next byte */
9145               emitPtrByteGet (rname, p_type, TRUE);
9146
9147               emitcode ("anl", "a,#0x%02x", mask);
9148               emitcode ("orl", "a,b");
9149               if (p_type == GPOINTER)
9150                 emitcode ("pop", "b");
9151
9152               popB (pushedB);
9153            }
9154         }
9155
9156       emitPtrByteSet (rname, p_type, "a");
9157       return;
9158     }
9159
9160   /* Bit length is greater than 7 bits. In this case, copy  */
9161   /* all except the partial byte at the end                 */
9162   for (rlen=blen;rlen>=8;rlen-=8)
9163     {
9164       emitPtrByteSet (rname, p_type,
9165                       aopGet (AOP (right), offset++, FALSE, TRUE) );
9166       if (rlen>8)
9167         emitcode ("inc", "%s", rname);
9168     }
9169
9170   /* If there was a partial byte at the end */
9171   if (rlen)
9172     {
9173       mask = (((unsigned char) -1 << rlen) & 0xff);
9174
9175       if (AOP_TYPE (right) == AOP_LIT)
9176         {
9177           /* Case with partial byte and literal source
9178           */
9179           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9180           litval >>= (blen-rlen);
9181           litval &= (~mask) & 0xff;
9182           emitPtrByteGet (rname, p_type, FALSE);
9183           if ((mask|litval)!=0xff)
9184             emitcode ("anl","a,#0x%02x", mask);
9185           if (litval)
9186             emitcode ("orl","a,#0x%02x", litval);
9187         }
9188       else
9189         {
9190           bool pushedB;
9191           /* Case with partial byte and arbitrary source
9192           */
9193           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
9194           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9195
9196           pushedB = pushB ();
9197           /* transfer A to B and get next byte */
9198           emitPtrByteGet (rname, p_type, TRUE);
9199
9200           emitcode ("anl", "a,#0x%02x", mask);
9201           emitcode ("orl", "a,b");
9202           if (p_type == GPOINTER)
9203             emitcode ("pop", "b");
9204
9205           popB (pushedB);
9206         }
9207       emitPtrByteSet (rname, p_type, "a");
9208     }
9209
9210 }
9211
9212
9213 /*-----------------------------------------------------------------*/
9214 /* genDataPointerSet - remat pointer to data space                 */
9215 /*-----------------------------------------------------------------*/
9216 static void
9217 genDataPointerSet (operand * right,
9218                    operand * result,
9219                    iCode * ic)
9220 {
9221   int size, offset = 0;
9222   char *l, buffer[256];
9223
9224   D(emitcode (";     genDataPointerSet",""));
9225
9226   aopOp (right, ic, FALSE);
9227
9228   l = aopGet (AOP (result), 0, FALSE, TRUE);
9229   size = AOP_SIZE (right);
9230   while (size--)
9231     {
9232       if (offset)
9233         sprintf (buffer, "(%s + %d)", l + 1, offset);
9234       else
9235         sprintf (buffer, "%s", l + 1);
9236       emitcode ("mov", "%s,%s", buffer,
9237                 aopGet (AOP (right), offset++, FALSE, FALSE));
9238     }
9239
9240   freeAsmop (right, NULL, ic, TRUE);
9241   freeAsmop (result, NULL, ic, TRUE);
9242 }
9243
9244 /*-----------------------------------------------------------------*/
9245 /* genNearPointerSet - emitcode for near pointer put                */
9246 /*-----------------------------------------------------------------*/
9247 static void
9248 genNearPointerSet (operand * right,
9249                    operand * result,
9250                    iCode * ic,
9251                    iCode * pi)
9252 {
9253   asmop *aop = NULL;
9254   regs *preg = NULL;
9255   char *rname, *l;
9256   sym_link *retype, *letype;
9257   sym_link *ptype = operandType (result);
9258
9259   D(emitcode (";     genNearPointerSet",""));
9260
9261   retype = getSpec (operandType (right));
9262   letype = getSpec (ptype);
9263   aopOp (result, ic, FALSE);
9264
9265   /* if the result is rematerializable &
9266      in data space & not a bit variable */
9267   if (AOP_TYPE (result) == AOP_IMMD &&
9268       DCL_TYPE (ptype) == POINTER &&
9269       !IS_BITVAR (retype) &&
9270       !IS_BITVAR (letype))
9271     {
9272       genDataPointerSet (right, result, ic);
9273       return;
9274     }
9275
9276   /* if the value is already in a pointer register
9277      then don't need anything more */
9278   if (!AOP_INPREG (AOP (result)))
9279     {
9280         if (
9281             //AOP_TYPE (result) == AOP_STK
9282             IS_AOP_PREG(result)
9283             )
9284         {
9285             // Aha, it is a pointer, just in disguise.
9286             rname = aopGet (AOP (result), 0, FALSE, FALSE);
9287             if (*rname != '@')
9288             {
9289                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9290                         __FILE__, __LINE__);
9291             }
9292             else
9293             {
9294                 // Expected case.
9295                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9296                 rname++;  // skip the '@'.
9297             }
9298         }
9299         else
9300         {
9301             /* otherwise get a free pointer register */
9302             aop = newAsmop (0);
9303             preg = getFreePtr (ic, &aop, FALSE);
9304             emitcode ("mov", "%s,%s",
9305                       preg->name,
9306                       aopGet (AOP (result), 0, FALSE, TRUE));
9307             rname = preg->name;
9308         }
9309     }
9310     else
9311     {
9312         rname = aopGet (AOP (result), 0, FALSE, FALSE);
9313     }
9314
9315   aopOp (right, ic, FALSE);
9316
9317   /* if bitfield then unpack the bits */
9318   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9319     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9320   else
9321     {
9322       /* we have can just get the values */
9323       int size = AOP_SIZE (right);
9324       int offset = 0;
9325
9326       while (size--)
9327         {
9328           l = aopGet (AOP (right), offset, FALSE, TRUE);
9329           if (*l == '@')
9330             {
9331               MOVA (l);
9332               emitcode ("mov", "@%s,a", rname);
9333             }
9334           else
9335             emitcode ("mov", "@%s,%s", rname, l);
9336           if (size || pi)
9337             emitcode ("inc", "%s", rname);
9338           offset++;
9339         }
9340     }
9341
9342   /* now some housekeeping stuff */
9343   if (aop) /* we had to allocate for this iCode */
9344     {
9345       if (pi)
9346         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9347       freeAsmop (NULL, aop, ic, TRUE);
9348     }
9349   else
9350     {
9351       /* we did not allocate which means left
9352          already in a pointer register, then
9353          if size > 0 && this could be used again
9354          we have to point it back to where it
9355          belongs */
9356       if ((AOP_SIZE (right) > 1 &&
9357            !OP_SYMBOL (result)->remat &&
9358            (OP_SYMBOL (result)->liveTo > ic->seq ||
9359             ic->depth)) &&
9360           !pi)
9361         {
9362           int size = AOP_SIZE (right) - 1;
9363           while (size--)
9364             emitcode ("dec", "%s", rname);
9365         }
9366     }
9367
9368   /* done */
9369   if (pi) pi->generated = 1;
9370   freeAsmop (result, NULL, ic, TRUE);
9371   freeAsmop (right, NULL, ic, TRUE);
9372 }
9373
9374 /*-----------------------------------------------------------------*/
9375 /* genPagedPointerSet - emitcode for Paged pointer put             */
9376 /*-----------------------------------------------------------------*/
9377 static void
9378 genPagedPointerSet (operand * right,
9379                     operand * result,
9380                     iCode * ic,
9381                     iCode * pi)
9382 {
9383   asmop *aop = NULL;
9384   regs *preg = NULL;
9385   char *rname, *l;
9386   sym_link *retype, *letype;
9387
9388   D(emitcode (";     genPagedPointerSet",""));
9389
9390   retype = getSpec (operandType (right));
9391   letype = getSpec (operandType (result));
9392
9393   aopOp (result, ic, FALSE);
9394
9395   /* if the value is already in a pointer register
9396      then don't need anything more */
9397   if (!AOP_INPREG (AOP (result)))
9398     {
9399       /* otherwise get a free pointer register */
9400       aop = newAsmop (0);
9401       preg = getFreePtr (ic, &aop, FALSE);
9402       emitcode ("mov", "%s,%s",
9403                 preg->name,
9404                 aopGet (AOP (result), 0, FALSE, TRUE));
9405       rname = preg->name;
9406     }
9407   else
9408     rname = aopGet (AOP (result), 0, FALSE, FALSE);
9409
9410   aopOp (right, ic, FALSE);
9411
9412   /* if bitfield then unpack the bits */
9413   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9414     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9415   else
9416     {
9417       /* we have can just get the values */
9418       int size = AOP_SIZE (right);
9419       int offset = 0;
9420
9421       while (size--)
9422         {
9423           l = aopGet (AOP (right), offset, FALSE, TRUE);
9424
9425           MOVA (l);
9426           emitcode ("movx", "@%s,a", rname);
9427
9428           if (size || pi)
9429             emitcode ("inc", "%s", rname);
9430
9431           offset++;
9432         }
9433     }
9434
9435   /* now some housekeeping stuff */
9436   if (aop) /* we had to allocate for this iCode */
9437     {
9438       if (pi)
9439         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9440       freeAsmop (NULL, aop, ic, TRUE);
9441     }
9442   else
9443     {
9444       /* we did not allocate which means left
9445          already in a pointer register, then
9446          if size > 0 && this could be used again
9447          we have to point it back to where it
9448          belongs */
9449       if (AOP_SIZE (right) > 1 &&
9450           !OP_SYMBOL (result)->remat &&
9451           (OP_SYMBOL (result)->liveTo > ic->seq ||
9452            ic->depth))
9453         {
9454           int size = AOP_SIZE (right) - 1;
9455           while (size--)
9456             emitcode ("dec", "%s", rname);
9457         }
9458     }
9459
9460   /* done */
9461   if (pi) pi->generated = 1;
9462   freeAsmop (result, NULL, ic, TRUE);
9463   freeAsmop (right, NULL, ic, TRUE);
9464
9465
9466 }
9467
9468 /*-----------------------------------------------------------------*/
9469 /* genFarPointerSet - set value from far space                     */
9470 /*-----------------------------------------------------------------*/
9471 static void
9472 genFarPointerSet (operand * right,
9473                   operand * result, iCode * ic, iCode * pi)
9474 {
9475   int size, offset;
9476   sym_link *retype = getSpec (operandType (right));
9477   sym_link *letype = getSpec (operandType (result));
9478
9479   D(emitcode (";     genFarPointerSet",""));
9480
9481   aopOp (result, ic, FALSE);
9482   loadDptrFromOperand (result, FALSE);
9483
9484   /* so dptr know contains the address */
9485   aopOp (right, ic, FALSE);
9486
9487   /* if bit then unpack */
9488   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9489     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9490   else
9491     {
9492       size = AOP_SIZE (right);
9493       offset = 0;
9494
9495       while (size--)
9496         {
9497           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9498           MOVA (l);
9499           emitcode ("movx", "@dptr,a");
9500           if (size || pi)
9501             emitcode ("inc", "dptr");
9502         }
9503     }
9504   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9505     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9506     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9507     pi->generated=1;
9508   }
9509   freeAsmop (result, NULL, ic, TRUE);
9510   freeAsmop (right, NULL, ic, TRUE);
9511 }
9512
9513 /*-----------------------------------------------------------------*/
9514 /* genGenPointerSet - set value from generic pointer space         */
9515 /*-----------------------------------------------------------------*/
9516 static void
9517 genGenPointerSet (operand * right,
9518                   operand * result, iCode * ic, iCode * pi)
9519 {
9520   int size, offset;
9521   sym_link *retype = getSpec (operandType (right));
9522   sym_link *letype = getSpec (operandType (result));
9523
9524   D(emitcode (";     genGenPointerSet",""));
9525
9526   aopOp (result, ic, FALSE);
9527   loadDptrFromOperand (result, TRUE);
9528
9529   /* so dptr know contains the address */
9530   aopOp (right, ic, FALSE);
9531
9532   /* if bit then unpack */
9533   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9534     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9535   else
9536     {
9537       size = AOP_SIZE (right);
9538       offset = 0;
9539
9540       while (size--)
9541         {
9542           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9543           MOVA (l);
9544           emitcode ("lcall", "__gptrput");
9545           if (size || pi)
9546             emitcode ("inc", "dptr");
9547         }
9548     }
9549
9550   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9551     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9552     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9553     pi->generated=1;
9554   }
9555   freeAsmop (result, NULL, ic, TRUE);
9556   freeAsmop (right, NULL, ic, TRUE);
9557 }
9558
9559 /*-----------------------------------------------------------------*/
9560 /* genPointerSet - stores the value into a pointer location        */
9561 /*-----------------------------------------------------------------*/
9562 static void
9563 genPointerSet (iCode * ic, iCode *pi)
9564 {
9565   operand *right, *result;
9566   sym_link *type, *etype;
9567   int p_type;
9568
9569   D(emitcode (";     genPointerSet",""));
9570
9571   right = IC_RIGHT (ic);
9572   result = IC_RESULT (ic);
9573
9574   /* depending on the type of pointer we need to
9575      move it to the correct pointer register */
9576   type = operandType (result);
9577   etype = getSpec (type);
9578   /* if left is of type of pointer then it is simple */
9579   if (IS_PTR (type) && !IS_FUNC (type->next))
9580     {
9581       p_type = DCL_TYPE (type);
9582     }
9583   else
9584     {
9585       /* we have to go by the storage class */
9586       p_type = PTR_TYPE (SPEC_OCLS (etype));
9587     }
9588
9589   /* special case when cast remat */
9590   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9591       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9592           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9593           type = operandType (result);
9594           p_type = DCL_TYPE (type);
9595   }
9596   /* now that we have the pointer type we assign
9597      the pointer values */
9598   switch (p_type)
9599     {
9600
9601     case POINTER:
9602     case IPOINTER:
9603       genNearPointerSet (right, result, ic, pi);
9604       break;
9605
9606     case PPOINTER:
9607       genPagedPointerSet (right, result, ic, pi);
9608       break;
9609
9610     case FPOINTER:
9611       genFarPointerSet (right, result, ic, pi);
9612       break;
9613
9614     case GPOINTER:
9615       genGenPointerSet (right, result, ic, pi);
9616       break;
9617
9618     default:
9619       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9620               "genPointerSet: illegal pointer type");
9621     }
9622
9623 }
9624
9625 /*-----------------------------------------------------------------*/
9626 /* genIfx - generate code for Ifx statement                        */
9627 /*-----------------------------------------------------------------*/
9628 static void
9629 genIfx (iCode * ic, iCode * popIc)
9630 {
9631   operand *cond = IC_COND (ic);
9632   int isbit = 0;
9633
9634   D(emitcode (";     genIfx",""));
9635
9636   aopOp (cond, ic, FALSE);
9637
9638   /* get the value into acc */
9639   if (AOP_TYPE (cond) != AOP_CRY)
9640     toBoolean (cond);
9641   else
9642     isbit = 1;
9643   /* the result is now in the accumulator */
9644   freeAsmop (cond, NULL, ic, TRUE);
9645
9646   /* if there was something to be popped then do it */
9647   if (popIc)
9648     genIpop (popIc);
9649
9650   /* if the condition is a bit variable */
9651   if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
9652     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9653   else if (isbit && !IS_ITEMP (cond))
9654     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9655   else
9656     genIfxJump (ic, "a", NULL, NULL, NULL);
9657
9658   ic->generated = 1;
9659 }
9660
9661 /*-----------------------------------------------------------------*/
9662 /* genAddrOf - generates code for address of                       */
9663 /*-----------------------------------------------------------------*/
9664 static void
9665 genAddrOf (iCode * ic)
9666 {
9667   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9668   int size, offset;
9669
9670   D(emitcode (";     genAddrOf",""));
9671
9672   aopOp (IC_RESULT (ic), ic, FALSE);
9673
9674   /* if the operand is on the stack then we
9675      need to get the stack offset of this
9676      variable */
9677   if (sym->onStack)
9678     {
9679       /* if it has an offset then we need to compute
9680          it */
9681       if (sym->stack)
9682         {
9683           emitcode ("mov", "a,%s", SYM_BP (sym));
9684           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9685                                          ((char) (sym->stack - _G.nRegsSaved)) :
9686                                          ((char) sym->stack)) & 0xff);
9687           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9688         }
9689       else
9690         {
9691           /* we can just move _bp */
9692           aopPut (AOP (IC_RESULT (ic)), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9693         }
9694       /* fill the result with zero */
9695       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9696
9697       offset = 1;
9698       while (size--)
9699         {
9700           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9701         }
9702
9703       goto release;
9704     }
9705
9706   /* object not on stack then we need the name */
9707   size = AOP_SIZE (IC_RESULT (ic));
9708   offset = 0;
9709
9710   while (size--)
9711     {
9712       char s[SDCC_NAME_MAX];
9713       if (offset)
9714         sprintf (s, "#(%s >> %d)",
9715                  sym->rname,
9716                  offset * 8);
9717       else
9718         sprintf (s, "#%s", sym->rname);
9719       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9720     }
9721
9722 release:
9723   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9724
9725 }
9726
9727 /*-----------------------------------------------------------------*/
9728 /* genFarFarAssign - assignment when both are in far space         */
9729 /*-----------------------------------------------------------------*/
9730 static void
9731 genFarFarAssign (operand * result, operand * right, iCode * ic)
9732 {
9733   int size = AOP_SIZE (right);
9734   int offset = 0;
9735   char *l;
9736
9737   D(emitcode (";     genFarFarAssign",""));
9738
9739   /* first push the right side on to the stack */
9740   while (size--)
9741     {
9742       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9743       MOVA (l);
9744       emitcode ("push", "acc");
9745     }
9746
9747   freeAsmop (right, NULL, ic, FALSE);
9748   /* now assign DPTR to result */
9749   aopOp (result, ic, FALSE);
9750   size = AOP_SIZE (result);
9751   while (size--)
9752     {
9753       emitcode ("pop", "acc");
9754       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9755     }
9756   freeAsmop (result, NULL, ic, FALSE);
9757
9758 }
9759
9760 /*-----------------------------------------------------------------*/
9761 /* genAssign - generate code for assignment                        */
9762 /*-----------------------------------------------------------------*/
9763 static void
9764 genAssign (iCode * ic)
9765 {
9766   operand *result, *right;
9767   int size, offset;
9768   unsigned long lit = 0L;
9769
9770   D(emitcode(";     genAssign",""));
9771
9772   result = IC_RESULT (ic);
9773   right = IC_RIGHT (ic);
9774
9775   /* if they are the same */
9776   if (operandsEqu (result, right) &&
9777       !isOperandVolatile (result, FALSE) &&
9778       !isOperandVolatile (right, FALSE))
9779     return;
9780
9781   aopOp (right, ic, FALSE);
9782
9783   /* special case both in far space */
9784   if (AOP_TYPE (right) == AOP_DPTR &&
9785       IS_TRUE_SYMOP (result) &&
9786       isOperandInFarSpace (result))
9787     {
9788
9789       genFarFarAssign (result, right, ic);
9790       return;
9791     }
9792
9793   aopOp (result, ic, TRUE);
9794
9795   /* if they are the same registers */
9796   if (sameRegs (AOP (right), AOP (result)) &&
9797       !isOperandVolatile (result, FALSE) &&
9798       !isOperandVolatile (right, FALSE))
9799     goto release;
9800
9801   /* if the result is a bit */
9802   if (AOP_TYPE (result) == AOP_CRY)
9803     {
9804
9805       /* if the right size is a literal then
9806          we know what the value is */
9807       if (AOP_TYPE (right) == AOP_LIT)
9808         {
9809           if (((int) operandLitValue (right)))
9810             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9811           else
9812             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9813           goto release;
9814         }
9815
9816       /* the right is also a bit variable */
9817       if (AOP_TYPE (right) == AOP_CRY)
9818         {
9819           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9820           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9821           goto release;
9822         }
9823
9824       /* we need to or */
9825       toBoolean (right);
9826       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9827       goto release;
9828     }
9829
9830   /* bit variables done */
9831   /* general case */
9832   size = AOP_SIZE (result);
9833   offset = 0;
9834   if (AOP_TYPE (right) == AOP_LIT)
9835     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9836   if ((size > 1) &&
9837       (AOP_TYPE (result) != AOP_REG) &&
9838       (AOP_TYPE (right) == AOP_LIT) &&
9839       !IS_FLOAT (operandType (right)) &&
9840       (lit < 256L))
9841     {
9842       while ((size) && (lit))
9843         {
9844           aopPut (AOP (result),
9845                   aopGet (AOP (right), offset, FALSE, FALSE),
9846                   offset,
9847                   isOperandVolatile (result, FALSE));
9848           lit >>= 8;
9849           offset++;
9850           size--;
9851         }
9852       emitcode ("clr", "a");
9853       while (size--)
9854         {
9855           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
9856           offset++;
9857         }
9858     }
9859   else
9860     {
9861       while (size--)
9862         {
9863           aopPut (AOP (result),
9864                   aopGet (AOP (right), offset, FALSE, FALSE),
9865                   offset,
9866                   isOperandVolatile (result, FALSE));
9867           offset++;
9868         }
9869     }
9870
9871 release:
9872   freeAsmop (right, NULL, ic, TRUE);
9873   freeAsmop (result, NULL, ic, TRUE);
9874 }
9875
9876 /*-----------------------------------------------------------------*/
9877 /* genJumpTab - generates code for jump table                      */
9878 /*-----------------------------------------------------------------*/
9879 static void
9880 genJumpTab (iCode * ic)
9881 {
9882   symbol *jtab,*jtablo,*jtabhi;
9883   char *l;
9884   unsigned int count;
9885
9886   D(emitcode (";     genJumpTab",""));
9887
9888   count = elementsInSet( IC_JTLABELS (ic) );
9889
9890   if( count <= 16 )
9891     {
9892       /* this algorithm needs 9 cycles and 7 + 3*n bytes
9893          if the switch argument is in a register.
9894          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
9895       /* (MB) What if peephole converts ljmp to sjmp or ret ???
9896          How will multiply by three be updated ???*/
9897       aopOp (IC_JTCOND (ic), ic, FALSE);
9898       /* get the condition into accumulator */
9899       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9900       MOVA (l);
9901       /* multiply by three */
9902       emitcode ("add", "a,acc");
9903       emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9904       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9905
9906       jtab = newiTempLabel (NULL);
9907       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9908       emitcode ("jmp", "@a+dptr");
9909       emitcode ("", "%05d$:", jtab->key + 100);
9910       /* now generate the jump labels */
9911       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9912            jtab = setNextItem (IC_JTLABELS (ic)))
9913         emitcode ("ljmp", "%05d$", jtab->key + 100);
9914     }
9915   else
9916     {
9917       /* this algorithm needs 14 cycles and 13 + 2*n bytes
9918          if the switch argument is in a register.
9919          For n>6 this algorithm may be more compact */
9920       jtablo = newiTempLabel (NULL);
9921       jtabhi = newiTempLabel (NULL);
9922
9923       /* get the condition into accumulator.
9924          Using b as temporary storage, if register push/pop is needed */
9925       aopOp (IC_JTCOND (ic), ic, FALSE);
9926       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9927       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
9928           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
9929         {
9930           // (MB) what if B is in use???
9931           wassertl(!BINUSE, "B was in use");
9932           emitcode ("mov", "b,%s", l);
9933           l = "b";
9934         }
9935       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9936       MOVA (l);
9937       if( count <= 112 )
9938         {
9939           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
9940           emitcode ("movc", "a,@a+pc");
9941           emitcode ("push", "acc");
9942
9943           MOVA (l);
9944           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
9945           emitcode ("movc", "a,@a+pc");
9946           emitcode ("push", "acc");
9947         }
9948       else
9949         {
9950           /* this scales up to n<=255, but needs two more bytes
9951              and changes dptr */
9952           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
9953           emitcode ("movc", "a,@a+dptr");
9954           emitcode ("push", "acc");
9955
9956           MOVA (l);
9957           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
9958           emitcode ("movc", "a,@a+dptr");
9959           emitcode ("push", "acc");
9960         }
9961
9962       emitcode ("ret", "");
9963
9964       /* now generate jump table, LSB */
9965       emitcode ("", "%05d$:", jtablo->key + 100);
9966       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9967            jtab = setNextItem (IC_JTLABELS (ic)))
9968         emitcode (".db", "%05d$", jtab->key + 100);
9969
9970       /* now generate jump table, MSB */
9971       emitcode ("", "%05d$:", jtabhi->key + 100);
9972       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9973            jtab = setNextItem (IC_JTLABELS (ic)))
9974          emitcode (".db", "%05d$>>8", jtab->key + 100);
9975     }
9976 }
9977
9978 /*-----------------------------------------------------------------*/
9979 /* genCast - gen code for casting                                  */
9980 /*-----------------------------------------------------------------*/
9981 static void
9982 genCast (iCode * ic)
9983 {
9984   operand *result = IC_RESULT (ic);
9985   sym_link *ctype = operandType (IC_LEFT (ic));
9986   sym_link *rtype = operandType (IC_RIGHT (ic));
9987   operand *right = IC_RIGHT (ic);
9988   int size, offset;
9989
9990   D(emitcode(";     genCast",""));
9991
9992   /* if they are equivalent then do nothing */
9993   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9994     return;
9995
9996   aopOp (right, ic, FALSE);
9997   aopOp (result, ic, FALSE);
9998
9999   /* if the result is a bit (and not a bitfield) */
10000   // if (AOP_TYPE (result) == AOP_CRY)
10001   if (IS_BITVAR (OP_SYMBOL (result)->type)
10002       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10003     {
10004       /* if the right size is a literal then
10005          we know what the value is */
10006       if (AOP_TYPE (right) == AOP_LIT)
10007         {
10008           if (((int) operandLitValue (right)))
10009             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
10010           else
10011             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
10012
10013           goto release;
10014         }
10015
10016       /* the right is also a bit variable */
10017       if (AOP_TYPE (right) == AOP_CRY)
10018         {
10019           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10020           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
10021           goto release;
10022         }
10023
10024       /* we need to or */
10025       toBoolean (right);
10026       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
10027       goto release;
10028     }
10029
10030
10031   /* if they are the same size : or less */
10032   if (AOP_SIZE (result) <= AOP_SIZE (right))
10033     {
10034
10035       /* if they are in the same place */
10036       if (sameRegs (AOP (right), AOP (result)))
10037         goto release;
10038
10039       /* if they in different places then copy */
10040       size = AOP_SIZE (result);
10041       offset = 0;
10042       while (size--)
10043         {
10044           aopPut (AOP (result),
10045                   aopGet (AOP (right), offset, FALSE, FALSE),
10046                   offset,
10047                   isOperandVolatile (result, FALSE));
10048           offset++;
10049         }
10050       goto release;
10051     }
10052
10053
10054   /* if the result is of type pointer */
10055   if (IS_PTR (ctype))
10056     {
10057
10058       int p_type;
10059       sym_link *type = operandType (right);
10060       sym_link *etype = getSpec (type);
10061
10062       /* pointer to generic pointer */
10063       if (IS_GENPTR (ctype))
10064         {
10065           if (IS_PTR (type))
10066             p_type = DCL_TYPE (type);
10067           else
10068             {
10069               if (SPEC_SCLS(etype)==S_REGISTER) {
10070                 // let's assume it is a generic pointer
10071                 p_type=GPOINTER;
10072               } else {
10073                 /* we have to go by the storage class */
10074                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10075               }
10076             }
10077
10078           /* the first two bytes are known */
10079           size = GPTRSIZE - 1;
10080           offset = 0;
10081           while (size--)
10082             {
10083               aopPut (AOP (result),
10084                       aopGet (AOP (right), offset, FALSE, FALSE),
10085                       offset,
10086                       isOperandVolatile (result, FALSE));
10087               offset++;
10088             }
10089           /* the last byte depending on type */
10090             {
10091                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10092                 char gpValStr[10];
10093
10094                 if (gpVal == -1)
10095                 {
10096                     // pointerTypeToGPByte will have bitched.
10097                     exit(1);
10098                 }
10099
10100                 sprintf(gpValStr, "#0x%d", gpVal);
10101                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10102             }
10103           goto release;
10104         }
10105
10106       /* just copy the pointers */
10107       size = AOP_SIZE (result);
10108       offset = 0;
10109       while (size--)
10110         {
10111           aopPut (AOP (result),
10112                   aopGet (AOP (right), offset, FALSE, FALSE),
10113                   offset,
10114                   isOperandVolatile (result, FALSE));
10115           offset++;
10116         }
10117       goto release;
10118     }
10119
10120   /* so we now know that the size of destination is greater
10121      than the size of the source */
10122   /* we move to result for the size of source */
10123   size = AOP_SIZE (right);
10124   offset = 0;
10125   while (size--)
10126     {
10127       aopPut (AOP (result),
10128               aopGet (AOP (right), offset, FALSE, FALSE),
10129               offset,
10130               isOperandVolatile (result, FALSE));
10131       offset++;
10132     }
10133
10134   /* now depending on the sign of the source && destination */
10135   size = AOP_SIZE (result) - AOP_SIZE (right);
10136   /* if unsigned or not an integral type */
10137   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10138     {
10139       while (size--)
10140         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
10141     }
10142   else
10143     {
10144       /* we need to extend the sign :{ */
10145       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
10146                         FALSE, FALSE);
10147       MOVA (l);
10148       emitcode ("rlc", "a");
10149       emitcode ("subb", "a,acc");
10150       while (size--)
10151         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
10152     }
10153
10154   /* we are done hurray !!!! */
10155
10156 release:
10157   freeAsmop (right, NULL, ic, TRUE);
10158   freeAsmop (result, NULL, ic, TRUE);
10159
10160 }
10161
10162 /*-----------------------------------------------------------------*/
10163 /* genDjnz - generate decrement & jump if not zero instrucion      */
10164 /*-----------------------------------------------------------------*/
10165 static int
10166 genDjnz (iCode * ic, iCode * ifx)
10167 {
10168   symbol *lbl, *lbl1;
10169   if (!ifx)
10170     return 0;
10171
10172   D(emitcode (";     genDjnz",""));
10173
10174   /* if the if condition has a false label
10175      then we cannot save */
10176   if (IC_FALSE (ifx))
10177     return 0;
10178
10179   /* if the minus is not of the form
10180      a = a - 1 */
10181   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10182       !IS_OP_LITERAL (IC_RIGHT (ic)))
10183     return 0;
10184
10185   if (operandLitValue (IC_RIGHT (ic)) != 1)
10186     return 0;
10187
10188   /* if the size of this greater than one then no
10189      saving */
10190   if (getSize (operandType (IC_RESULT (ic))) > 1)
10191     return 0;
10192
10193   /* otherwise we can save BIG */
10194   lbl = newiTempLabel (NULL);
10195   lbl1 = newiTempLabel (NULL);
10196
10197   aopOp (IC_RESULT (ic), ic, FALSE);
10198
10199   if (AOP_NEEDSACC(IC_RESULT(ic)))
10200   {
10201       /* If the result is accessed indirectly via
10202        * the accumulator, we must explicitly write
10203        * it back after the decrement.
10204        */
10205       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
10206
10207       if (strcmp(rByte, "a"))
10208       {
10209            /* Something is hopelessly wrong */
10210            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10211                    __FILE__, __LINE__);
10212            /* We can just give up; the generated code will be inefficient,
10213             * but what the hey.
10214             */
10215            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10216            return 0;
10217       }
10218       emitcode ("dec", "%s", rByte);
10219       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10220       emitcode ("jnz", "%05d$", lbl->key + 100);
10221   }
10222   else if (IS_AOP_PREG (IC_RESULT (ic)))
10223     {
10224       emitcode ("dec", "%s",
10225                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
10226       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
10227       emitcode ("jnz", "%05d$", lbl->key + 100);
10228     }
10229   else
10230     {
10231       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
10232                 lbl->key + 100);
10233     }
10234   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10235   emitcode ("", "%05d$:", lbl->key + 100);
10236   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10237   emitcode ("", "%05d$:", lbl1->key + 100);
10238
10239   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10240   ifx->generated = 1;
10241   return 1;
10242 }
10243
10244 /*-----------------------------------------------------------------*/
10245 /* genReceive - generate code for a receive iCode                  */
10246 /*-----------------------------------------------------------------*/
10247 static void
10248 genReceive (iCode * ic)
10249 {
10250     int size = getSize (operandType (IC_RESULT (ic)));
10251     int offset = 0;
10252   D(emitcode (";     genReceive",""));
10253
10254   if (ic->argreg == 1) { /* first parameter */
10255       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10256           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10257            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
10258
10259           regs *tempRegs[4];
10260           int receivingA = 0;
10261           int roffset = 0;
10262
10263           for (offset = 0; offset<size; offset++)
10264             if (!strcmp (fReturn[offset], "a"))
10265               receivingA = 1;
10266
10267           if (!receivingA)
10268             {
10269               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10270                 {
10271                   for (offset = size-1; offset>0; offset--)
10272                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10273                   emitcode("mov","a,%s", fReturn[0]);
10274                   _G.accInUse++;
10275                   aopOp (IC_RESULT (ic), ic, FALSE);
10276                   _G.accInUse--;
10277                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
10278                           isOperandVolatile (IC_RESULT (ic), FALSE));
10279                   for (offset = 1; offset<size; offset++)
10280                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
10281                             isOperandVolatile (IC_RESULT (ic), FALSE));
10282                   goto release;
10283                 }
10284             }
10285           else
10286             {
10287               if (getTempRegs(tempRegs, size, ic))
10288                 {
10289                   for (offset = 0; offset<size; offset++)
10290                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10291                   aopOp (IC_RESULT (ic), ic, FALSE);
10292                   for (offset = 0; offset<size; offset++)
10293                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
10294                             isOperandVolatile (IC_RESULT (ic), FALSE));
10295                   goto release;
10296                 }
10297             }
10298
10299           offset = fReturnSizeMCS51 - size;
10300           while (size--) {
10301               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10302                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10303               offset++;
10304           }
10305           aopOp (IC_RESULT (ic), ic, FALSE);
10306           size = AOP_SIZE (IC_RESULT (ic));
10307           offset = 0;
10308           while (size--) {
10309               emitcode ("pop", "acc");
10310               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10311           }
10312
10313       } else {
10314           _G.accInUse++;
10315           aopOp (IC_RESULT (ic), ic, FALSE);
10316           _G.accInUse--;
10317           assignResultValue (IC_RESULT (ic));
10318       }
10319   } else { /* second receive onwards */
10320       int rb1off ;
10321       aopOp (IC_RESULT (ic), ic, FALSE);
10322       rb1off = ic->argreg;
10323       while (size--) {
10324           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10325       }
10326   }
10327
10328 release:
10329   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10330 }
10331
10332 /*-----------------------------------------------------------------*/
10333 /* genDummyRead - generate code for dummy read of volatiles        */
10334 /*-----------------------------------------------------------------*/
10335 static void
10336 genDummyRead (iCode * ic)
10337 {
10338   operand *op;
10339   int size, offset;
10340
10341   D(emitcode(";     genDummyRead",""));
10342
10343   op = IC_RIGHT (ic);
10344   if (op && IS_SYMOP (op))
10345     {
10346       aopOp (op, ic, FALSE);
10347
10348       /* if the result is a bit */
10349       if (AOP_TYPE (op) == AOP_CRY)
10350         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10351       else
10352         {
10353           /* bit variables done */
10354           /* general case */
10355           size = AOP_SIZE (op);
10356           offset = 0;
10357           while (size--)
10358           {
10359             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10360             offset++;
10361           }
10362         }
10363
10364       freeAsmop (op, NULL, ic, TRUE);
10365     }
10366
10367   op = IC_LEFT (ic);
10368   if (op && IS_SYMOP (op))
10369     {
10370       aopOp (op, ic, FALSE);
10371
10372       /* if the result is a bit */
10373       if (AOP_TYPE (op) == AOP_CRY)
10374         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10375       else
10376         {
10377           /* bit variables done */
10378           /* general case */
10379           size = AOP_SIZE (op);
10380           offset = 0;
10381           while (size--)
10382           {
10383             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10384             offset++;
10385           }
10386         }
10387
10388       freeAsmop (op, NULL, ic, TRUE);
10389     }
10390 }
10391
10392 /*-----------------------------------------------------------------*/
10393 /* genCritical - generate code for start of a critical sequence    */
10394 /*-----------------------------------------------------------------*/
10395 static void
10396 genCritical (iCode *ic)
10397 {
10398   symbol *tlbl = newiTempLabel (NULL);
10399
10400   D(emitcode(";     genCritical",""));
10401
10402   if (IC_RESULT (ic))
10403     {
10404       aopOp (IC_RESULT (ic), ic, TRUE);
10405       aopPut (AOP (IC_RESULT (ic)), one, 0, 0);
10406       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10407       aopPut (AOP (IC_RESULT (ic)), zero, 0, 0);
10408       emitcode ("", "%05d$:", (tlbl->key + 100));
10409       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10410     }
10411   else
10412     {
10413       emitcode ("setb", "c");
10414       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10415       emitcode ("clr", "c");
10416       emitcode ("", "%05d$:", (tlbl->key + 100));
10417       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10418     }
10419 }
10420
10421 /*-----------------------------------------------------------------*/
10422 /* genEndCritical - generate code for end of a critical sequence   */
10423 /*-----------------------------------------------------------------*/
10424 static void
10425 genEndCritical (iCode *ic)
10426 {
10427   D(emitcode(";     genEndCritical",""));
10428
10429   if (IC_RIGHT (ic))
10430     {
10431       aopOp (IC_RIGHT (ic), ic, FALSE);
10432       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10433         {
10434           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10435           emitcode ("mov", "ea,c");
10436         }
10437       else
10438         {
10439           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10440             MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
10441           emitcode ("rrc", "a");
10442           emitcode ("mov", "ea,c");
10443         }
10444       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10445     }
10446   else
10447     {
10448       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10449       emitcode ("mov", "ea,c");
10450     }
10451 }
10452
10453 /*-----------------------------------------------------------------*/
10454 /* gen51Code - generate code for 8051 based controllers            */
10455 /*-----------------------------------------------------------------*/
10456 void
10457 gen51Code (iCode * lic)
10458 {
10459   iCode *ic;
10460   int cln = 0;
10461   /* int cseq = 0; */
10462
10463   _G.currentFunc = NULL;
10464   lineHead = lineCurr = NULL;
10465
10466   /* print the allocation information */
10467   if (allocInfo && currFunc)
10468     printAllocInfo (currFunc, codeOutFile);
10469   /* if debug information required */
10470   if (options.debug && currFunc)
10471     {
10472       debugFile->writeFunction (currFunc, lic);
10473     }
10474   /* stack pointer name */
10475   if (options.useXstack)
10476     spname = "_spx";
10477   else
10478     spname = "sp";
10479
10480
10481   for (ic = lic; ic; ic = ic->next)
10482     {
10483       _G.current_iCode = ic;
10484
10485       if (ic->lineno && cln != ic->lineno)
10486         {
10487           if (options.debug)
10488             {
10489               debugFile->writeCLine (ic);
10490             }
10491           if (!options.noCcodeInAsm) {
10492             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10493                       printCLine(ic->filename, ic->lineno));
10494           }
10495           cln = ic->lineno;
10496         }
10497       #if 0
10498       if (ic->seqPoint && ic->seqPoint != cseq)
10499         {
10500           emitcode ("", "; sequence point %d", ic->seqPoint);
10501           cseq = ic->seqPoint;
10502         }
10503       #endif
10504       if (options.iCodeInAsm) {
10505         char regsInUse[80];
10506         int i;
10507
10508         for (i=0; i<8; i++) {
10509           sprintf (&regsInUse[i],
10510                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10511         }
10512         regsInUse[i]=0;
10513         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10514       }
10515       /* if the result is marked as
10516          spilt and rematerializable or code for
10517          this has already been generated then
10518          do nothing */
10519       if (resultRemat (ic) || ic->generated)
10520         continue;
10521
10522       /* depending on the operation */
10523       switch (ic->op)
10524         {
10525         case '!':
10526           genNot (ic);
10527           break;
10528
10529         case '~':
10530           genCpl (ic);
10531           break;
10532
10533         case UNARYMINUS:
10534           genUminus (ic);
10535           break;
10536
10537         case IPUSH:
10538           genIpush (ic);
10539           break;
10540
10541         case IPOP:
10542           /* IPOP happens only when trying to restore a
10543              spilt live range, if there is an ifx statement
10544              following this pop then the if statement might
10545              be using some of the registers being popped which
10546              would destory the contents of the register so
10547              we need to check for this condition and handle it */
10548           if (ic->next &&
10549               ic->next->op == IFX &&
10550               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10551             genIfx (ic->next, ic);
10552           else
10553             genIpop (ic);
10554           break;
10555
10556         case CALL:
10557           genCall (ic);
10558           break;
10559
10560         case PCALL:
10561           genPcall (ic);
10562           break;
10563
10564         case FUNCTION:
10565           genFunction (ic);
10566           break;
10567
10568         case ENDFUNCTION:
10569           genEndFunction (ic);
10570           break;
10571
10572         case RETURN:
10573           genRet (ic);
10574           break;
10575
10576         case LABEL:
10577           genLabel (ic);
10578           break;
10579
10580         case GOTO:
10581           genGoto (ic);
10582           break;
10583
10584         case '+':
10585           genPlus (ic);
10586           break;
10587
10588         case '-':
10589           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10590             genMinus (ic);
10591           break;
10592
10593         case '*':
10594           genMult (ic);
10595           break;
10596
10597         case '/':
10598           genDiv (ic);
10599           break;
10600
10601         case '%':
10602           genMod (ic);
10603           break;
10604
10605         case '>':
10606           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10607           break;
10608
10609         case '<':
10610           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10611           break;
10612
10613         case LE_OP:
10614         case GE_OP:
10615         case NE_OP:
10616
10617           /* note these two are xlated by algebraic equivalence
10618              during parsing SDCC.y */
10619           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10620                   "got '>=' or '<=' shouldn't have come here");
10621           break;
10622
10623         case EQ_OP:
10624           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10625           break;
10626
10627         case AND_OP:
10628           genAndOp (ic);
10629           break;
10630
10631         case OR_OP:
10632           genOrOp (ic);
10633           break;
10634
10635         case '^':
10636           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10637           break;
10638
10639         case '|':
10640           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10641           break;
10642
10643         case BITWISEAND:
10644           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10645           break;
10646
10647         case INLINEASM:
10648           genInline (ic);
10649           break;
10650
10651         case RRC:
10652           genRRC (ic);
10653           break;
10654
10655         case RLC:
10656           genRLC (ic);
10657           break;
10658
10659         case GETHBIT:
10660           genGetHbit (ic);
10661           break;
10662
10663         case LEFT_OP:
10664           genLeftShift (ic);
10665           break;
10666
10667         case RIGHT_OP:
10668           genRightShift (ic);
10669           break;
10670
10671         case GET_VALUE_AT_ADDRESS:
10672           genPointerGet (ic,
10673                          hasInc (IC_LEFT (ic), ic,
10674                                  getSize (operandType (IC_RESULT (ic)))),
10675                          ifxForOp (IC_RESULT (ic), ic) );
10676           break;
10677
10678         case '=':
10679           if (POINTER_SET (ic))
10680             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10681           else
10682             genAssign (ic);
10683           break;
10684
10685         case IFX:
10686           genIfx (ic, NULL);
10687           break;
10688
10689         case ADDRESS_OF:
10690           genAddrOf (ic);
10691           break;
10692
10693         case JUMPTABLE:
10694           genJumpTab (ic);
10695           break;
10696
10697         case CAST:
10698           genCast (ic);
10699           break;
10700
10701         case RECEIVE:
10702           genReceive (ic);
10703           break;
10704
10705         case SEND:
10706           addSet (&_G.sendSet, ic);
10707           break;
10708
10709         case DUMMY_READ_VOLATILE:
10710           genDummyRead (ic);
10711           break;
10712
10713         case CRITICAL:
10714           genCritical (ic);
10715           break;
10716
10717         case ENDCRITICAL:
10718           genEndCritical (ic);
10719           break;
10720
10721         case SWAP:
10722           genSwap (ic);
10723           break;
10724
10725         default:
10726           ic = ic;
10727         }
10728     }
10729
10730   _G.current_iCode = NULL;
10731
10732   /* now we are ready to call the
10733      peep hole optimizer */
10734   if (!options.nopeep)
10735     peepHole (&lineHead);
10736
10737   /* now do the actual printing */
10738   printLine (lineHead, codeOutFile);
10739   return;
10740 }