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