* device/include/malloc.h: removed redundant __reentrant prototypes
[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       return TRUE;
1111     case AOP_LIT:
1112       return FALSE;
1113     case AOP_STR:
1114       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1115         return TRUE;
1116       return FALSE;
1117     case AOP_DUMMY:
1118       return FALSE;
1119     default:
1120       /* Error case --- will have been caught already */
1121       wassert(0);
1122       return FALSE;
1123     }
1124 }
1125
1126 /*-----------------------------------------------------------------*/
1127 /* aopGet - for fetching value of the aop                          */
1128 /*-----------------------------------------------------------------*/
1129 static char *
1130 aopGet (asmop * aop, int offset, bool bit16, bool dname)
1131 {
1132   char *s = buffer;
1133   char *rs;
1134
1135   /* offset is greater than
1136      size then zero */
1137   if (offset > (aop->size - 1) &&
1138       aop->type != AOP_LIT)
1139     return zero;
1140
1141   /* depending on type */
1142   switch (aop->type)
1143     {
1144     case AOP_DUMMY:
1145       return zero;
1146
1147     case AOP_R0:
1148     case AOP_R1:
1149       /* if we need to increment it */
1150       while (offset > aop->coff)
1151         {
1152           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1153           aop->coff++;
1154         }
1155
1156       while (offset < aop->coff)
1157         {
1158           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1159           aop->coff--;
1160         }
1161
1162       aop->coff = offset;
1163       if (aop->paged)
1164         {
1165           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1166           return (dname ? "acc" : "a");
1167         }
1168       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1169       rs = Safe_calloc (1, strlen (s) + 1);
1170       strcpy (rs, s);
1171       return rs;
1172
1173     case AOP_DPTR:
1174       if (aop->code && aop->coff==0 && offset>=1) {
1175         emitcode ("mov", "a,#0x%02x", offset);
1176         emitcode ("movc", "a,@a+dptr");
1177         return (dname ? "acc" : "a");
1178       }
1179
1180       while (offset > aop->coff)
1181         {
1182           emitcode ("inc", "dptr");
1183           aop->coff++;
1184         }
1185
1186       while (offset < aop->coff)
1187         {
1188           emitcode ("lcall", "__decdptr");
1189           aop->coff--;
1190         }
1191
1192       aop->coff = offset;
1193       if (aop->code)
1194         {
1195           emitcode ("clr", "a");
1196           emitcode ("movc", "a,@a+dptr");
1197         }
1198       else
1199         {
1200           emitcode ("movx", "a,@dptr");
1201         }
1202       return (dname ? "acc" : "a");
1203
1204
1205     case AOP_IMMD:
1206       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1207               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1208       } else if (bit16)
1209         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1210       else if (offset)
1211         sprintf (s, "#(%s >> %d)",
1212                  aop->aopu.aop_immd.aop_immd1,
1213                  offset * 8);
1214       else
1215         sprintf (s, "#%s",
1216                  aop->aopu.aop_immd.aop_immd1);
1217       rs = Safe_calloc (1, strlen (s) + 1);
1218       strcpy (rs, s);
1219       return rs;
1220
1221     case AOP_DIR:
1222       if (offset)
1223         sprintf (s, "(%s + %d)",
1224                  aop->aopu.aop_dir,
1225                  offset);
1226       else
1227         sprintf (s, "%s", aop->aopu.aop_dir);
1228       rs = Safe_calloc (1, strlen (s) + 1);
1229       strcpy (rs, s);
1230       return rs;
1231
1232     case AOP_REG:
1233       if (dname)
1234         return aop->aopu.aop_reg[offset]->dname;
1235       else
1236         return aop->aopu.aop_reg[offset]->name;
1237
1238     case AOP_CRY:
1239       emitcode ("clr", "a");
1240       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1241       emitcode ("rlc", "a");
1242       return (dname ? "acc" : "a");
1243
1244     case AOP_ACC:
1245       if (!offset && dname)
1246         return "acc";
1247       return aop->aopu.aop_str[offset];
1248
1249     case AOP_LIT:
1250       return aopLiteral (aop->aopu.aop_lit, offset);
1251
1252     case AOP_STR:
1253       aop->coff = offset;
1254       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1255           dname)
1256         return "acc";
1257
1258       return aop->aopu.aop_str[offset];
1259
1260     }
1261
1262   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1263           "aopget got unsupported aop->type");
1264   exit (1);
1265 }
1266 /*-----------------------------------------------------------------*/
1267 /* aopPut - puts a string for a aop and indicates if acc is in use */
1268 /*-----------------------------------------------------------------*/
1269 static bool
1270 aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
1271 {
1272   char *d = buffer;
1273   bool accuse = FALSE;
1274
1275   if (aop->size && offset > (aop->size - 1))
1276     {
1277       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1278               "aopPut got offset > aop->size");
1279       exit (1);
1280     }
1281
1282   /* will assign value to value */
1283   /* depending on where it is ofcourse */
1284   switch (aop->type)
1285     {
1286     case AOP_DUMMY:
1287       MOVA (s);         /* read s in case it was volatile */
1288       accuse = TRUE;
1289       break;
1290
1291     case AOP_DIR:
1292       if (offset)
1293         sprintf (d, "(%s + %d)",
1294                  aop->aopu.aop_dir, offset);
1295       else
1296         sprintf (d, "%s", aop->aopu.aop_dir);
1297
1298       if (strcmp (d, s) ||
1299           bvolatile)
1300           emitcode ("mov", "%s,%s", d, s);
1301       if (!strcmp (d, "acc"))
1302           accuse = TRUE;
1303
1304       break;
1305
1306     case AOP_REG:
1307       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1308           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1309         {
1310           if (*s == '@' ||
1311               strcmp (s, "r0") == 0 ||
1312               strcmp (s, "r1") == 0 ||
1313               strcmp (s, "r2") == 0 ||
1314               strcmp (s, "r3") == 0 ||
1315               strcmp (s, "r4") == 0 ||
1316               strcmp (s, "r5") == 0 ||
1317               strcmp (s, "r6") == 0 ||
1318               strcmp (s, "r7") == 0)
1319             emitcode ("mov", "%s,%s",
1320                       aop->aopu.aop_reg[offset]->dname, s);
1321           else
1322             emitcode ("mov", "%s,%s",
1323                       aop->aopu.aop_reg[offset]->name, s);
1324         }
1325       break;
1326
1327     case AOP_DPTR:
1328       if (aop->code)
1329         {
1330           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1331                   "aopPut writing to code space");
1332           exit (1);
1333         }
1334
1335       while (offset > aop->coff)
1336         {
1337           aop->coff++;
1338           emitcode ("inc", "dptr");
1339         }
1340
1341       while (offset < aop->coff)
1342         {
1343           aop->coff--;
1344           emitcode ("lcall", "__decdptr");
1345         }
1346
1347       aop->coff = offset;
1348
1349       /* if not in accumulator */
1350       MOVA (s);
1351
1352       emitcode ("movx", "@dptr,a");
1353       break;
1354
1355     case AOP_R0:
1356     case AOP_R1:
1357       while (offset > aop->coff)
1358         {
1359           aop->coff++;
1360           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1361         }
1362       while (offset < aop->coff)
1363         {
1364           aop->coff--;
1365           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1366         }
1367       aop->coff = offset;
1368
1369       if (aop->paged)
1370         {
1371           MOVA (s);
1372           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1373
1374         }
1375       else if (*s == '@')
1376         {
1377           MOVA (s);
1378           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1379         }
1380       else if (strcmp (s, "r0") == 0 ||
1381                strcmp (s, "r1") == 0 ||
1382                strcmp (s, "r2") == 0 ||
1383                strcmp (s, "r3") == 0 ||
1384                strcmp (s, "r4") == 0 ||
1385                strcmp (s, "r5") == 0 ||
1386                strcmp (s, "r6") == 0 ||
1387                strcmp (s, "r7") == 0)
1388         {
1389           char buffer[10];
1390           sprintf (buffer, "a%s", s);
1391           emitcode ("mov", "@%s,%s",
1392                     aop->aopu.aop_ptr->name, buffer);
1393         }
1394       else
1395         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1396
1397       break;
1398
1399     case AOP_STK:
1400       if (strcmp (s, "a") == 0)
1401         emitcode ("push", "acc");
1402       else
1403         if (*s=='@') {
1404           MOVA(s);
1405           emitcode ("push", "acc");
1406         } else {
1407           emitcode ("push", s);
1408         }
1409
1410       break;
1411
1412     case AOP_CRY:
1413       /* if not bit variable */
1414       if (!aop->aopu.aop_dir)
1415         {
1416           /* inefficient: move carry into A and use jz/jnz */
1417           emitcode ("clr", "a");
1418           emitcode ("rlc", "a");
1419           accuse = TRUE;
1420         }
1421       else
1422         {
1423           if (s == zero)
1424             emitcode ("clr", "%s", aop->aopu.aop_dir);
1425           else if (s == one)
1426             emitcode ("setb", "%s", aop->aopu.aop_dir);
1427           else if (!strcmp (s, "c"))
1428             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1429           else
1430             {
1431               MOVA (s);
1432               /* set C, if a >= 1 */
1433               emitcode ("add", "a,#0xff");
1434               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1435             }
1436         }
1437       break;
1438
1439     case AOP_STR:
1440       aop->coff = offset;
1441       if (strcmp (aop->aopu.aop_str[offset], s) ||
1442           bvolatile)
1443         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1444       break;
1445
1446     case AOP_ACC:
1447       accuse = TRUE;
1448       aop->coff = offset;
1449       if (!offset && (strcmp (s, "acc") == 0) &&
1450           !bvolatile)
1451         break;
1452
1453       if (strcmp (aop->aopu.aop_str[offset], s) &&
1454           !bvolatile)
1455         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1456       break;
1457
1458     default:
1459       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1460               "aopPut got unsupported aop->type");
1461       exit (1);
1462     }
1463
1464     return accuse;
1465 }
1466
1467
1468 #if 0
1469 /*-----------------------------------------------------------------*/
1470 /* pointToEnd :- points to the last byte of the operand            */
1471 /*-----------------------------------------------------------------*/
1472 static void
1473 pointToEnd (asmop * aop)
1474 {
1475   int count;
1476   if (!aop)
1477     return;
1478
1479   aop->coff = count = (aop->size - 1);
1480   switch (aop->type)
1481     {
1482     case AOP_R0:
1483     case AOP_R1:
1484       while (count--)
1485         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1486       break;
1487     case AOP_DPTR:
1488       while (count--)
1489         emitcode ("inc", "dptr");
1490       break;
1491     }
1492
1493 }
1494 #endif
1495
1496 /*-----------------------------------------------------------------*/
1497 /* reAdjustPreg - points a register back to where it should        */
1498 /*-----------------------------------------------------------------*/
1499 static void
1500 reAdjustPreg (asmop * aop)
1501 {
1502   if ((aop->coff==0) || aop->size <= 1)
1503     return;
1504
1505   switch (aop->type)
1506     {
1507     case AOP_R0:
1508     case AOP_R1:
1509       while (aop->coff--)
1510         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1511       break;
1512     case AOP_DPTR:
1513       while (aop->coff--)
1514         {
1515           emitcode ("lcall", "__decdptr");
1516         }
1517       break;
1518     }
1519   aop->coff = 0;
1520 }
1521
1522 #define AOP(op) op->aop
1523 #define AOP_TYPE(op) AOP(op)->type
1524 #define AOP_SIZE(op) AOP(op)->size
1525 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1526                        AOP_TYPE(x) == AOP_R0))
1527
1528 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1529                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
1530
1531 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1532                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
1533                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
1534
1535
1536 /*-----------------------------------------------------------------*/
1537 /* opIsGptr: returns non-zero if the passed operand is       */
1538 /* a generic pointer type.             */
1539 /*-----------------------------------------------------------------*/
1540 static int
1541 opIsGptr (operand * op)
1542 {
1543   sym_link *type = operandType (op);
1544
1545   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1546     {
1547       return 1;
1548     }
1549   return 0;
1550 }
1551
1552 /*-----------------------------------------------------------------*/
1553 /* getDataSize - get the operand data size                         */
1554 /*-----------------------------------------------------------------*/
1555 static int
1556 getDataSize (operand * op)
1557 {
1558   int size;
1559   size = AOP_SIZE (op);
1560   if (size == GPTRSIZE)
1561     {
1562       sym_link *type = operandType (op);
1563       if (IS_GENPTR (type))
1564         {
1565           /* generic pointer; arithmetic operations
1566            * should ignore the high byte (pointer type).
1567            */
1568           size--;
1569         }
1570     }
1571   return size;
1572 }
1573
1574 /*-----------------------------------------------------------------*/
1575 /* outAcc - output Acc                                             */
1576 /*-----------------------------------------------------------------*/
1577 static void
1578 outAcc (operand * result)
1579 {
1580   int size, offset;
1581   size = getDataSize (result);
1582   if (size)
1583     {
1584       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
1585       size--;
1586       offset = 1;
1587       /* unsigned or positive */
1588       while (size--)
1589         {
1590           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
1591         }
1592     }
1593 }
1594
1595 /*-----------------------------------------------------------------*/
1596 /* outBitC - output a bit C                                        */
1597 /*-----------------------------------------------------------------*/
1598 static void
1599 outBitC (operand * result)
1600 {
1601   /* if the result is bit */
1602   if (AOP_TYPE (result) == AOP_CRY)
1603     aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
1604   else
1605     {
1606       emitcode ("clr", "a");
1607       emitcode ("rlc", "a");
1608       outAcc (result);
1609     }
1610 }
1611
1612 /*-----------------------------------------------------------------*/
1613 /* toBoolean - emit code for orl a,operator(sizeop)                */
1614 /*-----------------------------------------------------------------*/
1615 static void
1616 toBoolean (operand * oper)
1617 {
1618   int size = AOP_SIZE (oper) - 1;
1619   int offset = 1;
1620   bool AccUsed = FALSE;
1621   bool pushedB;
1622
1623   while (!AccUsed && size--)
1624     {
1625       AccUsed |= aopGetUsesAcc(AOP (oper), offset++);
1626     }
1627
1628   size = AOP_SIZE (oper) - 1;
1629   offset = 1;
1630   MOVA (aopGet (AOP (oper), 0, FALSE, FALSE));
1631   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1632     {
1633       pushedB = pushB ();
1634       emitcode("mov", "b,a");
1635       while (--size)
1636         {
1637           MOVA (aopGet (AOP (oper), offset++, FALSE, FALSE));
1638           emitcode ("orl", "b,a");
1639         }
1640       MOVA (aopGet (AOP (oper), offset++, FALSE, FALSE));
1641       emitcode ("orl", "a,b");
1642       popB (pushedB);
1643     }
1644   else
1645     {
1646       while (size--)
1647         {
1648           emitcode ("orl", "a,%s", aopGet (AOP (oper), offset++, FALSE, FALSE));
1649         }
1650     }
1651 }
1652
1653
1654 /*-----------------------------------------------------------------*/
1655 /* genNot - generate code for ! operation                          */
1656 /*-----------------------------------------------------------------*/
1657 static void
1658 genNot (iCode * ic)
1659 {
1660   symbol *tlbl;
1661
1662   D(emitcode (";     genNot",""));
1663
1664   /* assign asmOps to operand & result */
1665   aopOp (IC_LEFT (ic), ic, FALSE);
1666   aopOp (IC_RESULT (ic), ic, TRUE);
1667
1668   /* if in bit space then a special case */
1669   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1670     {
1671       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1672       emitcode ("cpl", "c");
1673       outBitC (IC_RESULT (ic));
1674       goto release;
1675     }
1676
1677   toBoolean (IC_LEFT (ic));
1678
1679   tlbl = newiTempLabel (NULL);
1680   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1681   emitcode ("", "%05d$:", tlbl->key + 100);
1682   outBitC (IC_RESULT (ic));
1683
1684 release:
1685   /* release the aops */
1686   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1687   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1688 }
1689
1690
1691 /*-----------------------------------------------------------------*/
1692 /* genCpl - generate code for complement                           */
1693 /*-----------------------------------------------------------------*/
1694 static void
1695 genCpl (iCode * ic)
1696 {
1697   int offset = 0;
1698   int size;
1699   symbol *tlbl;
1700   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1701
1702   D(emitcode (";", "genCpl"));
1703
1704   /* assign asmOps to operand & result */
1705   aopOp (IC_LEFT (ic), ic, FALSE);
1706   aopOp (IC_RESULT (ic), ic, TRUE);
1707
1708   /* special case if in bit space */
1709   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1710     {
1711       char *l;
1712
1713       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1714           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1715         {
1716           /* promotion rules are responsible for this strange result:
1717              bit -> int -> ~int -> bit
1718              uchar -> int -> ~int -> bit
1719           */
1720           werror(W_COMPLEMENT);
1721           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1722           goto release;
1723         }
1724
1725       tlbl=newiTempLabel(NULL);
1726       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, FALSE);
1727       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC ||
1728           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1729           IS_AOP_PREG (IC_LEFT (ic)))
1730         {
1731           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1732         }
1733       else
1734         {
1735           MOVA (l);
1736           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1737         }
1738       emitcode ("", "%05d$:", tlbl->key + 100);
1739       outBitC (IC_RESULT(ic));
1740       goto release;
1741     }
1742
1743   size = AOP_SIZE (IC_RESULT (ic));
1744   while (size--)
1745     {
1746       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1747       MOVA (l);
1748       emitcode ("cpl", "a");
1749       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1750     }
1751
1752
1753 release:
1754   /* release the aops */
1755   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1756   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1757 }
1758
1759 /*-----------------------------------------------------------------*/
1760 /* genUminusFloat - unary minus for floating points                */
1761 /*-----------------------------------------------------------------*/
1762 static void
1763 genUminusFloat (operand * op, operand * result)
1764 {
1765   int size, offset = 0;
1766   char *l;
1767
1768   D(emitcode (";     genUminusFloat",""));
1769
1770   /* for this we just copy and then flip the bit */
1771
1772   size = AOP_SIZE (op) - 1;
1773
1774   while (size--)
1775     {
1776       aopPut (AOP (result),
1777               aopGet (AOP (op), offset, FALSE, FALSE),
1778               offset,
1779               isOperandVolatile (result, FALSE));
1780       offset++;
1781     }
1782
1783   l = aopGet (AOP (op), offset, FALSE, FALSE);
1784
1785   MOVA (l);
1786
1787   emitcode ("cpl", "acc.7");
1788   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
1789 }
1790
1791 /*-----------------------------------------------------------------*/
1792 /* genUminus - unary minus code generation                         */
1793 /*-----------------------------------------------------------------*/
1794 static void
1795 genUminus (iCode * ic)
1796 {
1797   int offset, size;
1798   sym_link *optype, *rtype;
1799
1800
1801   D(emitcode (";     genUminus",""));
1802
1803   /* assign asmops */
1804   aopOp (IC_LEFT (ic), ic, FALSE);
1805   aopOp (IC_RESULT (ic), ic, TRUE);
1806
1807   /* if both in bit space then special
1808      case */
1809   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1810       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1811     {
1812
1813       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1814       emitcode ("cpl", "c");
1815       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1816       goto release;
1817     }
1818
1819   optype = operandType (IC_LEFT (ic));
1820   rtype = operandType (IC_RESULT (ic));
1821
1822   /* if float then do float stuff */
1823   if (IS_FLOAT (optype))
1824     {
1825       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1826       goto release;
1827     }
1828
1829   /* otherwise subtract from zero */
1830   size = AOP_SIZE (IC_LEFT (ic));
1831   offset = 0;
1832   //CLRC ;
1833   while (size--)
1834     {
1835       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1836       if (!strcmp (l, "a"))
1837         {
1838           if (offset == 0)
1839             SETC;
1840           emitcode ("cpl", "a");
1841           emitcode ("addc", "a,#0");
1842         }
1843       else
1844         {
1845           if (offset == 0)
1846             CLRC;
1847           emitcode ("clr", "a");
1848           emitcode ("subb", "a,%s", l);
1849         }
1850       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1851     }
1852
1853   /* if any remaining bytes in the result */
1854   /* we just need to propagate the sign   */
1855   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1856     {
1857       emitcode ("rlc", "a");
1858       emitcode ("subb", "a,acc");
1859       while (size--)
1860         aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1861     }
1862
1863 release:
1864   /* release the aops */
1865   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1866   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1867 }
1868
1869 /*-----------------------------------------------------------------*/
1870 /* saveRegisters - will look for a call and save the registers     */
1871 /*-----------------------------------------------------------------*/
1872 static void
1873 saveRegisters (iCode * lic)
1874 {
1875   int i;
1876   iCode *ic;
1877   bitVect *rsave;
1878
1879   /* look for call */
1880   for (ic = lic; ic; ic = ic->next)
1881     if (ic->op == CALL || ic->op == PCALL)
1882       break;
1883
1884   if (!ic)
1885     {
1886       fprintf (stderr, "found parameter push with no function call\n");
1887       return;
1888     }
1889
1890   /* if the registers have been saved already or don't need to be then
1891      do nothing */
1892   if (ic->regsSaved)
1893     return;
1894   if (IS_SYMOP(IC_LEFT(ic)) &&
1895       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1896        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1897     return;
1898
1899   /* save the registers in use at this time but skip the
1900      ones for the result */
1901   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1902                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1903
1904   ic->regsSaved = 1;
1905   if (options.useXstack)
1906     {
1907       int count = bitVectnBitsOn (rsave);
1908
1909       if (count == 1)
1910         {
1911           i = bitVectFirstBit (rsave);
1912           emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1913           emitcode ("mov", "r0,%s", spname);
1914           emitcode ("inc", "%s", spname);// allocate before use
1915           emitcode ("movx", "@r0,a");
1916           if (bitVectBitValue (rsave, R0_IDX))
1917             emitcode ("mov", "r0,a");
1918         }
1919       else if (count != 0)
1920         {
1921           if (bitVectBitValue (rsave, R0_IDX))
1922             {
1923               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1924             }
1925           emitcode ("mov", "r0,%s", spname);
1926           MOVA ("r0");
1927           emitcode ("add", "a,#%d", count);
1928           emitcode ("mov", "%s,a", spname);
1929           for (i = 0; i < mcs51_nRegs; i++)
1930             {
1931               if (bitVectBitValue (rsave, i))
1932                 {
1933                   if (i == R0_IDX)
1934                     {
1935                       emitcode ("pop", "acc");
1936                       emitcode ("push", "acc");
1937                     }
1938                   else
1939                     {
1940                       emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1941                     }
1942                   emitcode ("movx", "@r0,a");
1943                   if (--count)
1944                     {
1945                       emitcode ("inc", "r0");
1946                     }
1947                 }
1948             }
1949           if (bitVectBitValue (rsave, R0_IDX))
1950             {
1951               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1952             }
1953         }
1954     }
1955   else
1956     for (i = 0; i < mcs51_nRegs; i++)
1957       {
1958         if (bitVectBitValue (rsave, i))
1959           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1960       }
1961 }
1962
1963 /*-----------------------------------------------------------------*/
1964 /* unsaveRegisters - pop the pushed registers                      */
1965 /*-----------------------------------------------------------------*/
1966 static void
1967 unsaveRegisters (iCode * ic)
1968 {
1969   int i;
1970   bitVect *rsave;
1971
1972   /* restore the registers in use at this time but skip the
1973      ones for the result */
1974   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1975                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1976
1977   if (options.useXstack)
1978     {
1979       int count = bitVectnBitsOn (rsave);
1980
1981       if (count == 1)
1982         {
1983           emitcode ("mov", "r0,%s", spname);
1984           emitcode ("dec", "r0");
1985           emitcode ("movx", "a,@r0");
1986           i = bitVectFirstBit (rsave);
1987           emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1988           emitcode ("dec", "%s", spname);
1989         }
1990       else if (count != 0)
1991         {
1992           emitcode ("mov", "r0,%s", spname);
1993           for (i = mcs51_nRegs; i >= 0; i--)
1994             {
1995               if (bitVectBitValue (rsave, i))
1996                 {
1997                   emitcode ("dec", "r0");
1998                   emitcode ("movx", "a,@r0");
1999                   if (i != R0_IDX)
2000                     emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
2001                   else
2002                     emitcode ("push", "acc");
2003                 }
2004             }
2005           emitcode ("mov", "%s,r0", spname);
2006           if (bitVectBitValue (rsave, R0_IDX))
2007             {
2008               emitcode ("pop", "ar0");
2009             }
2010         }
2011     }
2012   else
2013     for (i = mcs51_nRegs; i >= 0; i--)
2014       {
2015         if (bitVectBitValue (rsave, i))
2016           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2017       }
2018 }
2019
2020
2021 /*-----------------------------------------------------------------*/
2022 /* pushSide -                */
2023 /*-----------------------------------------------------------------*/
2024 static void
2025 pushSide (operand * oper, int size)
2026 {
2027   int offset = 0;
2028   while (size--)
2029     {
2030       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE);
2031       if (AOP_TYPE (oper) != AOP_REG &&
2032           AOP_TYPE (oper) != AOP_DIR &&
2033           strcmp (l, "a"))
2034         {
2035           MOVA (l);
2036           emitcode ("push", "acc");
2037         }
2038       else
2039           emitcode ("push", "%s", l);
2040         }
2041     }
2042
2043 /*-----------------------------------------------------------------*/
2044 /* assignResultValue - also indicates if acc is in use afterwards  */
2045 /*-----------------------------------------------------------------*/
2046 static bool
2047 assignResultValue (operand * oper)
2048 {
2049   int offset = 0;
2050   int size = AOP_SIZE (oper);
2051   bool accuse = FALSE;
2052
2053   while (size--)
2054     {
2055       accuse |= aopPut (AOP (oper), fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2056       offset++;
2057     }
2058   return accuse;
2059 }
2060
2061
2062 /*-----------------------------------------------------------------*/
2063 /* genXpush - pushes onto the external stack                       */
2064 /*-----------------------------------------------------------------*/
2065 static void
2066 genXpush (iCode * ic)
2067 {
2068   asmop *aop = newAsmop (0);
2069   regs *r;
2070   int size, offset = 0;
2071
2072   D(emitcode (";     genXpush",""));
2073
2074   aopOp (IC_LEFT (ic), ic, FALSE);
2075   r = getFreePtr (ic, &aop, FALSE);
2076
2077   size = AOP_SIZE (IC_LEFT (ic));
2078
2079   if (size == 1)
2080     {
2081       MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
2082       emitcode ("mov", "%s,%s", r->name, spname);
2083       emitcode ("inc", "%s", spname); // allocate space first
2084       emitcode ("movx", "@%s,a", r->name);
2085     }
2086   else
2087     {
2088       // allocate space first
2089       emitcode ("mov", "%s,%s", r->name, spname);
2090       MOVA (r->name);
2091       emitcode ("add", "a,#%d", size);
2092       emitcode ("mov", "%s,a", spname);
2093
2094       while (size--)
2095         {
2096           MOVA (aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, FALSE));
2097           emitcode ("movx", "@%s,a", r->name);
2098           emitcode ("inc", "%s", r->name);
2099         }
2100     }
2101
2102   freeAsmop (NULL, aop, ic, TRUE);
2103   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2104 }
2105
2106 /*-----------------------------------------------------------------*/
2107 /* genIpush - generate code for pushing this gets a little complex */
2108 /*-----------------------------------------------------------------*/
2109 static void
2110 genIpush (iCode * ic)
2111 {
2112   int size, offset = 0;
2113   char *l;
2114
2115   D(emitcode (";     genIpush",""));
2116
2117   /* if this is not a parm push : ie. it is spill push
2118      and spill push is always done on the local stack */
2119   if (!ic->parmPush)
2120     {
2121
2122       /* and the item is spilt then do nothing */
2123       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2124         return;
2125
2126       aopOp (IC_LEFT (ic), ic, FALSE);
2127       size = AOP_SIZE (IC_LEFT (ic));
2128       /* push it on the stack */
2129       while (size--)
2130         {
2131           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2132           if (*l == '#')
2133             {
2134               MOVA (l);
2135               l = "acc";
2136             }
2137           emitcode ("push", "%s", l);
2138         }
2139       return;
2140     }
2141
2142   /* this is a paramter push: in this case we call
2143      the routine to find the call and save those
2144      registers that need to be saved */
2145   saveRegisters (ic);
2146
2147   /* if use external stack then call the external
2148      stack pushing routine */
2149   if (options.useXstack)
2150     {
2151       genXpush (ic);
2152       return;
2153     }
2154
2155   /* then do the push */
2156   aopOp (IC_LEFT (ic), ic, FALSE);
2157
2158   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2159   size = AOP_SIZE (IC_LEFT (ic));
2160
2161   while (size--)
2162     {
2163       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2164       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2165           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2166           strcmp (l, "a"))
2167         {
2168           MOVA (l);
2169           emitcode ("push", "acc");
2170         }
2171       else
2172           emitcode ("push", "%s", l);
2173     }
2174
2175   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2176 }
2177
2178 /*-----------------------------------------------------------------*/
2179 /* genIpop - recover the registers: can happen only for spilling   */
2180 /*-----------------------------------------------------------------*/
2181 static void
2182 genIpop (iCode * ic)
2183 {
2184   int size, offset;
2185
2186   D(emitcode (";     genIpop",""));
2187
2188   /* if the temp was not pushed then */
2189   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2190     return;
2191
2192   aopOp (IC_LEFT (ic), ic, FALSE);
2193   size = AOP_SIZE (IC_LEFT (ic));
2194   offset = (size - 1);
2195   while (size--)
2196     emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2197                                    FALSE, TRUE));
2198
2199   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2200 }
2201
2202 /*-----------------------------------------------------------------*/
2203 /* saveRBank - saves an entire register bank on the stack          */
2204 /*-----------------------------------------------------------------*/
2205 static void
2206 saveRBank (int bank, iCode * ic, bool pushPsw)
2207 {
2208   int i;
2209   int count = mcs51_nRegs + (pushPsw ? 1 : 0);
2210   asmop *aop = NULL;
2211   regs *r = NULL;
2212
2213   if (options.useXstack)
2214     {
2215       if (!ic)
2216       {
2217           /* Assume r0 is available for use. */
2218           r = mcs51_regWithIdx (R0_IDX);;
2219       }
2220       else
2221       {
2222           aop = newAsmop (0);
2223           r = getFreePtr (ic, &aop, FALSE);
2224       }
2225       // allocate space first
2226       emitcode ("mov", "%s,%s", r->name, spname);
2227       MOVA (r->name);
2228       emitcode ("add", "a,#%d", count);
2229       emitcode ("mov", "%s,a", spname);
2230     }
2231
2232   for (i = 0; i < mcs51_nRegs; i++)
2233     {
2234       if (options.useXstack)
2235         {
2236           emitcode ("mov", "a,(%s+%d)",
2237                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2238           emitcode ("movx", "@%s,a", r->name);
2239           if (--count)
2240             emitcode ("inc", "%s", r->name);
2241         }
2242       else
2243         emitcode ("push", "(%s+%d)",
2244                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2245     }
2246
2247   if (pushPsw)
2248     {
2249       if (options.useXstack)
2250         {
2251           emitcode ("mov", "a,psw");
2252           emitcode ("movx", "@%s,a", r->name);
2253
2254         }
2255       else
2256         {
2257           emitcode ("push", "psw");
2258         }
2259
2260       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2261     }
2262
2263   if (aop)
2264     {
2265       freeAsmop (NULL, aop, ic, TRUE);
2266     }
2267
2268   if (ic)
2269   {
2270     ic->bankSaved = 1;
2271   }
2272 }
2273
2274 /*-----------------------------------------------------------------*/
2275 /* unsaveRBank - restores the register bank from stack             */
2276 /*-----------------------------------------------------------------*/
2277 static void
2278 unsaveRBank (int bank, iCode * ic, bool popPsw)
2279 {
2280   int i;
2281   asmop *aop = NULL;
2282   regs *r = NULL;
2283
2284   if (options.useXstack)
2285     {
2286       if (!ic)
2287         {
2288           /* Assume r0 is available for use. */
2289           r = mcs51_regWithIdx (R0_IDX);;
2290         }
2291       else
2292         {
2293           aop = newAsmop (0);
2294           r = getFreePtr (ic, &aop, FALSE);
2295         }
2296       emitcode ("mov", "%s,%s", r->name, spname);
2297     }
2298
2299   if (popPsw)
2300     {
2301       if (options.useXstack)
2302         {
2303           emitcode ("dec", "%s", r->name);
2304           emitcode ("movx", "a,@%s", r->name);
2305           emitcode ("mov", "psw,a");
2306         }
2307       else
2308         {
2309           emitcode ("pop", "psw");
2310         }
2311     }
2312
2313   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2314     {
2315       if (options.useXstack)
2316         {
2317           emitcode ("dec", "%s", r->name);
2318           emitcode ("movx", "a,@%s", r->name);
2319           emitcode ("mov", "(%s+%d),a",
2320                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2321         }
2322       else
2323         {
2324           emitcode ("pop", "(%s+%d)",
2325                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2326         }
2327     }
2328
2329   if (options.useXstack)
2330     {
2331       emitcode ("mov", "%s,%s", spname, r->name);
2332     }
2333
2334   if (aop)
2335     {
2336       freeAsmop (NULL, aop, ic, TRUE);
2337     }
2338 }
2339
2340 /*-----------------------------------------------------------------*/
2341 /* genSend - gen code for SEND                                     */
2342 /*-----------------------------------------------------------------*/
2343 static void genSend(set *sendSet)
2344 {
2345     iCode *sic;
2346     int rb1_count = 0 ;
2347
2348     for (sic = setFirstItem (sendSet); sic;
2349          sic = setNextItem (sendSet)) {
2350           int size, offset = 0;
2351           aopOp (IC_LEFT (sic), sic, FALSE);
2352           size = AOP_SIZE (IC_LEFT (sic));
2353
2354           if (sic->argreg == 1) {
2355               while (size--) {
2356                   char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2357                                     FALSE, FALSE);
2358                   if (strcmp (l, fReturn[offset]))
2359                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2360                   offset++;
2361               }
2362               rb1_count = 0;
2363           } else {
2364               while (size--) {
2365                   emitcode ("mov","b1_%d,%s",rb1_count++,
2366                             aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE));
2367               }
2368           }
2369           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2370     }
2371 }
2372
2373 /*-----------------------------------------------------------------*/
2374 /* genCall - generates a call statement                            */
2375 /*-----------------------------------------------------------------*/
2376 static void
2377 genCall (iCode * ic)
2378 {
2379   sym_link *dtype;
2380 //  bool restoreBank = FALSE;
2381   bool swapBanks = FALSE;
2382   bool accuse = FALSE;
2383   bool accPushed = FALSE;
2384
2385   D(emitcode(";     genCall",""));
2386
2387   dtype = operandType (IC_LEFT (ic));
2388   /* if send set is not empty then assign */
2389   if (_G.sendSet)
2390     {
2391         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2392             genSend(reverseSet(_G.sendSet));
2393         } else {
2394             genSend(_G.sendSet);
2395         }
2396
2397       _G.sendSet = NULL;
2398     }
2399
2400   /* if we are calling a not _naked function that is not using
2401      the same register bank then we need to save the
2402      destination registers on the stack */
2403   dtype = operandType (IC_LEFT (ic));
2404   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2405       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2406        !IFFUNC_ISISR (dtype))
2407   {
2408       swapBanks = TRUE;
2409   }
2410
2411   /* if caller saves & we have not saved then */
2412   if (!ic->regsSaved)
2413       saveRegisters (ic);
2414
2415   if (swapBanks)
2416   {
2417         emitcode ("mov", "psw,#0x%02x",
2418            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2419   }
2420
2421   /* make the call */
2422   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2423                             OP_SYMBOL (IC_LEFT (ic))->rname :
2424                             OP_SYMBOL (IC_LEFT (ic))->name));
2425
2426   if (swapBanks)
2427   {
2428        emitcode ("mov", "psw,#0x%02x",
2429           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2430   }
2431
2432   /* if we need assign a result value */
2433   if ((IS_ITEMP (IC_RESULT (ic)) &&
2434        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2435         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2436         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2437       IS_TRUE_SYMOP (IC_RESULT (ic)))
2438     {
2439
2440       _G.accInUse++;
2441       aopOp (IC_RESULT (ic), ic, FALSE);
2442       _G.accInUse--;
2443
2444       accuse = assignResultValue (IC_RESULT (ic));
2445
2446       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2447     }
2448
2449   /* adjust the stack for parameters if
2450      required */
2451   if (ic->parmBytes)
2452     {
2453       int i;
2454       if (ic->parmBytes > 3)
2455         {
2456           if (accuse)
2457             {
2458               emitcode ("push", "acc");
2459               accPushed = TRUE;
2460             }
2461           emitcode ("mov", "a,%s", spname);
2462           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2463           emitcode ("mov", "%s,a", spname);
2464         }
2465       else
2466         for (i = 0; i < ic->parmBytes; i++)
2467           emitcode ("dec", "%s", spname);
2468     }
2469
2470   /* if we hade saved some registers then unsave them */
2471   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2472     {
2473       if (accuse && !accPushed && options.useXstack)
2474         {
2475           emitcode ("push", "acc");
2476           accPushed = TRUE;
2477         }
2478       unsaveRegisters (ic);
2479     }
2480
2481 //  /* if register bank was saved then pop them */
2482 //  if (restoreBank)
2483 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2484
2485   if (accPushed)
2486     emitcode ("pop", "acc");
2487 }
2488
2489 /*-----------------------------------------------------------------*/
2490 /* -10l - generates a call by pointer statement                */
2491 /*-----------------------------------------------------------------*/
2492 static void
2493 genPcall (iCode * ic)
2494 {
2495   sym_link *dtype;
2496   symbol *rlbl = newiTempLabel (NULL);
2497 //  bool restoreBank=FALSE;
2498   bool swapBanks = FALSE;
2499
2500   D(emitcode(";     genPCall",""));
2501
2502   /* if caller saves & we have not saved then */
2503   if (!ic->regsSaved)
2504     saveRegisters (ic);
2505
2506   /* if we are calling a not _naked function that is not using
2507      the same register bank then we need to save the
2508      destination registers on the stack */
2509   dtype = operandType (IC_LEFT (ic))->next;
2510   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2511       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2512       !IFFUNC_ISISR (dtype))
2513   {
2514 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2515 //    restoreBank=TRUE;
2516       swapBanks = TRUE;
2517       // need caution message to user here
2518   }
2519
2520   /* push the return address on to the stack */
2521   emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2522   emitcode ("push", "acc");
2523   emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2524   emitcode ("push", "acc");
2525
2526   /* now push the calling address */
2527   aopOp (IC_LEFT (ic), ic, FALSE);
2528
2529   pushSide (IC_LEFT (ic), FPTRSIZE);
2530
2531   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2532
2533   /* if send set is not empty the assign */
2534   if (_G.sendSet)
2535     {
2536         genSend(reverseSet(_G.sendSet));
2537         _G.sendSet = NULL;
2538     }
2539
2540   if (swapBanks)
2541   {
2542         emitcode ("mov", "psw,#0x%02x",
2543            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2544   }
2545
2546   /* make the call */
2547   emitcode ("ret", "");
2548   emitcode ("", "%05d$:", (rlbl->key + 100));
2549
2550
2551   if (swapBanks)
2552   {
2553        emitcode ("mov", "psw,#0x%02x",
2554           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2555   }
2556
2557   /* if we need assign a result value */
2558   if ((IS_ITEMP (IC_RESULT (ic)) &&
2559        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2560         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2561       IS_TRUE_SYMOP (IC_RESULT (ic)))
2562     {
2563
2564       _G.accInUse++;
2565       aopOp (IC_RESULT (ic), ic, FALSE);
2566       _G.accInUse--;
2567
2568       assignResultValue (IC_RESULT (ic));
2569
2570       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2571     }
2572
2573   /* adjust the stack for parameters if
2574      required */
2575   if (ic->parmBytes)
2576     {
2577       int i;
2578       if (ic->parmBytes > 3)
2579         {
2580           emitcode ("mov", "a,%s", spname);
2581           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2582           emitcode ("mov", "%s,a", spname);
2583         }
2584       else
2585         for (i = 0; i < ic->parmBytes; i++)
2586           emitcode ("dec", "%s", spname);
2587
2588     }
2589
2590 //  /* if register bank was saved then unsave them */
2591 //  if (restoreBank)
2592 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2593
2594   /* if we hade saved some registers then
2595      unsave them */
2596   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2597     unsaveRegisters (ic);
2598 }
2599
2600 /*-----------------------------------------------------------------*/
2601 /* resultRemat - result  is rematerializable                       */
2602 /*-----------------------------------------------------------------*/
2603 static int
2604 resultRemat (iCode * ic)
2605 {
2606   if (SKIP_IC (ic) || ic->op == IFX)
2607     return 0;
2608
2609   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2610     {
2611       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2612       if (sym->remat && !POINTER_SET (ic))
2613         return 1;
2614     }
2615
2616   return 0;
2617 }
2618
2619 #if defined(__BORLANDC__) || defined(_MSC_VER)
2620 #define STRCASECMP stricmp
2621 #else
2622 #define STRCASECMP strcasecmp
2623 #endif
2624
2625 /*-----------------------------------------------------------------*/
2626 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2627 /*-----------------------------------------------------------------*/
2628 static int
2629 regsCmp(void *p1, void *p2)
2630 {
2631   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2632 }
2633
2634 static bool
2635 inExcludeList (char *s)
2636 {
2637   const char *p = setFirstItem(options.excludeRegsSet);
2638
2639   if (p == NULL || STRCASECMP(p, "none") == 0)
2640     return FALSE;
2641
2642
2643   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2644 }
2645
2646 /*-----------------------------------------------------------------*/
2647 /* genFunction - generated code for function entry                 */
2648 /*-----------------------------------------------------------------*/
2649 static void
2650 genFunction (iCode * ic)
2651 {
2652   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
2653   sym_link *ftype;
2654   bool     switchedPSW = FALSE;
2655   int      calleesaves_saved_register = -1;
2656   int      stackAdjust = sym->stack;
2657   int      accIsFree = sym->recvSize < 4;
2658   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2659   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
2660
2661   _G.nRegsSaved = 0;
2662   /* create the function header */
2663   emitcode (";", "-----------------------------------------");
2664   emitcode (";", " function %s", sym->name);
2665   emitcode (";", "-----------------------------------------");
2666
2667   emitcode ("", "%s:", sym->rname);
2668   ftype = operandType (IC_LEFT (ic));
2669   _G.currentFunc = sym;
2670
2671   if (IFFUNC_ISNAKED(ftype))
2672   {
2673       emitcode(";", "naked function: no prologue.");
2674       return;
2675   }
2676
2677   /* here we need to generate the equates for the
2678      register bank if required */
2679   if (FUNC_REGBANK (ftype) != rbank)
2680     {
2681       int i;
2682
2683       rbank = FUNC_REGBANK (ftype);
2684       for (i = 0; i < mcs51_nRegs; i++)
2685         {
2686           if (strcmp (regs8051[i].base, "0") == 0)
2687             emitcode ("", "%s = 0x%02x",
2688                       regs8051[i].dname,
2689                       8 * rbank + regs8051[i].offset);
2690           else
2691             emitcode ("", "%s = %s + 0x%02x",
2692                       regs8051[i].dname,
2693                       regs8051[i].base,
2694                       8 * rbank + regs8051[i].offset);
2695         }
2696     }
2697
2698   /* if this is an interrupt service routine then
2699      save acc, b, dpl, dph  */
2700   if (IFFUNC_ISISR (sym->type))
2701     {
2702
2703       if (!inExcludeList ("acc"))
2704         emitcode ("push", "acc");
2705       if (!inExcludeList ("b"))
2706         emitcode ("push", "b");
2707       if (!inExcludeList ("dpl"))
2708         emitcode ("push", "dpl");
2709       if (!inExcludeList ("dph"))
2710         emitcode ("push", "dph");
2711       /* if this isr has no bank i.e. is going to
2712          run with bank 0 , then we need to save more
2713          registers :-) */
2714       if (!FUNC_REGBANK (sym->type))
2715         {
2716
2717           /* if this function does not call any other
2718              function then we can be economical and
2719              save only those registers that are used */
2720           if (!IFFUNC_HASFCALL(sym->type))
2721             {
2722               int i;
2723
2724               /* if any registers used */
2725               if (sym->regsUsed)
2726                 {
2727                   /* save the registers used */
2728                   for (i = 0; i < sym->regsUsed->size; i++)
2729                     {
2730                       if (bitVectBitValue (sym->regsUsed, i))
2731                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2732                     }
2733                 }
2734             }
2735           else
2736             {
2737
2738               /* this function has a function call. We cannot
2739                  determines register usage so we will have to push the
2740                  entire bank */
2741                 saveRBank (0, ic, FALSE);
2742                 if (options.parms_in_bank1) {
2743                     int i;
2744                     for (i=0; i < 8 ; i++ ) {
2745                         emitcode ("push","%s",rb1regs[i]);
2746                     }
2747                 }
2748             }
2749         }
2750         else
2751         {
2752             /* This ISR uses a non-zero bank.
2753              *
2754              * We assume that the bank is available for our
2755              * exclusive use.
2756              *
2757              * However, if this ISR calls a function which uses some
2758              * other bank, we must save that bank entirely.
2759              */
2760             unsigned long banksToSave = 0;
2761
2762             if (IFFUNC_HASFCALL(sym->type))
2763             {
2764
2765 #define MAX_REGISTER_BANKS 4
2766
2767                 iCode *i;
2768                 int ix;
2769
2770                 for (i = ic; i; i = i->next)
2771                 {
2772                     if (i->op == ENDFUNCTION)
2773                     {
2774                         /* we got to the end OK. */
2775                         break;
2776                     }
2777
2778                     if (i->op == CALL)
2779                     {
2780                         sym_link *dtype;
2781
2782                         dtype = operandType (IC_LEFT(i));
2783                         if (dtype
2784                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2785                         {
2786                              /* Mark this bank for saving. */
2787                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2788                              {
2789                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2790                              }
2791                              else
2792                              {
2793                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2794                              }
2795
2796                              /* And note that we don't need to do it in
2797                               * genCall.
2798                               */
2799                              i->bankSaved = 1;
2800                         }
2801                     }
2802                     if (i->op == PCALL)
2803                     {
2804                         /* This is a mess; we have no idea what
2805                          * register bank the called function might
2806                          * use.
2807                          *
2808                          * The only thing I can think of to do is
2809                          * throw a warning and hope.
2810                          */
2811                         werror(W_FUNCPTR_IN_USING_ISR);
2812                     }
2813                 }
2814
2815                 if (banksToSave && options.useXstack)
2816                 {
2817                     /* Since we aren't passing it an ic,
2818                      * saveRBank will assume r0 is available to abuse.
2819                      *
2820                      * So switch to our (trashable) bank now, so
2821                      * the caller's R0 isn't trashed.
2822                      */
2823                     emitcode ("push", "psw");
2824                     emitcode ("mov", "psw,#0x%02x",
2825                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2826                     switchedPSW = TRUE;
2827                 }
2828
2829                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2830                 {
2831                      if (banksToSave & (1 << ix))
2832                      {
2833                          saveRBank(ix, NULL, FALSE);
2834                      }
2835                 }
2836             }
2837             // TODO: this needs a closer look
2838             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2839         }
2840
2841       /* Set the register bank to the desired value if nothing else */
2842       /* has done so yet. */
2843       if (!switchedPSW)
2844         {
2845           emitcode ("push", "psw");
2846           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2847         }
2848     }
2849   else
2850     {
2851       /* This is a non-ISR function. The caller has already switched register */
2852       /* banks, if necessary, so just handle the callee-saves option. */
2853
2854       /* if callee-save to be used for this function
2855          then save the registers being used in this function */
2856       if (IFFUNC_CALLEESAVES(sym->type))
2857         {
2858           int i;
2859
2860           /* if any registers used */
2861           if (sym->regsUsed)
2862             {
2863               /* save the registers used */
2864               for (i = 0; i < sym->regsUsed->size; i++)
2865                 {
2866                   if (bitVectBitValue (sym->regsUsed, i))
2867                     {
2868                       /* remember one saved register for later usage */
2869                       if (calleesaves_saved_register < 0)
2870                         calleesaves_saved_register = i;
2871                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2872                       _G.nRegsSaved++;
2873                     }
2874                 }
2875             }
2876         }
2877     }
2878
2879
2880   if (fReentrant)
2881     {
2882       if (options.useXstack)
2883         {
2884           emitcode ("mov", "r0,%s", spname);
2885           emitcode ("inc", "%s", spname);
2886           emitcode ("xch", "a,_bpx");
2887           emitcode ("movx", "@r0,a");
2888           emitcode ("inc", "r0");
2889           emitcode ("mov", "a,r0");
2890           emitcode ("xch", "a,_bpx");
2891           emitcode ("push", "_bp");     /* save the callers stack  */
2892           emitcode ("mov", "_bp,sp");
2893         }
2894       else
2895         {
2896           /* set up the stack */
2897           emitcode ("push", "_bp");     /* save the callers stack  */
2898           emitcode ("mov", "_bp,sp");
2899         }
2900     }
2901
2902   /* For some cases it is worthwhile to perform a RECEIVE iCode */
2903   /* before setting up the stack frame completely. */
2904   if (ric && ric->argreg == 1 && IC_RESULT (ric))
2905     {
2906       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
2907
2908       if (rsym->isitmp)
2909         {
2910           if (rsym && rsym->regType == REG_CND)
2911             rsym = NULL;
2912           if (rsym && (rsym->accuse || rsym->ruonly))
2913             rsym = NULL;
2914           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
2915             rsym = rsym->usl.spillLoc;
2916         }
2917
2918       /* If the RECEIVE operand immediately spills to the first entry on the */
2919       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
2920       /* rather than the usual @r0/r1 machinations. */
2921       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
2922         {
2923           int ofs;
2924
2925           _G.current_iCode = ric;
2926           D(emitcode (";     genReceive",""));
2927           for (ofs=0; ofs < sym->recvSize; ofs++)
2928             {
2929               if (!strcmp (fReturn[ofs], "a"))
2930                 emitcode ("push", "acc");
2931               else
2932                 emitcode ("push", fReturn[ofs]);
2933             }
2934           stackAdjust -= sym->recvSize;
2935           if (stackAdjust<0)
2936             {
2937               assert (stackAdjust>=0);
2938               stackAdjust = 0;
2939             }
2940           _G.current_iCode = ic;
2941           ric->generated = 1;
2942           accIsFree = 1;
2943         }
2944       /* If the RECEIVE operand is 4 registers, we can do the moves now */
2945       /* to free up the accumulator. */
2946       else if (rsym && rsym->nRegs && sym->recvSize == 4)
2947         {
2948           int ofs;
2949
2950           _G.current_iCode = ric;
2951           D(emitcode (";     genReceive",""));
2952           for (ofs=0; ofs < sym->recvSize; ofs++)
2953             {
2954               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
2955             }
2956           _G.current_iCode = ic;
2957           ric->generated = 1;
2958           accIsFree = 1;
2959         }
2960     }
2961
2962   /* adjust the stack for the function */
2963   if (stackAdjust)
2964     {
2965       int i = stackAdjust;
2966       if (i > 256)
2967         werror (W_STACK_OVERFLOW, sym->name);
2968
2969       if (i > 3 && accIsFree)
2970         {
2971           emitcode ("mov", "a,sp");
2972           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2973           emitcode ("mov", "sp,a");
2974         }
2975       else if (i > 5)
2976         {
2977           /* The accumulator is not free, so we will need another register */
2978           /* to clobber. No need to worry about a possible conflict with */
2979           /* the above early RECEIVE optimizations since they would have */
2980           /* freed the accumulator if they were generated. */
2981
2982           if (IFFUNC_CALLEESAVES(sym->type))
2983             {
2984               /* if it's a callee-saves function we need a saved register */
2985               if (calleesaves_saved_register >= 0)
2986                 {
2987                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2988                   emitcode ("mov", "a,sp");
2989                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2990                   emitcode ("mov", "sp,a");
2991                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2992                 }
2993               else
2994                 /* do it the hard way */
2995                 while (i--)
2996                   emitcode ("inc", "sp");
2997             }
2998           else
2999             {
3000               /* not callee-saves, we can clobber r0 */
3001               emitcode ("mov", "r0,a");
3002               emitcode ("mov", "a,sp");
3003               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3004               emitcode ("mov", "sp,a");
3005               emitcode ("mov", "a,r0");
3006             }
3007         }
3008       else
3009         while (i--)
3010           emitcode ("inc", "sp");
3011     }
3012
3013   if (sym->xstack)
3014     {
3015       char i = ((char) sym->xstack & 0xff);
3016
3017       if (i > 3 && accIsFree)
3018         {
3019           emitcode ("mov", "a,_spx");
3020           emitcode ("add", "a,#0x%02x", i);
3021           emitcode ("mov", "_spx,a");
3022         }
3023       else if (i > 5)
3024         {
3025           emitcode ("push", "acc");
3026           emitcode ("mov", "a,_spx");
3027           emitcode ("add", "a,#0x%02x", i);
3028           emitcode ("mov", "_spx,a");
3029           emitcode ("pop", "acc");
3030         }
3031       else
3032         {
3033           while (i--)
3034             emitcode ("inc", "_spx");
3035         }
3036     }
3037
3038   /* if critical function then turn interrupts off */
3039   if (IFFUNC_ISCRITICAL (ftype))
3040     {
3041       symbol *tlbl = newiTempLabel (NULL);
3042       emitcode ("setb", "c");
3043       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3044       emitcode ("clr", "c");
3045       emitcode ("", "%05d$:", (tlbl->key + 100));
3046       emitcode ("push", "psw"); /* save old ea via c in psw */
3047     }
3048 }
3049
3050 /*-----------------------------------------------------------------*/
3051 /* genEndFunction - generates epilogue for functions               */
3052 /*-----------------------------------------------------------------*/
3053 static void
3054 genEndFunction (iCode * ic)
3055 {
3056   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3057   lineNode *lnp = lineCurr;
3058   bitVect  *regsUsed;
3059   bitVect  *regsUsedPrologue;
3060   bitVect  *regsUnneeded;
3061   int      accIsFree = sym->recvSize < 4;
3062   int      idx;
3063
3064   _G.currentFunc = NULL;
3065   if (IFFUNC_ISNAKED(sym->type))
3066   {
3067       emitcode(";", "naked function: no epilogue.");
3068       if (options.debug && currFunc)
3069         debugFile->writeEndFunction (currFunc, ic, 0);
3070       return;
3071   }
3072
3073   if (IFFUNC_ISCRITICAL (sym->type))
3074     {
3075       emitcode ("pop", "psw"); /* restore ea via c in psw */
3076       emitcode ("mov", "ea,c");
3077     }
3078
3079   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))// && !options.useXstack)
3080     {
3081       emitcode ("mov", "sp,_bp");
3082     }
3083   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3084     {
3085       if (options.useXstack)
3086         {
3087           emitcode ("pop", "_bp");
3088           emitcode ("xch", "a,_bpx");
3089           emitcode ("mov", "r0,a");
3090           emitcode ("dec", "r0");
3091           emitcode ("movx", "a,@r0");
3092           emitcode ("xch", "a,_bpx");
3093           emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3094         }
3095       else
3096         {
3097           emitcode ("pop", "_bp");
3098         }
3099     }
3100
3101   /* restore the register bank  */
3102   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3103   {
3104     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3105      || !options.useXstack)
3106     {
3107         /* Special case of ISR using non-zero bank with useXstack
3108          * is handled below.
3109          */
3110         emitcode ("pop", "psw");
3111     }
3112   }
3113
3114   if (IFFUNC_ISISR (sym->type))
3115     {
3116
3117       /* now we need to restore the registers */
3118       /* if this isr has no bank i.e. is going to
3119          run with bank 0 , then we need to save more
3120          registers :-) */
3121       if (!FUNC_REGBANK (sym->type))
3122         {
3123           /* if this function does not call any other
3124              function then we can be economical and
3125              save only those registers that are used */
3126           if (!IFFUNC_HASFCALL(sym->type))
3127             {
3128               int i;
3129
3130               /* if any registers used */
3131               if (sym->regsUsed)
3132                 {
3133                   /* save the registers used */
3134                   for (i = sym->regsUsed->size; i >= 0; i--)
3135                     {
3136                       if (bitVectBitValue (sym->regsUsed, i))
3137                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3138                     }
3139                 }
3140             }
3141           else
3142             {
3143               if (options.parms_in_bank1) {
3144                   int i;
3145                   for (i = 7 ; i >= 0 ; i-- ) {
3146                       emitcode ("pop","%s",rb1regs[i]);
3147                   }
3148               }
3149               /* this function has  a function call cannot
3150                  determines register usage so we will have to pop the
3151                  entire bank */
3152               unsaveRBank (0, ic, FALSE);
3153             }
3154         }
3155         else
3156         {
3157             /* This ISR uses a non-zero bank.
3158              *
3159              * Restore any register banks saved by genFunction
3160              * in reverse order.
3161              */
3162             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3163             int ix;
3164
3165             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3166             {
3167                 if (savedBanks & (1 << ix))
3168                 {
3169                     unsaveRBank(ix, NULL, FALSE);
3170                 }
3171             }
3172
3173             if (options.useXstack)
3174             {
3175                 /* Restore bank AFTER calling unsaveRBank,
3176                  * since it can trash r0.
3177                  */
3178                 emitcode ("pop", "psw");
3179             }
3180         }
3181
3182       if (!inExcludeList ("dph"))
3183         emitcode ("pop", "dph");
3184       if (!inExcludeList ("dpl"))
3185         emitcode ("pop", "dpl");
3186       if (!inExcludeList ("b"))
3187         emitcode ("pop", "b");
3188       if (!inExcludeList ("acc"))
3189         emitcode ("pop", "acc");
3190
3191       /* if debug then send end of function */
3192       if (options.debug && currFunc)
3193         {
3194           debugFile->writeEndFunction (currFunc, ic, 1);
3195         }
3196
3197       emitcode ("reti", "");
3198     }
3199   else
3200     {
3201       if (IFFUNC_CALLEESAVES(sym->type))
3202         {
3203           int i;
3204
3205           /* if any registers used */
3206           if (sym->regsUsed)
3207             {
3208               /* save the registers used */
3209               for (i = sym->regsUsed->size; i >= 0; i--)
3210                 {
3211                   if (bitVectBitValue (sym->regsUsed, i) ||
3212                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3213                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3214                 }
3215             }
3216           else if (mcs51_ptrRegReq)
3217             {
3218               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3219               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3220             }
3221
3222         }
3223
3224       /* if debug then send end of function */
3225       if (options.debug && currFunc)
3226         {
3227           debugFile->writeEndFunction (currFunc, ic, 1);
3228         }
3229
3230       emitcode ("ret", "");
3231     }
3232
3233   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3234     return;
3235
3236   /* If this was an interrupt handler using bank 0 that called another */
3237   /* function, then all registers must be saved; nothing to optimized. */
3238   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3239       && !FUNC_REGBANK(sym->type))
3240     return;
3241
3242   /* There are no push/pops to optimize if not callee-saves or ISR */
3243   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3244     return;
3245
3246   /* If there were stack parameters, we cannot optimize without also    */
3247   /* fixing all of the stack offsets; this is too dificult to consider. */
3248   if (FUNC_HASSTACKPARM(sym->type))
3249     return;
3250
3251   /* Compute the registers actually used */
3252   regsUsed = newBitVect (mcs51_nRegs);
3253   regsUsedPrologue = newBitVect (mcs51_nRegs);
3254   while (lnp)
3255     {
3256       if (lnp->ic && lnp->ic->op == FUNCTION)
3257         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3258       else
3259         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3260
3261       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3262           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3263         break;
3264       if (!lnp->prev)
3265         break;
3266       lnp = lnp->prev;
3267     }
3268
3269   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3270       && !bitVectBitValue (regsUsed, CND_IDX))
3271     {
3272       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3273       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3274           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3275         bitVectUnSetBit (regsUsed, CND_IDX);
3276     }
3277   else
3278     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3279
3280   /* If this was an interrupt handler that called another function */
3281   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3282   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3283     {
3284       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3285       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3286       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3287       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3288       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3289     }
3290
3291   /* Remove the unneeded push/pops */
3292   regsUnneeded = newBitVect (mcs51_nRegs);
3293   while (lnp)
3294     {
3295       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3296         {
3297           if (!strncmp(lnp->line, "push", 4))
3298             {
3299               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3300               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3301                 {
3302                   connectLine (lnp->prev, lnp->next);
3303                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3304                 }
3305             }
3306           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3307             {
3308               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3309               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3310                 {
3311                   connectLine (lnp->prev, lnp->next);
3312                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3313                 }
3314             }
3315         }
3316       lnp = lnp->next;
3317     }
3318
3319   for (idx = 0; idx < regsUnneeded->size; idx++)
3320     if (bitVectBitValue (regsUnneeded, idx))
3321       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3322
3323   freeBitVect (regsUnneeded);
3324   freeBitVect (regsUsed);
3325   freeBitVect (regsUsedPrologue);
3326 }
3327
3328 /*-----------------------------------------------------------------*/
3329 /* genRet - generate code for return statement                     */
3330 /*-----------------------------------------------------------------*/
3331 static void
3332 genRet (iCode * ic)
3333 {
3334   int size, offset = 0, pushed = 0;
3335
3336   D(emitcode (";     genRet",""));
3337
3338   /* if we have no return value then
3339      just generate the "ret" */
3340   if (!IC_LEFT (ic))
3341     goto jumpret;
3342
3343   /* we have something to return then
3344      move the return value into place */
3345   aopOp (IC_LEFT (ic), ic, FALSE);
3346   size = AOP_SIZE (IC_LEFT (ic));
3347
3348   while (size--)
3349     {
3350       char *l;
3351       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3352         {
3353           /* #NOCHANGE */
3354           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3355                       FALSE, TRUE);
3356           emitcode ("push", "%s", l);
3357           pushed++;
3358         }
3359       else
3360         {
3361           l = aopGet (AOP (IC_LEFT (ic)), offset,
3362                       FALSE, FALSE);
3363           if (strcmp (fReturn[offset], l))
3364             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3365         }
3366     }
3367
3368   if (pushed)
3369     {
3370       while (pushed)
3371         {
3372           pushed--;
3373           if (strcmp (fReturn[pushed], "a"))
3374             emitcode ("pop", fReturn[pushed]);
3375           else
3376             emitcode ("pop", "acc");
3377         }
3378     }
3379   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3380
3381 jumpret:
3382   /* generate a jump to the return label
3383      if the next is not the return statement */
3384   if (!(ic->next && ic->next->op == LABEL &&
3385         IC_LABEL (ic->next) == returnLabel))
3386
3387     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3388
3389 }
3390
3391 /*-----------------------------------------------------------------*/
3392 /* genLabel - generates a label                                    */
3393 /*-----------------------------------------------------------------*/
3394 static void
3395 genLabel (iCode * ic)
3396 {
3397   /* special case never generate */
3398   if (IC_LABEL (ic) == entryLabel)
3399     return;
3400
3401   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3402 }
3403
3404 /*-----------------------------------------------------------------*/
3405 /* genGoto - generates a ljmp                                      */
3406 /*-----------------------------------------------------------------*/
3407 static void
3408 genGoto (iCode * ic)
3409 {
3410   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3411 }
3412
3413 /*-----------------------------------------------------------------*/
3414 /* findLabelBackwards: walks back through the iCode chain looking  */
3415 /* for the given label. Returns number of iCode instructions     */
3416 /* between that label and given ic.          */
3417 /* Returns zero if label not found.          */
3418 /*-----------------------------------------------------------------*/
3419 static int
3420 findLabelBackwards (iCode * ic, int key)
3421 {
3422   int count = 0;
3423
3424   while (ic->prev)
3425     {
3426       ic = ic->prev;
3427       count++;
3428
3429       /* If we have any pushes or pops, we cannot predict the distance.
3430          I don't like this at all, this should be dealt with in the
3431          back-end */
3432       if (ic->op == IPUSH || ic->op == IPOP) {
3433         return 0;
3434       }
3435
3436       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3437         {
3438           return count;
3439         }
3440     }
3441
3442   return 0;
3443 }
3444
3445 /*-----------------------------------------------------------------*/
3446 /* genPlusIncr :- does addition with increment if possible         */
3447 /*-----------------------------------------------------------------*/
3448 static bool
3449 genPlusIncr (iCode * ic)
3450 {
3451   unsigned int icount;
3452   unsigned int size = getDataSize (IC_RESULT (ic));
3453
3454   /* will try to generate an increment */
3455   /* if the right side is not a literal
3456      we cannot */
3457   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3458     return FALSE;
3459
3460   /* if the literal value of the right hand side
3461      is greater than 4 then it is not worth it */
3462   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3463     return FALSE;
3464
3465   D(emitcode (";     genPlusIncr",""));
3466
3467   /* if increment >=16 bits in register or direct space */
3468   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3469       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3470       (size > 1) &&
3471       (icount == 1))
3472     {
3473       symbol *tlbl;
3474       int emitTlbl;
3475       int labelRange;
3476
3477       /* If the next instruction is a goto and the goto target
3478        * is < 10 instructions previous to this, we can generate
3479        * jumps straight to that target.
3480        */
3481       if (ic->next && ic->next->op == GOTO
3482           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3483           && labelRange <= 10)
3484         {
3485           emitcode (";", "tail increment optimized");
3486           tlbl = IC_LABEL (ic->next);
3487           emitTlbl = 0;
3488         }
3489       else
3490         {
3491           tlbl = newiTempLabel (NULL);
3492           emitTlbl = 1;
3493         }
3494       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3495       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3496           IS_AOP_PREG (IC_RESULT (ic)))
3497         emitcode ("cjne", "%s,#0x00,%05d$",
3498                   aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3499                   tlbl->key + 100);
3500       else
3501         {
3502           emitcode ("clr", "a");
3503           emitcode ("cjne", "a,%s,%05d$",
3504                     aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3505                     tlbl->key + 100);
3506         }
3507
3508       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3509       if (size > 2)
3510         {
3511           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3512               IS_AOP_PREG (IC_RESULT (ic)))
3513             emitcode ("cjne", "%s,#0x00,%05d$",
3514                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3515                       tlbl->key + 100);
3516           else
3517             emitcode ("cjne", "a,%s,%05d$",
3518                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3519                       tlbl->key + 100);
3520
3521           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3522         }
3523       if (size > 3)
3524         {
3525           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3526               IS_AOP_PREG (IC_RESULT (ic)))
3527             emitcode ("cjne", "%s,#0x00,%05d$",
3528                       aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3529                       tlbl->key + 100);
3530           else
3531             {
3532               emitcode ("cjne", "a,%s,%05d$",
3533                         aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3534                         tlbl->key + 100);
3535             }
3536           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3537         }
3538
3539       if (emitTlbl)
3540         {
3541           emitcode ("", "%05d$:", tlbl->key + 100);
3542         }
3543       return TRUE;
3544     }
3545
3546   /* if the sizes are greater than 1 then we cannot */
3547   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3548       AOP_SIZE (IC_LEFT (ic)) > 1)
3549     return FALSE;
3550
3551   /* we can if the aops of the left & result match or
3552      if they are in registers and the registers are the
3553      same */
3554   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3555     {
3556
3557       if (icount > 3)
3558         {
3559           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3560           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3561           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3562         }
3563       else
3564         {
3565
3566           while (icount--)
3567             emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3568         }
3569
3570       return TRUE;
3571     }
3572
3573   return FALSE;
3574 }
3575
3576 /*-----------------------------------------------------------------*/
3577 /* outBitAcc - output a bit in acc                                 */
3578 /*-----------------------------------------------------------------*/
3579 static void
3580 outBitAcc (operand * result)
3581 {
3582   symbol *tlbl = newiTempLabel (NULL);
3583   /* if the result is a bit */
3584   if (AOP_TYPE (result) == AOP_CRY)
3585     {
3586       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
3587     }
3588   else
3589     {
3590       emitcode ("jz", "%05d$", tlbl->key + 100);
3591       emitcode ("mov", "a,%s", one);
3592       emitcode ("", "%05d$:", tlbl->key + 100);
3593       outAcc (result);
3594     }
3595 }
3596
3597 /*-----------------------------------------------------------------*/
3598 /* genPlusBits - generates code for addition of two bits           */
3599 /*-----------------------------------------------------------------*/
3600 static void
3601 genPlusBits (iCode * ic)
3602 {
3603   D(emitcode (";     genPlusBits",""));
3604
3605   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3606     {
3607       symbol *lbl = newiTempLabel (NULL);
3608       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3609       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3610       emitcode ("cpl", "c");
3611       emitcode ("", "%05d$:", (lbl->key + 100));
3612       outBitC (IC_RESULT (ic));
3613     }
3614   else
3615     {
3616       emitcode ("clr", "a");
3617       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3618       emitcode ("rlc", "a");
3619       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3620       emitcode ("addc", "a,#0x00");
3621       outAcc (IC_RESULT (ic));
3622     }
3623 }
3624
3625 #if 0
3626 /* This is the original version of this code.
3627
3628  * This is being kept around for reference,
3629  * because I am not entirely sure I got it right...
3630  */
3631 static void
3632 adjustArithmeticResult (iCode * ic)
3633 {
3634   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3635       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3636       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3637     aopPut (AOP (IC_RESULT (ic)),
3638             aopGet (AOP (IC_LEFT (ic)), 2, FALSE, FALSE),
3639             2,
3640             isOperandVolatile (IC_RESULT (ic), FALSE));
3641
3642   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3643       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3644       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3645     aopPut (AOP (IC_RESULT (ic)),
3646             aopGet (AOP (IC_RIGHT (ic)), 2, FALSE, FALSE),
3647             2,
3648             isOperandVolatile (IC_RESULT (ic), FALSE));
3649
3650   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3651       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3652       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3653       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3654       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3655     {
3656       char buffer[5];
3657       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3658       aopPut (AOP (IC_RESULT (ic)), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3659     }
3660 }
3661 #else
3662 /* This is the pure and virtuous version of this code.
3663  * I'm pretty certain it's right, but not enough to toss the old
3664  * code just yet...
3665  */
3666 static void
3667 adjustArithmeticResult (iCode * ic)
3668 {
3669   if (opIsGptr (IC_RESULT (ic)) &&
3670       opIsGptr (IC_LEFT (ic)) &&
3671       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3672     {
3673       aopPut (AOP (IC_RESULT (ic)),
3674               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3675               GPTRSIZE - 1,
3676               isOperandVolatile (IC_RESULT (ic), FALSE));
3677     }
3678
3679   if (opIsGptr (IC_RESULT (ic)) &&
3680       opIsGptr (IC_RIGHT (ic)) &&
3681       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3682     {
3683       aopPut (AOP (IC_RESULT (ic)),
3684               aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3685               GPTRSIZE - 1,
3686               isOperandVolatile (IC_RESULT (ic), FALSE));
3687     }
3688
3689   if (opIsGptr (IC_RESULT (ic)) &&
3690       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3691       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3692       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3693       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3694     {
3695       char buffer[5];
3696       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3697       aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3698     }
3699 }
3700 #endif
3701
3702 /*-----------------------------------------------------------------*/
3703 /* genPlus - generates code for addition                           */
3704 /*-----------------------------------------------------------------*/
3705 static void
3706 genPlus (iCode * ic)
3707 {
3708   int size, offset = 0;
3709   int skip_bytes = 0;
3710   char *add = "add";
3711   asmop *leftOp, *rightOp;
3712   operand * op;
3713
3714   /* special cases :- */
3715
3716   D(emitcode (";     genPlus",""));
3717
3718   aopOp (IC_LEFT (ic), ic, FALSE);
3719   aopOp (IC_RIGHT (ic), ic, FALSE);
3720   aopOp (IC_RESULT (ic), ic, TRUE);
3721
3722   /* if literal, literal on the right or
3723      if left requires ACC or right is already
3724      in ACC */
3725   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3726       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3727       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3728     {
3729       operand *t = IC_RIGHT (ic);
3730       IC_RIGHT (ic) = IC_LEFT (ic);
3731       IC_LEFT (ic) = t;
3732     }
3733
3734   /* if both left & right are in bit
3735      space */
3736   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3737       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3738     {
3739       genPlusBits (ic);
3740       goto release;
3741     }
3742
3743   /* if left in bit space & right literal */
3744   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3745       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3746     {
3747       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3748       /* if result in bit space */
3749       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3750         {
3751           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3752             emitcode ("cpl", "c");
3753           outBitC (IC_RESULT (ic));
3754         }
3755       else
3756         {
3757           size = getDataSize (IC_RESULT (ic));
3758           while (size--)
3759             {
3760               MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE));
3761               emitcode ("addc", "a,#00");
3762               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3763             }
3764         }
3765       goto release;
3766     }
3767
3768   /* if I can do an increment instead
3769      of add then GOOD for ME */
3770   if (genPlusIncr (ic) == TRUE)
3771     goto release;
3772
3773   size = getDataSize (IC_RESULT (ic));
3774   leftOp = AOP(IC_LEFT(ic));
3775   rightOp = AOP(IC_RIGHT(ic));
3776   op=IC_LEFT(ic);
3777
3778   /* if this is an add for an array access
3779      at a 256 byte boundary */
3780   if ( 2 == size
3781        && AOP_TYPE (op) == AOP_IMMD
3782        && IS_SYMOP (op)
3783        && IS_SPEC (OP_SYM_ETYPE (op))
3784        && SPEC_ABSA (OP_SYM_ETYPE (op))
3785        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3786      )
3787     {
3788       D(emitcode (";     genPlus aligned array",""));
3789       aopPut (AOP (IC_RESULT (ic)),
3790               aopGet (rightOp, 0, FALSE, FALSE),
3791               0,
3792               isOperandVolatile (IC_RESULT (ic), FALSE));
3793
3794       if( 1 == getDataSize (IC_RIGHT (ic)) )
3795         {
3796           aopPut (AOP (IC_RESULT (ic)),
3797                   aopGet (leftOp, 1, FALSE, FALSE),
3798                   1,
3799                   isOperandVolatile (IC_RESULT (ic), FALSE));
3800         }
3801       else
3802         {
3803           MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
3804           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3805           aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3806         }
3807       goto release;
3808     }
3809
3810   /* if the lower bytes of a literal are zero skip the addition */
3811   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3812     {
3813        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3814               (skip_bytes+1 < size))
3815          {
3816            skip_bytes++;
3817          }
3818        if (skip_bytes)
3819          D(emitcode (";     genPlus shortcut",""));
3820     }
3821
3822   while (size--)
3823     {
3824       if( offset >= skip_bytes )
3825         {
3826           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3827             {
3828               bool pushedB;
3829               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3830               pushedB = pushB ();
3831               emitcode("xch", "a,b");
3832               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3833               emitcode (add, "a,b");
3834               popB (pushedB);
3835             }
3836           else if (aopGetUsesAcc (leftOp, offset))
3837             {
3838               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3839               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3840             }
3841           else
3842             {
3843               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3844               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3845             }
3846           aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3847           add = "addc";  /* further adds must propagate carry */
3848         }
3849       else
3850         {
3851           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3852               isOperandVolatile (IC_RESULT (ic), FALSE))
3853             {
3854               /* just move */
3855               aopPut (AOP (IC_RESULT (ic)),
3856                       aopGet (leftOp, offset, FALSE, FALSE),
3857                       offset,
3858                       isOperandVolatile (IC_RESULT (ic), FALSE));
3859             }
3860         }
3861       offset++;
3862     }
3863
3864   adjustArithmeticResult (ic);
3865
3866 release:
3867   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3868   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3869   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3870 }
3871
3872 /*-----------------------------------------------------------------*/
3873 /* genMinusDec :- does subtraction with deccrement if possible     */
3874 /*-----------------------------------------------------------------*/
3875 static bool
3876 genMinusDec (iCode * ic)
3877 {
3878   unsigned int icount;
3879   unsigned int size = getDataSize (IC_RESULT (ic));
3880
3881   /* will try to generate an increment */
3882   /* if the right side is not a literal
3883      we cannot */
3884   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3885     return FALSE;
3886
3887   /* if the literal value of the right hand side
3888      is greater than 4 then it is not worth it */
3889   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3890     return FALSE;
3891
3892   D(emitcode (";     genMinusDec",""));
3893
3894   /* if decrement >=16 bits in register or direct space */
3895   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3896       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3897       (size > 1) &&
3898       (icount == 1))
3899     {
3900       symbol *tlbl;
3901       int emitTlbl;
3902       int labelRange;
3903
3904       /* If the next instruction is a goto and the goto target
3905        * is <= 10 instructions previous to this, we can generate
3906        * jumps straight to that target.
3907        */
3908       if (ic->next && ic->next->op == GOTO
3909           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3910           && labelRange <= 10)
3911         {
3912           emitcode (";", "tail decrement optimized");
3913           tlbl = IC_LABEL (ic->next);
3914           emitTlbl = 0;
3915         }
3916       else
3917         {
3918           tlbl = newiTempLabel (NULL);
3919           emitTlbl = 1;
3920         }
3921
3922       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3923       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3924           IS_AOP_PREG (IC_RESULT (ic)))
3925         emitcode ("cjne", "%s,#0xff,%05d$"
3926                   ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3927                   ,tlbl->key + 100);
3928       else
3929         {
3930           emitcode ("mov", "a,#0xff");
3931           emitcode ("cjne", "a,%s,%05d$"
3932                     ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3933                     ,tlbl->key + 100);
3934         }
3935       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3936       if (size > 2)
3937         {
3938           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3939               IS_AOP_PREG (IC_RESULT (ic)))
3940             emitcode ("cjne", "%s,#0xff,%05d$"
3941                       ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3942                       ,tlbl->key + 100);
3943           else
3944             {
3945               emitcode ("cjne", "a,%s,%05d$"
3946                         ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3947                         ,tlbl->key + 100);
3948             }
3949           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3950         }
3951       if (size > 3)
3952         {
3953           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3954               IS_AOP_PREG (IC_RESULT (ic)))
3955             emitcode ("cjne", "%s,#0xff,%05d$"
3956                       ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3957                       ,tlbl->key + 100);
3958           else
3959             {
3960               emitcode ("cjne", "a,%s,%05d$"
3961                         ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3962                         ,tlbl->key + 100);
3963             }
3964           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3965         }
3966       if (emitTlbl)
3967         {
3968           emitcode ("", "%05d$:", tlbl->key + 100);
3969         }
3970       return TRUE;
3971     }
3972
3973   /* if the sizes are greater than 1 then we cannot */
3974   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3975       AOP_SIZE (IC_LEFT (ic)) > 1)
3976     return FALSE;
3977
3978   /* we can if the aops of the left & result match or
3979      if they are in registers and the registers are the
3980      same */
3981   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3982     {
3983
3984       while (icount--)
3985         emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
3986
3987       return TRUE;
3988     }
3989
3990   return FALSE;
3991 }
3992
3993 /*-----------------------------------------------------------------*/
3994 /* addSign - complete with sign                                    */
3995 /*-----------------------------------------------------------------*/
3996 static void
3997 addSign (operand * result, int offset, int sign)
3998 {
3999   int size = (getDataSize (result) - offset);
4000   if (size > 0)
4001     {
4002       if (sign)
4003         {
4004           emitcode ("rlc", "a");
4005           emitcode ("subb", "a,acc");
4006           while (size--)
4007             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4008         }
4009       else
4010         while (size--)
4011           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4012     }
4013 }
4014
4015 /*-----------------------------------------------------------------*/
4016 /* genMinusBits - generates code for subtraction  of two bits      */
4017 /*-----------------------------------------------------------------*/
4018 static void
4019 genMinusBits (iCode * ic)
4020 {
4021   symbol *lbl = newiTempLabel (NULL);
4022
4023   D(emitcode (";     genMinusBits",""));
4024
4025   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4026     {
4027       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4028       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4029       emitcode ("cpl", "c");
4030       emitcode ("", "%05d$:", (lbl->key + 100));
4031       outBitC (IC_RESULT (ic));
4032     }
4033   else
4034     {
4035       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4036       emitcode ("subb", "a,acc");
4037       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4038       emitcode ("inc", "a");
4039       emitcode ("", "%05d$:", (lbl->key + 100));
4040       aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4041       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4042     }
4043 }
4044
4045 /*-----------------------------------------------------------------*/
4046 /* genMinus - generates code for subtraction                       */
4047 /*-----------------------------------------------------------------*/
4048 static void
4049 genMinus (iCode * ic)
4050 {
4051   int size, offset = 0;
4052
4053   D(emitcode (";     genMinus",""));
4054
4055   aopOp (IC_LEFT (ic), ic, FALSE);
4056   aopOp (IC_RIGHT (ic), ic, FALSE);
4057   aopOp (IC_RESULT (ic), ic, TRUE);
4058
4059   /* special cases :- */
4060   /* if both left & right are in bit space */
4061   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4062       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4063     {
4064       genMinusBits (ic);
4065       goto release;
4066     }
4067
4068   /* if I can do an decrement instead
4069      of subtract then GOOD for ME */
4070   if (genMinusDec (ic) == TRUE)
4071     goto release;
4072
4073   size = getDataSize (IC_RESULT (ic));
4074
4075   /* if literal, add a,#-lit, else normal subb */
4076   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4077     {
4078       unsigned long lit = 0L;
4079
4080       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4081       lit = -(long) lit;
4082
4083       while (size--)
4084         {
4085           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE));
4086           /* first add without previous c */
4087           if (!offset) {
4088             if (!size && lit== (unsigned long) -1) {
4089               emitcode ("dec", "a");
4090             } else {
4091               emitcode ("add", "a,#0x%02x",
4092                         (unsigned int) (lit & 0x0FFL));
4093             }
4094           } else {
4095             emitcode ("addc", "a,#0x%02x",
4096                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4097           }
4098           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4099         }
4100     }
4101   else
4102     {
4103       asmop *leftOp, *rightOp;
4104
4105       leftOp = AOP(IC_LEFT(ic));
4106       rightOp = AOP(IC_RIGHT(ic));
4107
4108       while (size--)
4109         {
4110           if (aopGetUsesAcc(rightOp, offset)) {
4111             if (aopGetUsesAcc(leftOp, offset)) {
4112               bool pushedB;
4113
4114               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4115               pushedB = pushB ();
4116               emitcode ("mov", "b,a");
4117               if (offset == 0)
4118                 CLRC;
4119               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4120               emitcode ("subb", "a,b");
4121               popB (pushedB);
4122             } else {
4123               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4124               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4125               if (offset == 0) {
4126                 emitcode( "setb", "c");
4127               }
4128               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4129               emitcode("cpl", "a");
4130             }
4131           } else {
4132             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4133             if (offset == 0)
4134               CLRC;
4135             emitcode ("subb", "a,%s",
4136                       aopGet(rightOp, offset, FALSE, TRUE));
4137           }
4138
4139           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4140         }
4141     }
4142
4143
4144   adjustArithmeticResult (ic);
4145
4146 release:
4147   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4148   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4149   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4150 }
4151
4152
4153 /*-----------------------------------------------------------------*/
4154 /* genMultbits :- multiplication of bits                           */
4155 /*-----------------------------------------------------------------*/
4156 static void
4157 genMultbits (operand * left,
4158              operand * right,
4159              operand * result)
4160 {
4161   D(emitcode (";     genMultbits",""));
4162
4163   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4164   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4165   outBitC (result);
4166 }
4167
4168 /*-----------------------------------------------------------------*/
4169 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4170 /*-----------------------------------------------------------------*/
4171 static void
4172 genMultOneByte (operand * left,
4173                 operand * right,
4174                 operand * result)
4175 {
4176   symbol *lbl;
4177   int size = AOP_SIZE (result);
4178   bool runtimeSign, compiletimeSign;
4179   bool lUnsigned, rUnsigned, pushedB;
4180
4181   D(emitcode (";     genMultOneByte",""));
4182
4183   if (size < 1 || size > 2)
4184     {
4185       /* this should never happen */
4186       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4187                AOP_SIZE(result), __FILE__, lineno);
4188       exit (1);
4189     }
4190
4191   /* (if two literals: the value is computed before) */
4192   /* if one literal, literal on the right */
4193   if (AOP_TYPE (left) == AOP_LIT)
4194     {
4195       operand *t = right;
4196       right = left;
4197       left = t;
4198       /* emitcode (";", "swapped left and right"); */
4199     }
4200   /* if no literal, unsigned on the right: shorter code */
4201   if (   AOP_TYPE (right) != AOP_LIT
4202       && SPEC_USIGN (getSpec (operandType (left))))
4203     {
4204       operand *t = right;
4205       right = left;
4206       left = t;
4207     }
4208
4209   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4210   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4211
4212   pushedB = pushB ();
4213
4214   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4215                    no need to take care about the signedness! */
4216       || (lUnsigned && rUnsigned))
4217     {
4218       /* just an unsigned 8 * 8 = 8 multiply
4219          or 8u * 8u = 16u */
4220       /* emitcode (";","unsigned"); */
4221       /* TODO: check for accumulator clash between left & right aops? */
4222
4223       if (AOP_TYPE (right) == AOP_LIT)
4224         {
4225           /* moving to accumulator first helps peepholes */
4226           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4227           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4228         }
4229       else
4230         {
4231           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4232           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4233         }
4234
4235       emitcode ("mul", "ab");
4236       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4237       if (size == 2)
4238         aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4239
4240       popB (pushedB);
4241       return;
4242     }
4243
4244   /* we have to do a signed multiply */
4245   /* emitcode (";", "signed"); */
4246
4247   /* now sign adjust for both left & right */
4248
4249   /* let's see what's needed: */
4250   /* apply negative sign during runtime */
4251   runtimeSign = FALSE;
4252   /* negative sign from literals */
4253   compiletimeSign = FALSE;
4254
4255   if (!lUnsigned)
4256     {
4257       if (AOP_TYPE(left) == AOP_LIT)
4258         {
4259           /* signed literal */
4260           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4261           if (val < 0)
4262             compiletimeSign = TRUE;
4263         }
4264       else
4265         /* signed but not literal */
4266         runtimeSign = TRUE;
4267     }
4268
4269   if (!rUnsigned)
4270     {
4271       if (AOP_TYPE(right) == AOP_LIT)
4272         {
4273           /* signed literal */
4274           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4275           if (val < 0)
4276             compiletimeSign ^= TRUE;
4277         }
4278       else
4279         /* signed but not literal */
4280         runtimeSign = TRUE;
4281     }
4282
4283   /* initialize F0, which stores the runtime sign */
4284   if (runtimeSign)
4285     {
4286       if (compiletimeSign)
4287         emitcode ("setb", "F0"); /* set sign flag */
4288       else
4289         emitcode ("clr", "F0"); /* reset sign flag */
4290     }
4291
4292   /* save the signs of the operands */
4293   if (AOP_TYPE(right) == AOP_LIT)
4294     {
4295       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4296
4297       if (!rUnsigned && val < 0)
4298         emitcode ("mov", "b,#0x%02x", -val);
4299       else
4300         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4301     }
4302   else /* ! literal */
4303     {
4304       if (rUnsigned)  /* emitcode (";", "signed"); */
4305
4306         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4307       else
4308         {
4309           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4310           lbl = newiTempLabel (NULL);
4311           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4312           emitcode ("cpl", "F0"); /* complement sign flag */
4313           emitcode ("cpl", "a");  /* 2's complement */
4314           emitcode ("inc", "a");
4315           emitcode ("", "%05d$:", (lbl->key + 100));
4316           emitcode ("mov", "b,a");
4317         }
4318     }
4319
4320   if (AOP_TYPE(left) == AOP_LIT)
4321     {
4322       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4323
4324       if (!lUnsigned && val < 0)
4325         emitcode ("mov", "a,#0x%02x", -val);
4326       else
4327         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4328     }
4329   else /* ! literal */
4330     {
4331       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4332
4333       if (!lUnsigned)
4334         {
4335           lbl = newiTempLabel (NULL);
4336           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4337           emitcode ("cpl", "F0"); /* complement sign flag */
4338           emitcode ("cpl", "a"); /* 2's complement */
4339           emitcode ("inc", "a");
4340           emitcode ("", "%05d$:", (lbl->key + 100));
4341         }
4342     }
4343
4344   /* now the multiplication */
4345   emitcode ("mul", "ab");
4346   if (runtimeSign || compiletimeSign)
4347     {
4348       lbl = newiTempLabel (NULL);
4349       if (runtimeSign)
4350         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4351       emitcode ("cpl", "a"); /* lsb 2's complement */
4352       if (size != 2)
4353         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4354       else
4355         {
4356           emitcode ("add", "a,#1"); /* this sets carry flag */
4357           emitcode ("xch", "a,b");
4358           emitcode ("cpl", "a"); /* msb 2's complement */
4359           emitcode ("addc", "a,#0");
4360           emitcode ("xch", "a,b");
4361         }
4362       emitcode ("", "%05d$:", (lbl->key + 100));
4363     }
4364   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4365   if (size == 2)
4366     aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4367
4368   popB (pushedB);
4369 }
4370
4371 /*-----------------------------------------------------------------*/
4372 /* genMult - generates code for multiplication                     */
4373 /*-----------------------------------------------------------------*/
4374 static void
4375 genMult (iCode * ic)
4376 {
4377   operand *left = IC_LEFT (ic);
4378   operand *right = IC_RIGHT (ic);
4379   operand *result = IC_RESULT (ic);
4380
4381   D(emitcode (";     genMult",""));
4382
4383   /* assign the amsops */
4384   aopOp (left, ic, FALSE);
4385   aopOp (right, ic, FALSE);
4386   aopOp (result, ic, TRUE);
4387
4388   /* special cases first */
4389   /* both are bits */
4390   if (AOP_TYPE (left) == AOP_CRY &&
4391       AOP_TYPE (right) == AOP_CRY)
4392     {
4393       genMultbits (left, right, result);
4394       goto release;
4395     }
4396
4397   /* if both are of size == 1 */
4398 #if 0 // one of them can be a sloc shared with the result
4399     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4400 #else
4401   if (getSize(operandType(left)) == 1 &&
4402       getSize(operandType(right)) == 1)
4403 #endif
4404     {
4405       genMultOneByte (left, right, result);
4406       goto release;
4407     }
4408
4409   /* should have been converted to function call */
4410     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4411              getSize(OP_SYMBOL(right)->type));
4412   assert (0);
4413
4414 release:
4415   freeAsmop (result, NULL, ic, TRUE);
4416   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4417   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4418 }
4419
4420 /*-----------------------------------------------------------------*/
4421 /* genDivbits :- division of bits                                  */
4422 /*-----------------------------------------------------------------*/
4423 static void
4424 genDivbits (operand * left,
4425             operand * right,
4426             operand * result)
4427 {
4428   char *l;
4429   bool pushedB;
4430
4431   D(emitcode (";     genDivbits",""));
4432
4433   pushedB = pushB ();
4434
4435   /* the result must be bit */
4436   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4437   l = aopGet (AOP (left), 0, FALSE, FALSE);
4438
4439   MOVA (l);
4440
4441   emitcode ("div", "ab");
4442   emitcode ("rrc", "a");
4443
4444   popB (pushedB);
4445
4446   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4447 }
4448
4449 /*-----------------------------------------------------------------*/
4450 /* genDivOneByte : 8 bit division                                  */
4451 /*-----------------------------------------------------------------*/
4452 static void
4453 genDivOneByte (operand * left,
4454                operand * right,
4455                operand * result)
4456 {
4457   bool lUnsigned, rUnsigned, pushedB;
4458   bool runtimeSign, compiletimeSign;
4459   symbol *lbl;
4460   int size, offset;
4461
4462   D(emitcode (";     genDivOneByte",""));
4463
4464   /* Why is it necessary that genDivOneByte() can return an int result?
4465      Have a look at:
4466
4467         volatile unsigned char uc;
4468         volatile signed char sc1, sc2;
4469         volatile int i;
4470
4471         uc  = 255;
4472         sc1 = -1;
4473         i = uc / sc1;
4474
4475      Or:
4476
4477         sc1 = -128;
4478         sc2 = -1;
4479         i = sc1 / sc2;
4480
4481      In all cases a one byte result would overflow, the following cast to int
4482      would return the wrong result.
4483
4484      Two possible solution:
4485         a) cast operands to int, if ((unsigned) / (signed)) or
4486            ((signed) / (signed))
4487         b) return an 16 bit signed int; this is what we're doing here!
4488   */
4489
4490   size = AOP_SIZE (result) - 1;
4491   offset = 1;
4492   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4493   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4494
4495   pushedB = pushB ();
4496
4497   /* signed or unsigned */
4498   if (lUnsigned && rUnsigned)
4499     {
4500       /* unsigned is easy */
4501       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4502       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4503       emitcode ("div", "ab");
4504       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4505       while (size--)
4506         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4507
4508       popB (pushedB);
4509       return;
4510     }
4511
4512   /* signed is a little bit more difficult */
4513
4514   /* now sign adjust for both left & right */
4515
4516   /* let's see what's needed: */
4517   /* apply negative sign during runtime */
4518   runtimeSign = FALSE;
4519   /* negative sign from literals */
4520   compiletimeSign = FALSE;
4521
4522   if (!lUnsigned)
4523     {
4524       if (AOP_TYPE(left) == AOP_LIT)
4525         {
4526           /* signed literal */
4527           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4528           if (val < 0)
4529             compiletimeSign = TRUE;
4530         }
4531       else
4532         /* signed but not literal */
4533         runtimeSign = TRUE;
4534     }
4535
4536   if (!rUnsigned)
4537     {
4538       if (AOP_TYPE(right) == AOP_LIT)
4539         {
4540           /* signed literal */
4541           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4542           if (val < 0)
4543             compiletimeSign ^= TRUE;
4544         }
4545       else
4546         /* signed but not literal */
4547         runtimeSign = TRUE;
4548     }
4549
4550   /* initialize F0, which stores the runtime sign */
4551   if (runtimeSign)
4552     {
4553       if (compiletimeSign)
4554         emitcode ("setb", "F0"); /* set sign flag */
4555       else
4556         emitcode ("clr", "F0"); /* reset sign flag */
4557     }
4558
4559   /* save the signs of the operands */
4560   if (AOP_TYPE(right) == AOP_LIT)
4561     {
4562       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4563
4564       if (!rUnsigned && val < 0)
4565         emitcode ("mov", "b,#0x%02x", -val);
4566       else
4567         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4568     }
4569   else /* ! literal */
4570     {
4571       if (rUnsigned)
4572         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4573       else
4574         {
4575           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4576           lbl = newiTempLabel (NULL);
4577           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4578           emitcode ("cpl", "F0"); /* complement sign flag */
4579           emitcode ("cpl", "a");  /* 2's complement */
4580           emitcode ("inc", "a");
4581           emitcode ("", "%05d$:", (lbl->key + 100));
4582           emitcode ("mov", "b,a");
4583         }
4584     }
4585
4586   if (AOP_TYPE(left) == AOP_LIT)
4587     {
4588       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4589
4590       if (!lUnsigned && val < 0)
4591         emitcode ("mov", "a,#0x%02x", -val);
4592       else
4593         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4594     }
4595   else /* ! literal */
4596     {
4597       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4598
4599       if (!lUnsigned)
4600         {
4601           lbl = newiTempLabel (NULL);
4602           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4603           emitcode ("cpl", "F0"); /* complement sign flag */
4604           emitcode ("cpl", "a");  /* 2's complement */
4605           emitcode ("inc", "a");
4606           emitcode ("", "%05d$:", (lbl->key + 100));
4607         }
4608     }
4609
4610   /* now the division */
4611   emitcode ("div", "ab");
4612
4613   if (runtimeSign || compiletimeSign)
4614     {
4615       lbl = newiTempLabel (NULL);
4616       if (runtimeSign)
4617         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4618       emitcode ("cpl", "a"); /* lsb 2's complement */
4619       emitcode ("inc", "a");
4620       emitcode ("", "%05d$:", (lbl->key + 100));
4621
4622       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4623       if (size > 0)
4624         {
4625           /* msb is 0x00 or 0xff depending on the sign */
4626           if (runtimeSign)
4627             {
4628               emitcode ("mov", "c,F0");
4629               emitcode ("subb", "a,acc");
4630               while (size--)
4631                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4632             }
4633           else /* compiletimeSign */
4634             while (size--)
4635               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4636         }
4637     }
4638   else
4639     {
4640       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4641       while (size--)
4642         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4643     }
4644
4645   popB (pushedB);
4646 }
4647
4648 /*-----------------------------------------------------------------*/
4649 /* genDiv - generates code for division                            */
4650 /*-----------------------------------------------------------------*/
4651 static void
4652 genDiv (iCode * ic)
4653 {
4654   operand *left = IC_LEFT (ic);
4655   operand *right = IC_RIGHT (ic);
4656   operand *result = IC_RESULT (ic);
4657
4658   D(emitcode (";     genDiv",""));
4659
4660   /* assign the amsops */
4661   aopOp (left, ic, FALSE);
4662   aopOp (right, ic, FALSE);
4663   aopOp (result, ic, TRUE);
4664
4665   /* special cases first */
4666   /* both are bits */
4667   if (AOP_TYPE (left) == AOP_CRY &&
4668       AOP_TYPE (right) == AOP_CRY)
4669     {
4670       genDivbits (left, right, result);
4671       goto release;
4672     }
4673
4674   /* if both are of size == 1 */
4675   if (AOP_SIZE (left) == 1 &&
4676       AOP_SIZE (right) == 1)
4677     {
4678       genDivOneByte (left, right, result);
4679       goto release;
4680     }
4681
4682   /* should have been converted to function call */
4683   assert (0);
4684 release:
4685   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4686   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4687   freeAsmop (result, NULL, ic, TRUE);
4688 }
4689
4690 /*-----------------------------------------------------------------*/
4691 /* genModbits :- modulus of bits                                   */
4692 /*-----------------------------------------------------------------*/
4693 static void
4694 genModbits (operand * left,
4695             operand * right,
4696             operand * result)
4697 {
4698   char *l;
4699   bool pushedB;
4700
4701   D(emitcode (";     genModbits",""));
4702
4703   pushedB = pushB ();
4704
4705   /* the result must be bit */
4706   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4707   l = aopGet (AOP (left), 0, FALSE, FALSE);
4708
4709   MOVA (l);
4710
4711   emitcode ("div", "ab");
4712   emitcode ("mov", "a,b");
4713   emitcode ("rrc", "a");
4714
4715   popB (pushedB);
4716
4717   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4718 }
4719
4720 /*-----------------------------------------------------------------*/
4721 /* genModOneByte : 8 bit modulus                                   */
4722 /*-----------------------------------------------------------------*/
4723 static void
4724 genModOneByte (operand * left,
4725                operand * right,
4726                operand * result)
4727 {
4728   bool lUnsigned, rUnsigned, pushedB;
4729   bool runtimeSign, compiletimeSign;
4730   symbol *lbl;
4731   int size, offset;
4732
4733   D(emitcode (";     genModOneByte",""));
4734
4735   size = AOP_SIZE (result) - 1;
4736   offset = 1;
4737   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4738   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4739
4740   /* if right is a literal, check it for 2^n */
4741   if (AOP_TYPE(right) == AOP_LIT)
4742     {
4743       unsigned char val = abs((int) operandLitValue(right));
4744       symbol *lbl2 = NULL;
4745
4746       switch (val)
4747         {
4748           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
4749           case 2:
4750           case 4:
4751           case 8:
4752           case 16:
4753           case 32:
4754           case 64:
4755           case 128:
4756             if (lUnsigned)
4757               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
4758                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
4759               /* because iCode should have been changed to genAnd  */
4760               /* see file "SDCCopt.c", function "convertToFcall()" */
4761
4762             MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4763             emitcode ("mov", "c,acc.7");
4764             emitcode ("anl", "a,#0x%02x", val - 1);
4765             lbl = newiTempLabel (NULL);
4766             emitcode ("jz", "%05d$", (lbl->key + 100));
4767             emitcode ("jnc", "%05d$", (lbl->key + 100));
4768             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
4769             if (size)
4770               {
4771                 int size2 = size;
4772                 int offs2 = offset;
4773
4774                 aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4775                 while (size2--)
4776                   aopPut (AOP (result), "#0xff", offs2++, isOperandVolatile (result, FALSE));
4777                 lbl2 = newiTempLabel (NULL);
4778                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
4779               }
4780             emitcode ("", "%05d$:", (lbl->key + 100));
4781             aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4782             while (size--)
4783               aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4784             if (lbl2)
4785               {
4786                 emitcode ("", "%05d$:", (lbl2->key + 100));
4787               }
4788             return;
4789
4790           default:
4791             break;
4792         }
4793     }
4794
4795   pushedB = pushB ();
4796
4797   /* signed or unsigned */
4798   if (lUnsigned && rUnsigned)
4799     {
4800       /* unsigned is easy */
4801       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4802       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4803       emitcode ("div", "ab");
4804       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4805       while (size--)
4806         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4807
4808       popB (pushedB);
4809       return;
4810     }
4811
4812   /* signed is a little bit more difficult */
4813
4814   /* now sign adjust for both left & right */
4815
4816   /* modulus: sign of the right operand has no influence on the result! */
4817   if (AOP_TYPE(right) == AOP_LIT)
4818     {
4819       signed char val = (char) operandLitValue(right);
4820
4821       if (!rUnsigned && val < 0)
4822         emitcode ("mov", "b,#0x%02x", -val);
4823       else
4824         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4825     }
4826   else /* not literal */
4827     {
4828       if (rUnsigned)
4829         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4830       else
4831         {
4832           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4833           lbl = newiTempLabel (NULL);
4834           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4835           emitcode ("cpl", "a"); /* 2's complement */
4836           emitcode ("inc", "a");
4837           emitcode ("", "%05d$:", (lbl->key + 100));
4838           emitcode ("mov", "b,a");
4839         }
4840     }
4841
4842   /* let's see what's needed: */
4843   /* apply negative sign during runtime */
4844   runtimeSign = FALSE;
4845   /* negative sign from literals */
4846   compiletimeSign = FALSE;
4847
4848   /* sign adjust left side */
4849   if (AOP_TYPE(left) == AOP_LIT)
4850     {
4851       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4852
4853       if (!lUnsigned && val < 0)
4854         {
4855           compiletimeSign = TRUE; /* set sign flag */
4856           emitcode ("mov", "a,#0x%02x", -val);
4857         }
4858       else
4859         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4860     }
4861   else /* ! literal */
4862     {
4863       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4864
4865       if (!lUnsigned)
4866         {
4867           runtimeSign = TRUE;
4868           emitcode ("clr", "F0"); /* clear sign flag */
4869
4870           lbl = newiTempLabel (NULL);
4871           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4872           emitcode ("setb", "F0"); /* set sign flag */
4873           emitcode ("cpl", "a");   /* 2's complement */
4874           emitcode ("inc", "a");
4875           emitcode ("", "%05d$:", (lbl->key + 100));
4876         }
4877     }
4878
4879   /* now the modulus */
4880   emitcode ("div", "ab");
4881
4882   if (runtimeSign || compiletimeSign)
4883     {
4884       emitcode ("mov", "a,b");
4885       lbl = newiTempLabel (NULL);
4886       if (runtimeSign)
4887         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4888       emitcode ("cpl", "a"); /* 2's complement */
4889       emitcode ("inc", "a");
4890       emitcode ("", "%05d$:", (lbl->key + 100));
4891
4892       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4893       if (size > 0)
4894         {
4895           /* msb is 0x00 or 0xff depending on the sign */
4896           if (runtimeSign)
4897             {
4898               emitcode ("mov", "c,F0");
4899               emitcode ("subb", "a,acc");
4900               while (size--)
4901                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4902             }
4903           else /* compiletimeSign */
4904             while (size--)
4905               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4906         }
4907     }
4908   else
4909     {
4910       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4911       while (size--)
4912         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4913     }
4914
4915   popB (pushedB);
4916 }
4917
4918 /*-----------------------------------------------------------------*/
4919 /* genMod - generates code for division                            */
4920 /*-----------------------------------------------------------------*/
4921 static void
4922 genMod (iCode * ic)
4923 {
4924   operand *left = IC_LEFT (ic);
4925   operand *right = IC_RIGHT (ic);
4926   operand *result = IC_RESULT (ic);
4927
4928   D(emitcode (";     genMod",""));
4929
4930   /* assign the asmops */
4931   aopOp (left, ic, FALSE);
4932   aopOp (right, ic, FALSE);
4933   aopOp (result, ic, TRUE);
4934
4935   /* special cases first */
4936   /* both are bits */
4937   if (AOP_TYPE (left) == AOP_CRY &&
4938       AOP_TYPE (right) == AOP_CRY)
4939     {
4940       genModbits (left, right, result);
4941       goto release;
4942     }
4943
4944   /* if both are of size == 1 */
4945   if (AOP_SIZE (left) == 1 &&
4946       AOP_SIZE (right) == 1)
4947     {
4948       genModOneByte (left, right, result);
4949       goto release;
4950     }
4951
4952   /* should have been converted to function call */
4953   assert (0);
4954
4955 release:
4956   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4957   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4958   freeAsmop (result, NULL, ic, TRUE);
4959 }
4960
4961 /*-----------------------------------------------------------------*/
4962 /* genIfxJump :- will create a jump depending on the ifx           */
4963 /*-----------------------------------------------------------------*/
4964 static void
4965 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
4966 {
4967   symbol *jlbl;
4968   symbol *tlbl = newiTempLabel (NULL);
4969   char *inst;
4970
4971   D(emitcode (";     genIfxJump",""));
4972
4973   /* if true label then we jump if condition
4974      supplied is true */
4975   if (IC_TRUE (ic))
4976     {
4977       jlbl = IC_TRUE (ic);
4978       inst = ((strcmp (jval, "a") == 0 ? "jz" :
4979                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
4980     }
4981   else
4982     {
4983       /* false label is present */
4984       jlbl = IC_FALSE (ic);
4985       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
4986                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
4987     }
4988   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
4989     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
4990   else
4991     emitcode (inst, "%05d$", tlbl->key + 100);
4992   freeForBranchAsmop (result);
4993   freeForBranchAsmop (right);
4994   freeForBranchAsmop (left);
4995   emitcode ("ljmp", "%05d$", jlbl->key + 100);
4996   emitcode ("", "%05d$:", tlbl->key + 100);
4997
4998   /* mark the icode as generated */
4999   ic->generated = 1;
5000 }
5001
5002 /*-----------------------------------------------------------------*/
5003 /* genCmp :- greater or less than comparison                       */
5004 /*-----------------------------------------------------------------*/
5005 static void
5006 genCmp (operand * left, operand * right,
5007         operand * result, iCode * ifx, int sign, iCode *ic)
5008 {
5009   int size, offset = 0;
5010   unsigned long lit = 0L;
5011   bool rightInB;
5012
5013   D(emitcode (";     genCmp",""));
5014
5015   /* if left & right are bit variables */
5016   if (AOP_TYPE (left) == AOP_CRY &&
5017       AOP_TYPE (right) == AOP_CRY)
5018     {
5019       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5020       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5021     }
5022   else
5023     {
5024       /* subtract right from left if at the
5025          end the carry flag is set then we know that
5026          left is greater than right */
5027       size = max (AOP_SIZE (left), AOP_SIZE (right));
5028
5029       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5030       if ((size == 1) && !sign &&
5031           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5032         {
5033           symbol *lbl = newiTempLabel (NULL);
5034           emitcode ("cjne", "%s,%s,%05d$",
5035                     aopGet (AOP (left), offset, FALSE, FALSE),
5036                     aopGet (AOP (right), offset, FALSE, FALSE),
5037                     lbl->key + 100);
5038           emitcode ("", "%05d$:", lbl->key + 100);
5039         }
5040       else
5041         {
5042           if (AOP_TYPE (right) == AOP_LIT)
5043             {
5044               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5045               /* optimize if(x < 0) or if(x >= 0) */
5046               if (lit == 0L)
5047                 {
5048                   if (!sign)
5049                     {
5050                       CLRC;
5051                     }
5052                   else
5053                     {
5054                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
5055                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5056                         {
5057                           genIfxJump (ifx, "acc.7", left, right, result);
5058                           freeAsmop (right, NULL, ic, TRUE);
5059                           freeAsmop (left, NULL, ic, TRUE);
5060
5061                           return;
5062                         }
5063                       else
5064                         emitcode ("rlc", "a");
5065                     }
5066                   goto release;
5067                 }
5068             }
5069           CLRC;
5070           while (size--)
5071             {
5072               bool pushedB = FALSE;
5073               rightInB = aopGetUsesAcc(AOP (right), offset);
5074               if (rightInB)
5075                 {
5076                   pushedB = pushB ();
5077                   emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5078                 }
5079               MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5080               if (sign && size == 0)
5081                 {
5082                   emitcode ("xrl", "a,#0x80");
5083                   if (AOP_TYPE (right) == AOP_LIT)
5084                     {
5085                       unsigned long lit = (unsigned long)
5086                       floatFromVal (AOP (right)->aopu.aop_lit);
5087                       emitcode ("subb", "a,#0x%02x",
5088                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5089                     }
5090                   else
5091                     {
5092                       if (!rightInB)
5093                         {
5094                           pushedB = pushB ();
5095                           rightInB++;
5096                           emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5097                         }
5098                       emitcode ("xrl", "b,#0x80");
5099                       emitcode ("subb", "a,b");
5100                     }
5101                 }
5102               else
5103                 {
5104                   if (rightInB)
5105                     emitcode ("subb", "a,b");
5106                   else
5107                     emitcode ("subb", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5108                 }
5109               if (rightInB)
5110                 popB (pushedB);
5111               offset++;
5112             }
5113         }
5114     }
5115
5116 release:
5117   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5118   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5119   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5120     {
5121       outBitC (result);
5122     }
5123   else
5124     {
5125       /* if the result is used in the next
5126          ifx conditional branch then generate
5127          code a little differently */
5128       if (ifx)
5129         genIfxJump (ifx, "c", NULL, NULL, result);
5130       else
5131         outBitC (result);
5132       /* leave the result in acc */
5133     }
5134 }
5135
5136 /*-----------------------------------------------------------------*/
5137 /* genCmpGt :- greater than comparison                             */
5138 /*-----------------------------------------------------------------*/
5139 static void
5140 genCmpGt (iCode * ic, iCode * ifx)
5141 {
5142   operand *left, *right, *result;
5143   sym_link *letype, *retype;
5144   int sign;
5145
5146   D(emitcode (";     genCmpGt",""));
5147
5148   left = IC_LEFT (ic);
5149   right = IC_RIGHT (ic);
5150   result = IC_RESULT (ic);
5151
5152   letype = getSpec (operandType (left));
5153   retype = getSpec (operandType (right));
5154   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5155            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5156   /* assign the amsops */
5157   aopOp (left, ic, FALSE);
5158   aopOp (right, ic, FALSE);
5159   aopOp (result, ic, TRUE);
5160
5161   genCmp (right, left, result, ifx, sign, ic);
5162
5163   freeAsmop (result, NULL, ic, TRUE);
5164 }
5165
5166 /*-----------------------------------------------------------------*/
5167 /* genCmpLt - less than comparisons                                */
5168 /*-----------------------------------------------------------------*/
5169 static void
5170 genCmpLt (iCode * ic, iCode * ifx)
5171 {
5172   operand *left, *right, *result;
5173   sym_link *letype, *retype;
5174   int sign;
5175
5176   D(emitcode (";     genCmpLt",""));
5177
5178   left = IC_LEFT (ic);
5179   right = IC_RIGHT (ic);
5180   result = IC_RESULT (ic);
5181
5182   letype = getSpec (operandType (left));
5183   retype = getSpec (operandType (right));
5184   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5185            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5186   /* assign the amsops */
5187   aopOp (left, ic, FALSE);
5188   aopOp (right, ic, FALSE);
5189   aopOp (result, ic, TRUE);
5190
5191   genCmp (left, right, result, ifx, sign,ic);
5192
5193   freeAsmop (result, NULL, ic, TRUE);
5194 }
5195
5196 /*-----------------------------------------------------------------*/
5197 /* gencjneshort - compare and jump if not equal                    */
5198 /*-----------------------------------------------------------------*/
5199 static void
5200 gencjneshort (operand * left, operand * right, symbol * lbl)
5201 {
5202   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5203   int offset = 0;
5204   unsigned long lit = 0L;
5205
5206   /* if the left side is a literal or
5207      if the right is in a pointer register and left
5208      is not */
5209   if ((AOP_TYPE (left) == AOP_LIT) ||
5210       (AOP_TYPE (left) == AOP_IMMD) ||
5211       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5212     {
5213       operand *t = right;
5214       right = left;
5215       left = t;
5216     }
5217
5218   if (AOP_TYPE (right) == AOP_LIT)
5219     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5220
5221   /* if the right side is a literal then anything goes */
5222   if (AOP_TYPE (right) == AOP_LIT &&
5223       AOP_TYPE (left) != AOP_DIR  &&
5224       AOP_TYPE (left) != AOP_IMMD)
5225     {
5226       while (size--)
5227         {
5228           emitcode ("cjne", "%s,%s,%05d$",
5229                     aopGet (AOP (left), offset, FALSE, FALSE),
5230                     aopGet (AOP (right), offset, FALSE, FALSE),
5231                     lbl->key + 100);
5232           offset++;
5233         }
5234     }
5235
5236   /* if the right side is in a register or in direct space or
5237      if the left is a pointer register & right is not */
5238   else if (AOP_TYPE (right) == AOP_REG ||
5239            AOP_TYPE (right) == AOP_DIR ||
5240            AOP_TYPE (right) == AOP_LIT ||
5241            AOP_TYPE (right) == AOP_IMMD ||
5242            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5243            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5244     {
5245       while (size--)
5246         {
5247           MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5248           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5249               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5250             emitcode ("jnz", "%05d$", lbl->key + 100);
5251           else
5252             emitcode ("cjne", "a,%s,%05d$",
5253                       aopGet (AOP (right), offset, FALSE, TRUE),
5254                       lbl->key + 100);
5255           offset++;
5256         }
5257     }
5258   else
5259     {
5260       /* right is a pointer reg need both a & b */
5261       while (size--)
5262         {
5263           char *l;
5264           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5265           wassertl(!BINUSE, "B was in use");
5266           l = aopGet (AOP (left), offset, FALSE, FALSE);
5267           if (strcmp (l, "b"))
5268             emitcode ("mov", "b,%s", l);
5269           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5270           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5271           offset++;
5272         }
5273     }
5274 }
5275
5276 /*-----------------------------------------------------------------*/
5277 /* gencjne - compare and jump if not equal                         */
5278 /*-----------------------------------------------------------------*/
5279 static void
5280 gencjne (operand * left, operand * right, symbol * lbl)
5281 {
5282   symbol *tlbl = newiTempLabel (NULL);
5283
5284   gencjneshort (left, right, lbl);
5285
5286   emitcode ("mov", "a,%s", one);
5287   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5288   emitcode ("", "%05d$:", lbl->key + 100);
5289   emitcode ("clr", "a");
5290   emitcode ("", "%05d$:", tlbl->key + 100);
5291 }
5292
5293 /*-----------------------------------------------------------------*/
5294 /* genCmpEq - generates code for equal to                          */
5295 /*-----------------------------------------------------------------*/
5296 static void
5297 genCmpEq (iCode * ic, iCode * ifx)
5298 {
5299   operand *left, *right, *result;
5300
5301   D(emitcode (";     genCmpEq",""));
5302
5303   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5304   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5305   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5306
5307   /* if literal, literal on the right or
5308      if the right is in a pointer register and left
5309      is not */
5310   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5311       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5312     {
5313       operand *t = IC_RIGHT (ic);
5314       IC_RIGHT (ic) = IC_LEFT (ic);
5315       IC_LEFT (ic) = t;
5316     }
5317
5318   if (ifx && !AOP_SIZE (result))
5319     {
5320       symbol *tlbl;
5321       /* if they are both bit variables */
5322       if (AOP_TYPE (left) == AOP_CRY &&
5323           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5324         {
5325           if (AOP_TYPE (right) == AOP_LIT)
5326             {
5327               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5328               if (lit == 0L)
5329                 {
5330                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5331                   emitcode ("cpl", "c");
5332                 }
5333               else if (lit == 1L)
5334                 {
5335                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5336                 }
5337               else
5338                 {
5339                   emitcode ("clr", "c");
5340                 }
5341               /* AOP_TYPE(right) == AOP_CRY */
5342             }
5343           else
5344             {
5345               symbol *lbl = newiTempLabel (NULL);
5346               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5347               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5348               emitcode ("cpl", "c");
5349               emitcode ("", "%05d$:", (lbl->key + 100));
5350             }
5351           /* if true label then we jump if condition
5352              supplied is true */
5353           tlbl = newiTempLabel (NULL);
5354           if (IC_TRUE (ifx))
5355             {
5356               emitcode ("jnc", "%05d$", tlbl->key + 100);
5357               freeForBranchAsmop (result);
5358               freeForBranchAsmop (right);
5359               freeForBranchAsmop (left);
5360               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5361             }
5362           else
5363             {
5364               emitcode ("jc", "%05d$", tlbl->key + 100);
5365               freeForBranchAsmop (result);
5366               freeForBranchAsmop (right);
5367               freeForBranchAsmop (left);
5368               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5369             }
5370           emitcode ("", "%05d$:", tlbl->key + 100);
5371         }
5372       else
5373         {
5374           tlbl = newiTempLabel (NULL);
5375           gencjneshort (left, right, tlbl);
5376           if (IC_TRUE (ifx))
5377             {
5378               freeForBranchAsmop (result);
5379               freeForBranchAsmop (right);
5380               freeForBranchAsmop (left);
5381               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5382               emitcode ("", "%05d$:", tlbl->key + 100);
5383             }
5384           else
5385             {
5386               symbol *lbl = newiTempLabel (NULL);
5387               emitcode ("sjmp", "%05d$", lbl->key + 100);
5388               emitcode ("", "%05d$:", tlbl->key + 100);
5389               freeForBranchAsmop (result);
5390               freeForBranchAsmop (right);
5391               freeForBranchAsmop (left);
5392               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5393               emitcode ("", "%05d$:", lbl->key + 100);
5394             }
5395         }
5396       /* mark the icode as generated */
5397       ifx->generated = 1;
5398       goto release;
5399     }
5400
5401   /* if they are both bit variables */
5402   if (AOP_TYPE (left) == AOP_CRY &&
5403       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5404     {
5405       if (AOP_TYPE (right) == AOP_LIT)
5406         {
5407           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5408           if (lit == 0L)
5409             {
5410               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5411               emitcode ("cpl", "c");
5412             }
5413           else if (lit == 1L)
5414             {
5415               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5416             }
5417           else
5418             {
5419               emitcode ("clr", "c");
5420             }
5421           /* AOP_TYPE(right) == AOP_CRY */
5422         }
5423       else
5424         {
5425           symbol *lbl = newiTempLabel (NULL);
5426           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5427           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5428           emitcode ("cpl", "c");
5429           emitcode ("", "%05d$:", (lbl->key + 100));
5430         }
5431       /* c = 1 if egal */
5432       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5433         {
5434           outBitC (result);
5435           goto release;
5436         }
5437       if (ifx)
5438         {
5439           genIfxJump (ifx, "c", left, right, result);
5440           goto release;
5441         }
5442       /* if the result is used in an arithmetic operation
5443          then put the result in place */
5444       outBitC (result);
5445     }
5446   else
5447     {
5448       gencjne (left, right, newiTempLabel (NULL));
5449       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5450         {
5451           aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
5452           goto release;
5453         }
5454       if (ifx)
5455         {
5456           genIfxJump (ifx, "a", left, right, result);
5457           goto release;
5458         }
5459       /* if the result is used in an arithmetic operation
5460          then put the result in place */
5461       if (AOP_TYPE (result) != AOP_CRY)
5462         outAcc (result);
5463       /* leave the result in acc */
5464     }
5465
5466 release:
5467   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5468   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5469   freeAsmop (result, NULL, ic, TRUE);
5470 }
5471
5472 /*-----------------------------------------------------------------*/
5473 /* ifxForOp - returns the icode containing the ifx for operand     */
5474 /*-----------------------------------------------------------------*/
5475 static iCode *
5476 ifxForOp (operand * op, iCode * ic)
5477 {
5478   /* if true symbol then needs to be assigned */
5479   if (IS_TRUE_SYMOP (op))
5480     return NULL;
5481
5482   /* if this has register type condition and
5483      the next instruction is ifx with the same operand
5484      and live to of the operand is upto the ifx only then */
5485   if (ic->next &&
5486       ic->next->op == IFX &&
5487       IC_COND (ic->next)->key == op->key &&
5488       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5489     return ic->next;
5490
5491   return NULL;
5492 }
5493
5494 /*-----------------------------------------------------------------*/
5495 /* hasInc - operand is incremented before any other use            */
5496 /*-----------------------------------------------------------------*/
5497 static iCode *
5498 hasInc (operand *op, iCode *ic,int osize)
5499 {
5500   sym_link *type = operandType(op);
5501   sym_link *retype = getSpec (type);
5502   iCode *lic = ic->next;
5503   int isize ;
5504
5505   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5506   if (!IS_SYMOP(op)) return NULL;
5507
5508   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5509   if (IS_AGGREGATE(type->next)) return NULL;
5510   if (osize != (isize = getSize(type->next))) return NULL;
5511
5512   while (lic) {
5513     /* if operand of the form op = op + <sizeof *op> */
5514     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5515         isOperandEqual(IC_RESULT(lic),op) &&
5516         isOperandLiteral(IC_RIGHT(lic)) &&
5517         operandLitValue(IC_RIGHT(lic)) == isize) {
5518       return lic;
5519     }
5520     /* if the operand used or deffed */
5521     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5522       return NULL;
5523     }
5524     /* if GOTO or IFX */
5525     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5526     lic = lic->next;
5527   }
5528   return NULL;
5529 }
5530
5531 /*-----------------------------------------------------------------*/
5532 /* genAndOp - for && operation                                     */
5533 /*-----------------------------------------------------------------*/
5534 static void
5535 genAndOp (iCode * ic)
5536 {
5537   operand *left, *right, *result;
5538   symbol *tlbl;
5539
5540   D(emitcode (";     genAndOp",""));
5541
5542   /* note here that && operations that are in an
5543      if statement are taken away by backPatchLabels
5544      only those used in arthmetic operations remain */
5545   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5546   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5547   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5548
5549   /* if both are bit variables */
5550   if (AOP_TYPE (left) == AOP_CRY &&
5551       AOP_TYPE (right) == AOP_CRY)
5552     {
5553       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5554       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5555       outBitC (result);
5556     }
5557   else
5558     {
5559       tlbl = newiTempLabel (NULL);
5560       toBoolean (left);
5561       emitcode ("jz", "%05d$", tlbl->key + 100);
5562       toBoolean (right);
5563       emitcode ("", "%05d$:", tlbl->key + 100);
5564       outBitAcc (result);
5565     }
5566
5567   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5568   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5569   freeAsmop (result, NULL, ic, TRUE);
5570 }
5571
5572
5573 /*-----------------------------------------------------------------*/
5574 /* genOrOp - for || operation                                      */
5575 /*-----------------------------------------------------------------*/
5576 static void
5577 genOrOp (iCode * ic)
5578 {
5579   operand *left, *right, *result;
5580   symbol *tlbl;
5581
5582   D(emitcode (";     genOrOp",""));
5583
5584   /* note here that || operations that are in an
5585      if statement are taken away by backPatchLabels
5586      only those used in arthmetic operations remain */
5587   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5588   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5589   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5590
5591   /* if both are bit variables */
5592   if (AOP_TYPE (left) == AOP_CRY &&
5593       AOP_TYPE (right) == AOP_CRY)
5594     {
5595       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5596       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5597       outBitC (result);
5598     }
5599   else
5600     {
5601       tlbl = newiTempLabel (NULL);
5602       toBoolean (left);
5603       emitcode ("jnz", "%05d$", tlbl->key + 100);
5604       toBoolean (right);
5605       emitcode ("", "%05d$:", tlbl->key + 100);
5606       outBitAcc (result);
5607     }
5608
5609   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5610   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5611   freeAsmop (result, NULL, ic, TRUE);
5612 }
5613
5614 /*-----------------------------------------------------------------*/
5615 /* isLiteralBit - test if lit == 2^n                               */
5616 /*-----------------------------------------------------------------*/
5617 static int
5618 isLiteralBit (unsigned long lit)
5619 {
5620   unsigned long pw[32] =
5621   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5622    0x100L, 0x200L, 0x400L, 0x800L,
5623    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5624    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5625    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5626    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5627    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5628   int idx;
5629
5630   for (idx = 0; idx < 32; idx++)
5631     if (lit == pw[idx])
5632       return idx + 1;
5633   return 0;
5634 }
5635
5636 /*-----------------------------------------------------------------*/
5637 /* continueIfTrue -                                                */
5638 /*-----------------------------------------------------------------*/
5639 static void
5640 continueIfTrue (iCode * ic)
5641 {
5642   if (IC_TRUE (ic))
5643     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5644   ic->generated = 1;
5645 }
5646
5647 /*-----------------------------------------------------------------*/
5648 /* jmpIfTrue -                                                     */
5649 /*-----------------------------------------------------------------*/
5650 static void
5651 jumpIfTrue (iCode * ic)
5652 {
5653   if (!IC_TRUE (ic))
5654     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5655   ic->generated = 1;
5656 }
5657
5658 /*-----------------------------------------------------------------*/
5659 /* jmpTrueOrFalse -                                                */
5660 /*-----------------------------------------------------------------*/
5661 static void
5662 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5663 {
5664   // ugly but optimized by peephole
5665   if (IC_TRUE (ic))
5666     {
5667       symbol *nlbl = newiTempLabel (NULL);
5668       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5669       emitcode ("", "%05d$:", tlbl->key + 100);
5670       freeForBranchAsmop (result);
5671       freeForBranchAsmop (right);
5672       freeForBranchAsmop (left);
5673       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5674       emitcode ("", "%05d$:", nlbl->key + 100);
5675     }
5676   else
5677     {
5678       freeForBranchAsmop (result);
5679       freeForBranchAsmop (right);
5680       freeForBranchAsmop (left);
5681       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5682       emitcode ("", "%05d$:", tlbl->key + 100);
5683     }
5684   ic->generated = 1;
5685 }
5686
5687 /*-----------------------------------------------------------------*/
5688 /* genAnd  - code for and                                          */
5689 /*-----------------------------------------------------------------*/
5690 static void
5691 genAnd (iCode * ic, iCode * ifx)
5692 {
5693   operand *left, *right, *result;
5694   int size, offset = 0;
5695   unsigned long lit = 0L;
5696   int bytelit = 0;
5697   char buffer[10];
5698
5699   D(emitcode (";     genAnd",""));
5700
5701   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5702   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5703   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5704
5705 #ifdef DEBUG_TYPE
5706   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5707             AOP_TYPE (result),
5708             AOP_TYPE (left), AOP_TYPE (right));
5709   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5710             AOP_SIZE (result),
5711             AOP_SIZE (left), AOP_SIZE (right));
5712 #endif
5713
5714   /* if left is a literal & right is not then exchange them */
5715   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5716       AOP_NEEDSACC (left))
5717     {
5718       operand *tmp = right;
5719       right = left;
5720       left = tmp;
5721     }
5722
5723   /* if result = right then exchange left and right */
5724   if (sameRegs (AOP (result), AOP (right)))
5725     {
5726       operand *tmp = right;
5727       right = left;
5728       left = tmp;
5729     }
5730
5731   /* if right is bit then exchange them */
5732   if (AOP_TYPE (right) == AOP_CRY &&
5733       AOP_TYPE (left) != AOP_CRY)
5734     {
5735       operand *tmp = right;
5736       right = left;
5737       left = tmp;
5738     }
5739   if (AOP_TYPE (right) == AOP_LIT)
5740     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5741
5742   size = AOP_SIZE (result);
5743
5744   // if(bit & yy)
5745   // result = bit & yy;
5746   if (AOP_TYPE (left) == AOP_CRY)
5747     {
5748       // c = bit & literal;
5749       if (AOP_TYPE (right) == AOP_LIT)
5750         {
5751           if (lit & 1)
5752             {
5753               if (size && sameRegs (AOP (result), AOP (left)))
5754                 // no change
5755                 goto release;
5756               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5757             }
5758           else
5759             {
5760               // bit(result) = 0;
5761               if (size && (AOP_TYPE (result) == AOP_CRY))
5762                 {
5763                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5764                   goto release;
5765                 }
5766               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5767                 {
5768                   jumpIfTrue (ifx);
5769                   goto release;
5770                 }
5771               emitcode ("clr", "c");
5772             }
5773         }
5774       else
5775         {
5776           if (AOP_TYPE (right) == AOP_CRY)
5777             {
5778               // c = bit & bit;
5779               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5780               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5781             }
5782           else
5783             {
5784               // c = bit & val;
5785               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
5786               // c = lsb
5787               emitcode ("rrc", "a");
5788               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5789             }
5790         }
5791       // bit = c
5792       // val = c
5793       if (size)
5794         outBitC (result);
5795       // if(bit & ...)
5796       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5797         genIfxJump (ifx, "c", left, right, result);
5798       goto release;
5799     }
5800
5801   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5802   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5803   if ((AOP_TYPE (right) == AOP_LIT) &&
5804       (AOP_TYPE (result) == AOP_CRY) &&
5805       (AOP_TYPE (left) != AOP_CRY))
5806     {
5807       int posbit = isLiteralBit (lit);
5808       /* left &  2^n */
5809       if (posbit)
5810         {
5811           posbit--;
5812           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE));
5813           // bit = left & 2^n
5814           if (size)
5815             {
5816               switch (posbit & 0x07)
5817                 {
5818                   case 0: emitcode ("rrc", "a");
5819                           break;
5820                   case 7: emitcode ("rlc", "a");
5821                           break;
5822                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
5823                           break;
5824                 }
5825             }
5826           // if(left &  2^n)
5827           else
5828             {
5829               if (ifx)
5830                 {
5831                   SNPRINTF (buffer, sizeof(buffer),
5832                             "acc.%d", posbit & 0x07);
5833                   genIfxJump (ifx, buffer, left, right, result);
5834                 }
5835               else
5836                 {// what is this case? just found it in ds390/gen.c
5837                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
5838                 }
5839               goto release;
5840             }
5841         }
5842       else
5843         {
5844           symbol *tlbl = newiTempLabel (NULL);
5845           int sizel = AOP_SIZE (left);
5846           if (size)
5847             emitcode ("setb", "c");
5848           while (sizel--)
5849             {
5850               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5851                 {
5852                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5853                   // byte ==  2^n ?
5854                   if ((posbit = isLiteralBit (bytelit)) != 0)
5855                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5856                   else
5857                     {
5858                       if (bytelit != 0x0FFL)
5859                         emitcode ("anl", "a,%s",
5860                                   aopGet (AOP (right), offset, FALSE, TRUE));
5861                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5862                     }
5863                 }
5864               offset++;
5865             }
5866           // bit = left & literal
5867           if (size)
5868             {
5869               emitcode ("clr", "c");
5870               emitcode ("", "%05d$:", tlbl->key + 100);
5871             }
5872           // if(left & literal)
5873           else
5874             {
5875               if (ifx)
5876                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5877               else
5878                 emitcode ("", "%05d$:", tlbl->key + 100);
5879               goto release;
5880             }
5881         }
5882       outBitC (result);
5883       goto release;
5884     }
5885
5886   /* if left is same as result */
5887   if (sameRegs (AOP (result), AOP (left)))
5888     {
5889       for (; size--; offset++)
5890         {
5891           if (AOP_TYPE (right) == AOP_LIT)
5892             {
5893               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5894               if (bytelit == 0x0FF)
5895                 {
5896                   /* dummy read of volatile operand */
5897                   if (isOperandVolatile (left, FALSE))
5898                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5899                   else
5900                     continue;
5901                 }
5902               else if (bytelit == 0)
5903                 {
5904                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5905                 }
5906               else if (IS_AOP_PREG (result))
5907                 {
5908                   MOVA (aopGet (AOP (left), offset, FALSE, TRUE));
5909                   emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5910                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5911                 }
5912               else
5913                 emitcode ("anl", "%s,%s",
5914                           aopGet (AOP (left), offset, FALSE, TRUE),
5915                           aopGet (AOP (right), offset, FALSE, FALSE));
5916             }
5917           else
5918             {
5919               if (AOP_TYPE (left) == AOP_ACC)
5920                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5921               else
5922                 {
5923                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5924                   if (IS_AOP_PREG (result))
5925                     {
5926                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5927                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5928                     }
5929                   else
5930                     emitcode ("anl", "%s,a",
5931                               aopGet (AOP (left), offset, FALSE, TRUE));
5932                 }
5933             }
5934         }
5935     }
5936   else
5937     {
5938       // left & result in different registers
5939       if (AOP_TYPE (result) == AOP_CRY)
5940         {
5941           // result = bit
5942           // if(size), result in bit
5943           // if(!size && ifx), conditional oper: if(left & right)
5944           symbol *tlbl = newiTempLabel (NULL);
5945           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5946           if (size)
5947             emitcode ("setb", "c");
5948           while (sizer--)
5949             {
5950               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5951                 emitcode ("anl", "a,%s",
5952                           aopGet (AOP (right), offset, FALSE, FALSE));
5953               } else {
5954                 if (AOP_TYPE(left)==AOP_ACC) {
5955                   bool pushedB = pushB ();
5956                   emitcode("mov", "b,a");
5957                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5958                   emitcode("anl", "a,b");
5959                   popB (pushedB);
5960                 }else {
5961                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5962                   emitcode ("anl", "a,%s",
5963                             aopGet (AOP (left), offset, FALSE, FALSE));
5964                 }
5965               }
5966               emitcode ("jnz", "%05d$", tlbl->key + 100);
5967               offset++;
5968             }
5969           if (size)
5970             {
5971               CLRC;
5972               emitcode ("", "%05d$:", tlbl->key + 100);
5973               outBitC (result);
5974             }
5975           else if (ifx)
5976             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5977           else
5978             emitcode ("", "%05d$:", tlbl->key + 100);
5979         }
5980       else
5981         {
5982           for (; (size--); offset++)
5983             {
5984               // normal case
5985               // result = left & right
5986               if (AOP_TYPE (right) == AOP_LIT)
5987                 {
5988                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5989                   if (bytelit == 0x0FF)
5990                     {
5991                       aopPut (AOP (result),
5992                               aopGet (AOP (left), offset, FALSE, FALSE),
5993                               offset,
5994                               isOperandVolatile (result, FALSE));
5995                       continue;
5996                     }
5997                   else if (bytelit == 0)
5998                     {
5999                       /* dummy read of volatile operand */
6000                       if (isOperandVolatile (left, FALSE))
6001                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6002                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
6003                       continue;
6004                     }
6005                 }
6006               // faster than result <- left, anl result,right
6007               // and better if result is SFR
6008               if (AOP_TYPE (left) == AOP_ACC)
6009                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6010               else
6011                 {
6012                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6013                   emitcode ("anl", "a,%s",
6014                             aopGet (AOP (left), offset, FALSE, FALSE));
6015                 }
6016               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6017             }
6018         }
6019     }
6020
6021 release:
6022   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6023   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6024   freeAsmop (result, NULL, ic, TRUE);
6025 }
6026
6027 /*-----------------------------------------------------------------*/
6028 /* genOr  - code for or                                            */
6029 /*-----------------------------------------------------------------*/
6030 static void
6031 genOr (iCode * ic, iCode * ifx)
6032 {
6033   operand *left, *right, *result;
6034   int size, offset = 0;
6035   unsigned long lit = 0L;
6036   int bytelit = 0;
6037
6038   D(emitcode (";     genOr",""));
6039
6040   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6041   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6042   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6043
6044 #ifdef DEBUG_TYPE
6045   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6046             AOP_TYPE (result),
6047             AOP_TYPE (left), AOP_TYPE (right));
6048   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6049             AOP_SIZE (result),
6050             AOP_SIZE (left), AOP_SIZE (right));
6051 #endif
6052
6053   /* if left is a literal & right is not then exchange them */
6054   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6055       AOP_NEEDSACC (left))
6056     {
6057       operand *tmp = right;
6058       right = left;
6059       left = tmp;
6060     }
6061
6062   /* if result = right then exchange them */
6063   if (sameRegs (AOP (result), AOP (right)))
6064     {
6065       operand *tmp = right;
6066       right = left;
6067       left = tmp;
6068     }
6069
6070   /* if right is bit then exchange them */
6071   if (AOP_TYPE (right) == AOP_CRY &&
6072       AOP_TYPE (left) != AOP_CRY)
6073     {
6074       operand *tmp = right;
6075       right = left;
6076       left = tmp;
6077     }
6078   if (AOP_TYPE (right) == AOP_LIT)
6079     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6080
6081   size = AOP_SIZE (result);
6082
6083   // if(bit | yy)
6084   // xx = bit | yy;
6085   if (AOP_TYPE (left) == AOP_CRY)
6086     {
6087       if (AOP_TYPE (right) == AOP_LIT)
6088         {
6089           // c = bit | literal;
6090           if (lit)
6091             {
6092               // lit != 0 => result = 1
6093               if (AOP_TYPE (result) == AOP_CRY)
6094                 {
6095                   if (size)
6096                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6097                   else if (ifx)
6098                     continueIfTrue (ifx);
6099                   goto release;
6100                 }
6101               emitcode ("setb", "c");
6102             }
6103           else
6104             {
6105               // lit == 0 => result = left
6106               if (size && sameRegs (AOP (result), AOP (left)))
6107                 goto release;
6108               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6109             }
6110         }
6111       else
6112         {
6113           if (AOP_TYPE (right) == AOP_CRY)
6114             {
6115               // c = bit | bit;
6116               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6117               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6118             }
6119           else
6120             {
6121               // c = bit | val;
6122               symbol *tlbl = newiTempLabel (NULL);
6123               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6124                 emitcode ("setb", "c");
6125               emitcode ("jb", "%s,%05d$",
6126                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6127               toBoolean (right);
6128               emitcode ("jnz", "%05d$", tlbl->key + 100);
6129               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6130                 {
6131                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6132                   goto release;
6133                 }
6134               else
6135                 {
6136                   CLRC;
6137                   emitcode ("", "%05d$:", tlbl->key + 100);
6138                 }
6139             }
6140         }
6141       // bit = c
6142       // val = c
6143       if (size)
6144         outBitC (result);
6145       // if(bit | ...)
6146       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6147         genIfxJump (ifx, "c", left, right, result);
6148       goto release;
6149     }
6150
6151   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6152   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6153   if ((AOP_TYPE (right) == AOP_LIT) &&
6154       (AOP_TYPE (result) == AOP_CRY) &&
6155       (AOP_TYPE (left) != AOP_CRY))
6156     {
6157       if (lit)
6158         {
6159           // result = 1
6160           if (size)
6161             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6162           else
6163             continueIfTrue (ifx);
6164           goto release;
6165         }
6166       else
6167         {
6168           // lit = 0, result = boolean(left)
6169           if (size)
6170             emitcode ("setb", "c");
6171           toBoolean (right);
6172           if (size)
6173             {
6174               symbol *tlbl = newiTempLabel (NULL);
6175               emitcode ("jnz", "%05d$", tlbl->key + 100);
6176               CLRC;
6177               emitcode ("", "%05d$:", tlbl->key + 100);
6178             }
6179           else
6180             {
6181               genIfxJump (ifx, "a", left, right, result);
6182               goto release;
6183             }
6184         }
6185       outBitC (result);
6186       goto release;
6187     }
6188
6189   /* if left is same as result */
6190   if (sameRegs (AOP (result), AOP (left)))
6191     {
6192       for (; size--; offset++)
6193         {
6194           if (AOP_TYPE (right) == AOP_LIT)
6195             {
6196               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6197               if (bytelit == 0)
6198                 {
6199                   /* dummy read of volatile operand */
6200                   if (isOperandVolatile (left, FALSE))
6201                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6202                   else
6203                     continue;
6204                 }
6205               else if (bytelit == 0x0FF)
6206                 {
6207                   aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6208                 }
6209               else if (IS_AOP_PREG (left))
6210                 {
6211                   MOVA (aopGet (AOP (left), offset, FALSE, TRUE));
6212                   emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6213                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6214                 }
6215               else
6216                 {
6217                   emitcode ("orl", "%s,%s",
6218                             aopGet (AOP (left), offset, FALSE, TRUE),
6219                             aopGet (AOP (right), offset, FALSE, FALSE));
6220                 }
6221             }
6222           else
6223             {
6224               if (AOP_TYPE (left) == AOP_ACC)
6225                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6226               else
6227                 {
6228                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6229                   if (IS_AOP_PREG (left))
6230                     {
6231                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6232                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6233                     }
6234                   else
6235                     {
6236                       emitcode ("orl", "%s,a",
6237                                 aopGet (AOP (left), offset, FALSE, TRUE));
6238                     }
6239                 }
6240             }
6241         }
6242     }
6243   else
6244     {
6245       // left & result in different registers
6246       if (AOP_TYPE (result) == AOP_CRY)
6247         {
6248           // result = bit
6249           // if(size), result in bit
6250           // if(!size && ifx), conditional oper: if(left | right)
6251           symbol *tlbl = newiTempLabel (NULL);
6252           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6253           if (size)
6254             emitcode ("setb", "c");
6255           while (sizer--)
6256             {
6257               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6258                 emitcode ("orl", "a,%s",
6259                           aopGet (AOP (right), offset, FALSE, FALSE));
6260               } else {
6261                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6262                 emitcode ("orl", "a,%s",
6263                           aopGet (AOP (left), offset, FALSE, FALSE));
6264               }
6265               emitcode ("jnz", "%05d$", tlbl->key + 100);
6266               offset++;
6267             }
6268           if (size)
6269             {
6270               CLRC;
6271               emitcode ("", "%05d$:", tlbl->key + 100);
6272               outBitC (result);
6273             }
6274           else if (ifx)
6275             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6276           else
6277             emitcode ("", "%05d$:", tlbl->key + 100);
6278         }
6279       else
6280         {
6281           for (; (size--); offset++)
6282             {
6283               // normal case
6284               // result = left | right
6285               if (AOP_TYPE (right) == AOP_LIT)
6286                 {
6287                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6288                   if (bytelit == 0)
6289                     {
6290                       aopPut (AOP (result),
6291                               aopGet (AOP (left), offset, FALSE, FALSE),
6292                               offset,
6293                               isOperandVolatile (result, FALSE));
6294                       continue;
6295                     }
6296                   else if (bytelit == 0x0FF)
6297                     {
6298                       /* dummy read of volatile operand */
6299                       if (isOperandVolatile (left, FALSE))
6300                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6301                       aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6302                       continue;
6303                     }
6304                 }
6305               // faster than result <- left, anl result,right
6306               // and better if result is SFR
6307               if (AOP_TYPE (left) == AOP_ACC)
6308                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6309               else
6310                 {
6311                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6312                   emitcode ("orl", "a,%s",
6313                             aopGet (AOP (left), offset, FALSE, FALSE));
6314                 }
6315               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6316             }
6317         }
6318     }
6319
6320 release:
6321   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6322   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6323   freeAsmop (result, NULL, ic, TRUE);
6324 }
6325
6326 /*-----------------------------------------------------------------*/
6327 /* genXor - code for xclusive or                                   */
6328 /*-----------------------------------------------------------------*/
6329 static void
6330 genXor (iCode * ic, iCode * ifx)
6331 {
6332   operand *left, *right, *result;
6333   int size, offset = 0;
6334   unsigned long lit = 0L;
6335   int bytelit = 0;
6336
6337   D(emitcode (";     genXor",""));
6338
6339   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6340   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6341   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6342
6343 #ifdef DEBUG_TYPE
6344   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6345             AOP_TYPE (result),
6346             AOP_TYPE (left), AOP_TYPE (right));
6347   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6348             AOP_SIZE (result),
6349             AOP_SIZE (left), AOP_SIZE (right));
6350 #endif
6351
6352   /* if left is a literal & right is not ||
6353      if left needs acc & right does not */
6354   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6355       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6356     {
6357       operand *tmp = right;
6358       right = left;
6359       left = tmp;
6360     }
6361
6362   /* if result = right then exchange them */
6363   if (sameRegs (AOP (result), AOP (right)))
6364     {
6365       operand *tmp = right;
6366       right = left;
6367       left = tmp;
6368     }
6369
6370   /* if right is bit then exchange them */
6371   if (AOP_TYPE (right) == AOP_CRY &&
6372       AOP_TYPE (left) != AOP_CRY)
6373     {
6374       operand *tmp = right;
6375       right = left;
6376       left = tmp;
6377     }
6378   if (AOP_TYPE (right) == AOP_LIT)
6379     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6380
6381   size = AOP_SIZE (result);
6382
6383   // if(bit ^ yy)
6384   // xx = bit ^ yy;
6385   if (AOP_TYPE (left) == AOP_CRY)
6386     {
6387       if (AOP_TYPE (right) == AOP_LIT)
6388         {
6389           // c = bit & literal;
6390           if (lit >> 1)
6391             {
6392               // lit>>1  != 0 => result = 1
6393               if (AOP_TYPE (result) == AOP_CRY)
6394                 {
6395                   if (size)
6396                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6397                   else if (ifx)
6398                     continueIfTrue (ifx);
6399                   goto release;
6400                 }
6401               emitcode ("setb", "c");
6402             }
6403           else
6404             {
6405               // lit == (0 or 1)
6406               if (lit == 0)
6407                 {
6408                   // lit == 0, result = left
6409                   if (size && sameRegs (AOP (result), AOP (left)))
6410                     goto release;
6411                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6412                 }
6413               else
6414                 {
6415                   // lit == 1, result = not(left)
6416                   if (size && sameRegs (AOP (result), AOP (left)))
6417                     {
6418                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6419                       goto release;
6420                     }
6421                   else
6422                     {
6423                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6424                       emitcode ("cpl", "c");
6425                     }
6426                 }
6427             }
6428
6429         }
6430       else
6431         {
6432           // right != literal
6433           symbol *tlbl = newiTempLabel (NULL);
6434           if (AOP_TYPE (right) == AOP_CRY)
6435             {
6436               // c = bit ^ bit;
6437               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6438             }
6439           else
6440             {
6441               int sizer = AOP_SIZE (right);
6442               // c = bit ^ val
6443               // if val>>1 != 0, result = 1
6444               emitcode ("setb", "c");
6445               while (sizer)
6446                 {
6447                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
6448                   if (sizer == 1)
6449                     // test the msb of the lsb
6450                     emitcode ("anl", "a,#0xfe");
6451                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6452                   sizer--;
6453                 }
6454               // val = (0,1)
6455               emitcode ("rrc", "a");
6456             }
6457           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6458           emitcode ("cpl", "c");
6459           emitcode ("", "%05d$:", (tlbl->key + 100));
6460         }
6461       // bit = c
6462       // val = c
6463       if (size)
6464         outBitC (result);
6465       // if(bit | ...)
6466       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6467         genIfxJump (ifx, "c", left, right, result);
6468       goto release;
6469     }
6470
6471   /* if left is same as result */
6472   if (sameRegs (AOP (result), AOP (left)))
6473     {
6474       for (; size--; offset++)
6475         {
6476           if (AOP_TYPE (right) == AOP_LIT)
6477             {
6478               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6479               if (bytelit == 0)
6480                 {
6481                   /* dummy read of volatile operand */
6482                   if (isOperandVolatile (left, FALSE))
6483                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6484                   else
6485                     continue;
6486                 }
6487               else if (IS_AOP_PREG (left))
6488                 {
6489                   MOVA (aopGet (AOP (left), offset, FALSE, TRUE));
6490                   emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6491                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6492                 }
6493               else
6494                 {
6495                   emitcode ("xrl", "%s,%s",
6496                             aopGet (AOP (left), offset, FALSE, TRUE),
6497                             aopGet (AOP (right), offset, FALSE, FALSE));
6498                 }
6499             }
6500           else
6501             {
6502               if (AOP_TYPE (left) == AOP_ACC)
6503                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6504               else
6505                 {
6506                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6507                   if (IS_AOP_PREG (left))
6508                     {
6509                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6510                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6511                     }
6512                   else
6513                     emitcode ("xrl", "%s,a",
6514                               aopGet (AOP (left), offset, FALSE, TRUE));
6515                 }
6516             }
6517         }
6518     }
6519   else
6520     {
6521       // left & result in different registers
6522       if (AOP_TYPE (result) == AOP_CRY)
6523         {
6524           // result = bit
6525           // if(size), result in bit
6526           // if(!size && ifx), conditional oper: if(left ^ right)
6527           symbol *tlbl = newiTempLabel (NULL);
6528           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6529           if (size)
6530             emitcode ("setb", "c");
6531           while (sizer--)
6532             {
6533               if ((AOP_TYPE (right) == AOP_LIT) &&
6534                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6535                 {
6536                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6537                 }
6538               else
6539                 {
6540                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6541                     emitcode ("xrl", "a,%s",
6542                               aopGet (AOP (right), offset, FALSE, FALSE));
6543                   } else {
6544                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6545                     emitcode ("xrl", "a,%s",
6546                               aopGet (AOP (left), offset, FALSE, FALSE));
6547                   }
6548                 }
6549               emitcode ("jnz", "%05d$", tlbl->key + 100);
6550               offset++;
6551             }
6552           if (size)
6553             {
6554               CLRC;
6555               emitcode ("", "%05d$:", tlbl->key + 100);
6556               outBitC (result);
6557             }
6558           else if (ifx)
6559             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6560         }
6561       else
6562         {
6563           for (; (size--); offset++)
6564             {
6565               // normal case
6566               // result = left & right
6567               if (AOP_TYPE (right) == AOP_LIT)
6568                 {
6569                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6570                   if (bytelit == 0)
6571                     {
6572                       aopPut (AOP (result),
6573                               aopGet (AOP (left), offset, FALSE, FALSE),
6574                               offset,
6575                               isOperandVolatile (result, FALSE));
6576                       continue;
6577                     }
6578                 }
6579               // faster than result <- left, anl result,right
6580               // and better if result is SFR
6581               if (AOP_TYPE (left) == AOP_ACC)
6582                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6583               else
6584                 {
6585                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6586                   emitcode ("xrl", "a,%s",
6587                             aopGet (AOP (left), offset, FALSE, TRUE));
6588                 }
6589               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6590             }
6591         }
6592     }
6593
6594 release:
6595   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6596   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6597   freeAsmop (result, NULL, ic, TRUE);
6598 }
6599
6600 /*-----------------------------------------------------------------*/
6601 /* genInline - write the inline code out                           */
6602 /*-----------------------------------------------------------------*/
6603 static void
6604 genInline (iCode * ic)
6605 {
6606   char *buffer, *bp, *bp1;
6607
6608   D(emitcode (";     genInline",""));
6609
6610   _G.inLine += (!options.asmpeep);
6611
6612   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6613   strcpy (buffer, IC_INLINE (ic));
6614
6615   /* emit each line as a code */
6616   while (*bp)
6617     {
6618       if (*bp == '\n')
6619         {
6620           *bp++ = '\0';
6621           emitcode (bp1, "");
6622           bp1 = bp;
6623         }
6624       else
6625         {
6626           /* Add \n for labels, not dirs such as c:\mydir */
6627           if ( (*bp == ':') && (isspace(bp[1])) )
6628             {
6629               bp++;
6630               *bp = '\0';
6631               bp++;
6632               emitcode (bp1, "");
6633               bp1 = bp;
6634             }
6635           else
6636             bp++;
6637         }
6638     }
6639   if (bp1 != bp)
6640     emitcode (bp1, "");
6641   /*     emitcode("",buffer); */
6642   _G.inLine -= (!options.asmpeep);
6643 }
6644
6645 /*-----------------------------------------------------------------*/
6646 /* genRRC - rotate right with carry                                */
6647 /*-----------------------------------------------------------------*/
6648 static void
6649 genRRC (iCode * ic)
6650 {
6651   operand *left, *result;
6652   int size, offset = 0;
6653   char *l;
6654
6655   D(emitcode (";     genRRC",""));
6656
6657   /* rotate right with carry */
6658   left = IC_LEFT (ic);
6659   result = IC_RESULT (ic);
6660   aopOp (left, ic, FALSE);
6661   aopOp (result, ic, FALSE);
6662
6663   /* move it to the result */
6664   size = AOP_SIZE (result);
6665   offset = size - 1;
6666   if (size == 1) { /* special case for 1 byte */
6667       l = aopGet (AOP (left), offset, FALSE, FALSE);
6668       MOVA (l);
6669       emitcode ("rr", "a");
6670       goto release;
6671   }
6672   /* no need to clear carry, bit7 will be written later */
6673   while (size--)
6674     {
6675       l = aopGet (AOP (left), offset, FALSE, FALSE);
6676       MOVA (l);
6677       emitcode ("rrc", "a");
6678       if (AOP_SIZE (result) > 1)
6679         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6680     }
6681   /* now we need to put the carry into the
6682      highest order byte of the result */
6683   if (AOP_SIZE (result) > 1)
6684     {
6685       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6686       MOVA (l);
6687     }
6688   emitcode ("mov", "acc.7,c");
6689  release:
6690   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6691   freeAsmop (left, NULL, ic, TRUE);
6692   freeAsmop (result, NULL, ic, TRUE);
6693 }
6694
6695 /*-----------------------------------------------------------------*/
6696 /* genRLC - generate code for rotate left with carry               */
6697 /*-----------------------------------------------------------------*/
6698 static void
6699 genRLC (iCode * ic)
6700 {
6701   operand *left, *result;
6702   int size, offset = 0;
6703   char *l;
6704
6705   D(emitcode (";     genRLC",""));
6706
6707   /* rotate right with carry */
6708   left = IC_LEFT (ic);
6709   result = IC_RESULT (ic);
6710   aopOp (left, ic, FALSE);
6711   aopOp (result, ic, FALSE);
6712
6713   /* move it to the result */
6714   size = AOP_SIZE (result);
6715   offset = 0;
6716   if (size--)
6717     {
6718       l = aopGet (AOP (left), offset, FALSE, FALSE);
6719       MOVA (l);
6720       if (size == 0) { /* special case for 1 byte */
6721               emitcode("rl","a");
6722               goto release;
6723       }
6724       emitcode("rlc","a"); /* bit0 will be written later */
6725       if (AOP_SIZE (result) > 1)
6726         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6727       while (size--)
6728         {
6729           l = aopGet (AOP (left), offset, FALSE, FALSE);
6730           MOVA (l);
6731           emitcode ("rlc", "a");
6732           if (AOP_SIZE (result) > 1)
6733             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6734         }
6735     }
6736   /* now we need to put the carry into the
6737      highest order byte of the result */
6738   if (AOP_SIZE (result) > 1)
6739     {
6740       l = aopGet (AOP (result), 0, FALSE, FALSE);
6741       MOVA (l);
6742     }
6743   emitcode ("mov", "acc.0,c");
6744  release:
6745   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6746   freeAsmop (left, NULL, ic, TRUE);
6747   freeAsmop (result, NULL, ic, TRUE);
6748 }
6749
6750 /*-----------------------------------------------------------------*/
6751 /* genGetHbit - generates code get highest order bit               */
6752 /*-----------------------------------------------------------------*/
6753 static void
6754 genGetHbit (iCode * ic)
6755 {
6756   operand *left, *result;
6757
6758   D(emitcode (";     genGetHbit",""));
6759
6760   left = IC_LEFT (ic);
6761   result = IC_RESULT (ic);
6762   aopOp (left, ic, FALSE);
6763   aopOp (result, ic, FALSE);
6764
6765   /* get the highest order byte into a */
6766   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6767   if (AOP_TYPE (result) == AOP_CRY)
6768     {
6769       emitcode ("rlc", "a");
6770       outBitC (result);
6771     }
6772   else
6773     {
6774       emitcode ("rl", "a");
6775       emitcode ("anl", "a,#0x01");
6776       outAcc (result);
6777     }
6778
6779
6780   freeAsmop (left, NULL, ic, TRUE);
6781   freeAsmop (result, NULL, ic, TRUE);
6782 }
6783
6784 /*-----------------------------------------------------------------*/
6785 /* genSwap - generates code to swap nibbles or bytes               */
6786 /*-----------------------------------------------------------------*/
6787 static void
6788 genSwap (iCode * ic)
6789 {
6790   operand *left, *result;
6791
6792   D(emitcode (";     genSwap",""));
6793
6794   left = IC_LEFT (ic);
6795   result = IC_RESULT (ic);
6796   aopOp (left, ic, FALSE);
6797   aopOp (result, ic, FALSE);
6798
6799   switch (AOP_SIZE (left))
6800     {
6801     case 1: /* swap nibbles in byte */
6802       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6803       emitcode ("swap", "a");
6804       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6805       break;
6806     case 2: /* swap bytes in word */
6807       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6808         {
6809           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6810           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6811                   0, isOperandVolatile (result, FALSE));
6812           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6813         }
6814       else if (operandsEqu (left, result))
6815         {
6816           char * reg = "a";
6817           bool pushedB = FALSE, leftInB = FALSE;
6818
6819           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6820           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6821             {
6822               pushedB = pushB ();
6823               emitcode ("mov", "b,a");
6824               reg = "b";
6825               leftInB = TRUE;
6826             }
6827           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6828                   0, isOperandVolatile (result, FALSE));
6829           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6830
6831           if (leftInB)
6832             popB (pushedB);
6833         }
6834       else
6835         {
6836           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6837                   0, isOperandVolatile (result, FALSE));
6838           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6839                   1, isOperandVolatile (result, FALSE));
6840         }
6841       break;
6842     default:
6843       wassertl(FALSE, "unsupported SWAP operand size");
6844     }
6845
6846   freeAsmop (left, NULL, ic, TRUE);
6847   freeAsmop (result, NULL, ic, TRUE);
6848 }
6849
6850
6851 /*-----------------------------------------------------------------*/
6852 /* AccRol - rotate left accumulator by known count                 */
6853 /*-----------------------------------------------------------------*/
6854 static void
6855 AccRol (int shCount)
6856 {
6857   shCount &= 0x0007;            // shCount : 0..7
6858
6859   switch (shCount)
6860     {
6861     case 0:
6862       break;
6863     case 1:
6864       emitcode ("rl", "a");
6865       break;
6866     case 2:
6867       emitcode ("rl", "a");
6868       emitcode ("rl", "a");
6869       break;
6870     case 3:
6871       emitcode ("swap", "a");
6872       emitcode ("rr", "a");
6873       break;
6874     case 4:
6875       emitcode ("swap", "a");
6876       break;
6877     case 5:
6878       emitcode ("swap", "a");
6879       emitcode ("rl", "a");
6880       break;
6881     case 6:
6882       emitcode ("rr", "a");
6883       emitcode ("rr", "a");
6884       break;
6885     case 7:
6886       emitcode ("rr", "a");
6887       break;
6888     }
6889 }
6890
6891 /*-----------------------------------------------------------------*/
6892 /* AccLsh - left shift accumulator by known count                  */
6893 /*-----------------------------------------------------------------*/
6894 static void
6895 AccLsh (int shCount)
6896 {
6897   if (shCount != 0)
6898     {
6899       if (shCount == 1)
6900         emitcode ("add", "a,acc");
6901       else if (shCount == 2)
6902         {
6903           emitcode ("add", "a,acc");
6904           emitcode ("add", "a,acc");
6905         }
6906       else
6907         {
6908           /* rotate left accumulator */
6909           AccRol (shCount);
6910           /* and kill the lower order bits */
6911           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6912         }
6913     }
6914 }
6915
6916 /*-----------------------------------------------------------------*/
6917 /* AccRsh - right shift accumulator by known count                 */
6918 /*-----------------------------------------------------------------*/
6919 static void
6920 AccRsh (int shCount)
6921 {
6922   if (shCount != 0)
6923     {
6924       if (shCount == 1)
6925         {
6926           CLRC;
6927           emitcode ("rrc", "a");
6928         }
6929       else
6930         {
6931           /* rotate right accumulator */
6932           AccRol (8 - shCount);
6933           /* and kill the higher order bits */
6934           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6935         }
6936     }
6937 }
6938
6939 /*-----------------------------------------------------------------*/
6940 /* AccSRsh - signed right shift accumulator by known count                 */
6941 /*-----------------------------------------------------------------*/
6942 static void
6943 AccSRsh (int shCount)
6944 {
6945   symbol *tlbl;
6946   if (shCount != 0)
6947     {
6948       if (shCount == 1)
6949         {
6950           emitcode ("mov", "c,acc.7");
6951           emitcode ("rrc", "a");
6952         }
6953       else if (shCount == 2)
6954         {
6955           emitcode ("mov", "c,acc.7");
6956           emitcode ("rrc", "a");
6957           emitcode ("mov", "c,acc.7");
6958           emitcode ("rrc", "a");
6959         }
6960       else
6961         {
6962           tlbl = newiTempLabel (NULL);
6963           /* rotate right accumulator */
6964           AccRol (8 - shCount);
6965           /* and kill the higher order bits */
6966           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6967           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6968           emitcode ("orl", "a,#0x%02x",
6969                     (unsigned char) ~SRMask[shCount]);
6970           emitcode ("", "%05d$:", tlbl->key + 100);
6971         }
6972     }
6973 }
6974
6975 /*-----------------------------------------------------------------*/
6976 /* shiftR1Left2Result - shift right one byte from left to result   */
6977 /*-----------------------------------------------------------------*/
6978 static void
6979 shiftR1Left2Result (operand * left, int offl,
6980                     operand * result, int offr,
6981                     int shCount, int sign)
6982 {
6983   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6984   /* shift right accumulator */
6985   if (sign)
6986     AccSRsh (shCount);
6987   else
6988     AccRsh (shCount);
6989   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6990 }
6991
6992 /*-----------------------------------------------------------------*/
6993 /* shiftL1Left2Result - shift left one byte from left to result    */
6994 /*-----------------------------------------------------------------*/
6995 static void
6996 shiftL1Left2Result (operand * left, int offl,
6997                     operand * result, int offr, int shCount)
6998 {
6999   char *l;
7000   l = aopGet (AOP (left), offl, FALSE, FALSE);
7001   MOVA (l);
7002   /* shift left accumulator */
7003   AccLsh (shCount);
7004   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7005 }
7006
7007 /*-----------------------------------------------------------------*/
7008 /* movLeft2Result - move byte from left to result                  */
7009 /*-----------------------------------------------------------------*/
7010 static void
7011 movLeft2Result (operand * left, int offl,
7012                 operand * result, int offr, int sign)
7013 {
7014   char *l;
7015   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7016     {
7017       l = aopGet (AOP (left), offl, FALSE, FALSE);
7018
7019       if (*l == '@' && (IS_AOP_PREG (result)))
7020         {
7021           emitcode ("mov", "a,%s", l);
7022           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7023         }
7024       else
7025         {
7026           if (!sign)
7027             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
7028           else
7029             {
7030               /* MSB sign in acc.7 ! */
7031               if (getDataSize (left) == offl + 1)
7032                 {
7033                   emitcode ("mov", "a,%s", l);
7034                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7035                 }
7036             }
7037         }
7038     }
7039 }
7040
7041 /*-----------------------------------------------------------------*/
7042 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7043 /*-----------------------------------------------------------------*/
7044 static void
7045 AccAXRrl1 (char *x)
7046 {
7047   emitcode ("rrc", "a");
7048   emitcode ("xch", "a,%s", x);
7049   emitcode ("rrc", "a");
7050   emitcode ("xch", "a,%s", x);
7051 }
7052
7053 /*-----------------------------------------------------------------*/
7054 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7055 /*-----------------------------------------------------------------*/
7056 static void
7057 AccAXLrl1 (char *x)
7058 {
7059   emitcode ("xch", "a,%s", x);
7060   emitcode ("rlc", "a");
7061   emitcode ("xch", "a,%s", x);
7062   emitcode ("rlc", "a");
7063 }
7064
7065 /*-----------------------------------------------------------------*/
7066 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7067 /*-----------------------------------------------------------------*/
7068 static void
7069 AccAXLsh1 (char *x)
7070 {
7071   emitcode ("xch", "a,%s", x);
7072   emitcode ("add", "a,acc");
7073   emitcode ("xch", "a,%s", x);
7074   emitcode ("rlc", "a");
7075 }
7076
7077 /*-----------------------------------------------------------------*/
7078 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7079 /*-----------------------------------------------------------------*/
7080 static void
7081 AccAXLsh (char *x, int shCount)
7082 {
7083   switch (shCount)
7084     {
7085     case 0:
7086       break;
7087     case 1:
7088       AccAXLsh1 (x);
7089       break;
7090     case 2:
7091       AccAXLsh1 (x);
7092       AccAXLsh1 (x);
7093       break;
7094     case 3:
7095     case 4:
7096     case 5:                     // AAAAABBB:CCCCCDDD
7097
7098       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7099
7100       emitcode ("anl", "a,#0x%02x",
7101                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7102
7103       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7104
7105       AccRol (shCount);         // DDDCCCCC:BBB00000
7106
7107       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7108
7109       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7110
7111       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7112
7113       emitcode ("anl", "a,#0x%02x",
7114                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7115
7116       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7117
7118       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7119
7120       break;
7121     case 6:                     // AAAAAABB:CCCCCCDD
7122       emitcode ("anl", "a,#0x%02x",
7123                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7124       emitcode ("mov", "c,acc.0");      // c = B
7125       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7126 #if 0 // REMOVE ME
7127       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7128       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7129 #else
7130       emitcode("rrc","a");
7131       emitcode("xch","a,%s", x);
7132       emitcode("rrc","a");
7133       emitcode("mov","c,acc.0"); //<< get correct bit
7134       emitcode("xch","a,%s", x);
7135
7136       emitcode("rrc","a");
7137       emitcode("xch","a,%s", x);
7138       emitcode("rrc","a");
7139       emitcode("xch","a,%s", x);
7140 #endif
7141       break;
7142     case 7:                     // a:x <<= 7
7143
7144       emitcode ("anl", "a,#0x%02x",
7145                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7146
7147       emitcode ("mov", "c,acc.0");      // c = B
7148
7149       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7150
7151       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7152
7153       break;
7154     default:
7155       break;
7156     }
7157 }
7158
7159 /*-----------------------------------------------------------------*/
7160 /* AccAXRsh - right shift a:x known count (0..7)                   */
7161 /*-----------------------------------------------------------------*/
7162 static void
7163 AccAXRsh (char *x, int shCount)
7164 {
7165   switch (shCount)
7166     {
7167     case 0:
7168       break;
7169     case 1:
7170       CLRC;
7171       AccAXRrl1 (x);            // 0->a:x
7172
7173       break;
7174     case 2:
7175       CLRC;
7176       AccAXRrl1 (x);            // 0->a:x
7177
7178       CLRC;
7179       AccAXRrl1 (x);            // 0->a:x
7180
7181       break;
7182     case 3:
7183     case 4:
7184     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7185
7186       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7187
7188       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7189
7190       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7191
7192       emitcode ("anl", "a,#0x%02x",
7193                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7194
7195       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7196
7197       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7198
7199       emitcode ("anl", "a,#0x%02x",
7200                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7201
7202       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7203
7204       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7205
7206       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7207
7208       break;
7209     case 6:                     // AABBBBBB:CCDDDDDD
7210
7211       emitcode ("mov", "c,acc.7");
7212       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7213
7214       emitcode ("mov", "c,acc.7");
7215       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7216
7217       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7218
7219       emitcode ("anl", "a,#0x%02x",
7220                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7221
7222       break;
7223     case 7:                     // ABBBBBBB:CDDDDDDD
7224
7225       emitcode ("mov", "c,acc.7");      // c = A
7226
7227       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7228
7229       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7230
7231       emitcode ("anl", "a,#0x%02x",
7232                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7233
7234       break;
7235     default:
7236       break;
7237     }
7238 }
7239
7240 /*-----------------------------------------------------------------*/
7241 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7242 /*-----------------------------------------------------------------*/
7243 static void
7244 AccAXRshS (char *x, int shCount)
7245 {
7246   symbol *tlbl;
7247   switch (shCount)
7248     {
7249     case 0:
7250       break;
7251     case 1:
7252       emitcode ("mov", "c,acc.7");
7253       AccAXRrl1 (x);            // s->a:x
7254
7255       break;
7256     case 2:
7257       emitcode ("mov", "c,acc.7");
7258       AccAXRrl1 (x);            // s->a:x
7259
7260       emitcode ("mov", "c,acc.7");
7261       AccAXRrl1 (x);            // s->a:x
7262
7263       break;
7264     case 3:
7265     case 4:
7266     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7267
7268       tlbl = newiTempLabel (NULL);
7269       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7270
7271       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7272
7273       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7274
7275       emitcode ("anl", "a,#0x%02x",
7276                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7277
7278       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7279
7280       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7281
7282       emitcode ("anl", "a,#0x%02x",
7283                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7284
7285       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7286
7287       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7288
7289       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7290
7291       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7292       emitcode ("orl", "a,#0x%02x",
7293                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7294
7295       emitcode ("", "%05d$:", tlbl->key + 100);
7296       break;                    // SSSSAAAA:BBBCCCCC
7297
7298     case 6:                     // AABBBBBB:CCDDDDDD
7299
7300       tlbl = newiTempLabel (NULL);
7301       emitcode ("mov", "c,acc.7");
7302       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7303
7304       emitcode ("mov", "c,acc.7");
7305       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7306
7307       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7308
7309       emitcode ("anl", "a,#0x%02x",
7310                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7311
7312       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7313       emitcode ("orl", "a,#0x%02x",
7314                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7315
7316       emitcode ("", "%05d$:", tlbl->key + 100);
7317       break;
7318     case 7:                     // ABBBBBBB:CDDDDDDD
7319
7320       tlbl = newiTempLabel (NULL);
7321       emitcode ("mov", "c,acc.7");      // c = A
7322
7323       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7324
7325       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7326
7327       emitcode ("anl", "a,#0x%02x",
7328                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7329
7330       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7331       emitcode ("orl", "a,#0x%02x",
7332                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7333
7334       emitcode ("", "%05d$:", tlbl->key + 100);
7335       break;
7336     default:
7337       break;
7338     }
7339 }
7340
7341 /*-----------------------------------------------------------------*/
7342 /* shiftL2Left2Result - shift left two bytes from left to result   */
7343 /*-----------------------------------------------------------------*/
7344 static void
7345 shiftL2Left2Result (operand * left, int offl,
7346                     operand * result, int offr, int shCount)
7347 {
7348   if (sameRegs (AOP (result), AOP (left)) &&
7349       ((offl + MSB16) == offr))
7350     {
7351       /* don't crash result[offr] */
7352       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7353       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7354     }
7355   else
7356     {
7357       movLeft2Result (left, offl, result, offr, 0);
7358       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7359     }
7360   /* ax << shCount (x = lsb(result)) */
7361   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7362   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7363 }
7364
7365
7366 /*-----------------------------------------------------------------*/
7367 /* shiftR2Left2Result - shift right two bytes from left to result  */
7368 /*-----------------------------------------------------------------*/
7369 static void
7370 shiftR2Left2Result (operand * left, int offl,
7371                     operand * result, int offr,
7372                     int shCount, int sign)
7373 {
7374   if (sameRegs (AOP (result), AOP (left)) &&
7375       ((offl + MSB16) == offr))
7376     {
7377       /* don't crash result[offr] */
7378       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7379       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7380     }
7381   else
7382     {
7383       movLeft2Result (left, offl, result, offr, 0);
7384       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7385     }
7386   /* a:x >> shCount (x = lsb(result)) */
7387   if (sign)
7388     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7389   else
7390     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7391   if (getDataSize (result) > 1)
7392     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7393 }
7394
7395 /*-----------------------------------------------------------------*/
7396 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7397 /*-----------------------------------------------------------------*/
7398 static void
7399 shiftLLeftOrResult (operand * left, int offl,
7400                     operand * result, int offr, int shCount)
7401 {
7402   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7403   /* shift left accumulator */
7404   AccLsh (shCount);
7405   /* or with result */
7406   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7407   /* back to result */
7408   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7409 }
7410
7411 /*-----------------------------------------------------------------*/
7412 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7413 /*-----------------------------------------------------------------*/
7414 static void
7415 shiftRLeftOrResult (operand * left, int offl,
7416                     operand * result, int offr, int shCount)
7417 {
7418   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7419   /* shift right accumulator */
7420   AccRsh (shCount);
7421   /* or with result */
7422   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7423   /* back to result */
7424   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7425 }
7426
7427 /*-----------------------------------------------------------------*/
7428 /* genlshOne - left shift a one byte quantity by known count       */
7429 /*-----------------------------------------------------------------*/
7430 static void
7431 genlshOne (operand * result, operand * left, int shCount)
7432 {
7433   D(emitcode (";     genlshOne",""));
7434
7435   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7436 }
7437
7438 /*-----------------------------------------------------------------*/
7439 /* genlshTwo - left shift two bytes by known amount != 0           */
7440 /*-----------------------------------------------------------------*/
7441 static void
7442 genlshTwo (operand * result, operand * left, int shCount)
7443 {
7444   int size;
7445
7446   D(emitcode (";     genlshTwo",""));
7447
7448   size = getDataSize (result);
7449
7450   /* if shCount >= 8 */
7451   if (shCount >= 8)
7452     {
7453       shCount -= 8;
7454
7455       if (size > 1)
7456         {
7457           if (shCount)
7458             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7459           else
7460             movLeft2Result (left, LSB, result, MSB16, 0);
7461         }
7462       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7463     }
7464
7465   /*  1 <= shCount <= 7 */
7466   else
7467     {
7468       if (size == 1)
7469         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7470       else
7471         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7472     }
7473 }
7474
7475 /*-----------------------------------------------------------------*/
7476 /* shiftLLong - shift left one long from left to result            */
7477 /* offl = LSB or MSB16                                             */
7478 /*-----------------------------------------------------------------*/
7479 static void
7480 shiftLLong (operand * left, operand * result, int offr)
7481 {
7482   char *l;
7483   int size = AOP_SIZE (result);
7484
7485   if (size >= LSB + offr)
7486     {
7487       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7488       MOVA (l);
7489       emitcode ("add", "a,acc");
7490       if (sameRegs (AOP (left), AOP (result)) &&
7491           size >= MSB16 + offr && offr != LSB)
7492         emitcode ("xch", "a,%s",
7493                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7494       else
7495         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7496     }
7497
7498   if (size >= MSB16 + offr)
7499     {
7500       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7501         {
7502           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7503           MOVA (l);
7504         }
7505       emitcode ("rlc", "a");
7506       if (sameRegs (AOP (left), AOP (result)) &&
7507           size >= MSB24 + offr && offr != LSB)
7508         emitcode ("xch", "a,%s",
7509                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7510       else
7511         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7512     }
7513
7514   if (size >= MSB24 + offr)
7515     {
7516       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7517         {
7518           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7519           MOVA (l);
7520         }
7521       emitcode ("rlc", "a");
7522       if (sameRegs (AOP (left), AOP (result)) &&
7523           size >= MSB32 + offr && offr != LSB)
7524         emitcode ("xch", "a,%s",
7525                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7526       else
7527         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7528     }
7529
7530   if (size > MSB32 + offr)
7531     {
7532       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7533         {
7534           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7535           MOVA (l);
7536         }
7537       emitcode ("rlc", "a");
7538       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7539     }
7540   if (offr != LSB)
7541     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7542 }
7543
7544 /*-----------------------------------------------------------------*/
7545 /* genlshFour - shift four byte by a known amount != 0             */
7546 /*-----------------------------------------------------------------*/
7547 static void
7548 genlshFour (operand * result, operand * left, int shCount)
7549 {
7550   int size;
7551
7552   D(emitcode (";     genlshFour",""));
7553
7554   size = AOP_SIZE (result);
7555
7556   /* if shifting more that 3 bytes */
7557   if (shCount >= 24)
7558     {
7559       shCount -= 24;
7560       if (shCount)
7561         /* lowest order of left goes to the highest
7562            order of the destination */
7563         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7564       else
7565         movLeft2Result (left, LSB, result, MSB32, 0);
7566       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7567       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7568       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7569       return;
7570     }
7571
7572   /* more than two bytes */
7573   else if (shCount >= 16)
7574     {
7575       /* lower order two bytes goes to higher order two bytes */
7576       shCount -= 16;
7577       /* if some more remaining */
7578       if (shCount)
7579         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7580       else
7581         {
7582           movLeft2Result (left, MSB16, result, MSB32, 0);
7583           movLeft2Result (left, LSB, result, MSB24, 0);
7584         }
7585       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7586       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7587       return;
7588     }
7589
7590   /* if more than 1 byte */
7591   else if (shCount >= 8)
7592     {
7593       /* lower order three bytes goes to higher order  three bytes */
7594       shCount -= 8;
7595       if (size == 2)
7596         {
7597           if (shCount)
7598             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7599           else
7600             movLeft2Result (left, LSB, result, MSB16, 0);
7601         }
7602       else
7603         {                       /* size = 4 */
7604           if (shCount == 0)
7605             {
7606               movLeft2Result (left, MSB24, result, MSB32, 0);
7607               movLeft2Result (left, MSB16, result, MSB24, 0);
7608               movLeft2Result (left, LSB, result, MSB16, 0);
7609               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7610             }
7611           else if (shCount == 1)
7612             shiftLLong (left, result, MSB16);
7613           else
7614             {
7615               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7616               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7617               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7618               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7619             }
7620         }
7621     }
7622
7623   /* 1 <= shCount <= 7 */
7624   else if (shCount <= 2)
7625     {
7626       shiftLLong (left, result, LSB);
7627       if (shCount == 2)
7628         shiftLLong (result, result, LSB);
7629     }
7630   /* 3 <= shCount <= 7, optimize */
7631   else
7632     {
7633       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7634       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7635       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7636     }
7637 }
7638
7639 /*-----------------------------------------------------------------*/
7640 /* genLeftShiftLiteral - left shifting by known count              */
7641 /*-----------------------------------------------------------------*/
7642 static void
7643 genLeftShiftLiteral (operand * left,
7644                      operand * right,
7645                      operand * result,
7646                      iCode * ic)
7647 {
7648   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7649   int size;
7650
7651   D(emitcode (";     genLeftShiftLiteral",""));
7652
7653   freeAsmop (right, NULL, ic, TRUE);
7654
7655   aopOp (left, ic, FALSE);
7656   aopOp (result, ic, FALSE);
7657
7658   size = getSize (operandType (result));
7659
7660 #if VIEW_SIZE
7661   emitcode ("; shift left ", "result %d, left %d", size,
7662             AOP_SIZE (left));
7663 #endif
7664
7665   /* I suppose that the left size >= result size */
7666   if (shCount == 0)
7667     {
7668       while (size--)
7669         {
7670           movLeft2Result (left, size, result, size, 0);
7671         }
7672     }
7673
7674   else if (shCount >= (size * 8))
7675     while (size--)
7676       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7677   else
7678     {
7679       switch (size)
7680         {
7681         case 1:
7682           genlshOne (result, left, shCount);
7683           break;
7684
7685         case 2:
7686           genlshTwo (result, left, shCount);
7687           break;
7688
7689         case 4:
7690           genlshFour (result, left, shCount);
7691           break;
7692         default:
7693           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7694                   "*** ack! mystery literal shift!\n");
7695           break;
7696         }
7697     }
7698   freeAsmop (left, NULL, ic, TRUE);
7699   freeAsmop (result, NULL, ic, TRUE);
7700 }
7701
7702 /*-----------------------------------------------------------------*/
7703 /* genLeftShift - generates code for left shifting                 */
7704 /*-----------------------------------------------------------------*/
7705 static void
7706 genLeftShift (iCode * ic)
7707 {
7708   operand *left, *right, *result;
7709   int size, offset;
7710   char *l;
7711   symbol *tlbl, *tlbl1;
7712   bool pushedB;
7713
7714   D(emitcode (";     genLeftShift",""));
7715
7716   right = IC_RIGHT (ic);
7717   left = IC_LEFT (ic);
7718   result = IC_RESULT (ic);
7719
7720   aopOp (right, ic, FALSE);
7721
7722   /* if the shift count is known then do it
7723      as efficiently as possible */
7724   if (AOP_TYPE (right) == AOP_LIT)
7725     {
7726       genLeftShiftLiteral (left, right, result, ic);
7727       return;
7728     }
7729
7730   /* shift count is unknown then we have to form
7731      a loop get the loop count in B : Note: we take
7732      only the lower order byte since shifting
7733      more that 32 bits make no sense anyway, ( the
7734      largest size of an object can be only 32 bits ) */
7735
7736   pushedB = pushB ();
7737   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7738   emitcode ("inc", "b");
7739   freeAsmop (right, NULL, ic, TRUE);
7740   aopOp (left, ic, FALSE);
7741   aopOp (result, ic, FALSE);
7742
7743   /* now move the left to the result if they are not the same */
7744   if (!sameRegs (AOP (left), AOP (result)) &&
7745       AOP_SIZE (result) > 1)
7746     {
7747
7748       size = AOP_SIZE (result);
7749       offset = 0;
7750       while (size--)
7751         {
7752           l = aopGet (AOP (left), offset, FALSE, TRUE);
7753           if (*l == '@' && (IS_AOP_PREG (result)))
7754             {
7755
7756               emitcode ("mov", "a,%s", l);
7757               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7758             }
7759           else
7760             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7761           offset++;
7762         }
7763     }
7764
7765   tlbl = newiTempLabel (NULL);
7766   size = AOP_SIZE (result);
7767   offset = 0;
7768   tlbl1 = newiTempLabel (NULL);
7769
7770   /* if it is only one byte then */
7771   if (size == 1)
7772     {
7773       symbol *tlbl1 = newiTempLabel (NULL);
7774
7775       l = aopGet (AOP (left), 0, FALSE, FALSE);
7776       MOVA (l);
7777       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7778       emitcode ("", "%05d$:", tlbl->key + 100);
7779       emitcode ("add", "a,acc");
7780       emitcode ("", "%05d$:", tlbl1->key + 100);
7781       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7782       popB (pushedB);
7783       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7784       goto release;
7785     }
7786
7787   reAdjustPreg (AOP (result));
7788
7789   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7790   emitcode ("", "%05d$:", tlbl->key + 100);
7791   l = aopGet (AOP (result), offset, FALSE, FALSE);
7792   MOVA (l);
7793   emitcode ("add", "a,acc");
7794   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7795   while (--size)
7796     {
7797       l = aopGet (AOP (result), offset, FALSE, FALSE);
7798       MOVA (l);
7799       emitcode ("rlc", "a");
7800       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7801     }
7802   reAdjustPreg (AOP (result));
7803
7804   emitcode ("", "%05d$:", tlbl1->key + 100);
7805   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7806   popB (pushedB);
7807 release:
7808   freeAsmop (left, NULL, ic, TRUE);
7809   freeAsmop (result, NULL, ic, TRUE);
7810 }
7811
7812 /*-----------------------------------------------------------------*/
7813 /* genrshOne - right shift a one byte quantity by known count      */
7814 /*-----------------------------------------------------------------*/
7815 static void
7816 genrshOne (operand * result, operand * left,
7817            int shCount, int sign)
7818 {
7819   D(emitcode (";     genrshOne",""));
7820
7821   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7822 }
7823
7824 /*-----------------------------------------------------------------*/
7825 /* genrshTwo - right shift two bytes by known amount != 0          */
7826 /*-----------------------------------------------------------------*/
7827 static void
7828 genrshTwo (operand * result, operand * left,
7829            int shCount, int sign)
7830 {
7831   D(emitcode (";     genrshTwo",""));
7832
7833   /* if shCount >= 8 */
7834   if (shCount >= 8)
7835     {
7836       shCount -= 8;
7837       if (shCount)
7838         shiftR1Left2Result (left, MSB16, result, LSB,
7839                             shCount, sign);
7840       else
7841         movLeft2Result (left, MSB16, result, LSB, sign);
7842       addSign (result, MSB16, sign);
7843     }
7844
7845   /*  1 <= shCount <= 7 */
7846   else
7847     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7848 }
7849
7850 /*-----------------------------------------------------------------*/
7851 /* shiftRLong - shift right one long from left to result           */
7852 /* offl = LSB or MSB16                                             */
7853 /*-----------------------------------------------------------------*/
7854 static void
7855 shiftRLong (operand * left, int offl,
7856             operand * result, int sign)
7857 {
7858   int isSameRegs=sameRegs(AOP(left),AOP(result));
7859
7860   if (isSameRegs && offl>1) {
7861     // we are in big trouble, but this shouldn't happen
7862     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7863   }
7864
7865   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7866
7867   if (offl==MSB16) {
7868     // shift is > 8
7869     if (sign) {
7870       emitcode ("rlc", "a");
7871       emitcode ("subb", "a,acc");
7872       if (isSameRegs)
7873         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7874       else {
7875         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7876         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7877       }
7878     } else {
7879       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7880     }
7881   }
7882
7883   if (!sign) {
7884     emitcode ("clr", "c");
7885   } else {
7886     emitcode ("mov", "c,acc.7");
7887   }
7888
7889   emitcode ("rrc", "a");
7890
7891   if (isSameRegs && offl==MSB16) {
7892     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7893   } else {
7894     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7895     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7896   }
7897
7898   emitcode ("rrc", "a");
7899   if (isSameRegs && offl==1) {
7900     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7901   } else {
7902     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7903     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7904   }
7905   emitcode ("rrc", "a");
7906   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7907
7908   if (offl == LSB)
7909     {
7910       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7911       emitcode ("rrc", "a");
7912       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7913     }
7914 }
7915
7916 /*-----------------------------------------------------------------*/
7917 /* genrshFour - shift four byte by a known amount != 0             */
7918 /*-----------------------------------------------------------------*/
7919 static void
7920 genrshFour (operand * result, operand * left,
7921             int shCount, int sign)
7922 {
7923   D(emitcode (";     genrshFour",""));
7924
7925   /* if shifting more that 3 bytes */
7926   if (shCount >= 24)
7927     {
7928       shCount -= 24;
7929       if (shCount)
7930         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7931       else
7932         movLeft2Result (left, MSB32, result, LSB, sign);
7933       addSign (result, MSB16, sign);
7934     }
7935   else if (shCount >= 16)
7936     {
7937       shCount -= 16;
7938       if (shCount)
7939         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7940       else
7941         {
7942           movLeft2Result (left, MSB24, result, LSB, 0);
7943           movLeft2Result (left, MSB32, result, MSB16, sign);
7944         }
7945       addSign (result, MSB24, sign);
7946     }
7947   else if (shCount >= 8)
7948     {
7949       shCount -= 8;
7950       if (shCount == 1)
7951         shiftRLong (left, MSB16, result, sign);
7952       else if (shCount == 0)
7953         {
7954           movLeft2Result (left, MSB16, result, LSB, 0);
7955           movLeft2Result (left, MSB24, result, MSB16, 0);
7956           movLeft2Result (left, MSB32, result, MSB24, sign);
7957           addSign (result, MSB32, sign);
7958         }
7959       else
7960         {
7961           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
7962           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
7963           /* the last shift is signed */
7964           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
7965           addSign (result, MSB32, sign);
7966         }
7967     }
7968   else
7969     {                           /* 1 <= shCount <= 7 */
7970       if (shCount <= 2)
7971         {
7972           shiftRLong (left, LSB, result, sign);
7973           if (shCount == 2)
7974             shiftRLong (result, LSB, result, sign);
7975         }
7976       else
7977         {
7978           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
7979           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
7980           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
7981         }
7982     }
7983 }
7984
7985 /*-----------------------------------------------------------------*/
7986 /* genRightShiftLiteral - right shifting by known count            */
7987 /*-----------------------------------------------------------------*/
7988 static void
7989 genRightShiftLiteral (operand * left,
7990                       operand * right,
7991                       operand * result,
7992                       iCode * ic,
7993                       int sign)
7994 {
7995   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7996   int size;
7997
7998   D(emitcode (";     genRightShiftLiteral",""));
7999
8000   freeAsmop (right, NULL, ic, TRUE);
8001
8002   aopOp (left, ic, FALSE);
8003   aopOp (result, ic, FALSE);
8004
8005 #if VIEW_SIZE
8006   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8007             AOP_SIZE (left));
8008 #endif
8009
8010   size = getDataSize (left);
8011   /* test the LEFT size !!! */
8012
8013   /* I suppose that the left size >= result size */
8014   if (shCount == 0)
8015     {
8016       size = getDataSize (result);
8017       while (size--)
8018         movLeft2Result (left, size, result, size, 0);
8019     }
8020
8021   else if (shCount >= (size * 8))
8022     {
8023       if (sign) {
8024         /* get sign in acc.7 */
8025         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
8026       }
8027       addSign (result, LSB, sign);
8028     }
8029   else
8030     {
8031       switch (size)
8032         {
8033         case 1:
8034           genrshOne (result, left, shCount, sign);
8035           break;
8036
8037         case 2:
8038           genrshTwo (result, left, shCount, sign);
8039           break;
8040
8041         case 4:
8042           genrshFour (result, left, shCount, sign);
8043           break;
8044         default:
8045           break;
8046         }
8047     }
8048   freeAsmop (left, NULL, ic, TRUE);
8049   freeAsmop (result, NULL, ic, TRUE);
8050 }
8051
8052 /*-----------------------------------------------------------------*/
8053 /* genSignedRightShift - right shift of signed number              */
8054 /*-----------------------------------------------------------------*/
8055 static void
8056 genSignedRightShift (iCode * ic)
8057 {
8058   operand *right, *left, *result;
8059   int size, offset;
8060   char *l;
8061   symbol *tlbl, *tlbl1;
8062   bool pushedB;
8063
8064   D(emitcode (";     genSignedRightShift",""));
8065
8066   /* we do it the hard way put the shift count in b
8067      and loop thru preserving the sign */
8068
8069   right = IC_RIGHT (ic);
8070   left = IC_LEFT (ic);
8071   result = IC_RESULT (ic);
8072
8073   aopOp (right, ic, FALSE);
8074
8075
8076   if (AOP_TYPE (right) == AOP_LIT)
8077     {
8078       genRightShiftLiteral (left, right, result, ic, 1);
8079       return;
8080     }
8081   /* shift count is unknown then we have to form
8082      a loop get the loop count in B : Note: we take
8083      only the lower order byte since shifting
8084      more that 32 bits make no sense anyway, ( the
8085      largest size of an object can be only 32 bits ) */
8086
8087   pushedB = pushB ();
8088   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
8089   emitcode ("inc", "b");
8090   freeAsmop (right, NULL, ic, TRUE);
8091   aopOp (left, ic, FALSE);
8092   aopOp (result, ic, FALSE);
8093
8094   /* now move the left to the result if they are not the
8095      same */
8096   if (!sameRegs (AOP (left), AOP (result)) &&
8097       AOP_SIZE (result) > 1)
8098     {
8099
8100       size = AOP_SIZE (result);
8101       offset = 0;
8102       while (size--)
8103         {
8104           l = aopGet (AOP (left), offset, FALSE, TRUE);
8105           if (*l == '@' && IS_AOP_PREG (result))
8106             {
8107
8108               emitcode ("mov", "a,%s", l);
8109               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8110             }
8111           else
8112             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
8113           offset++;
8114         }
8115     }
8116
8117   /* mov the highest order bit to OVR */
8118   tlbl = newiTempLabel (NULL);
8119   tlbl1 = newiTempLabel (NULL);
8120
8121   size = AOP_SIZE (result);
8122   offset = size - 1;
8123   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
8124   emitcode ("rlc", "a");
8125   emitcode ("mov", "ov,c");
8126   /* if it is only one byte then */
8127   if (size == 1)
8128     {
8129       l = aopGet (AOP (left), 0, FALSE, FALSE);
8130       MOVA (l);
8131       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8132       emitcode ("", "%05d$:", tlbl->key + 100);
8133       emitcode ("mov", "c,ov");
8134       emitcode ("rrc", "a");
8135       emitcode ("", "%05d$:", tlbl1->key + 100);
8136       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8137       popB (pushedB);
8138       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
8139       goto release;
8140     }
8141
8142   reAdjustPreg (AOP (result));
8143   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8144   emitcode ("", "%05d$:", tlbl->key + 100);
8145   emitcode ("mov", "c,ov");
8146   while (size--)
8147     {
8148       l = aopGet (AOP (result), offset, FALSE, FALSE);
8149       MOVA (l);
8150       emitcode ("rrc", "a");
8151       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
8152     }
8153   reAdjustPreg (AOP (result));
8154   emitcode ("", "%05d$:", tlbl1->key + 100);
8155   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8156   popB (pushedB);
8157
8158 release:
8159   freeAsmop (left, NULL, ic, TRUE);
8160   freeAsmop (result, NULL, ic, TRUE);
8161 }
8162
8163 /*-----------------------------------------------------------------*/
8164 /* genRightShift - generate code for right shifting                */
8165 /*-----------------------------------------------------------------*/
8166 static void
8167 genRightShift (iCode * ic)
8168 {
8169   operand *right, *left, *result;
8170   sym_link *letype;
8171   int size, offset;
8172   char *l;
8173   symbol *tlbl, *tlbl1;
8174   bool pushedB;
8175
8176   D(emitcode (";     genRightShift",""));
8177
8178   /* if signed then we do it the hard way preserve the
8179      sign bit moving it inwards */
8180   letype = getSpec (operandType (IC_LEFT (ic)));
8181
8182   if (!SPEC_USIGN (letype))
8183     {
8184       genSignedRightShift (ic);
8185       return;
8186     }
8187
8188   /* signed & unsigned types are treated the same : i.e. the
8189      signed is NOT propagated inwards : quoting from the
8190      ANSI - standard : "for E1 >> E2, is equivalent to division
8191      by 2**E2 if unsigned or if it has a non-negative value,
8192      otherwise the result is implementation defined ", MY definition
8193      is that the sign does not get propagated */
8194
8195   right = IC_RIGHT (ic);
8196   left = IC_LEFT (ic);
8197   result = IC_RESULT (ic);
8198
8199   aopOp (right, ic, FALSE);
8200
8201   /* if the shift count is known then do it
8202      as efficiently as possible */
8203   if (AOP_TYPE (right) == AOP_LIT)
8204     {
8205       genRightShiftLiteral (left, right, result, ic, 0);
8206       return;
8207     }
8208
8209   /* shift count is unknown then we have to form
8210      a loop get the loop count in B : Note: we take
8211      only the lower order byte since shifting
8212      more that 32 bits make no sense anyway, ( the
8213      largest size of an object can be only 32 bits ) */
8214
8215   pushedB = pushB ();
8216   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
8217   emitcode ("inc", "b");
8218   freeAsmop (right, NULL, ic, TRUE);
8219   aopOp (left, ic, FALSE);
8220   aopOp (result, ic, FALSE);
8221
8222   /* now move the left to the result if they are not the
8223      same */
8224   if (!sameRegs (AOP (left), AOP (result)) &&
8225       AOP_SIZE (result) > 1)
8226     {
8227
8228       size = AOP_SIZE (result);
8229       offset = 0;
8230       while (size--)
8231         {
8232           l = aopGet (AOP (left), offset, FALSE, TRUE);
8233           if (*l == '@' && IS_AOP_PREG (result))
8234             {
8235
8236               emitcode ("mov", "a,%s", l);
8237               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8238             }
8239           else
8240             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
8241           offset++;
8242         }
8243     }
8244
8245   tlbl = newiTempLabel (NULL);
8246   tlbl1 = newiTempLabel (NULL);
8247   size = AOP_SIZE (result);
8248   offset = size - 1;
8249
8250   /* if it is only one byte then */
8251   if (size == 1)
8252     {
8253       l = aopGet (AOP (left), 0, FALSE, FALSE);
8254       MOVA (l);
8255       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8256       emitcode ("", "%05d$:", tlbl->key + 100);
8257       CLRC;
8258       emitcode ("rrc", "a");
8259       emitcode ("", "%05d$:", tlbl1->key + 100);
8260       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8261       popB (pushedB);
8262       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
8263       goto release;
8264     }
8265
8266   reAdjustPreg (AOP (result));
8267   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8268   emitcode ("", "%05d$:", tlbl->key + 100);
8269   CLRC;
8270   while (size--)
8271     {
8272       l = aopGet (AOP (result), offset, FALSE, FALSE);
8273       MOVA (l);
8274       emitcode ("rrc", "a");
8275       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
8276     }
8277   reAdjustPreg (AOP (result));
8278
8279   emitcode ("", "%05d$:", tlbl1->key + 100);
8280   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8281   popB (pushedB);
8282
8283 release:
8284   freeAsmop (left, NULL, ic, TRUE);
8285   freeAsmop (result, NULL, ic, TRUE);
8286 }
8287
8288 /*-----------------------------------------------------------------*/
8289 /* emitPtrByteGet - emits code to get a byte into A through a      */
8290 /*                  pointer register (R0, R1, or DPTR). The        */
8291 /*                  original value of A can be preserved in B.     */
8292 /*-----------------------------------------------------------------*/
8293 static void
8294 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8295 {
8296   switch (p_type)
8297     {
8298     case IPOINTER:
8299     case POINTER:
8300       if (preserveAinB)
8301         emitcode ("mov", "b,a");
8302       emitcode ("mov", "a,@%s", rname);
8303       break;
8304
8305     case PPOINTER:
8306       if (preserveAinB)
8307         emitcode ("mov", "b,a");
8308       emitcode ("movx", "a,@%s", rname);
8309       break;
8310
8311     case FPOINTER:
8312       if (preserveAinB)
8313         emitcode ("mov", "b,a");
8314       emitcode ("movx", "a,@dptr");
8315       break;
8316
8317     case CPOINTER:
8318       if (preserveAinB)
8319         emitcode ("mov", "b,a");
8320       emitcode ("clr", "a");
8321       emitcode ("movc", "a,@a+dptr");
8322       break;
8323
8324     case GPOINTER:
8325       if (preserveAinB)
8326         {
8327           emitcode ("push", "b");
8328           emitcode ("push", "acc");
8329         }
8330       emitcode ("lcall", "__gptrget");
8331       if (preserveAinB)
8332         emitcode ("pop", "b");
8333       break;
8334     }
8335 }
8336
8337 /*-----------------------------------------------------------------*/
8338 /* emitPtrByteSet - emits code to set a byte from src through a    */
8339 /*                  pointer register (R0, R1, or DPTR).            */
8340 /*-----------------------------------------------------------------*/
8341 static void
8342 emitPtrByteSet (char *rname, int p_type, char *src)
8343 {
8344   switch (p_type)
8345     {
8346     case IPOINTER:
8347     case POINTER:
8348       if (*src=='@')
8349         {
8350           MOVA (src);
8351           emitcode ("mov", "@%s,a", rname);
8352         }
8353       else
8354         emitcode ("mov", "@%s,%s", rname, src);
8355       break;
8356
8357     case PPOINTER:
8358       MOVA (src);
8359       emitcode ("movx", "@%s,a", rname);
8360       break;
8361
8362     case FPOINTER:
8363       MOVA (src);
8364       emitcode ("movx", "@dptr,a");
8365       break;
8366
8367     case GPOINTER:
8368       MOVA (src);
8369       emitcode ("lcall", "__gptrput");
8370       break;
8371     }
8372 }
8373
8374 /*-----------------------------------------------------------------*/
8375 /* genUnpackBits - generates code for unpacking bits               */
8376 /*-----------------------------------------------------------------*/
8377 static void
8378 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8379 {
8380   int offset = 0;       /* result byte offset */
8381   int rsize;            /* result size */
8382   int rlen = 0;         /* remaining bitfield length */
8383   sym_link *etype;      /* bitfield type information */
8384   int blen;             /* bitfield length */
8385   int bstr;             /* bitfield starting bit within byte */
8386   char buffer[10];
8387
8388   D(emitcode (";     genUnpackBits",""));
8389
8390   etype = getSpec (operandType (result));
8391   rsize = getSize (operandType (result));
8392   blen = SPEC_BLEN (etype);
8393   bstr = SPEC_BSTR (etype);
8394
8395   if (ifx && blen <= 8)
8396     {
8397       emitPtrByteGet (rname, ptype, FALSE);
8398       if (blen == 1)
8399         {
8400           SNPRINTF (buffer, sizeof(buffer),
8401                     "acc.%d", bstr);
8402           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8403         }
8404       else
8405         {
8406           if (blen < 8)
8407             emitcode ("anl", "a,#0x%02x",
8408                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8409           genIfxJump (ifx, "a", NULL, NULL, NULL);
8410         }
8411       return;
8412     }
8413   wassert (!ifx);
8414
8415   /* If the bitfield length is less than a byte */
8416   if (blen < 8)
8417     {
8418       emitPtrByteGet (rname, ptype, FALSE);
8419       AccRsh (bstr);
8420       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8421       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8422       goto finish;
8423     }
8424
8425   /* Bit field did not fit in a byte. Copy all
8426      but the partial byte at the end.  */
8427   for (rlen=blen;rlen>=8;rlen-=8)
8428     {
8429       emitPtrByteGet (rname, ptype, FALSE);
8430       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8431       if (rlen>8)
8432         emitcode ("inc", "%s", rname);
8433     }
8434
8435   /* Handle the partial byte at the end */
8436   if (rlen)
8437     {
8438       emitPtrByteGet (rname, ptype, FALSE);
8439       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8440       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8441     }
8442
8443 finish:
8444   if (offset < rsize)
8445     {
8446       rsize -= offset;
8447       while (rsize--)
8448         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
8449     }
8450 }
8451
8452
8453 /*-----------------------------------------------------------------*/
8454 /* genDataPointerGet - generates code when ptr offset is known     */
8455 /*-----------------------------------------------------------------*/
8456 static void
8457 genDataPointerGet (operand * left,
8458                    operand * result,
8459                    iCode * ic)
8460 {
8461   char *l;
8462   char buffer[256];
8463   int size, offset = 0;
8464
8465   D(emitcode (";     genDataPointerGet",""));
8466
8467   aopOp (result, ic, TRUE);
8468
8469   /* get the string representation of the name */
8470   l = aopGet (AOP (left), 0, FALSE, TRUE);
8471   size = AOP_SIZE (result);
8472   while (size--)
8473     {
8474       if (offset)
8475         sprintf (buffer, "(%s + %d)", l + 1, offset);
8476       else
8477         sprintf (buffer, "%s", l + 1);
8478       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
8479     }
8480
8481   freeAsmop (left, NULL, ic, TRUE);
8482   freeAsmop (result, NULL, ic, TRUE);
8483 }
8484
8485 /*-----------------------------------------------------------------*/
8486 /* genNearPointerGet - emitcode for near pointer fetch             */
8487 /*-----------------------------------------------------------------*/
8488 static void
8489 genNearPointerGet (operand * left,
8490                    operand * result,
8491                    iCode * ic,
8492                    iCode * pi,
8493                    iCode * ifx)
8494 {
8495   asmop *aop = NULL;
8496   regs *preg = NULL;
8497   char *rname;
8498   sym_link *rtype, *retype;
8499   sym_link *ltype = operandType (left);
8500   char buffer[80];
8501
8502   D(emitcode (";     genNearPointerGet",""));
8503
8504   rtype = operandType (result);
8505   retype = getSpec (rtype);
8506
8507   aopOp (left, ic, FALSE);
8508
8509   /* if left is rematerialisable and
8510      result is not bitfield variable type and
8511      the left is pointer to data space i.e
8512      lower 128 bytes of space */
8513   if (AOP_TYPE (left) == AOP_IMMD &&
8514       !IS_BITFIELD (retype) &&
8515       DCL_TYPE (ltype) == POINTER)
8516     {
8517       genDataPointerGet (left, result, ic);
8518       return;
8519     }
8520
8521  /* if the value is already in a pointer register
8522      then don't need anything more */
8523   if (!AOP_INPREG (AOP (left)))
8524     {
8525       if (IS_AOP_PREG (left))
8526         {
8527           // Aha, it is a pointer, just in disguise.
8528           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8529           if (*rname != '@')
8530             {
8531               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8532                       __FILE__, __LINE__);
8533             }
8534           else
8535             {
8536               // Expected case.
8537               emitcode ("mov", "a%s,%s", rname + 1, rname);
8538               rname++;  // skip the '@'.
8539             }
8540         }
8541       else
8542         {
8543           /* otherwise get a free pointer register */
8544           aop = newAsmop (0);
8545           preg = getFreePtr (ic, &aop, FALSE);
8546           emitcode ("mov", "%s,%s",
8547                     preg->name,
8548                     aopGet (AOP (left), 0, FALSE, TRUE));
8549           rname = preg->name;
8550         }
8551     }
8552   else
8553     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8554
8555   //aopOp (result, ic, FALSE);
8556   aopOp (result, ic, result?TRUE:FALSE);
8557
8558   /* if bitfield then unpack the bits */
8559   if (IS_BITFIELD (retype))
8560     genUnpackBits (result, rname, POINTER, ifx);
8561   else
8562     {
8563       /* we have can just get the values */
8564       int size = AOP_SIZE (result);
8565       int offset = 0;
8566
8567       while (size--)
8568         {
8569           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8570             {
8571
8572               emitcode ("mov", "a,@%s", rname);
8573               if (!ifx)
8574               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8575             }
8576           else
8577             {
8578               sprintf (buffer, "@%s", rname);
8579               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8580             }
8581           offset++;
8582           if (size || pi)
8583             emitcode ("inc", "%s", rname);
8584         }
8585     }
8586
8587   /* now some housekeeping stuff */
8588   if (aop)       /* we had to allocate for this iCode */
8589     {
8590       if (pi) { /* post increment present */
8591         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8592       }
8593       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8594     }
8595   else
8596     {
8597       /* we did not allocate which means left
8598          already in a pointer register, then
8599          if size > 0 && this could be used again
8600          we have to point it back to where it
8601          belongs */
8602       if ((AOP_SIZE (result) > 1 &&
8603            !OP_SYMBOL (left)->remat &&
8604            (OP_SYMBOL (left)->liveTo > ic->seq ||
8605             ic->depth)) &&
8606           !pi)
8607         {
8608           int size = AOP_SIZE (result) - 1;
8609           while (size--)
8610             emitcode ("dec", "%s", rname);
8611         }
8612     }
8613
8614   if (ifx && !ifx->generated)
8615     {
8616       genIfxJump (ifx, "a", left, NULL, result);
8617     }
8618
8619   /* done */
8620   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8621   freeAsmop (left, NULL, ic, TRUE);
8622   if (pi) pi->generated = 1;
8623 }
8624
8625 /*-----------------------------------------------------------------*/
8626 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8627 /*-----------------------------------------------------------------*/
8628 static void
8629 genPagedPointerGet (operand * left,
8630                     operand * result,
8631                     iCode * ic,
8632                     iCode *pi,
8633                     iCode *ifx)
8634 {
8635   asmop *aop = NULL;
8636   regs *preg = NULL;
8637   char *rname;
8638   sym_link *rtype, *retype;
8639
8640   D(emitcode (";     genPagedPointerGet",""));
8641
8642   rtype = operandType (result);
8643   retype = getSpec (rtype);
8644
8645   aopOp (left, ic, FALSE);
8646
8647   /* if the value is already in a pointer register
8648      then don't need anything more */
8649   if (!AOP_INPREG (AOP (left)))
8650     {
8651       /* otherwise get a free pointer register */
8652       aop = newAsmop (0);
8653       preg = getFreePtr (ic, &aop, FALSE);
8654       emitcode ("mov", "%s,%s",
8655                 preg->name,
8656                 aopGet (AOP (left), 0, FALSE, TRUE));
8657       rname = preg->name;
8658     }
8659   else
8660     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8661
8662   aopOp (result, ic, FALSE);
8663
8664   /* if bitfield then unpack the bits */
8665   if (IS_BITFIELD (retype))
8666     genUnpackBits (result, rname, PPOINTER, ifx);
8667   else
8668     {
8669       /* we have can just get the values */
8670       int size = AOP_SIZE (result);
8671       int offset = 0;
8672
8673       while (size--)
8674         {
8675
8676           emitcode ("movx", "a,@%s", rname);
8677           if (!ifx)
8678           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8679
8680           offset++;
8681
8682           if (size || pi)
8683             emitcode ("inc", "%s", rname);
8684         }
8685     }
8686
8687   /* now some housekeeping stuff */
8688   if (aop) /* we had to allocate for this iCode */
8689     {
8690       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8691       freeAsmop (NULL, aop, ic, TRUE);
8692     }
8693   else
8694     {
8695       /* we did not allocate which means left
8696          already in a pointer register, then
8697          if size > 0 && this could be used again
8698          we have to point it back to where it
8699          belongs */
8700       if ((AOP_SIZE (result) > 1 &&
8701            !OP_SYMBOL (left)->remat &&
8702            (OP_SYMBOL (left)->liveTo > ic->seq ||
8703             ic->depth)) &&
8704           !pi)
8705         {
8706           int size = AOP_SIZE (result) - 1;
8707           while (size--)
8708             emitcode ("dec", "%s", rname);
8709         }
8710     }
8711
8712   if (ifx && !ifx->generated)
8713     {
8714       genIfxJump (ifx, "a", left, NULL, result);
8715     }
8716
8717   /* done */
8718   freeAsmop (left, NULL, ic, TRUE);
8719   freeAsmop (result, NULL, ic, TRUE);
8720   if (pi) pi->generated = 1;
8721
8722 }
8723
8724 /*--------------------------------------------------------------------*/
8725 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8726 /*--------------------------------------------------------------------*/
8727 static void
8728 loadDptrFromOperand (operand *op, bool loadBToo)
8729 {
8730   if (AOP_TYPE (op) != AOP_STR)
8731     {
8732       /* if this is rematerializable */
8733       if (AOP_TYPE (op) == AOP_IMMD)
8734         {
8735           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8736           if (loadBToo)
8737             {
8738               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8739                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8740               else
8741                 {
8742                   wassertl(FALSE, "need pointerCode");
8743                   emitcode ("", "; mov b,???");
8744                   /* genPointerGet and genPointerSet originally did different
8745                   ** things for this case. Both seem wrong.
8746                   ** from genPointerGet:
8747                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8748                   ** from genPointerSet:
8749                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8750                   */
8751                 }
8752             }
8753         }
8754       else if (AOP_TYPE (op) == AOP_DPTR)
8755         {
8756           if (loadBToo)
8757             {
8758               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8759               emitcode ("push", "acc");
8760               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8761               emitcode ("push", "acc");
8762               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8763               emitcode ("pop", "dph");
8764               emitcode ("pop", "dpl");
8765             }
8766           else
8767             {
8768               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8769               emitcode ("push", "acc");
8770               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8771               emitcode ("pop", "dpl");
8772             }
8773         }
8774       else
8775         {                       /* we need to get it byte by byte */
8776           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8777           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8778           if (loadBToo)
8779             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8780         }
8781     }
8782 }
8783
8784 /*-----------------------------------------------------------------*/
8785 /* genFarPointerGet - gget value from far space                    */
8786 /*-----------------------------------------------------------------*/
8787 static void
8788 genFarPointerGet (operand * left,
8789                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
8790 {
8791   int size, offset;
8792   sym_link *retype = getSpec (operandType (result));
8793
8794   D(emitcode (";     genFarPointerGet",""));
8795
8796   aopOp (left, ic, FALSE);
8797   loadDptrFromOperand (left, FALSE);
8798
8799   /* so dptr now contains the address */
8800   aopOp (result, ic, FALSE);
8801
8802   /* if bit then unpack */
8803   if (IS_BITFIELD (retype))
8804     genUnpackBits (result, "dptr", FPOINTER, ifx);
8805   else
8806     {
8807       size = AOP_SIZE (result);
8808       offset = 0;
8809
8810       while (size--)
8811         {
8812           emitcode ("movx", "a,@dptr");
8813           if (!ifx)
8814             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8815           if (size || pi)
8816             emitcode ("inc", "dptr");
8817         }
8818     }
8819
8820   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8821     {
8822     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8823     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8824     pi->generated = 1;
8825   }
8826
8827   if (ifx && !ifx->generated)
8828     {
8829       genIfxJump (ifx, "a", left, NULL, result);
8830     }
8831
8832   freeAsmop (left, NULL, ic, TRUE);
8833   freeAsmop (result, NULL, ic, TRUE);
8834 }
8835
8836 /*-----------------------------------------------------------------*/
8837 /* genCodePointerGet - gget value from code space                  */
8838 /*-----------------------------------------------------------------*/
8839 static void
8840 genCodePointerGet (operand * left,
8841                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
8842 {
8843   int size, offset;
8844   sym_link *retype = getSpec (operandType (result));
8845
8846   D(emitcode (";     genCodePointerGet",""));
8847
8848   aopOp (left, ic, FALSE);
8849   loadDptrFromOperand (left, FALSE);
8850
8851   /* so dptr now contains the address */
8852   aopOp (result, ic, FALSE);
8853
8854   /* if bit then unpack */
8855   if (IS_BITFIELD (retype))
8856     genUnpackBits (result, "dptr", CPOINTER, ifx);
8857   else
8858     {
8859       size = AOP_SIZE (result);
8860       offset = 0;
8861
8862       while (size--)
8863         {
8864           if (pi)
8865             {
8866               emitcode ("clr", "a");
8867               emitcode ("movc", "a,@a+dptr");
8868               if (!ifx)
8869               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8870               emitcode ("inc", "dptr");
8871             }
8872           else
8873             {
8874               emitcode ("mov", "a,#0x%02x", offset);
8875               emitcode ("movc", "a,@a+dptr");
8876               if (!ifx)
8877               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8878             }
8879         }
8880     }
8881
8882   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8883     {
8884     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8885     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8886     pi->generated = 1;
8887   }
8888
8889   if (ifx && !ifx->generated)
8890     {
8891       genIfxJump (ifx, "a", left, NULL, result);
8892     }
8893
8894   freeAsmop (left, NULL, ic, TRUE);
8895   freeAsmop (result, NULL, ic, TRUE);
8896 }
8897
8898 /*-----------------------------------------------------------------*/
8899 /* genGenPointerGet - gget value from generic pointer space        */
8900 /*-----------------------------------------------------------------*/
8901 static void
8902 genGenPointerGet (operand * left,
8903                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
8904 {
8905   int size, offset;
8906   sym_link *retype = getSpec (operandType (result));
8907
8908   D(emitcode (";     genGenPointerGet",""));
8909
8910   aopOp (left, ic, FALSE);
8911   loadDptrFromOperand (left, TRUE);
8912
8913   /* so dptr know contains the address */
8914   aopOp (result, ic, FALSE);
8915
8916   /* if bit then unpack */
8917   if (IS_BITFIELD (retype))
8918     genUnpackBits (result, "dptr", GPOINTER, ifx);
8919   else
8920     {
8921       size = AOP_SIZE (result);
8922       offset = 0;
8923
8924       while (size--)
8925         {
8926           emitcode ("lcall", "__gptrget");
8927           if (!ifx)
8928           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8929           if (size || pi)
8930             emitcode ("inc", "dptr");
8931         }
8932     }
8933
8934   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8935     {
8936     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8937     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8938     pi->generated = 1;
8939   }
8940
8941   if (ifx && !ifx->generated)
8942     {
8943       genIfxJump (ifx, "a", left, NULL, result);
8944     }
8945
8946
8947   freeAsmop (left, NULL, ic, TRUE);
8948   freeAsmop (result, NULL, ic, TRUE);
8949 }
8950
8951 /*-----------------------------------------------------------------*/
8952 /* genPointerGet - generate code for pointer get                   */
8953 /*-----------------------------------------------------------------*/
8954 static void
8955 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
8956 {
8957   operand *left, *result;
8958   sym_link *type, *etype;
8959   int p_type;
8960
8961   D(emitcode (";     genPointerGet",""));
8962
8963   left = IC_LEFT (ic);
8964   result = IC_RESULT (ic);
8965
8966   if (getSize (operandType (result))>1)
8967     ifx = NULL;
8968
8969   /* depending on the type of pointer we need to
8970      move it to the correct pointer register */
8971   type = operandType (left);
8972   etype = getSpec (type);
8973   /* if left is of type of pointer then it is simple */
8974   if (IS_PTR (type) && !IS_FUNC (type->next))
8975     p_type = DCL_TYPE (type);
8976   else
8977     {
8978       /* we have to go by the storage class */
8979       p_type = PTR_TYPE (SPEC_OCLS (etype));
8980     }
8981
8982   /* special case when cast remat */
8983   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
8984       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
8985           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
8986           type = operandType (left);
8987           p_type = DCL_TYPE (type);
8988   }
8989   /* now that we have the pointer type we assign
8990      the pointer values */
8991   switch (p_type)
8992     {
8993
8994     case POINTER:
8995     case IPOINTER:
8996       genNearPointerGet (left, result, ic, pi, ifx);
8997       break;
8998
8999     case PPOINTER:
9000       genPagedPointerGet (left, result, ic, pi, ifx);
9001       break;
9002
9003     case FPOINTER:
9004       genFarPointerGet (left, result, ic, pi, ifx);
9005       break;
9006
9007     case CPOINTER:
9008       genCodePointerGet (left, result, ic, pi, ifx);
9009       break;
9010
9011     case GPOINTER:
9012       genGenPointerGet (left, result, ic, pi, ifx);
9013       break;
9014     }
9015
9016 }
9017
9018
9019
9020 /*-----------------------------------------------------------------*/
9021 /* genPackBits - generates code for packed bit storage             */
9022 /*-----------------------------------------------------------------*/
9023 static void
9024 genPackBits (sym_link * etype,
9025              operand * right,
9026              char *rname, int p_type)
9027 {
9028   int offset = 0;       /* source byte offset */
9029   int rlen = 0;         /* remaining bitfield length */
9030   int blen;             /* bitfield length */
9031   int bstr;             /* bitfield starting bit within byte */
9032   int litval;           /* source literal value (if AOP_LIT) */
9033   unsigned char mask;   /* bitmask within current byte */
9034
9035   D(emitcode (";     genPackBits",""));
9036
9037   blen = SPEC_BLEN (etype);
9038   bstr = SPEC_BSTR (etype);
9039
9040   /* If the bitfield length is less than a byte */
9041   if (blen < 8)
9042     {
9043       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9044               (unsigned char) (0xFF >> (8 - bstr)));
9045
9046       if (AOP_TYPE (right) == AOP_LIT)
9047         {
9048           /* Case with a bitfield length <8 and literal source
9049           */
9050           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9051           litval <<= bstr;
9052           litval &= (~mask) & 0xff;
9053           emitPtrByteGet (rname, p_type, FALSE);
9054           if ((mask|litval)!=0xff)
9055             emitcode ("anl","a,#0x%02x", mask);
9056           if (litval)
9057             emitcode ("orl","a,#0x%02x", litval);
9058         }
9059       else
9060         {
9061           if ((blen==1) && (p_type!=GPOINTER))
9062             {
9063               /* Case with a bitfield length == 1 and no generic pointer
9064               */
9065               if (AOP_TYPE (right) == AOP_CRY)
9066                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9067               else
9068                 {
9069                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
9070                   emitcode ("rrc","a");
9071                 }
9072               emitPtrByteGet (rname, p_type, FALSE);
9073               emitcode ("mov","acc.%d,c",bstr);
9074             }
9075           else
9076             {
9077               bool pushedB;
9078               /* Case with a bitfield length < 8 and arbitrary source
9079               */
9080               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
9081               /* shift and mask source value */
9082               AccLsh (bstr);
9083               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9084
9085               pushedB = pushB ();
9086               /* transfer A to B and get next byte */
9087               emitPtrByteGet (rname, p_type, TRUE);
9088
9089               emitcode ("anl", "a,#0x%02x", mask);
9090               emitcode ("orl", "a,b");
9091               if (p_type == GPOINTER)
9092                 emitcode ("pop", "b");
9093
9094               popB (pushedB);
9095            }
9096         }
9097
9098       emitPtrByteSet (rname, p_type, "a");
9099       return;
9100     }
9101
9102   /* Bit length is greater than 7 bits. In this case, copy  */
9103   /* all except the partial byte at the end                 */
9104   for (rlen=blen;rlen>=8;rlen-=8)
9105     {
9106       emitPtrByteSet (rname, p_type,
9107                       aopGet (AOP (right), offset++, FALSE, TRUE) );
9108       if (rlen>8)
9109         emitcode ("inc", "%s", rname);
9110     }
9111
9112   /* If there was a partial byte at the end */
9113   if (rlen)
9114     {
9115       mask = (((unsigned char) -1 << rlen) & 0xff);
9116
9117       if (AOP_TYPE (right) == AOP_LIT)
9118         {
9119           /* Case with partial byte and literal source
9120           */
9121           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9122           litval >>= (blen-rlen);
9123           litval &= (~mask) & 0xff;
9124           emitPtrByteGet (rname, p_type, FALSE);
9125           if ((mask|litval)!=0xff)
9126             emitcode ("anl","a,#0x%02x", mask);
9127           if (litval)
9128             emitcode ("orl","a,#0x%02x", litval);
9129         }
9130       else
9131         {
9132           bool pushedB;
9133           /* Case with partial byte and arbitrary source
9134           */
9135           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
9136           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9137
9138           pushedB = pushB ();
9139           /* transfer A to B and get next byte */
9140           emitPtrByteGet (rname, p_type, TRUE);
9141
9142           emitcode ("anl", "a,#0x%02x", mask);
9143           emitcode ("orl", "a,b");
9144           if (p_type == GPOINTER)
9145             emitcode ("pop", "b");
9146
9147           popB (pushedB);
9148         }
9149       emitPtrByteSet (rname, p_type, "a");
9150     }
9151
9152 }
9153
9154
9155 /*-----------------------------------------------------------------*/
9156 /* genDataPointerSet - remat pointer to data space                 */
9157 /*-----------------------------------------------------------------*/
9158 static void
9159 genDataPointerSet (operand * right,
9160                    operand * result,
9161                    iCode * ic)
9162 {
9163   int size, offset = 0;
9164   char *l, buffer[256];
9165
9166   D(emitcode (";     genDataPointerSet",""));
9167
9168   aopOp (right, ic, FALSE);
9169
9170   l = aopGet (AOP (result), 0, FALSE, TRUE);
9171   size = AOP_SIZE (right);
9172   while (size--)
9173     {
9174       if (offset)
9175         sprintf (buffer, "(%s + %d)", l + 1, offset);
9176       else
9177         sprintf (buffer, "%s", l + 1);
9178       emitcode ("mov", "%s,%s", buffer,
9179                 aopGet (AOP (right), offset++, FALSE, FALSE));
9180     }
9181
9182   freeAsmop (right, NULL, ic, TRUE);
9183   freeAsmop (result, NULL, ic, TRUE);
9184 }
9185
9186 /*-----------------------------------------------------------------*/
9187 /* genNearPointerSet - emitcode for near pointer put                */
9188 /*-----------------------------------------------------------------*/
9189 static void
9190 genNearPointerSet (operand * right,
9191                    operand * result,
9192                    iCode * ic,
9193                    iCode * pi)
9194 {
9195   asmop *aop = NULL;
9196   regs *preg = NULL;
9197   char *rname, *l;
9198   sym_link *retype, *letype;
9199   sym_link *ptype = operandType (result);
9200
9201   D(emitcode (";     genNearPointerSet",""));
9202
9203   retype = getSpec (operandType (right));
9204   letype = getSpec (ptype);
9205   aopOp (result, ic, FALSE);
9206
9207   /* if the result is rematerializable &
9208      in data space & not a bit variable */
9209   if (AOP_TYPE (result) == AOP_IMMD &&
9210       DCL_TYPE (ptype) == POINTER &&
9211       !IS_BITVAR (retype) &&
9212       !IS_BITVAR (letype))
9213     {
9214       genDataPointerSet (right, result, ic);
9215       return;
9216     }
9217
9218   /* if the value is already in a pointer register
9219      then don't need anything more */
9220   if (!AOP_INPREG (AOP (result)))
9221     {
9222         if (
9223             //AOP_TYPE (result) == AOP_STK
9224             IS_AOP_PREG(result)
9225             )
9226         {
9227             // Aha, it is a pointer, just in disguise.
9228             rname = aopGet (AOP (result), 0, FALSE, FALSE);
9229             if (*rname != '@')
9230             {
9231                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9232                         __FILE__, __LINE__);
9233             }
9234             else
9235             {
9236                 // Expected case.
9237                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9238                 rname++;  // skip the '@'.
9239             }
9240         }
9241         else
9242         {
9243             /* otherwise get a free pointer register */
9244             aop = newAsmop (0);
9245             preg = getFreePtr (ic, &aop, FALSE);
9246             emitcode ("mov", "%s,%s",
9247                       preg->name,
9248                       aopGet (AOP (result), 0, FALSE, TRUE));
9249             rname = preg->name;
9250         }
9251     }
9252     else
9253     {
9254         rname = aopGet (AOP (result), 0, FALSE, FALSE);
9255     }
9256
9257   aopOp (right, ic, FALSE);
9258
9259   /* if bitfield then unpack the bits */
9260   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9261     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9262   else
9263     {
9264       /* we have can just get the values */
9265       int size = AOP_SIZE (right);
9266       int offset = 0;
9267
9268       while (size--)
9269         {
9270           l = aopGet (AOP (right), offset, FALSE, TRUE);
9271           if (*l == '@')
9272             {
9273               MOVA (l);
9274               emitcode ("mov", "@%s,a", rname);
9275             }
9276           else
9277             emitcode ("mov", "@%s,%s", rname, l);
9278           if (size || pi)
9279             emitcode ("inc", "%s", rname);
9280           offset++;
9281         }
9282     }
9283
9284   /* now some housekeeping stuff */
9285   if (aop) /* we had to allocate for this iCode */
9286     {
9287       if (pi)
9288         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9289       freeAsmop (NULL, aop, ic, TRUE);
9290     }
9291   else
9292     {
9293       /* we did not allocate which means left
9294          already in a pointer register, then
9295          if size > 0 && this could be used again
9296          we have to point it back to where it
9297          belongs */
9298       if ((AOP_SIZE (right) > 1 &&
9299            !OP_SYMBOL (result)->remat &&
9300            (OP_SYMBOL (result)->liveTo > ic->seq ||
9301             ic->depth)) &&
9302           !pi)
9303         {
9304           int size = AOP_SIZE (right) - 1;
9305           while (size--)
9306             emitcode ("dec", "%s", rname);
9307         }
9308     }
9309
9310   /* done */
9311   if (pi) pi->generated = 1;
9312   freeAsmop (result, NULL, ic, TRUE);
9313   freeAsmop (right, NULL, ic, TRUE);
9314 }
9315
9316 /*-----------------------------------------------------------------*/
9317 /* genPagedPointerSet - emitcode for Paged pointer put             */
9318 /*-----------------------------------------------------------------*/
9319 static void
9320 genPagedPointerSet (operand * right,
9321                     operand * result,
9322                     iCode * ic,
9323                     iCode * pi)
9324 {
9325   asmop *aop = NULL;
9326   regs *preg = NULL;
9327   char *rname, *l;
9328   sym_link *retype, *letype;
9329
9330   D(emitcode (";     genPagedPointerSet",""));
9331
9332   retype = getSpec (operandType (right));
9333   letype = getSpec (operandType (result));
9334
9335   aopOp (result, ic, FALSE);
9336
9337   /* if the value is already in a pointer register
9338      then don't need anything more */
9339   if (!AOP_INPREG (AOP (result)))
9340     {
9341       /* otherwise get a free pointer register */
9342       aop = newAsmop (0);
9343       preg = getFreePtr (ic, &aop, FALSE);
9344       emitcode ("mov", "%s,%s",
9345                 preg->name,
9346                 aopGet (AOP (result), 0, FALSE, TRUE));
9347       rname = preg->name;
9348     }
9349   else
9350     rname = aopGet (AOP (result), 0, FALSE, FALSE);
9351
9352   aopOp (right, ic, FALSE);
9353
9354   /* if bitfield then unpack the bits */
9355   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9356     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9357   else
9358     {
9359       /* we have can just get the values */
9360       int size = AOP_SIZE (right);
9361       int offset = 0;
9362
9363       while (size--)
9364         {
9365           l = aopGet (AOP (right), offset, FALSE, TRUE);
9366
9367           MOVA (l);
9368           emitcode ("movx", "@%s,a", rname);
9369
9370           if (size || pi)
9371             emitcode ("inc", "%s", rname);
9372
9373           offset++;
9374         }
9375     }
9376
9377   /* now some housekeeping stuff */
9378   if (aop) /* we had to allocate for this iCode */
9379     {
9380       if (pi)
9381         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9382       freeAsmop (NULL, aop, ic, TRUE);
9383     }
9384   else
9385     {
9386       /* we did not allocate which means left
9387          already in a pointer register, then
9388          if size > 0 && this could be used again
9389          we have to point it back to where it
9390          belongs */
9391       if (AOP_SIZE (right) > 1 &&
9392           !OP_SYMBOL (result)->remat &&
9393           (OP_SYMBOL (result)->liveTo > ic->seq ||
9394            ic->depth))
9395         {
9396           int size = AOP_SIZE (right) - 1;
9397           while (size--)
9398             emitcode ("dec", "%s", rname);
9399         }
9400     }
9401
9402   /* done */
9403   if (pi) pi->generated = 1;
9404   freeAsmop (result, NULL, ic, TRUE);
9405   freeAsmop (right, NULL, ic, TRUE);
9406
9407
9408 }
9409
9410 /*-----------------------------------------------------------------*/
9411 /* genFarPointerSet - set value from far space                     */
9412 /*-----------------------------------------------------------------*/
9413 static void
9414 genFarPointerSet (operand * right,
9415                   operand * result, iCode * ic, iCode * pi)
9416 {
9417   int size, offset;
9418   sym_link *retype = getSpec (operandType (right));
9419   sym_link *letype = getSpec (operandType (result));
9420
9421   D(emitcode (";     genFarPointerSet",""));
9422
9423   aopOp (result, ic, FALSE);
9424   loadDptrFromOperand (result, FALSE);
9425
9426   /* so dptr know contains the address */
9427   aopOp (right, ic, FALSE);
9428
9429   /* if bit then unpack */
9430   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9431     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9432   else
9433     {
9434       size = AOP_SIZE (right);
9435       offset = 0;
9436
9437       while (size--)
9438         {
9439           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9440           MOVA (l);
9441           emitcode ("movx", "@dptr,a");
9442           if (size || pi)
9443             emitcode ("inc", "dptr");
9444         }
9445     }
9446   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9447     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9448     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9449     pi->generated=1;
9450   }
9451   freeAsmop (result, NULL, ic, TRUE);
9452   freeAsmop (right, NULL, ic, TRUE);
9453 }
9454
9455 /*-----------------------------------------------------------------*/
9456 /* genGenPointerSet - set value from generic pointer space         */
9457 /*-----------------------------------------------------------------*/
9458 static void
9459 genGenPointerSet (operand * right,
9460                   operand * result, iCode * ic, iCode * pi)
9461 {
9462   int size, offset;
9463   sym_link *retype = getSpec (operandType (right));
9464   sym_link *letype = getSpec (operandType (result));
9465
9466   D(emitcode (";     genGenPointerSet",""));
9467
9468   aopOp (result, ic, FALSE);
9469   loadDptrFromOperand (result, TRUE);
9470
9471   /* so dptr know contains the address */
9472   aopOp (right, ic, FALSE);
9473
9474   /* if bit then unpack */
9475   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9476     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9477   else
9478     {
9479       size = AOP_SIZE (right);
9480       offset = 0;
9481
9482       while (size--)
9483         {
9484           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9485           MOVA (l);
9486           emitcode ("lcall", "__gptrput");
9487           if (size || pi)
9488             emitcode ("inc", "dptr");
9489         }
9490     }
9491
9492   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9493     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9494     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9495     pi->generated=1;
9496   }
9497   freeAsmop (result, NULL, ic, TRUE);
9498   freeAsmop (right, NULL, ic, TRUE);
9499 }
9500
9501 /*-----------------------------------------------------------------*/
9502 /* genPointerSet - stores the value into a pointer location        */
9503 /*-----------------------------------------------------------------*/
9504 static void
9505 genPointerSet (iCode * ic, iCode *pi)
9506 {
9507   operand *right, *result;
9508   sym_link *type, *etype;
9509   int p_type;
9510
9511   D(emitcode (";     genPointerSet",""));
9512
9513   right = IC_RIGHT (ic);
9514   result = IC_RESULT (ic);
9515
9516   /* depending on the type of pointer we need to
9517      move it to the correct pointer register */
9518   type = operandType (result);
9519   etype = getSpec (type);
9520   /* if left is of type of pointer then it is simple */
9521   if (IS_PTR (type) && !IS_FUNC (type->next))
9522     {
9523       p_type = DCL_TYPE (type);
9524     }
9525   else
9526     {
9527       /* we have to go by the storage class */
9528       p_type = PTR_TYPE (SPEC_OCLS (etype));
9529     }
9530
9531   /* special case when cast remat */
9532   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9533       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9534           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9535           type = operandType (result);
9536           p_type = DCL_TYPE (type);
9537   }
9538   /* now that we have the pointer type we assign
9539      the pointer values */
9540   switch (p_type)
9541     {
9542
9543     case POINTER:
9544     case IPOINTER:
9545       genNearPointerSet (right, result, ic, pi);
9546       break;
9547
9548     case PPOINTER:
9549       genPagedPointerSet (right, result, ic, pi);
9550       break;
9551
9552     case FPOINTER:
9553       genFarPointerSet (right, result, ic, pi);
9554       break;
9555
9556     case GPOINTER:
9557       genGenPointerSet (right, result, ic, pi);
9558       break;
9559
9560     default:
9561       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9562               "genPointerSet: illegal pointer type");
9563     }
9564
9565 }
9566
9567 /*-----------------------------------------------------------------*/
9568 /* genIfx - generate code for Ifx statement                        */
9569 /*-----------------------------------------------------------------*/
9570 static void
9571 genIfx (iCode * ic, iCode * popIc)
9572 {
9573   operand *cond = IC_COND (ic);
9574   int isbit = 0;
9575
9576   D(emitcode (";     genIfx",""));
9577
9578   aopOp (cond, ic, FALSE);
9579
9580   /* get the value into acc */
9581   if (AOP_TYPE (cond) != AOP_CRY)
9582     toBoolean (cond);
9583   else
9584     isbit = 1;
9585   /* the result is now in the accumulator */
9586   freeAsmop (cond, NULL, ic, TRUE);
9587
9588   /* if there was something to be popped then do it */
9589   if (popIc)
9590     genIpop (popIc);
9591
9592   /* if the condition is a bit variable */
9593   if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
9594     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9595   else if (isbit && !IS_ITEMP (cond))
9596     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9597   else
9598     genIfxJump (ic, "a", NULL, NULL, NULL);
9599
9600   ic->generated = 1;
9601 }
9602
9603 /*-----------------------------------------------------------------*/
9604 /* genAddrOf - generates code for address of                       */
9605 /*-----------------------------------------------------------------*/
9606 static void
9607 genAddrOf (iCode * ic)
9608 {
9609   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9610   int size, offset;
9611
9612   D(emitcode (";     genAddrOf",""));
9613
9614   aopOp (IC_RESULT (ic), ic, FALSE);
9615
9616   /* if the operand is on the stack then we
9617      need to get the stack offset of this
9618      variable */
9619   if (sym->onStack)
9620     {
9621       /* if it has an offset then we need to compute
9622          it */
9623       if (sym->stack)
9624         {
9625           emitcode ("mov", "a,%s", SYM_BP (sym));
9626           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9627                                          ((char) (sym->stack - _G.nRegsSaved)) :
9628                                          ((char) sym->stack)) & 0xff);
9629           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9630         }
9631       else
9632         {
9633           /* we can just move _bp */
9634           aopPut (AOP (IC_RESULT (ic)), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9635         }
9636       /* fill the result with zero */
9637       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9638
9639       offset = 1;
9640       while (size--)
9641         {
9642           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9643         }
9644
9645       goto release;
9646     }
9647
9648   /* object not on stack then we need the name */
9649   size = AOP_SIZE (IC_RESULT (ic));
9650   offset = 0;
9651
9652   while (size--)
9653     {
9654       char s[SDCC_NAME_MAX];
9655       if (offset)
9656         sprintf (s, "#(%s >> %d)",
9657                  sym->rname,
9658                  offset * 8);
9659       else
9660         sprintf (s, "#%s", sym->rname);
9661       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9662     }
9663
9664 release:
9665   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9666
9667 }
9668
9669 /*-----------------------------------------------------------------*/
9670 /* genFarFarAssign - assignment when both are in far space         */
9671 /*-----------------------------------------------------------------*/
9672 static void
9673 genFarFarAssign (operand * result, operand * right, iCode * ic)
9674 {
9675   int size = AOP_SIZE (right);
9676   int offset = 0;
9677   char *l;
9678
9679   D(emitcode (";     genFarFarAssign",""));
9680
9681   /* first push the right side on to the stack */
9682   while (size--)
9683     {
9684       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9685       MOVA (l);
9686       emitcode ("push", "acc");
9687     }
9688
9689   freeAsmop (right, NULL, ic, FALSE);
9690   /* now assign DPTR to result */
9691   aopOp (result, ic, FALSE);
9692   size = AOP_SIZE (result);
9693   while (size--)
9694     {
9695       emitcode ("pop", "acc");
9696       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9697     }
9698   freeAsmop (result, NULL, ic, FALSE);
9699
9700 }
9701
9702 /*-----------------------------------------------------------------*/
9703 /* genAssign - generate code for assignment                        */
9704 /*-----------------------------------------------------------------*/
9705 static void
9706 genAssign (iCode * ic)
9707 {
9708   operand *result, *right;
9709   int size, offset;
9710   unsigned long lit = 0L;
9711
9712   D(emitcode(";     genAssign",""));
9713
9714   result = IC_RESULT (ic);
9715   right = IC_RIGHT (ic);
9716
9717   /* if they are the same */
9718   if (operandsEqu (result, right) &&
9719       !isOperandVolatile (result, FALSE) &&
9720       !isOperandVolatile (right, FALSE))
9721     return;
9722
9723   aopOp (right, ic, FALSE);
9724
9725   /* special case both in far space */
9726   if (AOP_TYPE (right) == AOP_DPTR &&
9727       IS_TRUE_SYMOP (result) &&
9728       isOperandInFarSpace (result))
9729     {
9730
9731       genFarFarAssign (result, right, ic);
9732       return;
9733     }
9734
9735   aopOp (result, ic, TRUE);
9736
9737   /* if they are the same registers */
9738   if (sameRegs (AOP (right), AOP (result)) &&
9739       !isOperandVolatile (result, FALSE) &&
9740       !isOperandVolatile (right, FALSE))
9741     goto release;
9742
9743   /* if the result is a bit */
9744   if (AOP_TYPE (result) == AOP_CRY)
9745     {
9746
9747       /* if the right size is a literal then
9748          we know what the value is */
9749       if (AOP_TYPE (right) == AOP_LIT)
9750         {
9751           if (((int) operandLitValue (right)))
9752             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9753           else
9754             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9755           goto release;
9756         }
9757
9758       /* the right is also a bit variable */
9759       if (AOP_TYPE (right) == AOP_CRY)
9760         {
9761           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9762           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9763           goto release;
9764         }
9765
9766       /* we need to or */
9767       toBoolean (right);
9768       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9769       goto release;
9770     }
9771
9772   /* bit variables done */
9773   /* general case */
9774   size = AOP_SIZE (result);
9775   offset = 0;
9776   if (AOP_TYPE (right) == AOP_LIT)
9777     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9778   if ((size > 1) &&
9779       (AOP_TYPE (result) != AOP_REG) &&
9780       (AOP_TYPE (right) == AOP_LIT) &&
9781       !IS_FLOAT (operandType (right)) &&
9782       (lit < 256L))
9783     {
9784       while ((size) && (lit))
9785         {
9786           aopPut (AOP (result),
9787                   aopGet (AOP (right), offset, FALSE, FALSE),
9788                   offset,
9789                   isOperandVolatile (result, FALSE));
9790           lit >>= 8;
9791           offset++;
9792           size--;
9793         }
9794       emitcode ("clr", "a");
9795       while (size--)
9796         {
9797           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
9798           offset++;
9799         }
9800     }
9801   else
9802     {
9803       while (size--)
9804         {
9805           aopPut (AOP (result),
9806                   aopGet (AOP (right), offset, FALSE, FALSE),
9807                   offset,
9808                   isOperandVolatile (result, FALSE));
9809           offset++;
9810         }
9811     }
9812
9813 release:
9814   freeAsmop (right, NULL, ic, TRUE);
9815   freeAsmop (result, NULL, ic, TRUE);
9816 }
9817
9818 /*-----------------------------------------------------------------*/
9819 /* genJumpTab - generates code for jump table                      */
9820 /*-----------------------------------------------------------------*/
9821 static void
9822 genJumpTab (iCode * ic)
9823 {
9824   symbol *jtab,*jtablo,*jtabhi;
9825   char *l;
9826   unsigned int count;
9827
9828   D(emitcode (";     genJumpTab",""));
9829
9830   count = elementsInSet( IC_JTLABELS (ic) );
9831
9832   if( count <= 16 )
9833     {
9834       /* this algorithm needs 9 cycles and 7 + 3*n bytes
9835          if the switch argument is in a register.
9836          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
9837       /* (MB) What if peephole converts ljmp to sjmp or ret ???
9838          How will multiply by three be updated ???*/
9839       aopOp (IC_JTCOND (ic), ic, FALSE);
9840       /* get the condition into accumulator */
9841       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9842       MOVA (l);
9843       /* multiply by three */
9844       emitcode ("add", "a,acc");
9845       emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9846       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9847
9848       jtab = newiTempLabel (NULL);
9849       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9850       emitcode ("jmp", "@a+dptr");
9851       emitcode ("", "%05d$:", jtab->key + 100);
9852       /* now generate the jump labels */
9853       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9854            jtab = setNextItem (IC_JTLABELS (ic)))
9855         emitcode ("ljmp", "%05d$", jtab->key + 100);
9856     }
9857   else
9858     {
9859       /* this algorithm needs 14 cycles and 13 + 2*n bytes
9860          if the switch argument is in a register.
9861          For n>6 this algorithm may be more compact */
9862       jtablo = newiTempLabel (NULL);
9863       jtabhi = newiTempLabel (NULL);
9864
9865       /* get the condition into accumulator.
9866          Using b as temporary storage, if register push/pop is needed */
9867       aopOp (IC_JTCOND (ic), ic, FALSE);
9868       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9869       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
9870           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
9871         {
9872           // (MB) what if B is in use???
9873           wassertl(!BINUSE, "B was in use");
9874           emitcode ("mov", "b,%s", l);
9875           l = "b";
9876         }
9877       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9878       MOVA (l);
9879       if( count <= 112 )
9880         {
9881           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
9882           emitcode ("movc", "a,@a+pc");
9883           emitcode ("push", "acc");
9884
9885           MOVA (l);
9886           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
9887           emitcode ("movc", "a,@a+pc");
9888           emitcode ("push", "acc");
9889         }
9890       else
9891         {
9892           /* this scales up to n<=255, but needs two more bytes
9893              and changes dptr */
9894           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
9895           emitcode ("movc", "a,@a+dptr");
9896           emitcode ("push", "acc");
9897
9898           MOVA (l);
9899           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
9900           emitcode ("movc", "a,@a+dptr");
9901           emitcode ("push", "acc");
9902         }
9903
9904       emitcode ("ret", "");
9905
9906       /* now generate jump table, LSB */
9907       emitcode ("", "%05d$:", jtablo->key + 100);
9908       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9909            jtab = setNextItem (IC_JTLABELS (ic)))
9910         emitcode (".db", "%05d$", jtab->key + 100);
9911
9912       /* now generate jump table, MSB */
9913       emitcode ("", "%05d$:", jtabhi->key + 100);
9914       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9915            jtab = setNextItem (IC_JTLABELS (ic)))
9916          emitcode (".db", "%05d$>>8", jtab->key + 100);
9917     }
9918 }
9919
9920 /*-----------------------------------------------------------------*/
9921 /* genCast - gen code for casting                                  */
9922 /*-----------------------------------------------------------------*/
9923 static void
9924 genCast (iCode * ic)
9925 {
9926   operand *result = IC_RESULT (ic);
9927   sym_link *ctype = operandType (IC_LEFT (ic));
9928   sym_link *rtype = operandType (IC_RIGHT (ic));
9929   operand *right = IC_RIGHT (ic);
9930   int size, offset;
9931
9932   D(emitcode(";     genCast",""));
9933
9934   /* if they are equivalent then do nothing */
9935   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9936     return;
9937
9938   aopOp (right, ic, FALSE);
9939   aopOp (result, ic, FALSE);
9940
9941   /* if the result is a bit (and not a bitfield) */
9942   // if (AOP_TYPE (result) == AOP_CRY)
9943   if (IS_BITVAR (OP_SYMBOL (result)->type)
9944       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
9945     {
9946       /* if the right size is a literal then
9947          we know what the value is */
9948       if (AOP_TYPE (right) == AOP_LIT)
9949         {
9950           if (((int) operandLitValue (right)))
9951             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9952           else
9953             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9954
9955           goto release;
9956         }
9957
9958       /* the right is also a bit variable */
9959       if (AOP_TYPE (right) == AOP_CRY)
9960         {
9961           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9962           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9963           goto release;
9964         }
9965
9966       /* we need to or */
9967       toBoolean (right);
9968       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9969       goto release;
9970     }
9971
9972
9973   /* if they are the same size : or less */
9974   if (AOP_SIZE (result) <= AOP_SIZE (right))
9975     {
9976
9977       /* if they are in the same place */
9978       if (sameRegs (AOP (right), AOP (result)))
9979         goto release;
9980
9981       /* if they in different places then copy */
9982       size = AOP_SIZE (result);
9983       offset = 0;
9984       while (size--)
9985         {
9986           aopPut (AOP (result),
9987                   aopGet (AOP (right), offset, FALSE, FALSE),
9988                   offset,
9989                   isOperandVolatile (result, FALSE));
9990           offset++;
9991         }
9992       goto release;
9993     }
9994
9995
9996   /* if the result is of type pointer */
9997   if (IS_PTR (ctype))
9998     {
9999
10000       int p_type;
10001       sym_link *type = operandType (right);
10002       sym_link *etype = getSpec (type);
10003
10004       /* pointer to generic pointer */
10005       if (IS_GENPTR (ctype))
10006         {
10007           if (IS_PTR (type))
10008             p_type = DCL_TYPE (type);
10009           else
10010             {
10011               if (SPEC_SCLS(etype)==S_REGISTER) {
10012                 // let's assume it is a generic pointer
10013                 p_type=GPOINTER;
10014               } else {
10015                 /* we have to go by the storage class */
10016                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10017               }
10018             }
10019
10020           /* the first two bytes are known */
10021           size = GPTRSIZE - 1;
10022           offset = 0;
10023           while (size--)
10024             {
10025               aopPut (AOP (result),
10026                       aopGet (AOP (right), offset, FALSE, FALSE),
10027                       offset,
10028                       isOperandVolatile (result, FALSE));
10029               offset++;
10030             }
10031           /* the last byte depending on type */
10032             {
10033                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10034                 char gpValStr[10];
10035
10036                 if (gpVal == -1)
10037                 {
10038                     // pointerTypeToGPByte will have bitched.
10039                     exit(1);
10040                 }
10041
10042                 sprintf(gpValStr, "#0x%d", gpVal);
10043                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10044             }
10045           goto release;
10046         }
10047
10048       /* just copy the pointers */
10049       size = AOP_SIZE (result);
10050       offset = 0;
10051       while (size--)
10052         {
10053           aopPut (AOP (result),
10054                   aopGet (AOP (right), offset, FALSE, FALSE),
10055                   offset,
10056                   isOperandVolatile (result, FALSE));
10057           offset++;
10058         }
10059       goto release;
10060     }
10061
10062   /* so we now know that the size of destination is greater
10063      than the size of the source */
10064   /* we move to result for the size of source */
10065   size = AOP_SIZE (right);
10066   offset = 0;
10067   while (size--)
10068     {
10069       aopPut (AOP (result),
10070               aopGet (AOP (right), offset, FALSE, FALSE),
10071               offset,
10072               isOperandVolatile (result, FALSE));
10073       offset++;
10074     }
10075
10076   /* now depending on the sign of the source && destination */
10077   size = AOP_SIZE (result) - AOP_SIZE (right);
10078   /* if unsigned or not an integral type */
10079   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10080     {
10081       while (size--)
10082         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
10083     }
10084   else
10085     {
10086       /* we need to extend the sign :{ */
10087       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
10088                         FALSE, FALSE);
10089       MOVA (l);
10090       emitcode ("rlc", "a");
10091       emitcode ("subb", "a,acc");
10092       while (size--)
10093         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
10094     }
10095
10096   /* we are done hurray !!!! */
10097
10098 release:
10099   freeAsmop (right, NULL, ic, TRUE);
10100   freeAsmop (result, NULL, ic, TRUE);
10101
10102 }
10103
10104 /*-----------------------------------------------------------------*/
10105 /* genDjnz - generate decrement & jump if not zero instrucion      */
10106 /*-----------------------------------------------------------------*/
10107 static int
10108 genDjnz (iCode * ic, iCode * ifx)
10109 {
10110   symbol *lbl, *lbl1;
10111   if (!ifx)
10112     return 0;
10113
10114   D(emitcode (";     genDjnz",""));
10115
10116   /* if the if condition has a false label
10117      then we cannot save */
10118   if (IC_FALSE (ifx))
10119     return 0;
10120
10121   /* if the minus is not of the form
10122      a = a - 1 */
10123   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10124       !IS_OP_LITERAL (IC_RIGHT (ic)))
10125     return 0;
10126
10127   if (operandLitValue (IC_RIGHT (ic)) != 1)
10128     return 0;
10129
10130   /* if the size of this greater than one then no
10131      saving */
10132   if (getSize (operandType (IC_RESULT (ic))) > 1)
10133     return 0;
10134
10135   /* otherwise we can save BIG */
10136   lbl = newiTempLabel (NULL);
10137   lbl1 = newiTempLabel (NULL);
10138
10139   aopOp (IC_RESULT (ic), ic, FALSE);
10140
10141   if (AOP_NEEDSACC(IC_RESULT(ic)))
10142   {
10143       /* If the result is accessed indirectly via
10144        * the accumulator, we must explicitly write
10145        * it back after the decrement.
10146        */
10147       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
10148
10149       if (strcmp(rByte, "a"))
10150       {
10151            /* Something is hopelessly wrong */
10152            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10153                    __FILE__, __LINE__);
10154            /* We can just give up; the generated code will be inefficient,
10155             * but what the hey.
10156             */
10157            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10158            return 0;
10159       }
10160       emitcode ("dec", "%s", rByte);
10161       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10162       emitcode ("jnz", "%05d$", lbl->key + 100);
10163   }
10164   else if (IS_AOP_PREG (IC_RESULT (ic)))
10165     {
10166       emitcode ("dec", "%s",
10167                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
10168       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
10169       emitcode ("jnz", "%05d$", lbl->key + 100);
10170     }
10171   else
10172     {
10173       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
10174                 lbl->key + 100);
10175     }
10176   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10177   emitcode ("", "%05d$:", lbl->key + 100);
10178   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10179   emitcode ("", "%05d$:", lbl1->key + 100);
10180
10181   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10182   ifx->generated = 1;
10183   return 1;
10184 }
10185
10186 /*-----------------------------------------------------------------*/
10187 /* genReceive - generate code for a receive iCode                  */
10188 /*-----------------------------------------------------------------*/
10189 static void
10190 genReceive (iCode * ic)
10191 {
10192     int size = getSize (operandType (IC_RESULT (ic)));
10193     int offset = 0;
10194   D(emitcode (";     genReceive",""));
10195
10196   if (ic->argreg == 1) { /* first parameter */
10197       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10198           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10199            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
10200
10201           regs *tempRegs[4];
10202           int receivingA = 0;
10203           int roffset = 0;
10204
10205           for (offset = 0; offset<size; offset++)
10206             if (!strcmp (fReturn[offset], "a"))
10207               receivingA = 1;
10208
10209           if (!receivingA)
10210             {
10211               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10212                 {
10213                   for (offset = size-1; offset>0; offset--)
10214                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10215                   emitcode("mov","a,%s", fReturn[0]);
10216                   _G.accInUse++;
10217                   aopOp (IC_RESULT (ic), ic, FALSE);
10218                   _G.accInUse--;
10219                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
10220                           isOperandVolatile (IC_RESULT (ic), FALSE));
10221                   for (offset = 1; offset<size; offset++)
10222                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
10223                             isOperandVolatile (IC_RESULT (ic), FALSE));
10224                   goto release;
10225                 }
10226             }
10227           else
10228             {
10229               if (getTempRegs(tempRegs, size, ic))
10230                 {
10231                   for (offset = 0; offset<size; offset++)
10232                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10233                   aopOp (IC_RESULT (ic), ic, FALSE);
10234                   for (offset = 0; offset<size; offset++)
10235                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
10236                             isOperandVolatile (IC_RESULT (ic), FALSE));
10237                   goto release;
10238                 }
10239             }
10240
10241           offset = fReturnSizeMCS51 - size;
10242           while (size--) {
10243               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10244                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10245               offset++;
10246           }
10247           aopOp (IC_RESULT (ic), ic, FALSE);
10248           size = AOP_SIZE (IC_RESULT (ic));
10249           offset = 0;
10250           while (size--) {
10251               emitcode ("pop", "acc");
10252               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10253           }
10254
10255       } else {
10256           _G.accInUse++;
10257           aopOp (IC_RESULT (ic), ic, FALSE);
10258           _G.accInUse--;
10259           assignResultValue (IC_RESULT (ic));
10260       }
10261   } else { /* second receive onwards */
10262       int rb1off ;
10263       aopOp (IC_RESULT (ic), ic, FALSE);
10264       rb1off = ic->argreg;
10265       while (size--) {
10266           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10267       }
10268   }
10269
10270 release:
10271   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10272 }
10273
10274 /*-----------------------------------------------------------------*/
10275 /* genDummyRead - generate code for dummy read of volatiles        */
10276 /*-----------------------------------------------------------------*/
10277 static void
10278 genDummyRead (iCode * ic)
10279 {
10280   operand *op;
10281   int size, offset;
10282
10283   D(emitcode(";     genDummyRead",""));
10284
10285   op = IC_RIGHT (ic);
10286   if (op && IS_SYMOP (op))
10287     {
10288       aopOp (op, ic, FALSE);
10289
10290       /* if the result is a bit */
10291       if (AOP_TYPE (op) == AOP_CRY)
10292         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10293       else
10294         {
10295           /* bit variables done */
10296           /* general case */
10297           size = AOP_SIZE (op);
10298           offset = 0;
10299           while (size--)
10300           {
10301             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10302             offset++;
10303           }
10304         }
10305
10306       freeAsmop (op, NULL, ic, TRUE);
10307     }
10308
10309   op = IC_LEFT (ic);
10310   if (op && IS_SYMOP (op))
10311     {
10312       aopOp (op, ic, FALSE);
10313
10314       /* if the result is a bit */
10315       if (AOP_TYPE (op) == AOP_CRY)
10316         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10317       else
10318         {
10319           /* bit variables done */
10320           /* general case */
10321           size = AOP_SIZE (op);
10322           offset = 0;
10323           while (size--)
10324           {
10325             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10326             offset++;
10327           }
10328         }
10329
10330       freeAsmop (op, NULL, ic, TRUE);
10331     }
10332 }
10333
10334 /*-----------------------------------------------------------------*/
10335 /* genCritical - generate code for start of a critical sequence    */
10336 /*-----------------------------------------------------------------*/
10337 static void
10338 genCritical (iCode *ic)
10339 {
10340   symbol *tlbl = newiTempLabel (NULL);
10341
10342   D(emitcode(";     genCritical",""));
10343
10344   if (IC_RESULT (ic))
10345     {
10346       aopOp (IC_RESULT (ic), ic, TRUE);
10347       aopPut (AOP (IC_RESULT (ic)), one, 0, 0);
10348       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10349       aopPut (AOP (IC_RESULT (ic)), zero, 0, 0);
10350       emitcode ("", "%05d$:", (tlbl->key + 100));
10351       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10352     }
10353   else
10354     {
10355       emitcode ("setb", "c");
10356       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10357       emitcode ("clr", "c");
10358       emitcode ("", "%05d$:", (tlbl->key + 100));
10359       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10360     }
10361 }
10362
10363 /*-----------------------------------------------------------------*/
10364 /* genEndCritical - generate code for end of a critical sequence   */
10365 /*-----------------------------------------------------------------*/
10366 static void
10367 genEndCritical (iCode *ic)
10368 {
10369   D(emitcode(";     genEndCritical",""));
10370
10371   if (IC_RIGHT (ic))
10372     {
10373       aopOp (IC_RIGHT (ic), ic, FALSE);
10374       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10375         {
10376           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10377           emitcode ("mov", "ea,c");
10378         }
10379       else
10380         {
10381           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10382             MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
10383           emitcode ("rrc", "a");
10384           emitcode ("mov", "ea,c");
10385         }
10386       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10387     }
10388   else
10389     {
10390       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10391       emitcode ("mov", "ea,c");
10392     }
10393 }
10394
10395 /*-----------------------------------------------------------------*/
10396 /* gen51Code - generate code for 8051 based controllers            */
10397 /*-----------------------------------------------------------------*/
10398 void
10399 gen51Code (iCode * lic)
10400 {
10401   iCode *ic;
10402   int cln = 0;
10403   /* int cseq = 0; */
10404
10405   _G.currentFunc = NULL;
10406   lineHead = lineCurr = NULL;
10407
10408   /* print the allocation information */
10409   if (allocInfo && currFunc)
10410     printAllocInfo (currFunc, codeOutFile);
10411   /* if debug information required */
10412   if (options.debug && currFunc)
10413     {
10414       debugFile->writeFunction (currFunc, lic);
10415     }
10416   /* stack pointer name */
10417   if (options.useXstack)
10418     spname = "_spx";
10419   else
10420     spname = "sp";
10421
10422
10423   for (ic = lic; ic; ic = ic->next)
10424     {
10425       _G.current_iCode = ic;
10426
10427       if (ic->lineno && cln != ic->lineno)
10428         {
10429           if (options.debug)
10430             {
10431               debugFile->writeCLine (ic);
10432             }
10433           if (!options.noCcodeInAsm) {
10434             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10435                       printCLine(ic->filename, ic->lineno));
10436           }
10437           cln = ic->lineno;
10438         }
10439       #if 0
10440       if (ic->seqPoint && ic->seqPoint != cseq)
10441         {
10442           emitcode ("", "; sequence point %d", ic->seqPoint);
10443           cseq = ic->seqPoint;
10444         }
10445       #endif
10446       if (options.iCodeInAsm) {
10447         char regsInUse[80];
10448         int i;
10449
10450         for (i=0; i<8; i++) {
10451           sprintf (&regsInUse[i],
10452                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10453         }
10454         regsInUse[i]=0;
10455         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10456       }
10457       /* if the result is marked as
10458          spilt and rematerializable or code for
10459          this has already been generated then
10460          do nothing */
10461       if (resultRemat (ic) || ic->generated)
10462         continue;
10463
10464       /* depending on the operation */
10465       switch (ic->op)
10466         {
10467         case '!':
10468           genNot (ic);
10469           break;
10470
10471         case '~':
10472           genCpl (ic);
10473           break;
10474
10475         case UNARYMINUS:
10476           genUminus (ic);
10477           break;
10478
10479         case IPUSH:
10480           genIpush (ic);
10481           break;
10482
10483         case IPOP:
10484           /* IPOP happens only when trying to restore a
10485              spilt live range, if there is an ifx statement
10486              following this pop then the if statement might
10487              be using some of the registers being popped which
10488              would destory the contents of the register so
10489              we need to check for this condition and handle it */
10490           if (ic->next &&
10491               ic->next->op == IFX &&
10492               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10493             genIfx (ic->next, ic);
10494           else
10495             genIpop (ic);
10496           break;
10497
10498         case CALL:
10499           genCall (ic);
10500           break;
10501
10502         case PCALL:
10503           genPcall (ic);
10504           break;
10505
10506         case FUNCTION:
10507           genFunction (ic);
10508           break;
10509
10510         case ENDFUNCTION:
10511           genEndFunction (ic);
10512           break;
10513
10514         case RETURN:
10515           genRet (ic);
10516           break;
10517
10518         case LABEL:
10519           genLabel (ic);
10520           break;
10521
10522         case GOTO:
10523           genGoto (ic);
10524           break;
10525
10526         case '+':
10527           genPlus (ic);
10528           break;
10529
10530         case '-':
10531           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10532             genMinus (ic);
10533           break;
10534
10535         case '*':
10536           genMult (ic);
10537           break;
10538
10539         case '/':
10540           genDiv (ic);
10541           break;
10542
10543         case '%':
10544           genMod (ic);
10545           break;
10546
10547         case '>':
10548           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10549           break;
10550
10551         case '<':
10552           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10553           break;
10554
10555         case LE_OP:
10556         case GE_OP:
10557         case NE_OP:
10558
10559           /* note these two are xlated by algebraic equivalence
10560              during parsing SDCC.y */
10561           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10562                   "got '>=' or '<=' shouldn't have come here");
10563           break;
10564
10565         case EQ_OP:
10566           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10567           break;
10568
10569         case AND_OP:
10570           genAndOp (ic);
10571           break;
10572
10573         case OR_OP:
10574           genOrOp (ic);
10575           break;
10576
10577         case '^':
10578           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10579           break;
10580
10581         case '|':
10582           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10583           break;
10584
10585         case BITWISEAND:
10586           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10587           break;
10588
10589         case INLINEASM:
10590           genInline (ic);
10591           break;
10592
10593         case RRC:
10594           genRRC (ic);
10595           break;
10596
10597         case RLC:
10598           genRLC (ic);
10599           break;
10600
10601         case GETHBIT:
10602           genGetHbit (ic);
10603           break;
10604
10605         case LEFT_OP:
10606           genLeftShift (ic);
10607           break;
10608
10609         case RIGHT_OP:
10610           genRightShift (ic);
10611           break;
10612
10613         case GET_VALUE_AT_ADDRESS:
10614           genPointerGet (ic,
10615                          hasInc (IC_LEFT (ic), ic,
10616                                  getSize (operandType (IC_RESULT (ic)))),
10617                          ifxForOp (IC_RESULT (ic), ic) );
10618           break;
10619
10620         case '=':
10621           if (POINTER_SET (ic))
10622             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10623           else
10624             genAssign (ic);
10625           break;
10626
10627         case IFX:
10628           genIfx (ic, NULL);
10629           break;
10630
10631         case ADDRESS_OF:
10632           genAddrOf (ic);
10633           break;
10634
10635         case JUMPTABLE:
10636           genJumpTab (ic);
10637           break;
10638
10639         case CAST:
10640           genCast (ic);
10641           break;
10642
10643         case RECEIVE:
10644           genReceive (ic);
10645           break;
10646
10647         case SEND:
10648           addSet (&_G.sendSet, ic);
10649           break;
10650
10651         case DUMMY_READ_VOLATILE:
10652           genDummyRead (ic);
10653           break;
10654
10655         case CRITICAL:
10656           genCritical (ic);
10657           break;
10658
10659         case ENDCRITICAL:
10660           genEndCritical (ic);
10661           break;
10662
10663         case SWAP:
10664           genSwap (ic);
10665           break;
10666
10667         default:
10668           ic = ic;
10669         }
10670     }
10671
10672   _G.current_iCode = NULL;
10673
10674   /* now we are ready to call the
10675      peep hole optimizer */
10676   if (!options.nopeep)
10677     peepHole (&lineHead);
10678
10679   /* now do the actual printing */
10680   printLine (lineHead, codeOutFile);
10681   return;
10682 }